diff --git a/huia-compiler/src/clause.rs b/huia-compiler/src/clause.rs index 9181465..83b6870 100644 --- a/huia-compiler/src/clause.rs +++ b/huia-compiler/src/clause.rs @@ -33,8 +33,8 @@ impl Clause { } impl ResultType for Clause { - fn result_type(&self) -> Option<&TyIdx> { - Some(&self.result_type) + fn result_type(&self) -> &TyIdx { + &self.result_type } } diff --git a/huia-compiler/src/context/display.rs b/huia-compiler/src/context/display.rs index bbf151a..3cced80 100644 --- a/huia-compiler/src/context/display.rs +++ b/huia-compiler/src/context/display.rs @@ -159,7 +159,11 @@ fn fmt_types(buffer: &mut String, context: &Context) { } else if ty.is_unresolved() { buffer.push_str("unknown type"); } - buffer.push_str("\n") + if let Some(location) = ty.get_location() { + buffer.push_str(&format!(" defined at {}\n", location)); + } else { + buffer.push_str("\n"); + } } } @@ -195,7 +199,7 @@ fn fmt_functions(mut buffer: &mut String, context: &Context) { } buffer.push_str(&format!( " -> {}\n", - fmt_ty_name(clause.result_type().unwrap(), &context) + fmt_ty_name(clause.result_type(), &context) )); let mut jumps = Vec::new(); @@ -530,7 +534,7 @@ fn fmt_methods(mut buffer: &mut String, context: &Context) { } buffer.push_str(&format!( " -> {}\n", - fmt_ty_name(clause.result_type().unwrap(), &context) + fmt_ty_name(clause.result_type(), &context) )); let mut jumps = vec![clause.body().clone()]; diff --git a/huia-compiler/src/function.rs b/huia-compiler/src/function.rs index b2c481e..5e6765f 100644 --- a/huia-compiler/src/function.rs +++ b/huia-compiler/src/function.rs @@ -88,20 +88,20 @@ impl Locatable for &mut Function { } impl ResultType for Function { - fn result_type(&self) -> Option<&TyIdx> { - Some(&self.return_type) + fn result_type(&self) -> &TyIdx { + &self.return_type } } impl ResultType for &Function { - fn result_type(&self) -> Option<&TyIdx> { - Some(&self.return_type) + fn result_type(&self) -> &TyIdx { + &self.return_type } } impl ResultType for &mut Function { - fn result_type(&self) -> Option<&TyIdx> { - Some(&self.return_type) + fn result_type(&self) -> &TyIdx { + &self.return_type } } diff --git a/huia-compiler/src/improvements/block_result_types.rs b/huia-compiler/src/improvements/block_result_types.rs index fcfa834..fe1e53e 100644 --- a/huia-compiler/src/improvements/block_result_types.rs +++ b/huia-compiler/src/improvements/block_result_types.rs @@ -1,6 +1,7 @@ use crate::block::BlockIdx; use crate::clause::Clauseable; use crate::context::Context; +use crate::ty::ResultType; pub fn pass(fun: &mut T, mut context: &mut Context) { for clause in fun.clauses() { diff --git a/huia-compiler/src/improvements/clause_return_types.rs b/huia-compiler/src/improvements/clause_return_types.rs index b564052..6568a6e 100644 --- a/huia-compiler/src/improvements/clause_return_types.rs +++ b/huia-compiler/src/improvements/clause_return_types.rs @@ -6,7 +6,7 @@ use crate::ty::ResultType; pub fn pass(fun: &mut T, context: &mut Context) { for clause in fun.clauses() { let block_idx = clause.body(); - let ty_idx = clause.result_type().unwrap(); + let ty_idx = clause.result_type(); let result_type = context.get_block(block_idx).unwrap().result_type().clone(); let ty = context.get_type_mut(ty_idx).unwrap(); ty.resolve(&result_type); diff --git a/huia-compiler/src/improvements/desugar_infix.rs b/huia-compiler/src/improvements/desugar_infix.rs index b1e682b..563396a 100644 --- a/huia-compiler/src/improvements/desugar_infix.rs +++ b/huia-compiler/src/improvements/desugar_infix.rs @@ -43,6 +43,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) { mod test { use super::*; use crate::ir::builder::Builder; + use crate::location::Location; use huia_parser::ast::Term; #[test] @@ -50,6 +51,7 @@ mod test { let terms = Term::input("3 * 2").unwrap(); let mut context = Context::test(); let mut builder = Builder::default(); + builder.push_block(context.unknown_type(Location::test())); for term in terms { builder.build(term, &mut context); diff --git a/huia-compiler/src/improvements/desugar_unary.rs b/huia-compiler/src/improvements/desugar_unary.rs index 32286bb..8b14f85 100644 --- a/huia-compiler/src/improvements/desugar_unary.rs +++ b/huia-compiler/src/improvements/desugar_unary.rs @@ -27,6 +27,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) { mod test { use super::*; use crate::ir::builder::Builder; + use crate::location::Location; use huia_parser::ast::Term; #[test] @@ -34,6 +35,7 @@ mod test { let terms = Term::input("!3").unwrap(); let mut context = Context::test(); let mut builder = Builder::default(); + builder.push_block(context.unknown_type(Location::test())); for term in terms { builder.build(term, &mut context); diff --git a/huia-compiler/src/improvements/infix_folding.rs b/huia-compiler/src/improvements/infix_folding.rs index a47af32..c5cf98e 100644 --- a/huia-compiler/src/improvements/infix_folding.rs +++ b/huia-compiler/src/improvements/infix_folding.rs @@ -71,6 +71,7 @@ fn perform_f64_infix_fold(op: &BinOp, lhs: f64, rhs: f64) -> Option { mod test { use super::*; use crate::ir::builder::Builder; + use crate::location::Location; use huia_parser::ast::Term; #[test] @@ -78,6 +79,7 @@ mod test { let term = Term::input("3 * 2 + 13 / 2").unwrap()[0].clone(); let mut context = Context::test(); let mut builder = Builder::default(); + builder.push_block(context.unknown_type(Location::test())); builder.build(term, &mut context); let mut ir = builder.pop_ir().unwrap(); @@ -92,6 +94,7 @@ mod test { let term = Term::input("1.5 * 2.0 / 3.0").unwrap()[0].clone(); let mut context = Context::test(); let mut builder = Builder::default(); + builder.push_block(context.unknown_type(Location::test())); builder.build(term, &mut context); let mut ir = builder.pop_ir().unwrap(); diff --git a/huia-compiler/src/improvements/unary_folding.rs b/huia-compiler/src/improvements/unary_folding.rs index ed58cbe..08ea83b 100644 --- a/huia-compiler/src/improvements/unary_folding.rs +++ b/huia-compiler/src/improvements/unary_folding.rs @@ -54,6 +54,8 @@ pub fn pass(ir: &mut IR, context: &mut Context) { mod test { use super::*; use crate::ir::builder::Builder; + use crate::location::Location; + use crate::ty::ResultType; use huia_parser::ast::Term; #[test] @@ -61,6 +63,7 @@ mod test { let term = Term::input("!3").unwrap()[0].clone(); let mut context = Context::test(); let mut builder = Builder::default(); + builder.push_block(context.unknown_type(Location::test())); builder.build(term, &mut context); let mut ir = builder.pop_ir().unwrap(); diff --git a/huia-compiler/src/ir/builder.rs b/huia-compiler/src/ir/builder.rs index 95936aa..21925f7 100644 --- a/huia-compiler/src/ir/builder.rs +++ b/huia-compiler/src/ir/builder.rs @@ -9,7 +9,7 @@ use crate::location::Locatable; use crate::location::Location as Loc; use crate::method::{Method, MethodIdx, Modifier}; use crate::stable::StringIdx; -use crate::ty::TyIdx; +use crate::ty::{ResultType, TyIdx}; use huia_parser::ast::{Identifier, Location, NodeType, Term, TypeSpec, Value}; /// The Builder is a simple stack machine for converting AST into IR. @@ -69,7 +69,7 @@ impl Builder { context.reference_type(&name, location.clone()) } else if op.is_arithmetic() { - lhs.result_type() + lhs.result_type().clone() } else { panic!("Operator {:?} is neither arithmetic nor logical", op); @@ -123,7 +123,7 @@ impl Builder { self.build(rhs.clone(), &mut context); let rhs = self.pop_ir().unwrap(); self.env_set(&name, &rhs.result_type()); - self.push_ir(IR::new_set_local(rhs.result_type(), location, name, rhs)); + self.push_ir(IR::new_set_local(rhs.result_type().clone(), location, name, rhs)); } NodeType::Float => { let ty_idx = context.constant_string("Huia.Native.Float"); @@ -171,8 +171,8 @@ impl Builder { if let Some(last_ir) = self.pop_ir() { let rt = context.get_type_mut(&result_type).unwrap(); rt.resolve(&last_ir.result_type()); - self.push_ir(IR::new_set_local(last_ir.result_type(), location.clone(), value_var_name.clone(), last_ir.clone())); - self.push_ir(IR::new_jump(last_ir.result_type(), location.clone(), following_block_idx.into())); + self.push_ir(IR::new_set_local(last_ir.result_type().clone(), location.clone(), value_var_name.clone(), last_ir.clone())); + self.push_ir(IR::new_jump(last_ir.result_type().clone(), location.clone(), following_block_idx.into())); } else { self.push_ir(IR::new_jump(result_type.clone(), location.clone(), following_block_idx.into())); } @@ -198,12 +198,12 @@ impl Builder { if let Some(last_ir) = self.pop_ir() { let rt = context.get_type(&result_type).unwrap(); - if rt.target().unwrap() != &last_ir.result_type() { + if rt.target().unwrap() != last_ir.result_type() { context.compile_error("Both branches of an if statement must result in the same type.", location.clone(), ErrorKind::InconsistentBranchTypes); } - self.push_ir(IR::new_set_local(last_ir.result_type(), location.clone(), value_var_name.clone(), last_ir.clone())); - self.push_ir(IR::new_jump(last_ir.result_type(), location.clone(), following_block_idx.into())); + self.push_ir(IR::new_set_local(last_ir.result_type().clone(), location.clone(), value_var_name.clone(), last_ir.clone())); + self.push_ir(IR::new_jump(last_ir.result_type().clone(), location.clone(), following_block_idx.into())); } else { self.push_ir(IR::new_jump(result_type.clone(), location.clone(), following_block_idx.into())); } @@ -454,7 +454,7 @@ impl Builder { let (op, rhs) = node.unary().unwrap(); self.build(rhs.clone(), &mut context); let rhs = self.pop_ir().unwrap(); - let result_type = rhs.result_type(); + let result_type = rhs.result_type().clone(); self.push_ir(IR::new_unary( result_type, location, @@ -524,7 +524,7 @@ impl Builder { self.push_ir(last_ir); } else { self.push_ir(IR::new_return( - last_ir.result_type(), + last_ir.result_type().clone(), last_ir.get_location().clone(), last_ir, )); @@ -668,7 +668,7 @@ impl Builder { None } - fn push_block(&mut self, result_type: TyIdx) { + pub fn push_block(&mut self, result_type: TyIdx) { match self.peek_block() { Some(ref block) => { let env = block.env().clone(); @@ -707,6 +707,7 @@ mod test { let term = Term::input(":marty").unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -718,6 +719,7 @@ mod test { let term = Term::input("true").unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -729,6 +731,7 @@ mod test { let term = Term::input("1.23").unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -740,6 +743,7 @@ mod test { let term = Term::input(r#" "Marty McFly" "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -751,6 +755,7 @@ mod test { let term = Term::input(r#" MartyMcFly "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_type_reference()); @@ -762,6 +767,7 @@ mod test { let term = Term::input(r#" [1, 2, 3] "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -774,6 +780,7 @@ mod test { let term = Term::input(r#" { a: 2, :b => 3 } "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constant()); @@ -787,6 +794,7 @@ mod test { let term = Term::input(r#" if true do 123 end "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); // Pop the follower block off the block stack. @@ -803,6 +811,7 @@ mod test { let term = Term::input(r#" if true do 123 else 456 end "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); // Pop the follower block off the block stack. @@ -820,6 +829,7 @@ mod test { let term = Term::input(r#" 1 + 2 "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_infix()); @@ -831,6 +841,7 @@ mod test { let term = Term::input(r#" Delorean { speed: 88 } "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_constructor()); @@ -843,6 +854,7 @@ mod test { let term = Term::input(r#" +88 "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_unary()); @@ -854,6 +866,7 @@ mod test { let terms = Term::input(" let x = 1\n x(123) ").unwrap(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); for term in terms { builder.build(term, &mut context); } @@ -867,6 +880,7 @@ mod test { let term = Term::input(r#" let x = 123 "#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_set_local()); @@ -878,6 +892,7 @@ mod test { let term = Term::file("type Delorean(speed: Integer)").unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); assert!(context.find_type("Delorean").is_some()); assert!(context.find_type("Integer").is_some()); @@ -888,6 +903,7 @@ mod test { let term = Term::file("trait TimeMachine").unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); assert!(context.find_type("TimeMachine").is_some()); } @@ -905,6 +921,7 @@ mod test { .clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); assert!(context.find_type("Delorean").is_some()); assert!(context.find_type("TimeMachine").is_some()); @@ -915,6 +932,7 @@ mod test { let term = Term::input(r#"fn (speed: Integer) do "WAT" end"#).unwrap()[0].clone(); let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); let ir = builder.pop_ir().unwrap(); assert!(ir.is_function()); @@ -964,9 +982,7 @@ mod test { let mut builder = Builder::default(); let mut context = Context::test(); + builder.push_block(context.unknown_type(Loc::test())); builder.build(term, &mut context); - - // println!("context: {:#?}", context); - // assert!(false); } } diff --git a/huia-compiler/src/ir/mod.rs b/huia-compiler/src/ir/mod.rs index 98c32f5..f450bcc 100644 --- a/huia-compiler/src/ir/mod.rs +++ b/huia-compiler/src/ir/mod.rs @@ -5,7 +5,7 @@ use crate::context::Context; use crate::function::FunctionIdx; use crate::location::Location; use crate::stable::StringIdx; -use crate::ty::TyIdx; +use crate::ty::{ResultType, TyIdx}; use huia_parser::ast::binary::Operator as BinOp; use huia_parser::ast::unary::Operator as UnOp; @@ -526,10 +526,6 @@ impl IR { } } - pub fn result_type(&self) -> TyIdx { - self.result_type.clone() - } - pub fn set_kind(&mut self, kind: IRKind) { self.kind = kind; } @@ -539,6 +535,12 @@ impl IR { } } +impl ResultType for IR { + fn result_type(&self) -> &TyIdx { + &self.result_type + } +} + #[derive(Debug, PartialEq, Clone)] pub enum IRKind { /// Call the provided callee with arguments. diff --git a/huia-compiler/src/method.rs b/huia-compiler/src/method.rs index 9b7a026..b9b79cc 100644 --- a/huia-compiler/src/method.rs +++ b/huia-compiler/src/method.rs @@ -159,8 +159,8 @@ impl Locatable for &mut Method { } impl ResultType for &mut Method { - fn result_type(&self) -> Option<&TyIdx> { - Some(&self.return_type) + fn result_type(&self) -> &TyIdx { + &self.return_type } } diff --git a/huia-compiler/src/ty.rs b/huia-compiler/src/ty.rs index d706140..2241447 100644 --- a/huia-compiler/src/ty.rs +++ b/huia-compiler/src/ty.rs @@ -23,6 +23,10 @@ impl Ty { } } + pub fn get_location(&self) -> Option<&Location> { + self.location.as_ref() + } + pub fn get_prop_type(&self, name: &StringIdx) -> Option<&TyIdx> { match self.inner { TyInner::Type { ref properties } => properties.get(name), @@ -369,5 +373,5 @@ enum TyInner { } pub trait ResultType { - fn result_type(&self) -> Option<&TyIdx>; + fn result_type(&self) -> &TyIdx; }