diff --git a/examples/wip.rs b/examples/wip.rs index 80b5c89b4f376892b430a771bc22c3d6b5369f45..7756966ec21967c3b91b3fdfc6fda02d9fc62bfb 100644 --- a/examples/wip.rs +++ b/examples/wip.rs @@ -4,7 +4,7 @@ fn main() { let mut a = 5; a = 5; a = { 7 }; - a = if true { 7 } else { 5 } + a = if true { 7 } else { 5 }; } fn b(x: i32) -> i32 { diff --git a/src/check.rs b/src/check.rs index 8870a42cd9d6f52b68f12e56172c1ccf6e43a5ff..5baafbdc6566abadc1b23f16ea3603bcf3c359d3 100644 --- a/src/check.rs +++ b/src/check.rs @@ -190,7 +190,7 @@ fn expr_type( Block(b) => check_stmts(b, fn_env, type_env, var_env), - Stmt(s) => panic!(), + Stmt(s) => check_stmt(s, fn_env, type_env, var_env), } } @@ -246,128 +246,139 @@ fn is_known(t: &Type) -> bool { } } -pub fn check_stmts( - stmts: &Stmts, +pub fn check_stmt( + s: &Stmt, fn_env: &FnEnv, type_env: &TypeEnv, var_env: &mut VarEnv, ) -> Result<Type, Error> { use Stmt::*; - - var_env.push_empty_scope(); - - let t = stmts.stmts.iter().try_fold(Type::Unit, |_, s| { - trace!("stmt: {}", s); - match s { - Stmt::Block(b) => check_stmts(b, fn_env, type_env, var_env), - - Expr(e) => expr_type(&*e, fn_env, type_env, var_env), - - Let(var_id, is_mut, ot, oe) => { - let t: Type = match (ot, oe) { - (Some(t), Some(e)) => { - let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - let e_type = strip_mut(e_type); - match strip_mut(t.clone()) == e_type { - true => t.clone(), - false => { - trace!("e {}", e); - Err(format!("incompatible types, {} <> {}", t, e_type))? - } + trace!("stmt: {}", s); + match s { + Stmt::Block(b) => check_stmts(b, fn_env, type_env, var_env), + + Expr(e) => expr_type(&*e, fn_env, type_env, var_env), + + Let(var_id, is_mut, ot, oe) => { + let t: Type = match (ot, oe) { + (Some(t), Some(e)) => { + let e_type = expr_type(&*e, fn_env, type_env, var_env)?; + let e_type = strip_mut(e_type); + match strip_mut(t.clone()) == e_type { + true => t.clone(), + false => { + trace!("e {}", e); + Err(format!("incompatible types, {} <> {}", t, e_type))? } } - (None, Some(e)) => { - 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())?, - } + } + (None, Some(e)) => { + 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())?, } - (Some(t), None) => t.clone(), - _ => Type::Unknown, - }; - let t = match is_mut { - true => Type::Mut(Box::new(t)), - false => t, - }; - var_env.new_id(var_id.clone(), t); - trace!("var_env {:?}", var_env); - Ok(Type::Unit) - } + } + (Some(t), None) => t.clone(), + _ => Type::Unknown, + }; + let t = match is_mut { + true => Type::Mut(Box::new(t)), + false => t, + }; + var_env.new_id(var_id.clone(), t); + trace!("var_env {:?}", var_env); + Ok(Type::Unit) + } - Assign(lh, e) => { - trace!("assign"); + Assign(lh, e) => { + trace!("assign"); - let e_type = expr_type(&*e, fn_env, type_env, var_env)?; - trace!("e_type = {}", &e_type); - let e_type = strip_mut(e_type); - trace!("e_type stripped = {}", &e_type); + let e_type = expr_type(&*e, fn_env, type_env, var_env)?; + trace!("e_type = {}", &e_type); + let e_type = strip_mut(e_type); + trace!("e_type stripped = {}", &e_type); - trace!("lh expr = {:?}", lh); + trace!("lh expr = {:?}", lh); - let lh_type = lexpr_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 unknown"); - *lh_type = e_type.clone(); + trace!("assign to `mut Unknown`"); + *t = Box::new(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, - }, - - _ => Err(format!("assignment to immutable"))?, - } { - Ok(Type::Unit) - } else { - Err(format!("cannot assign {} = {}", &lh_type, e_type)) - } + _ => **t == e_type, + }, + + _ => Err(format!("assignment to immutable"))?, + } { + Ok(Type::Unit) + } else { + Err(format!("cannot assign {} = {}", &lh_type, e_type)) } + } - While(e, block) => match expr_type(&*e, fn_env, type_env, var_env) { - Ok(Type::Bool) => { - let _ = check_stmts(&block, fn_env, type_env, var_env)?; - Ok(Type::Unit) // a while statement is of unit type; - } - _ => Err("Condition not Boolean".to_string()), - }, - - If(e, then, o_else) => match expr_type(&*e, fn_env, type_env, var_env)? { - Type::Bool => { - // The condition is of Bool type - let then_type = check_stmts(&then, fn_env, type_env, var_env)?; - trace!("then type {}", then_type); - match o_else { - None => Ok(then_type), // type of the arm - Some(else_stmts) => { - let else_type = check_stmts(&else_stmts, fn_env, type_env, var_env)?; - trace!("else type {}", else_type); - - match then_type == else_type { - true => Ok(then_type), // same type of both arms - false => { - trace!("error-----"); - Err(format!( - "'then' arm :{} does not match 'else' arm :{}", - then_type, else_type - )) - } + While(e, block) => match expr_type(&*e, fn_env, type_env, var_env) { + Ok(Type::Bool) => { + let _ = check_stmts(&block, fn_env, type_env, var_env)?; + Ok(Type::Unit) // a while statement is of unit type; + } + _ => Err("Condition not Boolean".to_string()), + }, + + If(e, then, o_else) => match expr_type(&*e, fn_env, type_env, var_env)? { + Type::Bool => { + // The condition is of Bool type + let then_type = check_stmts(&then, fn_env, type_env, var_env)?; + trace!("then type {}", then_type); + match o_else { + None => Ok(then_type), // type of the arm + Some(else_stmts) => { + let else_type = check_stmts(&else_stmts, fn_env, type_env, var_env)?; + trace!("else type {}", else_type); + + match then_type == else_type { + true => Ok(then_type), // same type of both arms + false => { + trace!("error-----"); + Err(format!( + "'then' arm :{} does not match 'else' arm :{}", + then_type, else_type + )) } } } } - _ => Err("Condition not Boolean".to_string()), - }, - Semi => panic!("ICE"), - } - })?; + } + _ => Err("Condition not Boolean".to_string()), + }, + Semi => panic!("ICE"), + } +} + +pub fn check_stmts( + stmts: &Stmts, + fn_env: &FnEnv, + type_env: &TypeEnv, + var_env: &mut VarEnv, +) -> Result<Type, Error> { + use Stmt::*; + + var_env.push_empty_scope(); + + let t = stmts + .stmts + .iter() + .try_fold(Type::Unit, |_, s| check_stmt(s, fn_env, type_env, var_env))?; var_env.pop_scope(); if !stmts.ret {