diff --git a/compiler/src/passes/validate/error.rs b/compiler/src/passes/validate/error.rs index a0c1d4b..c0e983a 100644 --- a/compiler/src/passes/validate/error.rs +++ b/compiler/src/passes/validate/error.rs @@ -1,6 +1,7 @@ use crate::passes::parse::types::Type; use miette::Diagnostic; use thiserror::Error; +use crate::passes::validate::generate_constraints::PartialType; #[derive(Debug, Error, Diagnostic)] pub enum TypeError { @@ -10,48 +11,48 @@ pub enum TypeError { #[label = "This variable `{sym}` was not declared yet"] span: (usize, usize), }, - #[error("Type was mismatched.")] - MismatchedType { - expect: Type, - got: Type, - #[label = "Expected this to be of type `{expect}`, but got `{got}`"] - span: (usize, usize), - }, - #[error("Types were mismatched. Expected function, but found '{got}'.")] - TypeMismatchExpectFn { got: Type }, - #[error("Types were mismatched. Expected '{t1}' and '{t2}' to be equal.")] - MismatchedTypes { - t1: Type, - t2: Type, - #[label = "This has type `{t1}`"] - span_t1: (usize, usize), - #[label = "but this has type `{t2}`"] - span_t2: (usize, usize), - }, - #[error("There are multiple functions named `{sym}`.")] - DuplicateFunction { sym: String }, - #[error("Function `{sym}` has duplicate argument names.")] - DuplicateArg { sym: String }, - #[error("Function `{expected}` has {expected} arguments, but found {got} arguments.")] - ArgCountMismatch { expected: usize, got: usize }, - #[error("Found a break outside of a loop.")] - BreakOutsideLoop, - #[error("Tried to modify immutable variable '{sym}'")] - ModifyImmutable { sym: String }, - #[error("The name {sym} should refer to a variable binding.'")] - VariableShouldBeExpr { sym: String }, - #[error("The name `{sym}` should refer to a struct type.'")] - VariableShouldBeStruct { sym: String }, - #[error("The field `{sym}` is not present in the struct definition.'")] - UnknownStructField { sym: String }, - #[error("The field `{sym}` is missing in the struct.'")] - VariableConstructMissingField { sym: String }, - #[error("The field `{sym}` was already provided earlier.'")] - VariableConstructDuplicateField { sym: String }, - #[error("The type `{typ}` should be a struct type.'")] - TypeShouldBeStruct { typ: Type }, - #[error("The type definition `{sym}` is not sized.'")] - UnsizedType { sym: String }, + // #[error("Type was mismatched.")] + // MismatchedType { + // expect: Type, + // got: Type, + // #[label = "Expected this to be of type `{expect}`, but got `{got}`"] + // span: (usize, usize), + // }, + // #[error("Types were mismatched. Expected function, but found '{got}'.")] + // TypeMismatchExpectFn { got: Type }, + // #[error("Types were mismatched. Expected '{t1}' and '{t2}' to be equal.")] + // MismatchedTypes { + // t1: Type, + // t2: Type, + // #[label = "This has type `{t1}`"] + // span_t1: (usize, usize), + // #[label = "but this has type `{t2}`"] + // span_t2: (usize, usize), + // }, + // #[error("There are multiple functions named `{sym}`.")] + // DuplicateFunction { sym: String }, + // #[error("Function `{sym}` has duplicate argument names.")] + // DuplicateArg { sym: String }, + // #[error("Function `{expected}` has {expected} arguments, but found {got} arguments.")] + // ArgCountMismatch { expected: usize, got: usize }, + // #[error("Found a break outside of a loop.")] + // BreakOutsideLoop, + // #[error("Tried to modify immutable variable '{sym}'")] + // ModifyImmutable { sym: String }, + // #[error("The name {sym} should refer to a variable binding.'")] + // VariableShouldBeExpr { sym: String }, + // #[error("The name `{sym}` should refer to a struct type.'")] + // VariableShouldBeStruct { sym: String }, + // #[error("The field `{sym}` is not present in the struct definition.'")] + // UnknownStructField { sym: String }, + // #[error("The field `{sym}` is missing in the struct.'")] + // VariableConstructMissingField { sym: String }, + // #[error("The field `{sym}` was already provided earlier.'")] + // VariableConstructDuplicateField { sym: String }, + // #[error("The type `{typ}` should be a struct type.'")] + // TypeShouldBeStruct { typ: Type }, + // #[error("The type definition `{sym}` is not sized.'")] + // UnsizedType { sym: String }, #[error("Integer out of bounds.")] IntegerOutOfBounds { @@ -66,4 +67,16 @@ pub enum TypeError { }, #[error("The program doesn't have a main function.")] NoMain, + + #[error("Types did not match.")] + MismatchedFnReturn { + expect: String, + got: String, + + #[label = "Expected this function to be of type: `{expect}`"] + span_expected: (usize, usize), + + #[label = "but got this type: `{got}`"] + span_got: (usize, usize), + }, } diff --git a/compiler/src/passes/validate/generate_constraints.rs b/compiler/src/passes/validate/generate_constraints.rs index b488f64..51f6585 100644 --- a/compiler/src/passes/validate/generate_constraints.rs +++ b/compiler/src/passes/validate/generate_constraints.rs @@ -6,15 +6,14 @@ use crate::passes::validate::{CMeta, DefConstrained, DefUniquified, ExprConstrai use crate::utils::gen_sym::UniqueSym; use crate::utils::union_find::{UnionFind, UnionIndex}; use std::collections::HashMap; - -pub struct GraphThingy {} +use itertools::Itertools; +use crate::passes::validate::error::TypeError::MismatchedFnReturn; #[derive(Debug, Clone)] pub enum PartialType<'p> { I64, U64, Int, - Bool, Unit, Never, @@ -25,26 +24,28 @@ pub enum PartialType<'p> { params: Vec, typ: UnionIndex, }, - // TODO Any, } -// uf: &mut UnionFind> -fn combine_partial_types<'p>(a: &PartialType<'p>, b: &PartialType<'p>) -> Result, ()> { - match (a, b) { - (PartialType::I64, PartialType::I64 | PartialType::Int) => Ok(PartialType::I64), - (PartialType::Int, PartialType::I64) => Ok(PartialType::I64), - (PartialType::U64, PartialType::U64 | PartialType::Int) => Ok(PartialType::U64), - (PartialType::Int, PartialType::U64) => Ok(PartialType::U64), - (PartialType::Int, PartialType::Int) => Ok(PartialType::Int), - (PartialType::Bool, PartialType::Bool) => Ok(PartialType::Bool), - (PartialType::Unit, PartialType::Unit) => Ok(PartialType::Unit), - (PartialType::Never, t) => Ok(t.clone()), - (t, PartialType::Never) => Ok(t.clone()), - (PartialType::Var { sym: sym_a }, PartialType::Var { sym: sym_b }) if sym_a == sym_b => Ok(PartialType::Var { sym: *sym_a }), - (PartialType::Fn { params: params_a, typ: typ_a}, PartialType::Fn {params: params_b, typ: typ_b}) => { - //check if params and typ are eq - todo!() + +impl<'p> PartialType<'p> { + pub fn to_string(&self, uf: &mut UnionFind) -> String { + match self { + PartialType::I64 => "I64".to_string(), + PartialType::U64 => "U64".to_string(), + PartialType::Int => "{int}".to_string(), + PartialType::Bool => "Bool".to_string(), + PartialType::Unit => "Unit".to_string(), + PartialType::Never => "Never".to_string(), + PartialType::Var { sym } => format!("{}", sym.sym), + PartialType::Fn { params, typ } => { + let params_string = params.iter().map(|index| { + let pt = uf.get(*index).clone(); + pt.to_string(uf) + }).format(", ").to_string(); + let pt = uf.get(*typ).clone(); + let typ_string = pt.to_string(uf); + format!("fn({params_string}) -> {typ_string}") + } } - _ => Err(()) } } @@ -94,7 +95,12 @@ fn constrain_def<'p>( let bdy = constrain_expr(bdy, &mut env)?; - uf.try_union_by(return_index, bdy.meta.index, combine_partial_types).map_err(|_| todo!())?; + uf.try_union_by(return_index, bdy.meta.index, combine_partial_types).map_err(|_| MismatchedFnReturn { + expect: format!("{}", typ.clone()), + got: uf.get(bdy.meta.index).to_string(uf), + span_expected: (0, 0), + span_got: (0, 0), + })?; DefConstrained::Fn { sym, @@ -185,3 +191,24 @@ fn constrain_expr<'p>( ExprUniquified::Switch { .. } => todo!(), }) } + +// uf: &mut UnionFind> +fn combine_partial_types<'p>(a: &PartialType<'p>, b: &PartialType<'p>) -> Result, ()> { + match (a, b) { + (PartialType::I64, PartialType::I64 | PartialType::Int) => Ok(PartialType::I64), + (PartialType::Int, PartialType::I64) => Ok(PartialType::I64), + (PartialType::U64, PartialType::U64 | PartialType::Int) => Ok(PartialType::U64), + (PartialType::Int, PartialType::U64) => Ok(PartialType::U64), + (PartialType::Int, PartialType::Int) => Ok(PartialType::Int), + (PartialType::Bool, PartialType::Bool) => Ok(PartialType::Bool), + (PartialType::Unit, PartialType::Unit) => Ok(PartialType::Unit), + (PartialType::Never, t) => Ok(t.clone()), + (t, PartialType::Never) => Ok(t.clone()), + (PartialType::Var { sym: sym_a }, PartialType::Var { sym: sym_b }) if sym_a == sym_b => Ok(PartialType::Var { sym: *sym_a }), + (PartialType::Fn { params: params_a, typ: typ_a}, PartialType::Fn {params: params_b, typ: typ_b}) => { + //check if params and typ are eq + todo!() + } + _ => Err(()) + } +} diff --git a/compiler/src/passes/validate/tests.rs b/compiler/src/passes/validate/tests.rs index b763fe2..6a565ac 100644 --- a/compiler/src/passes/validate/tests.rs +++ b/compiler/src/passes/validate/tests.rs @@ -20,51 +20,51 @@ fn validate([test]: [&str; 1]) { TypeError::UndeclaredVar { .. } => { assert_eq!(expected_error, "UndeclaredVar") } - TypeError::MismatchedType { .. } => { - assert_eq!(expected_error, "MismatchedType") - } - TypeError::TypeMismatchExpectFn { .. } => { - assert_eq!(expected_error, "TypeMismatchExpectFn") - } - TypeError::MismatchedTypes { .. } => { - assert_eq!(expected_error, "MismatchedTypes") - } - TypeError::DuplicateFunction { .. } => { - assert_eq!(expected_error, "DuplicateFunction") - } - TypeError::DuplicateArg { .. } => { - assert_eq!(expected_error, "DuplicateArg") - } - TypeError::ArgCountMismatch { .. } => { - assert_eq!(expected_error, "ArgCountMismatch") - } - TypeError::BreakOutsideLoop => { - assert_eq!(expected_error, "BreakOutsideLoop") - } - TypeError::ModifyImmutable { .. } => { - assert_eq!(expected_error, "ModifyImmutable") - } - TypeError::VariableShouldBeExpr { .. } => { - assert_eq!(expected_error, "VariableShouldBeExpr") - } - TypeError::VariableShouldBeStruct { .. } => { - assert_eq!(expected_error, "VariableShouldBeStruct") - } - TypeError::UnknownStructField { .. } => { - assert_eq!(expected_error, "UnknownStructField") - } - TypeError::VariableConstructMissingField { .. } => { - assert_eq!(expected_error, "VariableConstructMissingField") - } - TypeError::VariableConstructDuplicateField { .. } => { - assert_eq!(expected_error, "VariableConstructDuplicateField") - } - TypeError::TypeShouldBeStruct { .. } => { - assert_eq!(expected_error, "TypeShouldBeStruct") - } - TypeError::UnsizedType { .. } => { - assert_eq!(expected_error, "UnsizedType") - } + // TypeError::MismatchedType { .. } => { + // assert_eq!(expected_error, "MismatchedType") + // } + // TypeError::TypeMismatchExpectFn { .. } => { + // assert_eq!(expected_error, "TypeMismatchExpectFn") + // } + // TypeError::MismatchedTypes { .. } => { + // assert_eq!(expected_error, "MismatchedTypes") + // } + // TypeError::DuplicateFunction { .. } => { + // assert_eq!(expected_error, "DuplicateFunction") + // } + // TypeError::DuplicateArg { .. } => { + // assert_eq!(expected_error, "DuplicateArg") + // } + // TypeError::ArgCountMismatch { .. } => { + // assert_eq!(expected_error, "ArgCountMismatch") + // } + // TypeError::BreakOutsideLoop => { + // assert_eq!(expected_error, "BreakOutsideLoop") + // } + // TypeError::ModifyImmutable { .. } => { + // assert_eq!(expected_error, "ModifyImmutable") + // } + // TypeError::VariableShouldBeExpr { .. } => { + // assert_eq!(expected_error, "VariableShouldBeExpr") + // } + // TypeError::VariableShouldBeStruct { .. } => { + // assert_eq!(expected_error, "VariableShouldBeStruct") + // } + // TypeError::UnknownStructField { .. } => { + // assert_eq!(expected_error, "UnknownStructField") + // } + // TypeError::VariableConstructMissingField { .. } => { + // assert_eq!(expected_error, "VariableConstructMissingField") + // } + // TypeError::VariableConstructDuplicateField { .. } => { + // assert_eq!(expected_error, "VariableConstructDuplicateField") + // } + // TypeError::TypeShouldBeStruct { .. } => { + // assert_eq!(expected_error, "TypeShouldBeStruct") + // } + // TypeError::UnsizedType { .. } => { + // assert_eq!(expected_error, "UnsizedType") + // } TypeError::IntegerOutOfBounds { .. } => { assert_eq!(expected_error, "IntegerOutOfBounds") } diff --git a/compiler/src/utils/gen_sym.rs b/compiler/src/utils/gen_sym.rs index cd0aa15..7f5a43c 100644 --- a/compiler/src/utils/gen_sym.rs +++ b/compiler/src/utils/gen_sym.rs @@ -5,12 +5,10 @@ use std::sync::atomic::{AtomicUsize, Ordering}; static COUNT: AtomicUsize = AtomicUsize::new(0); -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Ord, PartialOrd, Display)] +#[display(fmt = "{sym}.{id}")] pub struct UniqueSym<'p> { - #[cfg(release)] pub sym: &'p str, - #[cfg(not(release))] - pub sym: PhantomData<&'p str>, pub id: usize, } @@ -23,26 +21,6 @@ impl<'p> UniqueSym<'p> { } } -impl Display for UniqueSym<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - #[cfg(release)] - let r = write!(f, "{}{}", self.sym, self.id); - #[cfg(not(release))] - let r = write!(f, "v{}", self.id); - - r - } -} - -#[cfg(not(release))] -pub fn gen_sym(_sym: &str) -> UniqueSym<'_> { - UniqueSym { - sym: PhantomData, - id: COUNT.fetch_add(1, Ordering::SeqCst), - } -} - -#[cfg(release)] pub fn gen_sym(sym: &str) -> UniqueSym<'_> { UniqueSym { sym, diff --git a/compiler/src/utils/union_find.rs b/compiler/src/utils/union_find.rs index 71973cd..d83971e 100644 --- a/compiler/src/utils/union_find.rs +++ b/compiler/src/utils/union_find.rs @@ -97,6 +97,11 @@ impl UnionFind { let index = self.find(index).0; &self.data[index] } + + pub fn get_and(&mut self, index: UnionIndex, f: impl FnOnce(&T) -> T2) -> T2 { + let index = self.find(index).0; + &self.data[index] + } } diff --git a/programs/fail/validate/bad_return_simple.test b/programs/fail/validate/bad_return_simple.test new file mode 100644 index 0000000..d7aaed5 --- /dev/null +++ b/programs/fail/validate/bad_return_simple.test @@ -0,0 +1,4 @@ +//* err: todo! +fn main() -> I64 { + true +}