nac3core: fixed typevar with finite range
1. Function type variables should not include class type variables, because they are not bound to the function. 2. Defer type variable constraint evaluation until we get all fields definition.
This commit is contained in:
parent
be75fa7368
commit
1084ba2158
|
@ -38,7 +38,7 @@ use tempfile::{self, TempDir};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
|
codegen::{rpc_codegen_callback, ArtiqCodeGenerator},
|
||||||
symbol_resolver::{InnerResolver, PythonHelper, Resolver},
|
symbol_resolver::{InnerResolver, PythonHelper, Resolver, DeferredEvaluationStore},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
@ -89,6 +89,7 @@ struct Nac3 {
|
||||||
top_levels: Vec<TopLevelComponent>,
|
top_levels: Vec<TopLevelComponent>,
|
||||||
string_store: Arc<RwLock<HashMap<String, i32>>>,
|
string_store: Arc<RwLock<HashMap<String, i32>>>,
|
||||||
exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
||||||
|
deferred_eval_store: DeferredEvaluationStore
|
||||||
}
|
}
|
||||||
|
|
||||||
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
||||||
|
@ -400,6 +401,7 @@ impl Nac3 {
|
||||||
working_directory,
|
working_directory,
|
||||||
string_store: Default::default(),
|
string_store: Default::default(),
|
||||||
exception_ids: Default::default(),
|
exception_ids: Default::default(),
|
||||||
|
deferred_eval_store: DeferredEvaluationStore::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +524,7 @@ impl Nac3 {
|
||||||
helper,
|
helper,
|
||||||
string_store: self.string_store.clone(),
|
string_store: self.string_store.clone(),
|
||||||
exception_ids: self.exception_ids.clone(),
|
exception_ids: self.exception_ids.clone(),
|
||||||
|
deferred_eval_store: self.deferred_eval_store.clone(),
|
||||||
})))
|
})))
|
||||||
as Arc<dyn SymbolResolver + Send + Sync>;
|
as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
let name_to_pyid = Rc::new(name_to_pyid);
|
let name_to_pyid = Rc::new(name_to_pyid);
|
||||||
|
@ -607,6 +610,7 @@ impl Nac3 {
|
||||||
helper,
|
helper,
|
||||||
string_store: self.string_store.clone(),
|
string_store: self.string_store.clone(),
|
||||||
exception_ids: self.exception_ids.clone(),
|
exception_ids: self.exception_ids.clone(),
|
||||||
|
deferred_eval_store: self.deferred_eval_store.clone(),
|
||||||
}))) as Arc<dyn SymbolResolver + Send + Sync>;
|
}))) as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
let (_, def_id, _) = composer
|
let (_, def_id, _) = composer
|
||||||
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into())
|
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into())
|
||||||
|
|
|
@ -16,7 +16,10 @@ use pyo3::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
sync::Arc,
|
sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, Ordering::Relaxed}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::PrimitivePythonId;
|
use crate::PrimitivePythonId;
|
||||||
|
@ -30,6 +33,21 @@ pub enum PrimitiveValue {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DeferredEvaluationStore {
|
||||||
|
needs_defer: Arc<AtomicBool>,
|
||||||
|
store: Arc<RwLock<Vec<(Vec<Type>, 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 struct InnerResolver {
|
||||||
pub id_to_type: RwLock<HashMap<StrRef, Type>>,
|
pub id_to_type: RwLock<HashMap<StrRef, Type>>,
|
||||||
pub id_to_def: RwLock<HashMap<StrRef, DefinitionId>>,
|
pub id_to_def: RwLock<HashMap<StrRef, DefinitionId>>,
|
||||||
|
@ -44,6 +62,7 @@ pub struct InnerResolver {
|
||||||
pub helper: PythonHelper,
|
pub helper: PythonHelper,
|
||||||
pub string_store: Arc<RwLock<HashMap<String, i32>>>,
|
pub string_store: Arc<RwLock<HashMap<String, i32>>>,
|
||||||
pub exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
pub exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
||||||
|
pub deferred_eval_store: DeferredEvaluationStore,
|
||||||
// module specific
|
// module specific
|
||||||
pub name_to_pyid: HashMap<StrRef, u64>,
|
pub name_to_pyid: HashMap<StrRef, u64>,
|
||||||
pub module: PyObject,
|
pub module: PyObject,
|
||||||
|
@ -298,8 +317,12 @@ impl InnerResolver {
|
||||||
let constraint_types = {
|
let constraint_types = {
|
||||||
let constraints = pyty.getattr("__constraints__").unwrap();
|
let constraints = pyty.getattr("__constraints__").unwrap();
|
||||||
let mut result: Vec<Type> = vec![];
|
let mut result: Vec<Type> = vec![];
|
||||||
|
let needs_defer = self.deferred_eval_store.needs_defer.load(Relaxed);
|
||||||
for i in 0.. {
|
for i in 0.. {
|
||||||
if let Ok(constr) = constraints.get_item(i) {
|
if let Ok(constr) = constraints.get_item(i) {
|
||||||
|
if needs_defer {
|
||||||
|
result.push(unifier.get_dummy_var().0);
|
||||||
|
} else {
|
||||||
result.push({
|
result.push({
|
||||||
match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? {
|
match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? {
|
||||||
Ok((ty, _)) => {
|
Ok((ty, _)) => {
|
||||||
|
@ -316,10 +339,18 @@ impl InnerResolver {
|
||||||
Err(err) => return Ok(Err(err)),
|
Err(err) => return Ok(Err(err)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if needs_defer {
|
||||||
|
self.deferred_eval_store.store.write()
|
||||||
|
.push((result.clone(),
|
||||||
|
constraints.extract()?,
|
||||||
|
pyty.getattr("__name__")?.extract::<String>()?
|
||||||
|
))
|
||||||
|
}
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
let res =
|
let res =
|
||||||
|
@ -908,15 +939,14 @@ impl SymbolResolver for Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(t) = sym_ty {
|
if let Ok(t) = sym_ty {
|
||||||
|
if let TypeEnum::TVar { .. } = &*unifier.get_ty(t) {
|
||||||
self.0.pyid_to_type.write().insert(*id, t);
|
self.0.pyid_to_type.write().insert(*id, t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(sym_ty)
|
Ok(sym_ty)
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
if let Ok(t) = &result {
|
|
||||||
self.0.id_to_type.write().insert(str, *t);
|
|
||||||
}
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -992,6 +1022,45 @@ impl SymbolResolver for Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_deferred_eval(
|
||||||
|
&self,
|
||||||
|
unifier: &mut Unifier,
|
||||||
|
defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
|
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<Result<(), String>> {
|
||||||
|
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 {
|
fn get_exception_id(&self, tyid: usize) -> usize {
|
||||||
let exn_ids = self.0.exception_ids.read();
|
let exn_ids = self.0.exception_ids.read();
|
||||||
exn_ids.get(&tyid).cloned().unwrap_or(0)
|
exn_ids.get(&tyid).cloned().unwrap_or(0)
|
||||||
|
|
|
@ -496,7 +496,13 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
}
|
}
|
||||||
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
||||||
instance_to_symbol.insert(key, symbol.clone());
|
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 instance = instance_to_stmt.get(&key).unwrap();
|
||||||
|
|
||||||
let mut store = ConcreteTypeStore::new();
|
let mut store = ConcreteTypeStore::new();
|
||||||
|
|
|
@ -141,7 +141,15 @@ pub trait SymbolResolver {
|
||||||
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
||||||
fn get_string_id(&self, s: &str) -> i32;
|
fn get_string_id(&self, s: &str) -> i32;
|
||||||
fn get_exception_id(&self, tyid: usize) -> usize;
|
fn get_exception_id(&self, tyid: usize) -> usize;
|
||||||
// handle function call etc.
|
|
||||||
|
fn handle_deferred_eval(
|
||||||
|
&self,
|
||||||
|
_unifier: &mut Unifier,
|
||||||
|
_top_level_defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
|
_primitives: &PrimitiveStore
|
||||||
|
) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
|
|
@ -775,6 +775,18 @@ impl TopLevelComposer {
|
||||||
return Err(errors.into_iter().sorted().join("\n----------\n"));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,17 +1069,7 @@ impl TopLevelComposer {
|
||||||
let (method_dummy_ty, method_id) =
|
let (method_dummy_ty, method_id) =
|
||||||
Self::get_class_method_def_info(class_methods_def, *name)?;
|
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<u32, Type> = HashMap::new();
|
||||||
let mut method_var_map: HashMap<u32, Type> = 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 arg_types: Vec<FuncArg> = {
|
let arg_types: Vec<FuncArg> = {
|
||||||
// check method parameters cannot have same name
|
// check method parameters cannot have same name
|
||||||
|
@ -1494,8 +1496,8 @@ impl TopLevelComposer {
|
||||||
if new_var_ids != *var_id {
|
if new_var_ids != *var_id {
|
||||||
let new_signature = FunSignature {
|
let new_signature = FunSignature {
|
||||||
args: args.clone(),
|
args: args.clone(),
|
||||||
ret: ret.clone(),
|
ret: *ret,
|
||||||
vars: new_var_ids.iter().zip(vars.values()).map(|(id, v)| (*id, v.clone())).collect(),
|
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)));
|
unifier.unification_table.set_value(*signature, Rc::new(TypeEnum::TFunc(new_signature)));
|
||||||
*var_id = new_var_ids;
|
*var_id = new_var_ids;
|
||||||
|
@ -1674,13 +1676,13 @@ impl TopLevelComposer {
|
||||||
simple_name,
|
simple_name,
|
||||||
signature,
|
signature,
|
||||||
resolver,
|
resolver,
|
||||||
var_id: insted_vars,
|
|
||||||
..
|
..
|
||||||
} = &mut *function_def
|
} = &mut *function_def
|
||||||
{
|
{
|
||||||
if let TypeEnum::TFunc(FunSignature { args, ret, vars }) =
|
if let TypeEnum::TFunc(FunSignature { args, ret, vars }) =
|
||||||
unifier.get_ty(*signature).as_ref()
|
unifier.get_ty(*signature).as_ref()
|
||||||
{
|
{
|
||||||
|
let mut vars = vars.clone();
|
||||||
// None if is not class method
|
// None if is not class method
|
||||||
let uninst_self_type = {
|
let uninst_self_type = {
|
||||||
if let Some(class_id) = method_class.get(&DefinitionId(id)) {
|
if let Some(class_id) = method_class.get(&DefinitionId(id)) {
|
||||||
|
@ -1695,6 +1697,12 @@ impl TopLevelComposer {
|
||||||
&ty_ann,
|
&ty_ann,
|
||||||
&mut None
|
&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()))
|
Some((self_ty, type_vars.clone()))
|
||||||
} else {
|
} else {
|
||||||
unreachable!("must be class def")
|
unreachable!("must be class def")
|
||||||
|
@ -1725,7 +1733,7 @@ impl TopLevelComposer {
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let mut result: Vec<HashMap<u32, Type>> = Default::default();
|
let mut result: Vec<HashMap<u32, Type>> = Default::default();
|
||||||
for comb in var_combs {
|
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?
|
// NOTE: if is empty, means no type var, append a empty subst, ok to do this?
|
||||||
if result.is_empty() {
|
if result.is_empty() {
|
||||||
|
@ -1913,7 +1921,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_to_stmt.insert(
|
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 {
|
FunInstance {
|
||||||
body: Arc::new(fun_body),
|
body: Arc::new(fun_body),
|
||||||
unifier_id: 0,
|
unifier_id: 0,
|
||||||
|
|
Loading…
Reference in New Issue