forked from M-Labs/nac3
1
0
Fork 0

nac3core/artiq/standalone: symbol resolver return error msg for type error of host variables

This commit is contained in:
ychenfo 2022-01-13 03:14:06 +08:00
parent eba9fc8a69
commit 4a1a4dc076
6 changed files with 112 additions and 104 deletions

View File

@ -155,24 +155,30 @@ impl InnerResolver {
unifier: &mut Unifier, unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> { ) -> PyResult<Result<Type, String>> {
let first = self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)?; let mut ty = match self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)? {
Ok((1..len).fold(first, |a, i| { Ok(t) => t,
let b = list Err(e) => return Ok(Err(format!(
"type error ({}) at element #0 of the list", e
))),
};
for i in 1..len {
let b = match list
.get_item(i) .get_item(i)
.map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives)); .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))?? {
a.and_then(|a| { Ok(t) => t,
if let Ok(Ok(Some(ty))) = b { Err(e) => return Ok(Err(format!(
if unifier.unify(a, ty).is_ok() { "type error ({}) at element #{} of the list", e, i
Some(a) ))),
} else { };
None ty = match unifier.unify(ty, b) {
} Ok(_) => ty,
} else { Err(e) => return Ok(Err(format!(
None "inhomogeneous type ({}) at element #{} of the list", e, i
} )))
}) };
})) }
Ok(Ok(ty))
} }
// handle python objects that represent types themselves // handle python objects that represent types themselves
@ -311,7 +317,9 @@ impl InnerResolver {
Err(err) => return Ok(Err(err)), Err(err) => return Ok(Err(err)),
}; };
if !unifier.is_concrete(ty.0, &[]) && !ty.1 { if !unifier.is_concrete(ty.0, &[]) && !ty.1 {
panic!("type list should take concrete parameters in type var ranges") return Ok(Err(
"type list should take concrete parameters in typevar range".into()
));
} }
Ok(Ok((unifier.add_ty(TypeEnum::TList { ty: ty.0 }), true))) Ok(Ok((unifier.add_ty(TypeEnum::TList { ty: ty.0 }), true)))
} else { } else {
@ -430,7 +438,7 @@ impl InnerResolver {
unifier: &mut Unifier, unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> { ) -> PyResult<Result<Type, String>> {
let ty = self.helper.type_fn.call1(py, (obj,)).unwrap(); let ty = self.helper.type_fn.call1(py, (obj,)).unwrap();
let (extracted_ty, inst_check) = match self.get_pyty_obj_type( let (extracted_ty, inst_check) = match self.get_pyty_obj_type(
py, py,
@ -457,7 +465,7 @@ impl InnerResolver {
primitives, primitives,
)? { )? {
Ok(s) => s, Ok(s) => s,
Err(_) => return Ok(None), Err(e) => return Ok(Err(e)),
}; };
return match (&*unifier.get_ty(extracted_ty), inst_check) { return match (&*unifier.get_ty(extracted_ty), inst_check) {
// do the instantiation for these three types // do the instantiation for these three types
@ -469,21 +477,22 @@ impl InnerResolver {
TypeEnum::TVar { meta: nac3core::typecheck::typedef::TypeVarMeta::Generic, range, .. } TypeEnum::TVar { meta: nac3core::typecheck::typedef::TypeVarMeta::Generic, range, .. }
if range.borrow().is_empty() if range.borrow().is_empty()
)); ));
Ok(Some(extracted_ty)) Ok(Ok(extracted_ty))
} else { } else {
let actual_ty = let actual_ty =
self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?; self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?;
if let Some(actual_ty) = actual_ty { match actual_ty {
unifier.unify(*ty, actual_ty).unwrap(); Ok(t) => match unifier.unify(*ty, t) {
Ok(Some(extracted_ty)) Ok(_) => Ok(Ok(unifier.add_ty(TypeEnum::TList{ ty: *ty }))),
} else { Err(e) => Ok(Err(format!("type error ({}) for the list", e))),
Ok(None) }
Err(e) => Ok(Err(e)),
} }
} }
} }
(TypeEnum::TTuple { .. }, false) => { (TypeEnum::TTuple { .. }, false) => {
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements let types: Result<Result<Vec<_>, _>, _> = elements
.iter() .iter()
.map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives)) .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))
.collect(); .collect();
@ -510,29 +519,35 @@ impl InnerResolver {
continue; continue;
} else { } else {
let field_data = obj.getattr(&name)?; let field_data = obj.getattr(&name)?;
let ty = self let ty = match self
.get_obj_type(py, field_data, unifier, defs, primitives)? .get_obj_type(py, field_data, unifier, defs, primitives)? {
.unwrap_or(primitives.none); Ok(t) => t,
Err(e) => return Ok(Err(format!(
"error when getting type of field `{}` ({})", name, e
))),
};
let field_ty = unifier.subst(field.1 .0, &var_map).unwrap_or(field.1 .0); let field_ty = unifier.subst(field.1 .0, &var_map).unwrap_or(field.1 .0);
if unifier.unify(ty, field_ty).is_err() { if let Err(e) = unifier.unify(ty, field_ty) {
// field type mismatch // field type mismatch
return Ok(None); return Ok(Err(format!(
"error when getting type of field `{}` ({})", name, e
)));
} }
} }
} }
for (_, ty) in var_map.iter() { for (_, ty) in var_map.iter() {
// must be concrete type // must be concrete type
if !unifier.is_concrete(*ty, &[]) { if !unifier.is_concrete(*ty, &[]) {
return Ok(None); return Ok(Err("object is not of concrete type".into()));
} }
} }
return Ok(Some( return Ok(Ok(
unifier unifier
.subst(extracted_ty, &var_map) .subst(extracted_ty, &var_map)
.unwrap_or(extracted_ty), .unwrap_or(extracted_ty),
)); ));
} }
_ => Ok(Some(extracted_ty)), _ => Ok(Ok(extracted_ty)),
}; };
} }
@ -686,7 +701,7 @@ impl InnerResolver {
} }
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements let types: Result<Result<Vec<_>, _>, _> = elements
.iter() .iter()
.map(|elem| { .map(|elem| {
self.get_obj_type( self.get_obj_type(
@ -858,22 +873,25 @@ impl SymbolResolver for Resolver {
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Option<Type> { ) -> Result<Type, String> {
{ match {
let id_to_type = self.0.id_to_type.read(); let id_to_type = self.0.id_to_type.read();
id_to_type.get(&str).cloned() id_to_type.get(&str).cloned()
} } {
.or_else(|| { Some(ty) => Ok(ty),
let py_id = self.0.name_to_pyid.get(&str); None => {
let result = py_id.and_then(|id| { let id = match self.0.name_to_pyid.get(&str) {
{ Some(id) => id,
None => return Err(format!("cannot find symbol `{}`", str)),
};
let result = match {
let pyid_to_type = self.0.pyid_to_type.read(); let pyid_to_type = self.0.pyid_to_type.read();
pyid_to_type.get(id).copied() pyid_to_type.get(id).copied()
} } {
.or_else(|| { Some(t) => Ok(t),
let result = Python::with_gil(|py| -> PyResult<Option<Type>> { None => Python::with_gil(|py| -> PyResult<Result<Type, String>> {
let obj: &PyAny = self.0.module.extract(py)?; let obj: &PyAny = self.0.module.extract(py)?;
let mut sym_ty = None; let mut sym_ty = Err(format!("cannot find symbol `{}`", str));
let members: &PyDict = obj.getattr("__dict__").unwrap().cast_as().unwrap(); let members: &PyDict = obj.getattr("__dict__").unwrap().cast_as().unwrap();
for (key, val) in members.iter() { for (key, val) in members.iter() {
let key: &str = key.extract()?; let key: &str = key.extract()?;
@ -882,20 +900,19 @@ impl SymbolResolver for Resolver {
break; break;
} }
} }
if let Ok(t) = sym_ty {
self.0.pyid_to_type.write().insert(*id, t);
}
Ok(sym_ty) Ok(sym_ty)
}) })
.unwrap(); .unwrap(),
if let Some(result) = result { };
self.0.pyid_to_type.write().insert(*id, result); if let Ok(t) = &result {
} self.0.id_to_type.write().insert(str, *t);
result }
}) result
});
if let Some(result) = &result {
self.0.id_to_type.write().insert(str, *result);
} }
result }
})
} }
fn get_symbol_value<'ctx, 'a>( fn get_symbol_value<'ctx, 'a>(

View File

@ -92,7 +92,7 @@ pub trait SymbolResolver {
top_level_defs: &[Arc<RwLock<TopLevelDef>>], top_level_defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Option<Type>; ) -> Result<Type, String>;
// get the top-level definition of identifiers // get the top-level definition of identifiers
fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>; fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>;
@ -180,8 +180,7 @@ pub fn parse_type_annotation<T>(
} else { } else {
// it could be a type variable // it could be a type variable
let ty = resolver let ty = resolver
.get_symbol_type(unifier, top_level_defs, primitives, *id) .get_symbol_type(unifier, top_level_defs, primitives, *id)?;
.ok_or_else(|| "unknown type variable name".to_owned())?;
if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) {
Ok(ty) Ok(ty)
} else { } else {

View File

@ -88,7 +88,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
)); ));
} }
Ok(TypeAnnotation::CustomClass { id: obj_id, params: vec![] }) Ok(TypeAnnotation::CustomClass { id: obj_id, params: vec![] })
} else if let Some(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id) { } else if let Ok(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id) {
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() { if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
Ok(TypeAnnotation::TypeVar(ty)) Ok(TypeAnnotation::TypeVar(ty))
} else { } else {

View File

@ -69,23 +69,21 @@ impl<'a> Inferencer<'a> {
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
self.should_have_value(expr)?; self.should_have_value(expr)?;
if !defined_identifiers.contains(id) { if !defined_identifiers.contains(id) {
if self match self.function_data.resolver.get_symbol_type(
.function_data self.unifier,
.resolver &self.top_level.definitions.read(),
.get_symbol_type( self.primitives,
self.unifier, *id,
&self.top_level.definitions.read(), ) {
self.primitives, Ok(_) => {
*id, self.defined_identifiers.insert(*id);
) }
.is_some() Err(e) => {
{ return Err(format!(
defined_identifiers.insert(*id); "type error of identifier `{}` ({}) at {}",
} else { id, e, expr.location
return Err(format!( ));
"unknown identifier {} (use before def?) at {}", }
id, expr.location
));
} }
} }
} }

View File

@ -181,7 +181,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
self.primitives, self.primitives,
id, id,
) )
.unwrap_or_else(|| { .unwrap_or_else(|_| {
self.variable_mapping.insert(id, value_ty); self.variable_mapping.insert(id, value_ty);
value_ty value_ty
}) })
@ -360,23 +360,21 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
Some(self.infer_constant(value, &expr.location)?), Some(self.infer_constant(value, &expr.location)?),
ast::ExprKind::Name { id, .. } => { ast::ExprKind::Name { id, .. } => {
if !self.defined_identifiers.contains(id) { if !self.defined_identifiers.contains(id) {
if self match self.function_data.resolver.get_symbol_type(
.function_data self.unifier,
.resolver &self.top_level.definitions.read(),
.get_symbol_type( self.primitives,
self.unifier, *id,
&self.top_level.definitions.read(), ) {
self.primitives, Ok(_) => {
*id, self.defined_identifiers.insert(*id);
) }
.is_some() Err(e) => {
{ return report_error(
self.defined_identifiers.insert(*id); &format!("type error of identifier `{}` ({})", id, e),
} else { expr.location,
return report_error( );
&format!("unknown identifier {} (use before def?)", id), }
expr.location,
);
} }
} }
Some(self.infer_identifier(*id)?) Some(self.infer_identifier(*id)?)
@ -765,7 +763,7 @@ impl<'a> Inferencer<'a> {
.function_data .function_data
.resolver .resolver
.get_symbol_type(unifier, &self.top_level.definitions.read(), self.primitives, id) .get_symbol_type(unifier, &self.top_level.definitions.read(), self.primitives, id)
.unwrap_or_else(|| { .unwrap_or_else(|_| {
let ty = unifier.get_fresh_var().0; let ty = unifier.get_fresh_var().0;
variable_mapping.insert(id, ty); variable_mapping.insert(id, ty);
ty ty

View File

@ -51,12 +51,8 @@ impl SymbolResolver for Resolver {
_: &[Arc<RwLock<TopLevelDef>>], _: &[Arc<RwLock<TopLevelDef>>],
_: &PrimitiveStore, _: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Option<Type> { ) -> Result<Type, String> {
let ret = self.0.id_to_type.lock().get(&str).cloned(); self.0.id_to_type.lock().get(&str).cloned().ok_or(format!("cannot get type of {}", str))
if ret.is_none() {
// println!("unknown here resolver {}", str);
}
ret
} }
fn get_symbol_value<'ctx, 'a>( fn get_symbol_value<'ctx, 'a>(