All blocks have result types.

This commit is contained in:
James Harton 2019-04-03 19:56:05 +13:00
parent c465cdf9a4
commit 396a6d020b
13 changed files with 71 additions and 34 deletions

View file

@ -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
}
}

View file

@ -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()];

View file

@ -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
}
}

View file

@ -1,6 +1,7 @@
use crate::block::BlockIdx;
use crate::clause::Clauseable;
use crate::context::Context;
use crate::ty::ResultType;
pub fn pass<T: Clauseable>(fun: &mut T, mut context: &mut Context) {
for clause in fun.clauses() {

View file

@ -6,7 +6,7 @@ use crate::ty::ResultType;
pub fn pass<T: Clauseable + Locatable + ResultType>(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);

View file

@ -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);

View file

@ -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);

View file

@ -71,6 +71,7 @@ fn perform_f64_infix_fold(op: &BinOp, lhs: f64, rhs: f64) -> Option<f64> {
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();

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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
}
}

View file

@ -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;
}