From 4a1a4dc0763e69074faa12e1bed0a3bc6119affc Mon Sep 17 00:00:00 2001 From: ychenfo Date: Thu, 13 Jan 2022 03:14:06 +0800 Subject: [PATCH] nac3core/artiq/standalone: symbol resolver return error msg for type error of host variables --- nac3artiq/src/symbol_resolver.rs | 133 ++++++++++-------- nac3core/src/symbol_resolver.rs | 5 +- nac3core/src/toplevel/type_annotation.rs | 2 +- nac3core/src/typecheck/function_check.rs | 32 ++--- nac3core/src/typecheck/type_inferencer/mod.rs | 36 +++-- nac3standalone/src/basic_symbol_resolver.rs | 8 +- 6 files changed, 112 insertions(+), 104 deletions(-) diff --git a/nac3artiq/src/symbol_resolver.rs b/nac3artiq/src/symbol_resolver.rs index 5fa703f4..33608116 100644 --- a/nac3artiq/src/symbol_resolver.rs +++ b/nac3artiq/src/symbol_resolver.rs @@ -155,24 +155,30 @@ impl InnerResolver { unifier: &mut Unifier, defs: &[Arc>], primitives: &PrimitiveStore, - ) -> PyResult> { - let first = self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)?; - Ok((1..len).fold(first, |a, i| { - let b = list + ) -> PyResult> { + let mut ty = match self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)? { + Ok(t) => t, + 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) - .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives)); - a.and_then(|a| { - if let Ok(Ok(Some(ty))) = b { - if unifier.unify(a, ty).is_ok() { - Some(a) - } else { - None - } - } else { - None - } - }) - })) + .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))?? { + Ok(t) => t, + Err(e) => return Ok(Err(format!( + "type error ({}) at element #{} of the list", e, i + ))), + }; + ty = match unifier.unify(ty, b) { + Ok(_) => ty, + Err(e) => return Ok(Err(format!( + "inhomogeneous type ({}) at element #{} of the list", e, i + ))) + }; + } + Ok(Ok(ty)) } // handle python objects that represent types themselves @@ -311,7 +317,9 @@ impl InnerResolver { Err(err) => return Ok(Err(err)), }; 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))) } else { @@ -430,7 +438,7 @@ impl InnerResolver { unifier: &mut Unifier, defs: &[Arc>], primitives: &PrimitiveStore, - ) -> PyResult> { + ) -> PyResult> { let ty = self.helper.type_fn.call1(py, (obj,)).unwrap(); let (extracted_ty, inst_check) = match self.get_pyty_obj_type( py, @@ -457,7 +465,7 @@ impl InnerResolver { primitives, )? { Ok(s) => s, - Err(_) => return Ok(None), + Err(e) => return Ok(Err(e)), }; return match (&*unifier.get_ty(extracted_ty), inst_check) { // do the instantiation for these three types @@ -469,21 +477,22 @@ impl InnerResolver { TypeEnum::TVar { meta: nac3core::typecheck::typedef::TypeVarMeta::Generic, range, .. } if range.borrow().is_empty() )); - Ok(Some(extracted_ty)) + Ok(Ok(extracted_ty)) } else { let actual_ty = self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?; - if let Some(actual_ty) = actual_ty { - unifier.unify(*ty, actual_ty).unwrap(); - Ok(Some(extracted_ty)) - } else { - Ok(None) + match actual_ty { + Ok(t) => match unifier.unify(*ty, t) { + Ok(_) => Ok(Ok(unifier.add_ty(TypeEnum::TList{ ty: *ty }))), + Err(e) => Ok(Err(format!("type error ({}) for the list", e))), + } + Err(e) => Ok(Err(e)), } } } (TypeEnum::TTuple { .. }, false) => { let elements: &PyTuple = obj.cast_as()?; - let types: Result>, _> = elements + let types: Result, _>, _> = elements .iter() .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives)) .collect(); @@ -510,29 +519,35 @@ impl InnerResolver { continue; } else { let field_data = obj.getattr(&name)?; - let ty = self - .get_obj_type(py, field_data, unifier, defs, primitives)? - .unwrap_or(primitives.none); + let ty = match self + .get_obj_type(py, field_data, unifier, defs, primitives)? { + 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); - if unifier.unify(ty, field_ty).is_err() { + if let Err(e) = unifier.unify(ty, field_ty) { // field type mismatch - return Ok(None); + return Ok(Err(format!( + "error when getting type of field `{}` ({})", name, e + ))); } } } for (_, ty) in var_map.iter() { // must be concrete type 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 .subst(extracted_ty, &var_map) .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 types: Result>, _> = elements + let types: Result, _>, _> = elements .iter() .map(|elem| { self.get_obj_type( @@ -858,22 +873,25 @@ impl SymbolResolver for Resolver { defs: &[Arc>], primitives: &PrimitiveStore, str: StrRef, - ) -> Option { - { + ) -> Result { + match { let id_to_type = self.0.id_to_type.read(); id_to_type.get(&str).cloned() - } - .or_else(|| { - let py_id = self.0.name_to_pyid.get(&str); - let result = py_id.and_then(|id| { - { + } { + Some(ty) => Ok(ty), + None => { + 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(); pyid_to_type.get(id).copied() - } - .or_else(|| { - let result = Python::with_gil(|py| -> PyResult> { + } { + Some(t) => Ok(t), + None => Python::with_gil(|py| -> PyResult> { 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(); for (key, val) in members.iter() { let key: &str = key.extract()?; @@ -882,20 +900,19 @@ impl SymbolResolver for Resolver { break; } } + if let Ok(t) = sym_ty { + self.0.pyid_to_type.write().insert(*id, t); + } Ok(sym_ty) }) - .unwrap(); - if let Some(result) = result { - self.0.pyid_to_type.write().insert(*id, result); - } - result - }) - }); - if let Some(result) = &result { - self.0.id_to_type.write().insert(str, *result); + .unwrap(), + }; + if let Ok(t) = &result { + self.0.id_to_type.write().insert(str, *t); + } + result } - result - }) + } } fn get_symbol_value<'ctx, 'a>( diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index c5dbe54f..88b00dd3 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -92,7 +92,7 @@ pub trait SymbolResolver { top_level_defs: &[Arc>], primitives: &PrimitiveStore, str: StrRef, - ) -> Option; + ) -> Result; // get the top-level definition of identifiers fn get_identifier_def(&self, str: StrRef) -> Option; @@ -180,8 +180,7 @@ pub fn parse_type_annotation( } else { // it could be a type variable let ty = resolver - .get_symbol_type(unifier, top_level_defs, primitives, *id) - .ok_or_else(|| "unknown type variable name".to_owned())?; + .get_symbol_type(unifier, top_level_defs, primitives, *id)?; if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { Ok(ty) } else { diff --git a/nac3core/src/toplevel/type_annotation.rs b/nac3core/src/toplevel/type_annotation.rs index 3cbc85cc..8fb6c7f9 100644 --- a/nac3core/src/toplevel/type_annotation.rs +++ b/nac3core/src/toplevel/type_annotation.rs @@ -88,7 +88,7 @@ pub fn parse_ast_to_type_annotation_kinds( )); } 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() { Ok(TypeAnnotation::TypeVar(ty)) } else { diff --git a/nac3core/src/typecheck/function_check.rs b/nac3core/src/typecheck/function_check.rs index 65c810e0..1e28e13c 100644 --- a/nac3core/src/typecheck/function_check.rs +++ b/nac3core/src/typecheck/function_check.rs @@ -69,23 +69,21 @@ impl<'a> Inferencer<'a> { ExprKind::Name { id, .. } => { self.should_have_value(expr)?; if !defined_identifiers.contains(id) { - if self - .function_data - .resolver - .get_symbol_type( - self.unifier, - &self.top_level.definitions.read(), - self.primitives, - *id, - ) - .is_some() - { - defined_identifiers.insert(*id); - } else { - return Err(format!( - "unknown identifier {} (use before def?) at {}", - id, expr.location - )); + match self.function_data.resolver.get_symbol_type( + self.unifier, + &self.top_level.definitions.read(), + self.primitives, + *id, + ) { + Ok(_) => { + self.defined_identifiers.insert(*id); + } + Err(e) => { + return Err(format!( + "type error of identifier `{}` ({}) at {}", + id, e, expr.location + )); + } } } } diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index 0bd010b6..dc96638e 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -181,7 +181,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> { self.primitives, id, ) - .unwrap_or_else(|| { + .unwrap_or_else(|_| { self.variable_mapping.insert(id, value_ty); value_ty }) @@ -360,23 +360,21 @@ impl<'a> fold::Fold<()> for Inferencer<'a> { Some(self.infer_constant(value, &expr.location)?), ast::ExprKind::Name { id, .. } => { if !self.defined_identifiers.contains(id) { - if self - .function_data - .resolver - .get_symbol_type( - self.unifier, - &self.top_level.definitions.read(), - self.primitives, - *id, - ) - .is_some() - { - self.defined_identifiers.insert(*id); - } else { - return report_error( - &format!("unknown identifier {} (use before def?)", id), - expr.location, - ); + match self.function_data.resolver.get_symbol_type( + self.unifier, + &self.top_level.definitions.read(), + self.primitives, + *id, + ) { + Ok(_) => { + self.defined_identifiers.insert(*id); + } + Err(e) => { + return report_error( + &format!("type error of identifier `{}` ({})", id, e), + expr.location, + ); + } } } Some(self.infer_identifier(*id)?) @@ -765,7 +763,7 @@ impl<'a> Inferencer<'a> { .function_data .resolver .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; variable_mapping.insert(id, ty); ty diff --git a/nac3standalone/src/basic_symbol_resolver.rs b/nac3standalone/src/basic_symbol_resolver.rs index a32432e9..6dff3038 100644 --- a/nac3standalone/src/basic_symbol_resolver.rs +++ b/nac3standalone/src/basic_symbol_resolver.rs @@ -51,12 +51,8 @@ impl SymbolResolver for Resolver { _: &[Arc>], _: &PrimitiveStore, str: StrRef, - ) -> Option { - let ret = self.0.id_to_type.lock().get(&str).cloned(); - if ret.is_none() { - // println!("unknown here resolver {}", str); - } - ret + ) -> Result { + self.0.id_to_type.lock().get(&str).cloned().ok_or(format!("cannot get type of {}", str)) } fn get_symbol_value<'ctx, 'a>(