diff --git a/examples/mut.rs b/examples/mut.rs index a93ad514f1a2d99ec15ecb020564d501bc5698f9..ec2e14053f4a8740ff49f79be78c004f2d13d5b0 100644 --- a/examples/mut.rs +++ b/examples/mut.rs @@ -1,5 +1,5 @@ -fn main() -> i32 { +fn main() { let mut a = 0; a = 2; - a + let b = a; } diff --git a/examples/mut2.rs b/examples/mut2.rs index 21669598482275164deae1278c391f309ca2646e..33fd4af8276b1200ed6b92eb5603385a39dcd51d 100644 --- a/examples/mut2.rs +++ b/examples/mut2.rs @@ -1,8 +1,8 @@ -fn main() -> i32 { +fn main() { let mut a = 0; a = 2; let mut b = a; // copy semantics a = 3; b = b + 1; - a + b + let c = a + b; } diff --git a/src/check.rs b/src/check.rs index 1b169440030c1ce171971d696dddaba23240f9b5..18d567543835c534b225eeaad6d535c8e5f4a9bb 100644 --- a/src/check.rs +++ b/src/check.rs @@ -190,6 +190,41 @@ fn expr_type( } } +fn lexpr_type<'a>( + e: &Expr, + fn_env: &FnEnv, + type_env: &TypeEnv, + var_env: &'a mut VarEnv, +) -> Result<&'a mut Type, Error> { + use Expr::*; + trace!("expr_type {}", e); + trace!("var_env {:?}", var_env); + + match e { + Id(id) => match var_env.get_mut(id.to_string()) { + Some(t) => Ok(t), + None => Err(format!("variable not found {}", id)), + }, + + DeRef(deref_e) => { + let t = lexpr_type(deref_e, fn_env, type_env, var_env)?; + trace!("deref_t {}", &t); + + // strip mut + let t = match t { + Type::Mut(t) => t, + _ => t, + }; + trace!("strip deref_t {}", t); + match t { + Type::Ref(dt) => Ok(dt), + _ => Err(format!("cannot deref {} of type {}", e, t)), + } + } + _ => Err(format!("Illegal left hand expression {}", e)), + } +} + fn strip_mut(t: Type) -> Type { match t { Type::Mut(t) => *t, @@ -228,7 +263,8 @@ pub fn check_stmts( let t: Type = match (ot, oe) { (Some(t), Some(e)) => { let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - match *t == e_type { + let e_type = strip_mut(e_type); + match strip_mut(t.clone()) == e_type { true => t.clone(), false => { trace!("e {}", e); @@ -237,9 +273,9 @@ pub fn check_stmts( } } (None, Some(e)) => { - let et = expr_type(&*e, fn_env, type_env, var_env)?; - match is_known(&et) { - true => et, + let e_type = strip_mut(expr_type(&*e, fn_env, type_env, var_env)?); + match is_known(&e_type) { + true => e_type, _ => Err("reference to unknown type".to_string())?, } } @@ -256,21 +292,28 @@ pub fn check_stmts( } Assign(lh, e) => { + trace!("assign"); + let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - trace!("e_type = {}", e_type); - trace!("lh = {:?}", lh); + trace!("e_type = {}", &e_type); + let e_type = strip_mut(e_type); + trace!("e_type stripped = {}", &e_type); + + trace!("lh expr = {:?}", lh); - let lh_type = expr_type(lh, fn_env, type_env, var_env)?; - trace!("lh_type {}", &lh_type); + let lh_type = lexpr_type(lh, fn_env, type_env, var_env)?; + trace!("lh_type {}", lh_type); - if match &lh_type { + if match lh_type { Type::Unknown => { trace!("assign to unknown"); + *lh_type = e_type.clone(); true } Type::Mut(t) => match **t { Type::Unknown => { trace!("assign to `mut Unknown`"); + *t = Box::new(e_type.clone()); true } _ => **t == e_type, diff --git a/tests/test_check.rs b/tests/test_check.rs index d1209487f4d4d1e1d01863d9332d7e5602f9765e..6334148554f2942ae619d7e2a71c40ea61f5d876 100644 --- a/tests/test_check.rs +++ b/tests/test_check.rs @@ -21,6 +21,11 @@ fn check_assign2() { assert!(check(&read_file::parse("examples/assign2.rs")).is_ok()); } +#[test] +fn check_assign3() { + assert!(check(&read_file::parse("examples/assign3.rs")).is_ok()); +} + #[test] fn check_assign_err() { assert!(check(&read_file::parse("examples/assign_err.rs")).is_err()); @@ -154,3 +159,13 @@ fn check_ref_err3() { fn check_ref_err4() { assert!(check(&read_file::parse("examples/ref_err4.rs")).is_err()); } + +#[test] +fn check_scopes() { + assert!(check(&read_file::parse("examples/scopes.rs")).is_ok()); +} + +#[test] +fn check_scopes_err() { + assert!(check(&read_file::parse("examples/scopes_err.rs")).is_err()); +} diff --git a/tests/test_vm.rs b/tests/test_vm.rs index 27086b6f8606e08a5be220f8124c5deb43406fb5..33d77295160878024b5784eb8dae75c171cdf049 100644 --- a/tests/test_vm.rs +++ b/tests/test_vm.rs @@ -35,6 +35,10 @@ fn scopes_test() { eval_prog("examples/scopes.rs"); } +#[test] +fn scopes_err_test() { + eval_prog("examples/scopes_err.rs"); +} #[test] fn vm_test() { eval_prog("examples/vm.rs");