forked from M-Labs/nac3
1
0
Fork 0

nac3core: better check and err msg for default param

This commit is contained in:
ychenfo 2022-03-30 03:50:34 +08:00
parent e52d7fc97a
commit 388c9b7241
2 changed files with 75 additions and 93 deletions

View File

@ -416,103 +416,77 @@ impl TopLevelComposer {
primitive: &PrimitiveStore, primitive: &PrimitiveStore,
unifier: &mut Unifier, unifier: &mut Unifier,
) -> Result<(), String> { ) -> Result<(), String> {
let res = match val { fn type_default_param(
SymbolValue::Bool(..) => { val: &SymbolValue,
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.bool) { primitive: &PrimitiveStore,
None unifier: &mut Unifier,
} else { ) -> TypeAnnotation {
Some("bool".to_string()) match val {
SymbolValue::Bool(..) => TypeAnnotation::Primitive(primitive.bool),
SymbolValue::Double(..) => TypeAnnotation::Primitive(primitive.float),
SymbolValue::I32(..) => TypeAnnotation::Primitive(primitive.int32),
SymbolValue::I64(..) => TypeAnnotation::Primitive(primitive.int64),
SymbolValue::U32(..) => TypeAnnotation::Primitive(primitive.uint32),
SymbolValue::U64(..) => TypeAnnotation::Primitive(primitive.uint64),
SymbolValue::Str(..) => TypeAnnotation::Primitive(primitive.str),
SymbolValue::Tuple(vs) => {
let vs_tys = vs
.iter()
.map(|v| type_default_param(v, primitive, unifier))
.collect::<Vec<_>>();
TypeAnnotation::Tuple(vs_tys)
} }
} SymbolValue::OptionNone => TypeAnnotation::CustomClass {
SymbolValue::Double(..) => { id: primitive.option.get_obj_id(unifier),
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) { params: Default::default(),
None },
} else { SymbolValue::OptionSome(v) => {
Some("float".to_string()) let ty = type_default_param(v, primitive, unifier);
} TypeAnnotation::CustomClass {
} id: primitive.option.get_obj_id(unifier),
SymbolValue::I32(..) => { params: vec![ty],
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int32) {
None
} else {
Some("int32".to_string())
}
}
SymbolValue::I64(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int64) {
None
} else {
Some("int64".to_string())
}
}
SymbolValue::U32(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.uint32) {
None
} else {
Some("uint32".to_string())
}
}
SymbolValue::U64(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.uint64) {
None
} else {
Some("uint64".to_string())
}
}
SymbolValue::Str(..) => {
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.str) {
None
} else {
Some("str".to_string())
}
}
SymbolValue::Tuple(elts) => {
if let TypeAnnotation::Tuple(elts_ty) = ty {
for (e, t) in elts.iter().zip(elts_ty.iter()) {
Self::check_default_param_type(e, t, primitive, unifier)?
} }
if elts.len() != elts_ty.len() {
Some(format!("tuple of length {}", elts.len()))
} else {
None
}
} else {
Some("tuple".to_string())
} }
} }
SymbolValue::OptionNone => { }
if let TypeAnnotation::CustomClass { id, .. } = ty {
if *id == primitive.option.get_obj_id(unifier) { fn is_compatible(
None found: &TypeAnnotation,
} else { expect: &TypeAnnotation,
Some("option".into()) unifier: &mut Unifier,
} primitive: &PrimitiveStore,
} else { ) -> bool {
Some("option".into()) match (found, expect) {
(TypeAnnotation::Primitive(f), TypeAnnotation::Primitive(e)) => {
unifier.unioned(*f, *e)
} }
} (
SymbolValue::OptionSome(v) => { TypeAnnotation::CustomClass { id: f_id, params: f_param },
if let TypeAnnotation::CustomClass { id, params } = ty { TypeAnnotation::CustomClass { id: e_id, params: e_param },
if *id == primitive.option.get_obj_id(unifier) { ) => {
if params.len() == 1 { *f_id == *e_id
Self::check_default_param_type(v, &params[0], primitive, unifier)?; && *f_id == primitive.option.get_obj_id(unifier)
None && (f_param.is_empty()
} else { || (f_param.len() == 1
Some("option".into()) && e_param.len() == 1
} && is_compatible(&f_param[0], &e_param[0], unifier, primitive)))
} else {
Some("option".into())
}
} else {
Some("option".into())
} }
(TypeAnnotation::Tuple(f), TypeAnnotation::Tuple(e)) => {
f.len() == e.len()
&& f.iter()
.zip(e.iter())
.all(|(f, e)| is_compatible(f, e, unifier, primitive))
}
_ => false,
} }
}; }
if let Some(found) = res {
let found = type_default_param(val, primitive, unifier);
if !is_compatible(&found, ty, unifier, primitive) {
Err(format!( Err(format!(
"incompatible default parameter type, expect {}, found {}", "incompatible default parameter type, expect {}, found {}",
ty.stringify(unifier), ty.stringify(unifier),
found found.stringify(unifier),
)) ))
} else { } else {
Ok(()) Ok(())

View File

@ -29,20 +29,28 @@ impl TypeAnnotation {
{ {
(*name).into() (*name).into()
} else { } else {
format!("def_{}", id.0) unreachable!()
} }
} }
None => format!("def_{}", id.0), None => format!("class_def_{}", id.0),
}; };
format!( format!(
"{{class: {}, params: {:?}}}", "{}{}",
class_name, class_name,
params.iter().map(|p| p.stringify(unifier)).collect_vec() {
let param_list = params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", ");
if param_list.is_empty() {
"".into()
} else {
format!("[{}]", param_list)
}
}
) )
} }
Virtual(ty) | List(ty) => ty.stringify(unifier), Virtual(ty) => format!("virtual[{}]", ty.stringify(unifier)),
List(ty) => format!("list[{}]", ty.stringify(unifier)),
Tuple(types) => { Tuple(types) => {
format!("({:?})", types.iter().map(|p| p.stringify(unifier)).collect_vec()) format!("tuple[{}]", types.iter().map(|p| p.stringify(unifier)).collect_vec().join(", "))
} }
} }
} }