diff --git a/src/ast/mod.rs b/src/ast/mod.rs index f72340d..e8df80a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -303,9 +303,6 @@ impl Shape { (Shape::Hole(sym), other) | (other, Shape::Hole(sym)) => { if symbol_table.contains_key(&sym.val) { symbol_table.insert(sym.val.clone(), other.clone().with_pos(sym.pos.clone())); - } else { - // TODO(jwall): Is this an error? - todo!(); } other.clone() }, diff --git a/src/ast/typecheck/mod.rs b/src/ast/typecheck/mod.rs index bb5975b..309d28a 100644 --- a/src/ast/typecheck/mod.rs +++ b/src/ast/typecheck/mod.rs @@ -33,7 +33,7 @@ pub trait DeriveShape { } impl DeriveShape for FuncDef { - fn derive_shape(&self, _symbol_table: &mut BTreeMap, Shape>) -> Shape { + fn derive_shape(&self, symbol_table: &mut BTreeMap, Shape>) -> Shape { // 1. First set up our symbols. let mut table = self .argdefs @@ -41,11 +41,11 @@ impl DeriveShape for FuncDef { .map(|sym| (sym.val.clone(), Shape::Hole(sym.clone()))) .collect::, Shape>>(); // 2.Then determine the shapes of those symbols in our expression. - let _shape = self.fields.derive_shape(&mut table); + let shape = self.fields.derive_shape(&mut table); // 3. Finally determine what the return shape can be. Shape::Func(FuncShapeDef { args: table, - ret: todo!(), + ret: shape.into(), }) } } diff --git a/src/ast/typecheck/test.rs b/src/ast/typecheck/test.rs index 24ca475..66fd573 100644 --- a/src/ast/typecheck/test.rs +++ b/src/ast/typecheck/test.rs @@ -153,24 +153,101 @@ fn multiple_binary_typefail() { ); } +macro_rules! infer_symbol_test { + ($e:expr, $sym_list:expr, $sym_init_list:expr) => {{ + let expr = $e.into(); + let mut checker = Checker::new(); + for (idx, shape) in $sym_init_list.iter().enumerate() { + let symbol = $sym_list[idx].0.clone(); + checker + .symbol_table + .insert(symbol.clone(), shape.clone()); + } + let tokens = tokenize(expr, None).unwrap(); + let token_iter = SliceIter::new(&tokens); + let expr = expression(token_iter); + if let abortable_parser::Result::Complete(_, mut expr) = expr { + checker.walk_expression(&mut expr); + dbg!(&checker.symbol_table); + for (sym, shape) in $sym_list { + assert_eq!( + checker.symbol_table[&sym], + shape, + ); + } + } else { + assert!(false, "Expression failed to parse"); + } + }} +} + #[test] fn infer_symbol_type_test() { // foo should be determined to be int - let expr = "1 + foo".into(); - let symbol: Rc = "foo".into(); - let mut checker = Checker::new(); - checker - .symbol_table - .insert(symbol.clone(), Shape::Hole(PositionedItem::new(symbol.clone(), Position::new(0, 0, 0)))); - let tokens = tokenize(expr, None).unwrap(); - let token_iter = SliceIter::new(&tokens); - let expr = expression(token_iter); - if let abortable_parser::Result::Complete(_, mut expr) = expr { - checker.walk_expression(&mut expr); - dbg!(&checker.symbol_table); - assert_eq!( - checker.symbol_table[&symbol], - Shape::Int(PositionedItem::new(1, Position::new(0, 0, 0))) - ); + let foo = Into::>::into("foo"); + let bar = Into::>::into("bar"); + let table = vec![ + ( + "1 + foo", + vec![( + foo.clone(), + Shape::Int(PositionedItem::new(1, Position::new(0, 0, 0))), + )], + vec![Shape::Hole(PositionedItem::new( + foo.clone(), + Position::new(0, 0, 0), + ))], + ), + ( + "bar + foo", + vec![ + ( + foo.clone(), + Shape::Float(PositionedItem::new(1.0, Position::new(0, 0, 0))), + ), + ( + bar.clone(), + Shape::Float(PositionedItem::new(1.0, Position::new(0, 0, 0))), + ), + ], + vec![ + Shape::Hole(PositionedItem::new(foo.clone(), Position::new(0, 0, 0))), + Shape::Float(PositionedItem::new(1.0, Position::new(0, 0, 0))), + ], + ), + ]; + for (expr, sym_list, sym_init_list) in table { + infer_symbol_test!(expr, sym_list, sym_init_list) } } + +#[test] +fn infer_func_type_test() { + let mut args = BTreeMap::new(); + args.insert( + Into::>::into("foo"), + Shape::Int(PositionedItem { + pos: Position { + file: None, + line: 1, + column: 6, + offset: 5, + }, + val: 1, + }), + ); + let ret = Shape::Int(PositionedItem { + pos: Position { + file: None, + line: 1, + column: 20, + offset: 19, + }, + val: 1, + }) + .into(); + assert_type_success!( + "func(foo) => foo + 1;", + Shape::Func(FuncShapeDef { args, ret }) + ); +}