fixed some inference rules...

This commit is contained in:
pca006132 2021-06-25 16:49:58 +08:00
parent 5292f32835
commit 42511334f7
1 changed files with 24 additions and 60 deletions

View File

@ -65,15 +65,10 @@ fn infer_constant(
let int32: Result<i32, _> = value.try_into(); let int32: Result<i32, _> = value.try_into();
if int32.is_ok() { if int32.is_ok() {
Ok(Some(ctx.get_primitive(INT32_TYPE))) Ok(Some(ctx.get_primitive(INT32_TYPE)))
} else {
let int64: Result<i64, _> = value.try_into();
if int64.is_ok() {
Ok(Some(ctx.get_primitive(INT64_TYPE)))
} else { } else {
Err("integer out of range".into()) Err("integer out of range".into())
} }
} }
}
Number::Float { .. } => Ok(Some(ctx.get_primitive(FLOAT_TYPE))), Number::Float { .. } => Ok(Some(ctx.get_primitive(FLOAT_TYPE))),
_ => Err("not supported".into()), _ => Err("not supported".into()),
} }
@ -98,6 +93,7 @@ fn infer_list<'b: 'a, 'a>(
return Err("list elements must have some type".into()); return Err("list elements must have some type".into());
} }
for v in types { for v in types {
// TODO: try virtual type...
if v? != head { if v? != head {
return Err("inhomogeneous list is not allowed".into()); return Err("inhomogeneous list is not allowed".into());
} }
@ -124,31 +120,14 @@ fn infer_attribute<'a>(
name: &str, name: &str,
) -> ParserResult { ) -> ParserResult {
let value = infer_expr(ctx, value)?.ok_or_else(|| "no value".to_string())?; let value = infer_expr(ctx, value)?.ok_or_else(|| "no value".to_string())?;
if let TypeVariable(id) = value.as_ref() { if let TypeVariable(_) = value.as_ref() {
let v = ctx.get_variable_def(*id); return Err("no fields for type variable".into());
if v.bound.is_empty() {
return Err("no fields on unbounded type variable".into());
}
let ty = v.bound[0].get_base(ctx).and_then(|v| v.fields.get(name));
if ty.is_none() {
return Err("unknown field".into());
}
for x in v.bound[1..].iter() {
let ty1 = x.get_base(ctx).and_then(|v| v.fields.get(name));
if ty1 != ty {
return Err("unknown field (type mismatch between variants)".into());
}
}
return Ok(Some(ty.unwrap().clone()));
} }
match value.get_base(ctx) { value
Some(b) => match b.fields.get(name) { .get_base(ctx)
Some(t) => Ok(Some(t.clone())), .and_then(|b| b.fields.get(name).cloned())
None => Err("no such field".into()), .map_or_else(|| Err("no such field".to_string()), |v| Ok(Some(v)))
},
None => Err("this object has no fields".into()),
}
} }
fn infer_bool_ops<'a>(ctx: &mut InferenceContext<'a>, values: &'a [Expression]) -> ParserResult { fn infer_bool_ops<'a>(ctx: &mut InferenceContext<'a>, values: &'a [Expression]) -> ParserResult {
@ -223,6 +202,7 @@ fn infer_call<'b: 'a, 'a>(
args: &'b [Expression], args: &'b [Expression],
function: &'b Expression, function: &'b Expression,
) -> ParserResult { ) -> ParserResult {
// TODO: special handling for int64 constant
let types: Result<Option<Vec<_>>, _> = args.iter().map(|v| infer_expr(ctx, v)).collect(); let types: Result<Option<Vec<_>>, _> = args.iter().map(|v| infer_expr(ctx, v)).collect();
let types = types?; let types = types?;
if types.is_none() { if types.is_none() {
@ -396,15 +376,19 @@ mod test {
let ast = parse_expression("2147483648").unwrap(); let ast = parse_expression("2147483648").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
assert_eq!(result.unwrap().unwrap(), ctx.get_primitive(INT64_TYPE));
let ast = parse_expression("9223372036854775807").unwrap();
let result = infer_expr(&mut ctx, &ast);
assert_eq!(result.unwrap().unwrap(), ctx.get_primitive(INT64_TYPE));
let ast = parse_expression("9223372036854775808").unwrap();
let result = infer_expr(&mut ctx, &ast);
assert_eq!(result, Err("integer out of range".into())); assert_eq!(result, Err("integer out of range".into()));
//
// let ast = parse_expression("2147483648").unwrap();
// let result = infer_expr(&mut ctx, &ast);
// assert_eq!(result.unwrap().unwrap(), ctx.get_primitive(INT64_TYPE));
// let ast = parse_expression("9223372036854775807").unwrap();
// let result = infer_expr(&mut ctx, &ast);
// assert_eq!(result.unwrap().unwrap(), ctx.get_primitive(INT64_TYPE));
// let ast = parse_expression("9223372036854775808").unwrap();
// let result = infer_expr(&mut ctx, &ast);
// assert_eq!(result, Err("integer out of range".into()));
let ast = parse_expression("123.456").unwrap(); let ast = parse_expression("123.456").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
@ -582,31 +566,11 @@ mod test {
let ast = parse_expression("v0.a").unwrap(); let ast = parse_expression("v0.a").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
assert_eq!(result, Err("no fields on unbounded type variable".into())); assert_eq!(result, Err("no fields for type variable".into()));
let ast = parse_expression("v1.a").unwrap(); let ast = parse_expression("v1.a").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
assert_eq!(result.unwrap().unwrap(), ctx.get_primitive(INT32_TYPE)); assert_eq!(result, Err("no fields for type variable".into()));
// shall we support this?
let ast = parse_expression("v1.b").unwrap();
let result = infer_expr(&mut ctx, &ast);
assert_eq!(
result,
Err("unknown field (type mismatch between variants)".into())
);
// assert_eq!(result.unwrap().unwrap(), TypeVariable(v1).into());
let ast = parse_expression("v1.c").unwrap();
let result = infer_expr(&mut ctx, &ast);
assert_eq!(
result,
Err("unknown field (type mismatch between variants)".into())
);
let ast = parse_expression("v1.d").unwrap();
let result = infer_expr(&mut ctx, &ast);
assert_eq!(result, Err("unknown field".into()));
let ast = parse_expression("none().a").unwrap(); let ast = parse_expression("none().a").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
@ -614,7 +578,7 @@ mod test {
let ast = parse_expression("bot.a").unwrap(); let ast = parse_expression("bot.a").unwrap();
let result = infer_expr(&mut ctx, &ast); let result = infer_expr(&mut ctx, &ast);
assert_eq!(result, Err("this object has no fields".into())); assert_eq!(result, Err("no such field".into()));
} }
#[test] #[test]