forked from M-Labs/nac3
nac3core: better check and err msg for default param
This commit is contained in:
parent
e52d7fc97a
commit
388c9b7241
|
@ -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, ¶ms[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(())
|
||||||
|
|
|
@ -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(", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue