forked from M-Labs/nac3
nac3core/artiq/standalone: symbol resolver return error msg for type error of host variables
This commit is contained in:
parent
eba9fc8a69
commit
4a1a4dc076
|
@ -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>(
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
Loading…
Reference in New Issue