diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 7148255e..13bc850d 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -38,7 +38,7 @@ use tempfile::{self, TempDir}; use crate::{ codegen::{rpc_codegen_callback, ArtiqCodeGenerator}, - symbol_resolver::{InnerResolver, PythonHelper, Resolver}, + symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore}, }; mod codegen; @@ -89,6 +89,7 @@ struct Nac3 { top_levels: Vec, string_store: Arc>>, exception_ids: Arc>>, + deferred_eval_store: DeferredEvaluationStore } create_exception!(nac3artiq, CompileError, exceptions::PyException); @@ -400,6 +401,7 @@ impl Nac3 { working_directory, string_store: Default::default(), exception_ids: Default::default(), + deferred_eval_store: DeferredEvaluationStore::new(), }) } @@ -522,6 +524,7 @@ impl Nac3 { helper, string_store: self.string_store.clone(), exception_ids: self.exception_ids.clone(), + deferred_eval_store: self.deferred_eval_store.clone(), }))) as Arc; let name_to_pyid = Rc::new(name_to_pyid); @@ -607,6 +610,7 @@ impl Nac3 { helper, string_store: self.string_store.clone(), exception_ids: self.exception_ids.clone(), + deferred_eval_store: self.deferred_eval_store.clone(), }))) as Arc; let (_, def_id, _) = composer .register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into()) diff --git a/nac3artiq/src/symbol_resolver.rs b/nac3artiq/src/symbol_resolver.rs index 66380a3c..e26435c0 100644 --- a/nac3artiq/src/symbol_resolver.rs +++ b/nac3artiq/src/symbol_resolver.rs @@ -16,7 +16,10 @@ use pyo3::{ }; use std::{ collections::{HashMap, HashSet}, - sync::Arc, + sync::{ + Arc, + atomic::{AtomicBool, Ordering::Relaxed} + } }; use crate::PrimitivePythonId; @@ -30,6 +33,21 @@ pub enum PrimitiveValue { Bool(bool), } +#[derive(Clone)] +pub struct DeferredEvaluationStore { + needs_defer: Arc, + store: Arc, PyObject, String)>>>, +} + +impl DeferredEvaluationStore { + pub fn new() -> Self { + DeferredEvaluationStore { + needs_defer: Arc::new(AtomicBool::new(true)), + store: Arc::new(RwLock::new(Vec::new())), + } + } +} + pub struct InnerResolver { pub id_to_type: RwLock>, pub id_to_def: RwLock>, @@ -44,6 +62,7 @@ pub struct InnerResolver { pub helper: PythonHelper, pub string_store: Arc>>, pub exception_ids: Arc>>, + pub deferred_eval_store: DeferredEvaluationStore, // module specific pub name_to_pyid: HashMap, pub module: PyObject, @@ -298,28 +317,40 @@ impl InnerResolver { let constraint_types = { let constraints = pyty.getattr("__constraints__").unwrap(); let mut result: Vec = vec![]; + let needs_defer = self.deferred_eval_store.needs_defer.load(Relaxed); for i in 0.. { if let Ok(constr) = constraints.get_item(i) { - result.push({ - match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? { - Ok((ty, _)) => { - if unifier.is_concrete(ty, &[]) { - ty - } else { - return Ok(Err(format!( - "the {}th constraint of TypeVar `{}` is not concrete", - i + 1, - pyty.getattr("__name__")?.extract::()? - ))); + if needs_defer { + result.push(unifier.get_dummy_var().0); + } else { + result.push({ + match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? { + Ok((ty, _)) => { + if unifier.is_concrete(ty, &[]) { + ty + } else { + return Ok(Err(format!( + "the {}th constraint of TypeVar `{}` is not concrete", + i + 1, + pyty.getattr("__name__")?.extract::()? + ))); + } } + Err(err) => return Ok(Err(err)), } - Err(err) => return Ok(Err(err)), - } - }) + }) + } } else { break; } } + if needs_defer { + self.deferred_eval_store.store.write() + .push((result.clone(), + constraints.extract()?, + pyty.getattr("__name__")?.extract::()? + )) + } result }; let res = @@ -908,15 +939,14 @@ impl SymbolResolver for Resolver { } } if let Ok(t) = sym_ty { - self.0.pyid_to_type.write().insert(*id, t); + if let TypeEnum::TVar { .. } = &*unifier.get_ty(t) { + self.0.pyid_to_type.write().insert(*id, t); + } } Ok(sym_ty) }) .unwrap(), }; - if let Ok(t) = &result { - self.0.id_to_type.write().insert(str, *t); - } result } } @@ -992,6 +1022,45 @@ impl SymbolResolver for Resolver { } } + fn handle_deferred_eval( + &self, + unifier: &mut Unifier, + defs: &[Arc>], + primitives: &PrimitiveStore + ) -> Result<(), String> { + // we don't need a lock because this will only be run in a single thread + if self.0.deferred_eval_store.needs_defer.load(Relaxed) { + self.0.deferred_eval_store.needs_defer.store(false, Relaxed); + let store = self.0.deferred_eval_store.store.read(); + Python::with_gil(|py| -> PyResult> { + for (variables, constraints, name) in store.iter() { + let constraints: &PyAny = constraints.as_ref(py); + for (i, var) in variables.iter().enumerate() { + if let Ok(constr) = constraints.get_item(i) { + match self.0.get_pyty_obj_type(py, constr, unifier, defs, primitives)? { + Ok((ty, _)) => { + if !unifier.is_concrete(ty, &[]) { + return Ok(Err(format!( + "the {}th constraint of TypeVar `{}` is not concrete", + i + 1, + name, + ))); + } + unifier.unify(ty, *var).unwrap() + } + Err(err) => return Ok(Err(err)), + } + } else { + break; + } + } + } + Ok(Ok(())) + }).unwrap()? + } + Ok(()) + } + fn get_exception_id(&self, tyid: usize) -> usize { let exn_ids = self.0.exception_ids.read(); exn_ids.get(&tyid).cloned().unwrap_or(0) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index bfebffb6..5afeba8c 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -496,7 +496,13 @@ pub fn gen_func_instance<'ctx, 'a>( } let symbol = format!("{}.{}", name, instance_to_symbol.len()); instance_to_symbol.insert(key, symbol.clone()); - let key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), sign, Some(var_id)); + let mut filter = var_id.clone(); + if let Some((obj_ty, _)) = &obj { + if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty(*obj_ty) { + filter.extend(params.keys()); + } + } + let key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), sign, Some(&filter)); let instance = instance_to_stmt.get(&key).unwrap(); let mut store = ConcreteTypeStore::new(); diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index d5df9f2a..96f941d2 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -141,7 +141,15 @@ pub trait SymbolResolver { fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option; fn get_string_id(&self, s: &str) -> i32; fn get_exception_id(&self, tyid: usize) -> usize; - // handle function call etc. + + fn handle_deferred_eval( + &self, + _unifier: &mut Unifier, + _top_level_defs: &[Arc>], + _primitives: &PrimitiveStore + ) -> Result<(), String> { + Ok(()) + } } thread_local! { diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 6350f698..991926a6 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -775,6 +775,18 @@ impl TopLevelComposer { return Err(errors.into_iter().sorted().join("\n----------\n")); } + for (def, _) in def_ast_list.iter().skip(self.builtin_num) { + match &*def.read() { + TopLevelDef::Class { resolver: Some(resolver), .. } + | TopLevelDef::Function { resolver: Some(resolver), .. } => { + if let Err(e) = resolver.handle_deferred_eval(unifier, &temp_def_list, primitives) { + errors.insert(e); + } + } + _ => {} + } + } + Ok(()) } @@ -1057,17 +1069,7 @@ impl TopLevelComposer { let (method_dummy_ty, method_id) = Self::get_class_method_def_info(class_methods_def, *name)?; - // the method var map can surely include the class's generic parameters - let mut method_var_map: HashMap = class_type_vars_def - .iter() - .map(|ty| { - if let TypeEnum::TVar { id, .. } = unifier.get_ty(*ty).as_ref() { - (*id, *ty) - } else { - unreachable!("must be type var here") - } - }) - .collect(); + let mut method_var_map: HashMap = HashMap::new(); let arg_types: Vec = { // check method parameters cannot have same name @@ -1494,8 +1496,8 @@ impl TopLevelComposer { if new_var_ids != *var_id { let new_signature = FunSignature { args: args.clone(), - ret: ret.clone(), - vars: new_var_ids.iter().zip(vars.values()).map(|(id, v)| (*id, v.clone())).collect(), + ret: *ret, + vars: new_var_ids.iter().zip(vars.values()).map(|(id, v)| (*id, *v)).collect(), }; unifier.unification_table.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature))); *var_id = new_var_ids; @@ -1674,13 +1676,13 @@ impl TopLevelComposer { simple_name, signature, resolver, - var_id: insted_vars, .. } = &mut *function_def { if let TypeEnum::TFunc(FunSignature { args, ret, vars }) = unifier.get_ty(*signature).as_ref() { + let mut vars = vars.clone(); // None if is not class method let uninst_self_type = { if let Some(class_id) = method_class.get(&DefinitionId(id)) { @@ -1695,6 +1697,12 @@ impl TopLevelComposer { &ty_ann, &mut None )?; + vars.extend(type_vars.iter().map(|ty| + if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*ty) { + (*id, *ty) + } else { + unreachable!() + })); Some((self_ty, type_vars.clone())) } else { unreachable!("must be class def") @@ -1725,7 +1733,7 @@ impl TopLevelComposer { .collect_vec(); let mut result: Vec> = Default::default(); for comb in var_combs { - result.push(insted_vars.clone().into_iter().zip(comb).collect()); + result.push(vars.keys().cloned().zip(comb).collect()); } // NOTE: if is empty, means no type var, append a empty subst, ok to do this? if result.is_empty() { @@ -1913,7 +1921,7 @@ impl TopLevelComposer { } instance_to_stmt.insert( - get_subst_key(unifier, self_type, &subst, Some(insted_vars)), + get_subst_key(unifier, self_type, &subst, Some(&vars.keys().cloned().collect())), FunInstance { body: Arc::new(fun_body), unifier_id: 0,