Fixed typevar with fixed range #238
|
@ -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<TopLevelComponent>,
|
||||
string_store: Arc<RwLock<HashMap<String, i32>>>,
|
||||
exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
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<dyn SymbolResolver + Send + Sync>;
|
||||
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<dyn SymbolResolver + Send + Sync>;
|
||||
let (_, def_id, _) = composer
|
||||
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "".into())
|
||||
|
|
|
@ -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<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 id_to_type: RwLock<HashMap<StrRef, Type>>,
|
||||
pub id_to_def: RwLock<HashMap<StrRef, DefinitionId>>,
|
||||
|
@ -44,6 +62,7 @@ pub struct InnerResolver {
|
|||
pub helper: PythonHelper,
|
||||
pub string_store: Arc<RwLock<HashMap<String, i32>>>,
|
||||
pub exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
pub deferred_eval_store: DeferredEvaluationStore,
|
||||
// module specific
|
||||
pub name_to_pyid: HashMap<StrRef, u64>,
|
||||
pub module: PyObject,
|
||||
|
@ -298,28 +317,40 @@ impl InnerResolver {
|
|||
let constraint_types = {
|
||||
let constraints = pyty.getattr("__constraints__").unwrap();
|
||||
let mut result: Vec<Type> = 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::<String>()?
|
||||
)));
|
||||
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::<String>()?
|
||||
)));
|
||||
}
|
||||
}
|
||||
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::<String>()?
|
||||
))
|
||||
}
|
||||
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<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 {
|
||||
let exn_ids = self.0.exception_ids.read();
|
||||
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());
|
||||
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();
|
||||
|
|
|
@ -141,7 +141,15 @@ pub trait SymbolResolver {
|
|||
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
||||
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<RwLock<TopLevelDef>>],
|
||||
_primitives: &PrimitiveStore
|
||||
) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
|
|
|
@ -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<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 mut method_var_map: HashMap<u32, Type> = HashMap::new();
|
||||
|
||||
let arg_types: Vec<FuncArg> = {
|
||||
// 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<HashMap<u32, Type>> = 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,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
source: nac3core/src/toplevel/test.rs
|
||||
assertion_line: 540
|
||||
assertion_line: 549
|
||||
expression: res_vec
|
||||
|
||||
---
|
||||
[
|
||||
"Class {\nname: \"Generic_A\",\nancestors: [\"{class: Generic_A, params: [\\\"V\\\"]}\", \"{class: B, params: []}\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: [6]\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [6, 17]\n}\n",
|
||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [17]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: nac3core/src/toplevel/test.rs
|
||||
assertion_line: 540
|
||||
assertion_line: 549
|
||||
expression: res_vec
|
||||
|
||||
---
|
||||
|
@ -10,8 +10,8 @@ expression: res_vec
|
|||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: [\\\"var6\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"var6\"]\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: [6]\n}\n",
|
||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: [6]\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"C\",\nancestors: [\"{class: C, params: []}\", \"{class: B, params: [\\\"bool\\\"]}\", \"{class: A, params: [\\\"float\\\"]}\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
]
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
---
|
||||
source: nac3core/src/toplevel/test.rs
|
||||
assertion_line: 540
|
||||
assertion_line: 549
|
||||
expression: res_vec
|
||||
|
||||
---
|
||||
[
|
||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"T\\\", \\\"V\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [18, 19]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [19, 24]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [19]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [24]\n}\n",
|
||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[int32, list[float]]], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
source: nac3core/src/toplevel/test.rs
|
||||
assertion_line: 540
|
||||
assertion_line: 549
|
||||
expression: res_vec
|
||||
|
||||
---
|
||||
[
|
||||
"Class {\nname: \"A\",\nancestors: [\"{class: A, params: [\\\"var5\\\", \\\"var6\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[bool, float], b:B], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\")],\ntype_vars: [\"var5\", \"var6\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: [6]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: [6]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[bool, float], b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[bool, float]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"{class: B, params: []}\", \"{class: A, params: [\\\"int64\\\", \\\"bool\\\"]}\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[bool, float]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[int32, list[B]]], tuple[A[bool, virtual[A[B, int32]]], B]]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
|
||||
|
|
Loading…
Reference in New Issue