diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index 5b3c162..f3367ed 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -48,8 +48,8 @@ impl TypeKind { rhs: &TypeKind, binop: &ScopeBinopDef, ) -> Option<(TypeKind, TypeKind, TypeKind)> { - let lhs_ty = lhs.collapse_into(&binop.hands.0); - let rhs_ty = rhs.collapse_into(&binop.hands.1); + let lhs_ty = lhs.narrow_into(&binop.hands.0); + let rhs_ty = rhs.narrow_into(&binop.hands.1); if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { Some((lhs_ty, rhs_ty, binop.return_ty.clone())) } else { @@ -74,22 +74,6 @@ impl TypeKind { } } - pub fn binop_hint( - &self, - lhs: &TypeKind, - rhs: &TypeKind, - binop: &ScopeBinopDef, - ) -> Option<(TypeKind, TypeKind)> { - self.collapse_into(&binop.return_ty).ok()?; - let lhs_ty = lhs.collapse_into(&binop.hands.0); - let rhs_ty = rhs.collapse_into(&binop.hands.1); - if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { - Some((lhs_ty, rhs_ty)) - } else { - None - } - } - pub fn signed(&self) -> bool { match self { TypeKind::Bool => false, @@ -230,9 +214,9 @@ impl TypeKind { (lhs1, rhs1): (&TypeKind, &TypeKind), (lhs2, rhs2): (&TypeKind, &TypeKind), ) -> Option<(TypeKind, TypeKind)> { - if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&lhs2), rhs1.collapse_into(&rhs2)) { + if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&lhs2), rhs1.narrow_into(&rhs2)) { Some((lhs, rhs)) - } else if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&rhs2), rhs1.collapse_into(&lhs2)) { + } else if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&rhs2), rhs1.narrow_into(&lhs2)) { Some((rhs, lhs)) } else { None diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 86d039a..d43772a 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -112,7 +112,9 @@ pub enum TypeKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum VagueType { Unknown, + /// Some integer value (e.g. 5) Integer, + /// Some decimal fractional value (e.g. 1.5) Decimal, TypeRef(usize), } diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index a258a53..293f376 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -121,9 +121,11 @@ impl Storage { } } +pub type BinopMap = Storage; + #[derive(Clone, Default, Debug)] pub struct Scope { - pub binops: Storage, + pub binops: BinopMap, pub function_returns: Storage, pub variables: Storage, pub types: Storage, @@ -223,6 +225,34 @@ pub struct ScopeBinopDef { pub return_ty: TypeKind, } +impl ScopeBinopDef { + pub fn binop_hint_old( + &self, + lhs: &TypeKind, + rhs: &TypeKind, + ret_ty: &TypeKind, + ) -> Option<(TypeKind, TypeKind)> { + ret_ty.narrow_into(&self.return_ty).ok()?; + let lhs_ty = lhs.narrow_into(&self.hands.0); + let rhs_ty = rhs.narrow_into(&self.hands.1); + if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { + Some((lhs_ty, rhs_ty)) + } else { + None + } + } + + pub fn binop_ret_ty(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option { + let lhs_ty = lhs.narrow_into(&self.hands.0); + let rhs_ty = rhs.narrow_into(&self.hands.1); + if let (Ok(_), Ok(_)) = (lhs_ty, rhs_ty) { + Some(self.return_ty.clone()) + } else { + None + } + } +} + pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> { state: &'st mut State, pub scope: &'sc mut Scope, diff --git a/reid/src/mir/typecheck/mod.rs b/reid/src/mir/typecheck/mod.rs index 78b41d5..ea46dc4 100644 --- a/reid/src/mir/typecheck/mod.rs +++ b/reid/src/mir/typecheck/mod.rs @@ -79,7 +79,7 @@ pub enum ErrorKind { } impl TypeKind { - pub(super) fn collapse_into(&self, other: &TypeKind) -> Result { + pub(super) fn narrow_into(&self, other: &TypeKind) -> Result { if self == other { return Ok(self.clone()); } @@ -121,7 +121,7 @@ impl TypeKind { } (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { // Extracted to give priority for other collapse-error - let collapsed = val1.collapse_into(val2)?; + let collapsed = val1.narrow_into(val2)?; if mut1 == mut2 { Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) } else { @@ -132,14 +132,84 @@ impl TypeKind { } } (TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => { - Ok(TypeKind::UserPtr(Box::new(val1.collapse_into(val2)?))) + Ok(TypeKind::UserPtr(Box::new(val1.narrow_into(val2)?))) } _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), } } + pub(super) fn widen_into(&self, other: &TypeKind) -> TypeKind { + if self == other { + return self.clone(); + } + match (self, other) { + (TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => { + TypeKind::Vague(VagueType::Unknown) + } + (TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => { + match other { + TypeKind::I8 + | TypeKind::I16 + | TypeKind::I32 + | TypeKind::I64 + | TypeKind::I128 + | TypeKind::U8 + | TypeKind::U16 + | TypeKind::U32 + | TypeKind::U64 + | TypeKind::U128 => TypeKind::Vague(VagueType::Integer), + _ => TypeKind::Vague(VagueType::Unknown), + } + } + (TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => { + match other { + TypeKind::F16 + | TypeKind::F32B + | TypeKind::F32 + | TypeKind::F64 + | TypeKind::F80 + | TypeKind::F128 + | TypeKind::F128PPC => TypeKind::Vague(VagueType::Decimal), + _ => TypeKind::Vague(VagueType::Unknown), + } + } + (TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => { + TypeKind::UserPtr(Box::new(val1.widen_into(val2))) + } + (TypeKind::CodegenPtr(val1), TypeKind::CodegenPtr(val2)) => { + TypeKind::CodegenPtr(Box::new(val1.widen_into(val2))) + } + (TypeKind::Array(val1, len1), TypeKind::Array(val2, len2)) => { + if len1 == len2 { + TypeKind::Array(Box::new(val1.widen_into(val2)), *len1) + } else { + TypeKind::Vague(VagueType::Unknown) + } + } + (TypeKind::Borrow(val1, mutable1), TypeKind::Borrow(val2, mutable2)) => { + if mutable1 == mutable2 { + TypeKind::Borrow(Box::new(val1.widen_into(val2)), *mutable1) + } else { + TypeKind::Vague(VagueType::Unknown) + } + } + _ => { + if self.category() == other.category() { + match self.category() { + TypeCategory::Integer => TypeKind::Vague(VagueType::Integer), + TypeCategory::Real => TypeKind::Vague(VagueType::Decimal), + TypeCategory::Bool => TypeKind::Bool, + _ => TypeKind::Vague(VagueType::Unknown), + } + } else { + TypeKind::Vague(VagueType::Unknown) + } + } + } + } + pub(super) fn cast_into(&self, other: &TypeKind) -> Result { - if let Ok(collapsed) = self.collapse_into(other) { + if let Ok(collapsed) = self.narrow_into(other) { Ok(collapsed) } else { let self_cat = self.category(); @@ -191,7 +261,7 @@ impl TypeKind { pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind { match self { - TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(), + TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_wide_type(*idx).unwrap(), _ => self.clone(), } } diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index 0b76d03..090bde6 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -147,7 +147,7 @@ impl BinopDefinition { match inferred { Ok(t) => return_type - .collapse_into(&t.1) + .narrow_into(&t.1) .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), Err(e) => Ok(state.or_else( Err(e), @@ -191,7 +191,7 @@ impl FunctionDefinition { match inferred { Ok(t) => return_type - .collapse_into(&t.1) + .narrow_into(&t.1) .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())), } @@ -250,7 +250,7 @@ impl Block { // Make sure the expression and variable type really is the same let res_t = state.or_else( - res.collapse_into(&var_t_resolved), + res.narrow_into(&var_t_resolved), TypeKind::Vague(Vague::Unknown), variable_reference.2 + expression.1, ); @@ -315,7 +315,7 @@ impl Block { // Make sure the expression and variable type to really // be the same - state.ok(lhs_ty.collapse_into(&rhs_ty), lhs.1 + rhs.1); + state.ok(lhs_ty.narrow_into(&rhs_ty), lhs.1 + rhs.1); if let Some(named_var) = lhs.backing_var() { if let Some(scope_var) = state.scope.variables.get(&named_var.1) { @@ -435,7 +435,7 @@ impl Expression { // Update typing to be more accurate var_ref.0 = state.or_else( - var_ref.0.resolve_ref(typerefs).collapse_into(&existing), + var_ref.0.resolve_ref(typerefs).narrow_into(&existing), TypeKind::Vague(Vague::Unknown), var_ref.2, ); @@ -499,7 +499,7 @@ impl Expression { let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type)); let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); - let both_t = lhs_type.collapse_into(&rhs_type)?; + let both_t = lhs_type.narrow_into(&rhs_type)?; if *op == BinaryOperator::Minus && !lhs_type.signed() { if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?) @@ -510,7 +510,7 @@ impl Expression { } } - if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) { + if let Some(collapsed) = state.ok(rhs_type.narrow_into(&rhs_type), self.1) { // Try to coerce both sides again with collapsed type lhs.typecheck(state, &typerefs, Some(&collapsed)).ok(); rhs.typecheck(state, &typerefs, Some(&collapsed)).ok(); @@ -558,14 +558,14 @@ impl Expression { let param_res = param.typecheck(state, &typerefs, Some(&true_param_t)); let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1); - state.ok(param_t.collapse_into(&true_param_t), param.1); + state.ok(param_t.narrow_into(&true_param_t), param.1); } // Make sure function return type is the same as the claimed // return type let ret_t = f .ret - .collapse_into(&function_call.return_type.resolve_ref(typerefs))?; + .narrow_into(&function_call.return_type.resolve_ref(typerefs))?; // Update typing to be more accurate function_call.return_type = ret_t.clone(); Ok(ret_t.resolve_ref(typerefs)) @@ -576,7 +576,7 @@ impl Expression { ExprKind::If(IfExpression(cond, lhs, rhs)) => { let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool)); let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1); - state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1); + state.ok(cond_t.narrow_into(&TypeKind::Bool), cond.1); // Typecheck then/else return types and make sure they are the // same, if else exists. @@ -596,7 +596,7 @@ impl Expression { // Make sure then and else -blocks have the same return type let collapsed = then_ret_t - .collapse_into(&else_ret_t) + .narrow_into(&else_ret_t) .or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?; if let Some(rhs) = rhs.as_mut() { @@ -632,7 +632,7 @@ impl Expression { match expr_t { TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => { let ty = state.or_else( - elem_ty.resolve_ref(typerefs).collapse_into(&inferred_ty), + elem_ty.resolve_ref(typerefs).narrow_into(&inferred_ty), TypeKind::Vague(Vague::Unknown), self.1, ); @@ -660,7 +660,7 @@ impl Expression { let mut iter = expr_types.iter_mut(); if let Some(first) = iter.next() { for other in iter { - state.ok(first.collapse_into(other), self.1); + state.ok(first.narrow_into(other), self.1); } Ok(TypeKind::Array( Box::new(first.clone()), @@ -696,7 +696,7 @@ impl Expression { if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) { // Make sure they are the same let true_ty = state.or_else( - expr_field_ty.collapse_into(&expected_ty), + expr_field_ty.narrow_into(&expected_ty), TypeKind::Vague(Vague::Unknown), self.1, ); @@ -736,7 +736,7 @@ impl Expression { state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1); // Make sure both are the same type, report error if not - state.ok(expr_ty.collapse_into(&expr_ty), field_expr.1); + state.ok(expr_ty.narrow_into(&expr_ty), field_expr.1); } Ok(TypeKind::CustomType(type_key)) } @@ -762,7 +762,7 @@ impl Expression { // Update typing to be more accurate var_ref.0 = state.or_else( - var_ref.0.resolve_ref(typerefs).collapse_into(&existing), + var_ref.0.resolve_ref(typerefs).narrow_into(&existing), TypeKind::Vague(Vague::Unknown), var_ref.2, ); @@ -786,7 +786,7 @@ impl Expression { // Update typing to be more accurate let TypeKind::Borrow(inner, mutable) = state.or_else( - var_ref.0.resolve_ref(typerefs).collapse_into(&existing), + var_ref.0.resolve_ref(typerefs).narrow_into(&existing), TypeKind::Vague(Vague::Unknown), var_ref.2, ) else { diff --git a/reid/src/mir/typecheck/typerefs.rs b/reid/src/mir/typecheck/typerefs.rs index f87a189..0f3aa74 100644 --- a/reid/src/mir/typecheck/typerefs.rs +++ b/reid/src/mir/typecheck/typerefs.rs @@ -4,7 +4,7 @@ use std::{ rc::Rc, }; -use crate::mir::{BinaryOperator, TypeKind, VagueType}; +use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}; use super::{ super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, @@ -21,7 +21,7 @@ impl<'scope> TypeRef<'scope> { /// Resolve current type in a weak manner, not resolving any Arrays or /// further inner types pub fn resolve_weak(&self) -> Option { - Some(self.1.types.retrieve_type(*self.0.borrow())?) + Some(self.1.types.retrieve_wide_type(*self.0.borrow())?) } /// Resolve type deeply, trying to resolve any inner types as well. @@ -57,12 +57,46 @@ impl<'scope> std::fmt::Debug for TypeRef<'scope> { type TypeIdRef = Rc>; +#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] +pub enum TypeRefKind { + Direct(TypeKind), + BinOp(BinaryOperator, TypeKind, TypeKind), +} + +impl TypeRefKind { + pub fn widen(&self, types: &TypeRefs) -> Option { + match self { + TypeRefKind::BinOp(op, lhs, rhs) => { + let mut binops = types + .binop_types + .iter() + .filter(|b| b.1.operator == *op) + .map(|b| b.1.binop_ret_ty(&lhs, &rhs)) + .filter_map(|s| s); + if let Some(mut ty) = binops.next() { + while let Some(other) = binops.next() { + ty = ty.widen_into(&other); + } + Some(ty) + } else { + None + } + } + TypeRefKind::Direct(ty) => match ty { + TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id), + _ => Some(ty.clone()), + }, + } + } +} + #[derive(Debug, Default)] pub struct TypeRefs { /// Simple list of types that variables can refrence - pub(super) hints: RefCell>, + pub(super) hints: RefCell>, /// Indirect ID-references, referring to hints-vec pub(super) type_refs: RefCell>, + binop_types: BinopMap, } impl std::fmt::Display for TypeRefs { @@ -74,7 +108,7 @@ impl std::fmt::Display for TypeRefs { "{:<3} = {:<3} = {:?} = {}", i, unsafe { *self.recurse_type_ref(idx).borrow() }, - self.retrieve_type(idx), + self.retrieve_wide_type(idx), TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self) )?; } @@ -87,7 +121,9 @@ impl TypeRefs { let idx = self.hints.borrow().len(); let typecell = Rc::new(RefCell::new(idx)); self.type_refs.borrow_mut().push(typecell.clone()); - self.hints.borrow_mut().push(ty.clone()); + self.hints + .borrow_mut() + .push(TypeRefKind::Direct(ty.clone())); typecell } @@ -103,7 +139,7 @@ impl TypeRefs { .borrow_mut() .iter() .enumerate() - .find(|(_, t)| *t == ty) + .find(|(_, t)| t == &&TypeRefKind::Direct(ty.clone())) .map(|(i, _)| i) { Some(Rc::new(RefCell::new(idx))) @@ -124,16 +160,13 @@ impl TypeRefs { return refs.get_unchecked(idx).clone(); } - pub fn retrieve_type(&self, idx: usize) -> Option { + pub fn retrieve_wide_type(&self, idx: usize) -> Option { let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; self.hints .borrow() .get(inner_idx) .cloned() - .map(|t| match t { - TypeKind::Vague(VagueType::TypeRef(id)) => self.retrieve_type(id), - _ => Some(t), - }) + .map(|t| t.widen(self)) .flatten() } } @@ -203,7 +236,27 @@ impl<'outer> ScopeTypeRefs<'outer> { unsafe { let mut hints = self.types.hints.borrow_mut(); let existing = hints.get_unchecked_mut(*hint.0.borrow()); - *existing = existing.collapse_into(&ty).ok()?; + match existing { + TypeRefKind::Direct(type_kind) => { + *type_kind = type_kind.narrow_into(&ty).ok()?; + } + TypeRefKind::BinOp(op, lhs, rhs) => { + let binops = self + .types + .binop_types + .iter() + .filter(|b| b.1.operator == *op && b.1.return_ty == *ty); + for binop in binops { + if let (Ok(lhs_narrow), Ok(rhs_narrow)) = ( + lhs.narrow_into(&binop.1.hands.0), + rhs.narrow_into(&binop.1.hands.1), + ) { + *lhs = lhs_narrow; + *rhs = rhs_narrow + } + } + } + } Some(TypeRef(hint.0.clone(), self)) } } @@ -215,7 +268,9 @@ impl<'outer> ScopeTypeRefs<'outer> { .hints .borrow() .get_unchecked(*hint2.0.borrow()) - .clone(); + .clone() + .widen(self.types) + .unwrap(); self.narrow_to_type(&hint1, &ty)?; for idx in self.types.type_refs.borrow_mut().iter_mut() { if *idx == hint2.0 && idx != &hint1.0 {