forked from M-Labs/nac3
started adding error types
* converted to string to avoid breaking interface, would be fixed later * tests would not check error messages now, as messages are not finalized
This commit is contained in:
parent
779288d685
commit
b6e4e68587
|
@ -463,6 +463,7 @@ dependencies = [
|
|||
"num-bigint",
|
||||
"num-traits",
|
||||
"rustpython-parser",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -840,6 +841,26 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
|
|
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
num-bigint = "0.3"
|
||||
num-traits = "0.2"
|
||||
thiserror = "1.0"
|
||||
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm10-0"] }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/RustPython", branch = "master" }
|
||||
|
||||
|
|
|
@ -705,7 +705,7 @@ mod test {
|
|||
|
||||
let ast = parse_expression("a == a == 1").unwrap();
|
||||
let result = infer_expr(&mut ctx, &ast);
|
||||
assert_eq!(result, Err("not equal".into()));
|
||||
assert_eq!(result, Err("different types".into()));
|
||||
|
||||
let ast = parse_expression("True > False").unwrap();
|
||||
let result = infer_expr(&mut ctx, &ast);
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
use super::context::InferenceContext;
|
||||
use super::typedef::{TypeEnum::*, *};
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum SubstError {
|
||||
#[error("different type variables after substitution")]
|
||||
DifferentSubstVar(VariableId, VariableId),
|
||||
#[error("cannot substitute unbounded type variable into bounded one")]
|
||||
UnboundedTypeVar(VariableId, VariableId),
|
||||
#[error("incompatible bound for type variables")]
|
||||
IncompatibleBound(VariableId, VariableId),
|
||||
#[error("only subtype of virtual class can be substituted into virtual class type")]
|
||||
NotVirtualClassSubtype(Type, ClassId),
|
||||
#[error("different types")]
|
||||
DifferentTypes(Type, Type),
|
||||
}
|
||||
|
||||
fn find_subst(
|
||||
ctx: &InferenceContext,
|
||||
|
@ -8,8 +23,7 @@ fn find_subst(
|
|||
sub: &mut HashMap<VariableId, Type>,
|
||||
mut a: Type,
|
||||
mut b: Type,
|
||||
) -> Result<(), String> {
|
||||
// TODO: fix error messages later
|
||||
) -> Result<(), SubstError> {
|
||||
if let TypeVariable(id) = a.as_ref() {
|
||||
if let Some((assumption_id, t)) = valuation {
|
||||
if assumption_id == id {
|
||||
|
@ -33,14 +47,14 @@ fn find_subst(
|
|||
return if id_a == id_b {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("different variables".to_string())
|
||||
Err(SubstError::DifferentSubstVar(*id_a, *id_b))
|
||||
};
|
||||
}
|
||||
let v_a = ctx.get_variable_def(*id_a);
|
||||
let v_b = ctx.get_variable_def(*id_b);
|
||||
if !v_b.bound.is_empty() {
|
||||
if v_a.bound.is_empty() {
|
||||
return Err("unbounded a".to_string());
|
||||
return Err(SubstError::UnboundedTypeVar(*id_a, *id_b));
|
||||
} else {
|
||||
let diff: Vec<_> = v_a
|
||||
.bound
|
||||
|
@ -48,7 +62,7 @@ fn find_subst(
|
|||
.filter(|x| !v_b.bound.contains(x))
|
||||
.collect();
|
||||
if !diff.is_empty() {
|
||||
return Err("different domain".to_string());
|
||||
return Err(SubstError::IncompatibleBound(*id_a, *id_b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +74,7 @@ fn find_subst(
|
|||
if v_a.bound.len() == 1 && v_a.bound[0].as_ref() == b.as_ref() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("different domain".to_string())
|
||||
Err(SubstError::DifferentTypes(a.clone(), b.clone()))
|
||||
}
|
||||
}
|
||||
(_, TypeVariable(id_b)) => {
|
||||
|
@ -69,7 +83,7 @@ fn find_subst(
|
|||
sub.insert(*id_b, a.clone());
|
||||
Ok(())
|
||||
} else {
|
||||
Err("different domain".to_string())
|
||||
Err(SubstError::DifferentTypes(a.clone(), b.clone()))
|
||||
}
|
||||
}
|
||||
(_, VirtualClassType(id_b)) => {
|
||||
|
@ -82,7 +96,7 @@ fn find_subst(
|
|||
parents = [*id_a].to_vec();
|
||||
}
|
||||
_ => {
|
||||
return Err("cannot substitute non-class type into virtual class".to_string());
|
||||
return Err(SubstError::NotVirtualClassSubtype(a.clone(), *id_b));
|
||||
}
|
||||
};
|
||||
while !parents.is_empty() {
|
||||
|
@ -92,11 +106,11 @@ fn find_subst(
|
|||
let c = ctx.get_class_def(parents.remove(0));
|
||||
parents.extend_from_slice(&c.parents);
|
||||
}
|
||||
Err("not subtype".to_string())
|
||||
Err(SubstError::NotVirtualClassSubtype(a.clone(), *id_b))
|
||||
}
|
||||
(ParametricType(id_a, param_a), ParametricType(id_b, param_b)) => {
|
||||
if id_a != id_b || param_a.len() != param_b.len() {
|
||||
Err("different parametric types".to_string())
|
||||
Err(SubstError::DifferentTypes(a.clone(), b.clone()))
|
||||
} else {
|
||||
for (x, y) in param_a.iter().zip(param_b.iter()) {
|
||||
find_subst(ctx, valuation, sub, x.clone(), y.clone())?;
|
||||
|
@ -108,7 +122,7 @@ fn find_subst(
|
|||
if a == b {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("not equal".to_string())
|
||||
Err(SubstError::DifferentTypes(a.clone(), b.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +191,7 @@ fn resolve_call_rec(
|
|||
return Err("incorrect parameter number".to_string());
|
||||
}
|
||||
for (a, b) in args.iter().zip(fun.args.iter()) {
|
||||
find_subst(ctx, valuation, &mut subst, a.clone(), b.clone())?;
|
||||
find_subst(ctx, valuation, &mut subst, a.clone(), b.clone()).map_err(|v| v.to_string())?;
|
||||
}
|
||||
let result = fun.result.as_ref().map(|v| v.subst(&subst));
|
||||
Ok(result.map(|result| {
|
||||
|
@ -204,6 +218,7 @@ mod tests {
|
|||
super::{context::*, primitives::*},
|
||||
*,
|
||||
};
|
||||
use std::matches;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn get_inference_context(ctx: TopLevelContext) -> InferenceContext {
|
||||
|
@ -244,25 +259,25 @@ mod tests {
|
|||
Ok(Some(ctx.get_primitive(FLOAT_TYPE)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "float", &[ctx.get_primitive(BOOL_TYPE)]),
|
||||
Err("different domain".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "float", &[]),
|
||||
Err("incorrect parameter number".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
resolve_call(&ctx, None, "float", &[v1]),
|
||||
Ok(Some(ctx.get_primitive(FLOAT_TYPE)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "float", &[v2]),
|
||||
Err("different domain".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -309,40 +324,40 @@ mod tests {
|
|||
Ok(Some(int64.clone()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(int32), "__add__", &[int64]),
|
||||
Err("not equal".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
// with type variables
|
||||
assert_eq!(
|
||||
resolve_call(&ctx, Some(v1.clone()), "__add__", &[v1.clone()]),
|
||||
Ok(Some(v1.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v0.clone()), "__add__", &[v2.clone()]),
|
||||
Err("unbounded type var".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
Err(..)
|
||||
));
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v1.clone()), "__add__", &[v0]),
|
||||
Err("different domain".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
Err(..)
|
||||
));
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v1.clone()), "__add__", &[v2]),
|
||||
Err("different domain".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
Err(..)
|
||||
));
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v1.clone()), "__add__", &[v3.clone()]),
|
||||
Err("different domain".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
Err(..)
|
||||
));
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v3.clone()), "__add__", &[v1]),
|
||||
Err("no such function".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
Err(..)
|
||||
));
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, Some(v3.clone()), "__add__", &[v3]),
|
||||
Err("no such function".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -394,10 +409,10 @@ mod tests {
|
|||
resolve_call(&ctx, None, "foo", &[v2.clone(), v2.clone(), v3.clone()]),
|
||||
Ok(Some(v2.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "foo", &[v2.clone(), v3.clone(), v3.clone()]),
|
||||
Err("different variables".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
resolve_call(
|
||||
|
@ -417,15 +432,15 @@ mod tests {
|
|||
),
|
||||
Ok(Some(v2.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(
|
||||
&ctx,
|
||||
None,
|
||||
"foo1",
|
||||
&[ParametricType(TUPLE_TYPE, vec![v2, v3.clone(), v3]).into()]
|
||||
),
|
||||
Err("different variables".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -479,15 +494,15 @@ mod tests {
|
|||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(
|
||||
&ctx,
|
||||
Some(ParametricType(LIST_TYPE, vec![v0]).into()),
|
||||
"append",
|
||||
&[v1]
|
||||
),
|
||||
Err("different variables".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -561,10 +576,10 @@ mod tests {
|
|||
Ok(None)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "foo", &[ClassType(bar).into()]),
|
||||
Err("not subtype".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
resolve_call(&ctx, None, "foo1", &[ClassType(foo1).into()]),
|
||||
|
@ -576,10 +591,10 @@ mod tests {
|
|||
Ok(None)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "foo1", &[ClassType(foo).into()]),
|
||||
Err("not subtype".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
|
||||
// virtual class substitution
|
||||
assert_eq!(
|
||||
|
@ -594,9 +609,9 @@ mod tests {
|
|||
resolve_call(&ctx, None, "foo", &[VirtualClassType(foo2).into()]),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assert!(matches!(
|
||||
resolve_call(&ctx, None, "foo", &[VirtualClassType(bar).into()]),
|
||||
Err("not subtype".to_string())
|
||||
);
|
||||
Err(..)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue