forked from M-Labs/nac3
[core] Add IdentifierInfo
Keeps track of whether an identifier refers to a global or local variable.
This commit is contained in:
parent
1407553a2f
commit
192290889b
@ -28,7 +28,7 @@ use crate::{
|
|||||||
DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
|
DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
|
||||||
},
|
},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::{FunctionData, Inferencer, PrimitiveStore},
|
type_inferencer::{FunctionData, IdentifierInfo, Inferencer, PrimitiveStore},
|
||||||
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
|
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -141,7 +141,8 @@ fn test_primitives() {
|
|||||||
};
|
};
|
||||||
let mut virtual_checks = Vec::new();
|
let mut virtual_checks = Vec::new();
|
||||||
let mut calls = HashMap::new();
|
let mut calls = HashMap::new();
|
||||||
let mut identifiers: HashSet<_> = ["a".into(), "b".into()].into();
|
let mut identifiers: HashMap<_, _> =
|
||||||
|
["a".into(), "b".into()].map(|id| (id, IdentifierInfo::default())).into();
|
||||||
let mut inferencer = Inferencer {
|
let mut inferencer = Inferencer {
|
||||||
top_level: &top_level,
|
top_level: &top_level,
|
||||||
function_data: &mut function_data,
|
function_data: &mut function_data,
|
||||||
@ -320,7 +321,8 @@ fn test_simple_call() {
|
|||||||
};
|
};
|
||||||
let mut virtual_checks = Vec::new();
|
let mut virtual_checks = Vec::new();
|
||||||
let mut calls = HashMap::new();
|
let mut calls = HashMap::new();
|
||||||
let mut identifiers: HashSet<_> = ["a".into(), "foo".into()].into();
|
let mut identifiers: HashMap<_, _> =
|
||||||
|
["a".into(), "foo".into()].map(|id| (id, IdentifierInfo::default())).into();
|
||||||
let mut inferencer = Inferencer {
|
let mut inferencer = Inferencer {
|
||||||
top_level: &top_level,
|
top_level: &top_level,
|
||||||
function_data: &mut function_data,
|
function_data: &mut function_data,
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
codegen::{expr::get_subst_key, stmt::exn_constructor},
|
codegen::{expr::get_subst_key, stmt::exn_constructor},
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::{FunctionData, Inferencer},
|
type_inferencer::{FunctionData, IdentifierInfo, Inferencer},
|
||||||
typedef::{TypeVar, VarMap},
|
typedef::{TypeVar, VarMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -2057,11 +2057,12 @@ impl TopLevelComposer {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
let mut identifiers = {
|
let mut identifiers = {
|
||||||
let mut result: HashSet<_> = HashSet::new();
|
let mut result = HashMap::new();
|
||||||
if self_type.is_some() {
|
if self_type.is_some() {
|
||||||
result.insert("self".into());
|
result.insert("self".into(), IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
result.extend(inst_args.iter().map(|x| x.name));
|
result
|
||||||
|
.extend(inst_args.iter().map(|x| (x.name, IdentifierInfo::default())));
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
let mut calls: HashMap<CodeLocation, CallId> = HashMap::new();
|
let mut calls: HashMap<CodeLocation, CallId> = HashMap::new();
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use std::{collections::HashSet, iter::once};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
iter::once,
|
||||||
|
};
|
||||||
|
|
||||||
use nac3parser::ast::{
|
use nac3parser::ast::{
|
||||||
self, Constant, Expr, ExprKind,
|
self, Constant, Expr, ExprKind,
|
||||||
@ -7,7 +10,7 @@ use nac3parser::ast::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
type_inferencer::Inferencer,
|
type_inferencer::{IdentifierInfo, Inferencer},
|
||||||
typedef::{Type, TypeEnum},
|
typedef::{Type, TypeEnum},
|
||||||
};
|
};
|
||||||
use crate::toplevel::helper::PrimDef;
|
use crate::toplevel::helper::PrimDef;
|
||||||
@ -24,15 +27,15 @@ impl<'a> Inferencer<'a> {
|
|||||||
fn check_pattern(
|
fn check_pattern(
|
||||||
&mut self,
|
&mut self,
|
||||||
pattern: &Expr<Option<Type>>,
|
pattern: &Expr<Option<Type>>,
|
||||||
defined_identifiers: &mut HashSet<StrRef>,
|
defined_identifiers: &mut HashMap<StrRef, IdentifierInfo>,
|
||||||
) -> Result<(), HashSet<String>> {
|
) -> Result<(), HashSet<String>> {
|
||||||
match &pattern.node {
|
match &pattern.node {
|
||||||
ExprKind::Name { id, .. } if id == &"none".into() => {
|
ExprKind::Name { id, .. } if id == &"none".into() => {
|
||||||
Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)]))
|
Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)]))
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
if !defined_identifiers.contains(id) {
|
if !defined_identifiers.contains_key(id) {
|
||||||
defined_identifiers.insert(*id);
|
defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
self.should_have_value(pattern)?;
|
self.should_have_value(pattern)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -72,7 +75,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
fn check_expr(
|
fn check_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
defined_identifiers: &mut HashSet<StrRef>,
|
defined_identifiers: &mut HashMap<StrRef, IdentifierInfo>,
|
||||||
) -> Result<(), HashSet<String>> {
|
) -> Result<(), HashSet<String>> {
|
||||||
// there are some cases where the custom field is None
|
// there are some cases where the custom field is None
|
||||||
if let Some(ty) = &expr.custom {
|
if let Some(ty) = &expr.custom {
|
||||||
@ -93,7 +96,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.should_have_value(expr)?;
|
self.should_have_value(expr)?;
|
||||||
if !defined_identifiers.contains(id) {
|
if !defined_identifiers.contains_key(id) {
|
||||||
match self.function_data.resolver.get_symbol_type(
|
match self.function_data.resolver.get_symbol_type(
|
||||||
self.unifier,
|
self.unifier,
|
||||||
&self.top_level.definitions.read(),
|
&self.top_level.definitions.read(),
|
||||||
@ -101,7 +104,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
*id,
|
*id,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.defined_identifiers.insert(*id);
|
self.defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
@ -174,9 +177,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
let mut defined_identifiers = defined_identifiers.clone();
|
let mut defined_identifiers = defined_identifiers.clone();
|
||||||
for arg in &args.args {
|
for arg in &args.args {
|
||||||
// TODO: should we check the types here?
|
// TODO: should we check the types here?
|
||||||
if !defined_identifiers.contains(&arg.node.arg) {
|
defined_identifiers.entry(arg.node.arg).or_default();
|
||||||
defined_identifiers.insert(arg.node.arg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.check_expr(body, &mut defined_identifiers)?;
|
self.check_expr(body, &mut defined_identifiers)?;
|
||||||
}
|
}
|
||||||
@ -239,7 +240,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
fn check_stmt(
|
fn check_stmt(
|
||||||
&mut self,
|
&mut self,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
defined_identifiers: &mut HashSet<StrRef>,
|
defined_identifiers: &mut HashMap<StrRef, IdentifierInfo>,
|
||||||
) -> Result<bool, HashSet<String>> {
|
) -> Result<bool, HashSet<String>> {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StmtKind::For { target, iter, body, orelse, .. } => {
|
StmtKind::For { target, iter, body, orelse, .. } => {
|
||||||
@ -265,9 +266,11 @@ impl<'a> Inferencer<'a> {
|
|||||||
let body_returned = self.check_block(body, &mut body_identifiers)?;
|
let body_returned = self.check_block(body, &mut body_identifiers)?;
|
||||||
let orelse_returned = self.check_block(orelse, &mut orelse_identifiers)?;
|
let orelse_returned = self.check_block(orelse, &mut orelse_identifiers)?;
|
||||||
|
|
||||||
for ident in &body_identifiers {
|
for ident in body_identifiers.keys() {
|
||||||
if !defined_identifiers.contains(ident) && orelse_identifiers.contains(ident) {
|
if !defined_identifiers.contains_key(ident)
|
||||||
defined_identifiers.insert(*ident);
|
&& orelse_identifiers.contains_key(ident)
|
||||||
|
{
|
||||||
|
defined_identifiers.insert(*ident, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(body_returned && orelse_returned)
|
Ok(body_returned && orelse_returned)
|
||||||
@ -298,7 +301,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
let mut defined_identifiers = defined_identifiers.clone();
|
let mut defined_identifiers = defined_identifiers.clone();
|
||||||
let ast::ExcepthandlerKind::ExceptHandler { name, body, .. } = &handler.node;
|
let ast::ExcepthandlerKind::ExceptHandler { name, body, .. } = &handler.node;
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
defined_identifiers.insert(*name);
|
defined_identifiers.insert(*name, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
self.check_block(body, &mut defined_identifiers)?;
|
self.check_block(body, &mut defined_identifiers)?;
|
||||||
}
|
}
|
||||||
@ -370,7 +373,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
pub fn check_block(
|
pub fn check_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &[Stmt<Option<Type>>],
|
block: &[Stmt<Option<Type>>],
|
||||||
defined_identifiers: &mut HashSet<StrRef>,
|
defined_identifiers: &mut HashMap<StrRef, IdentifierInfo>,
|
||||||
) -> Result<bool, HashSet<String>> {
|
) -> Result<bool, HashSet<String>> {
|
||||||
let mut ret = false;
|
let mut ret = false;
|
||||||
for stmt in block {
|
for stmt in block {
|
||||||
|
@ -88,6 +88,20 @@ impl PrimitiveStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information regarding a defined identifier.
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct IdentifierInfo {
|
||||||
|
/// Whether this identifier refers to a global variable.
|
||||||
|
pub is_global: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentifierInfo {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> IdentifierInfo {
|
||||||
|
IdentifierInfo::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FunctionData {
|
pub struct FunctionData {
|
||||||
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||||
pub return_type: Option<Type>,
|
pub return_type: Option<Type>,
|
||||||
@ -96,7 +110,7 @@ pub struct FunctionData {
|
|||||||
|
|
||||||
pub struct Inferencer<'a> {
|
pub struct Inferencer<'a> {
|
||||||
pub top_level: &'a TopLevelContext,
|
pub top_level: &'a TopLevelContext,
|
||||||
pub defined_identifiers: HashSet<StrRef>,
|
pub defined_identifiers: HashMap<StrRef, IdentifierInfo>,
|
||||||
pub function_data: &'a mut FunctionData,
|
pub function_data: &'a mut FunctionData,
|
||||||
pub unifier: &'a mut Unifier,
|
pub unifier: &'a mut Unifier,
|
||||||
pub primitives: &'a PrimitiveStore,
|
pub primitives: &'a PrimitiveStore,
|
||||||
@ -228,9 +242,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
|||||||
handler.location,
|
handler.location,
|
||||||
));
|
));
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
if !self.defined_identifiers.contains(&name) {
|
self.defined_identifiers.entry(name).or_default();
|
||||||
self.defined_identifiers.insert(name);
|
|
||||||
}
|
|
||||||
if let Some(old_typ) = self.variable_mapping.insert(name, typ) {
|
if let Some(old_typ) = self.variable_mapping.insert(name, typ) {
|
||||||
let loc = handler.location;
|
let loc = handler.location;
|
||||||
self.unifier.unify(old_typ, typ).map_err(|e| {
|
self.unifier.unify(old_typ, typ).map_err(|e| {
|
||||||
@ -553,7 +565,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
|||||||
unreachable!("must be tobj")
|
unreachable!("must be tobj")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !self.defined_identifiers.contains(id) {
|
if !self.defined_identifiers.contains_key(id) {
|
||||||
match self.function_data.resolver.get_symbol_type(
|
match self.function_data.resolver.get_symbol_type(
|
||||||
self.unifier,
|
self.unifier,
|
||||||
&self.top_level.definitions.read(),
|
&self.top_level.definitions.read(),
|
||||||
@ -561,7 +573,7 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
|||||||
*id,
|
*id,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.defined_identifiers.insert(*id);
|
self.defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return report_error(
|
return report_error(
|
||||||
@ -626,8 +638,8 @@ impl<'a> Inferencer<'a> {
|
|||||||
fn infer_pattern<T>(&mut self, pattern: &ast::Expr<T>) -> Result<(), InferenceError> {
|
fn infer_pattern<T>(&mut self, pattern: &ast::Expr<T>) -> Result<(), InferenceError> {
|
||||||
match &pattern.node {
|
match &pattern.node {
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
if !self.defined_identifiers.contains(id) {
|
if !self.defined_identifiers.contains_key(id) {
|
||||||
self.defined_identifiers.insert(*id);
|
self.defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -736,8 +748,8 @@ impl<'a> Inferencer<'a> {
|
|||||||
let mut defined_identifiers = self.defined_identifiers.clone();
|
let mut defined_identifiers = self.defined_identifiers.clone();
|
||||||
for arg in &args.args {
|
for arg in &args.args {
|
||||||
let name = &arg.node.arg;
|
let name = &arg.node.arg;
|
||||||
if !defined_identifiers.contains(name) {
|
if !defined_identifiers.contains_key(name) {
|
||||||
defined_identifiers.insert(*name);
|
defined_identifiers.insert(*name, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let fn_args: Vec<_> = args
|
let fn_args: Vec<_> = args
|
||||||
|
@ -519,7 +519,7 @@ impl TestEnvironment {
|
|||||||
primitives: &mut self.primitives,
|
primitives: &mut self.primitives,
|
||||||
virtual_checks: &mut self.virtual_checks,
|
virtual_checks: &mut self.virtual_checks,
|
||||||
calls: &mut self.calls,
|
calls: &mut self.calls,
|
||||||
defined_identifiers: HashSet::default(),
|
defined_identifiers: HashMap::default(),
|
||||||
in_handler: false,
|
in_handler: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,8 +595,9 @@ fn test_basic(source: &str, mapping: &HashMap<&str, &str>, virtuals: &[(&str, &s
|
|||||||
println!("source:\n{source}");
|
println!("source:\n{source}");
|
||||||
let mut env = TestEnvironment::new();
|
let mut env = TestEnvironment::new();
|
||||||
let id_to_name = std::mem::take(&mut env.id_to_name);
|
let id_to_name = std::mem::take(&mut env.id_to_name);
|
||||||
let mut defined_identifiers: HashSet<_> = env.identifier_mapping.keys().copied().collect();
|
let mut defined_identifiers: HashMap<_, _> =
|
||||||
defined_identifiers.insert("virtual".into());
|
env.identifier_mapping.keys().copied().map(|id| (id, IdentifierInfo::default())).collect();
|
||||||
|
defined_identifiers.insert("virtual".into(), IdentifierInfo::default());
|
||||||
let mut inferencer = env.get_inferencer();
|
let mut inferencer = env.get_inferencer();
|
||||||
inferencer.defined_identifiers.clone_from(&defined_identifiers);
|
inferencer.defined_identifiers.clone_from(&defined_identifiers);
|
||||||
let statements = parse_program(source, FileName::default()).unwrap();
|
let statements = parse_program(source, FileName::default()).unwrap();
|
||||||
@ -741,8 +742,9 @@ fn test_primitive_magic_methods(source: &str, mapping: &HashMap<&str, &str>) {
|
|||||||
println!("source:\n{source}");
|
println!("source:\n{source}");
|
||||||
let mut env = TestEnvironment::basic_test_env();
|
let mut env = TestEnvironment::basic_test_env();
|
||||||
let id_to_name = std::mem::take(&mut env.id_to_name);
|
let id_to_name = std::mem::take(&mut env.id_to_name);
|
||||||
let mut defined_identifiers: HashSet<_> = env.identifier_mapping.keys().copied().collect();
|
let mut defined_identifiers: HashMap<_, _> =
|
||||||
defined_identifiers.insert("virtual".into());
|
env.identifier_mapping.keys().copied().map(|id| (id, IdentifierInfo::default())).collect();
|
||||||
|
defined_identifiers.insert("virtual".into(), IdentifierInfo::default());
|
||||||
let mut inferencer = env.get_inferencer();
|
let mut inferencer = env.get_inferencer();
|
||||||
inferencer.defined_identifiers.clone_from(&defined_identifiers);
|
inferencer.defined_identifiers.clone_from(&defined_identifiers);
|
||||||
let statements = parse_program(source, FileName::default()).unwrap();
|
let statements = parse_program(source, FileName::default()).unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user