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::Double(..) => { SymbolValue::I32(..) => TypeAnnotation::Primitive(primitive.int32),
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) { SymbolValue::I64(..) => TypeAnnotation::Primitive(primitive.int64),
None SymbolValue::U32(..) => TypeAnnotation::Primitive(primitive.uint32),
} else { SymbolValue::U64(..) => TypeAnnotation::Primitive(primitive.uint64),
Some("float".to_string()) SymbolValue::Str(..) => TypeAnnotation::Primitive(primitive.str),
} SymbolValue::Tuple(vs) => {
} let vs_tys = vs
SymbolValue::I32(..) => { .iter()
if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int32) { .map(|v| type_default_param(v, primitive, unifier))
None .collect::<Vec<_>>();
} else { TypeAnnotation::Tuple(vs_tys)
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) {
None
} else {
Some("option".into())
}
} else {
Some("option".into())
}
} }
SymbolValue::OptionNone => TypeAnnotation::CustomClass {
id: primitive.option.get_obj_id(unifier),
params: Default::default(),
},
SymbolValue::OptionSome(v) => { SymbolValue::OptionSome(v) => {
if let TypeAnnotation::CustomClass { id, params } = ty { let ty = type_default_param(v, primitive, unifier);
if *id == primitive.option.get_obj_id(unifier) { TypeAnnotation::CustomClass {
if params.len() == 1 { id: primitive.option.get_obj_id(unifier),
Self::check_default_param_type(v, &params[0], primitive, unifier)?; params: vec![ty],
None
} else {
Some("option".into())
}
} else {
Some("option".into())
}
} else {
Some("option".into())
} }
} }
}; }
if let Some(found) = res { }
fn is_compatible(
found: &TypeAnnotation,
expect: &TypeAnnotation,
unifier: &mut Unifier,
primitive: &PrimitiveStore,
) -> bool {
match (found, expect) {
(TypeAnnotation::Primitive(f), TypeAnnotation::Primitive(e)) => {
unifier.unioned(*f, *e)
}
(
TypeAnnotation::CustomClass { id: f_id, params: f_param },
TypeAnnotation::CustomClass { id: e_id, params: e_param },
) => {
*f_id == *e_id
&& *f_id == primitive.option.get_obj_id(unifier)
&& (f_param.is_empty()
|| (f_param.len() == 1
&& e_param.len() == 1
&& is_compatible(&f_param[0], &e_param[0], unifier, primitive)))
}
(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,
}
}
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(", "))
} }
} }
} }