Improve binop type narrowing
This commit is contained in:
		
							parent
							
								
									f8d2e4996a
								
							
						
					
					
						commit
						8d3dd4a49f
					
				| @ -48,8 +48,8 @@ impl TypeKind { | |||||||
|         rhs: &TypeKind, |         rhs: &TypeKind, | ||||||
|         binop: &ScopeBinopDef, |         binop: &ScopeBinopDef, | ||||||
|     ) -> Option<(TypeKind, TypeKind, TypeKind)> { |     ) -> Option<(TypeKind, TypeKind, TypeKind)> { | ||||||
|         let lhs_ty = lhs.collapse_into(&binop.hands.0); |         let lhs_ty = lhs.narrow_into(&binop.hands.0); | ||||||
|         let rhs_ty = rhs.collapse_into(&binop.hands.1); |         let rhs_ty = rhs.narrow_into(&binop.hands.1); | ||||||
|         if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { |         if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { | ||||||
|             Some((lhs_ty, rhs_ty, binop.return_ty.clone())) |             Some((lhs_ty, rhs_ty, binop.return_ty.clone())) | ||||||
|         } else { |         } 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 { |     pub fn signed(&self) -> bool { | ||||||
|         match self { |         match self { | ||||||
|             TypeKind::Bool => false, |             TypeKind::Bool => false, | ||||||
| @ -230,9 +214,9 @@ impl TypeKind { | |||||||
|         (lhs1, rhs1): (&TypeKind, &TypeKind), |         (lhs1, rhs1): (&TypeKind, &TypeKind), | ||||||
|         (lhs2, rhs2): (&TypeKind, &TypeKind), |         (lhs2, rhs2): (&TypeKind, &TypeKind), | ||||||
|     ) -> Option<(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)) |             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)) |             Some((rhs, lhs)) | ||||||
|         } else { |         } else { | ||||||
|             None |             None | ||||||
|  | |||||||
| @ -112,7 +112,9 @@ pub enum TypeKind { | |||||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||||||
| pub enum VagueType { | pub enum VagueType { | ||||||
|     Unknown, |     Unknown, | ||||||
|  |     /// Some integer value (e.g. 5)
 | ||||||
|     Integer, |     Integer, | ||||||
|  |     /// Some decimal fractional value (e.g. 1.5)
 | ||||||
|     Decimal, |     Decimal, | ||||||
|     TypeRef(usize), |     TypeRef(usize), | ||||||
| } | } | ||||||
|  | |||||||
| @ -121,9 +121,11 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>; | ||||||
|  | 
 | ||||||
| #[derive(Clone, Default, Debug)] | #[derive(Clone, Default, Debug)] | ||||||
| pub struct Scope<Data: Clone + Default> { | pub struct Scope<Data: Clone + Default> { | ||||||
|     pub binops: Storage<ScopeBinopKey, ScopeBinopDef>, |     pub binops: BinopMap, | ||||||
|     pub function_returns: Storage<String, ScopeFunction>, |     pub function_returns: Storage<String, ScopeFunction>, | ||||||
|     pub variables: Storage<String, ScopeVariable>, |     pub variables: Storage<String, ScopeVariable>, | ||||||
|     pub types: Storage<CustomTypeKey, TypeDefinition>, |     pub types: Storage<CustomTypeKey, TypeDefinition>, | ||||||
| @ -223,6 +225,34 @@ pub struct ScopeBinopDef { | |||||||
|     pub return_ty: TypeKind, |     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<TypeKind> { | ||||||
|  |         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> { | pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> { | ||||||
|     state: &'st mut State<TError>, |     state: &'st mut State<TError>, | ||||||
|     pub scope: &'sc mut Scope<Data>, |     pub scope: &'sc mut Scope<Data>, | ||||||
|  | |||||||
| @ -79,7 +79,7 @@ pub enum ErrorKind { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TypeKind { | impl TypeKind { | ||||||
|     pub(super) fn collapse_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> { |     pub(super) fn narrow_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> { | ||||||
|         if self == other { |         if self == other { | ||||||
|             return Ok(self.clone()); |             return Ok(self.clone()); | ||||||
|         } |         } | ||||||
| @ -121,7 +121,7 @@ impl TypeKind { | |||||||
|             } |             } | ||||||
|             (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { |             (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { | ||||||
|                 // Extracted to give priority for other collapse-error
 |                 // Extracted to give priority for other collapse-error
 | ||||||
|                 let collapsed = val1.collapse_into(val2)?; |                 let collapsed = val1.narrow_into(val2)?; | ||||||
|                 if mut1 == mut2 { |                 if mut1 == mut2 { | ||||||
|                     Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) |                     Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) | ||||||
|                 } else { |                 } else { | ||||||
| @ -132,14 +132,84 @@ impl TypeKind { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             (TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => { |             (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())), |             _ => 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<TypeKind, ErrorKind> { |     pub(super) fn cast_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> { | ||||||
|         if let Ok(collapsed) = self.collapse_into(other) { |         if let Ok(collapsed) = self.narrow_into(other) { | ||||||
|             Ok(collapsed) |             Ok(collapsed) | ||||||
|         } else { |         } else { | ||||||
|             let self_cat = self.category(); |             let self_cat = self.category(); | ||||||
| @ -191,7 +261,7 @@ impl TypeKind { | |||||||
| 
 | 
 | ||||||
|     pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind { |     pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind { | ||||||
|         match self { |         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(), |             _ => self.clone(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -147,7 +147,7 @@ impl BinopDefinition { | |||||||
| 
 | 
 | ||||||
|         match inferred { |         match inferred { | ||||||
|             Ok(t) => return_type |             Ok(t) => return_type | ||||||
|                 .collapse_into(&t.1) |                 .narrow_into(&t.1) | ||||||
|                 .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), |                 .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), | ||||||
|             Err(e) => Ok(state.or_else( |             Err(e) => Ok(state.or_else( | ||||||
|                 Err(e), |                 Err(e), | ||||||
| @ -191,7 +191,7 @@ impl FunctionDefinition { | |||||||
| 
 | 
 | ||||||
|         match inferred { |         match inferred { | ||||||
|             Ok(t) => return_type |             Ok(t) => return_type | ||||||
|                 .collapse_into(&t.1) |                 .narrow_into(&t.1) | ||||||
|                 .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), |                 .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), | ||||||
|             Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())), |             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
 |                     // Make sure the expression and variable type really is the same
 | ||||||
|                     let res_t = state.or_else( |                     let res_t = state.or_else( | ||||||
|                         res.collapse_into(&var_t_resolved), |                         res.narrow_into(&var_t_resolved), | ||||||
|                         TypeKind::Vague(Vague::Unknown), |                         TypeKind::Vague(Vague::Unknown), | ||||||
|                         variable_reference.2 + expression.1, |                         variable_reference.2 + expression.1, | ||||||
|                     ); |                     ); | ||||||
| @ -315,7 +315,7 @@ impl Block { | |||||||
| 
 | 
 | ||||||
|                     // Make sure the expression and variable type to really
 |                     // Make sure the expression and variable type to really
 | ||||||
|                     // be the same
 |                     // 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(named_var) = lhs.backing_var() { | ||||||
|                         if let Some(scope_var) = state.scope.variables.get(&named_var.1) { |                         if let Some(scope_var) = state.scope.variables.get(&named_var.1) { | ||||||
| @ -435,7 +435,7 @@ impl Expression { | |||||||
| 
 | 
 | ||||||
|                 // Update typing to be more accurate
 |                 // Update typing to be more accurate
 | ||||||
|                 var_ref.0 = state.or_else( |                 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), |                     TypeKind::Vague(Vague::Unknown), | ||||||
|                     var_ref.2, |                     var_ref.2, | ||||||
|                 ); |                 ); | ||||||
| @ -499,7 +499,7 @@ impl Expression { | |||||||
|                     let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type)); |                     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 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 *op == BinaryOperator::Minus && !lhs_type.signed() { | ||||||
|                         if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?) |                         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
 |                         // Try to coerce both sides again with collapsed type
 | ||||||
|                         lhs.typecheck(state, &typerefs, Some(&collapsed)).ok(); |                         lhs.typecheck(state, &typerefs, Some(&collapsed)).ok(); | ||||||
|                         rhs.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_res = param.typecheck(state, &typerefs, Some(&true_param_t)); | ||||||
|                         let param_t = |                         let param_t = | ||||||
|                             state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1); |                             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
 |                     // Make sure function return type is the same as the claimed
 | ||||||
|                     // return type
 |                     // return type
 | ||||||
|                     let ret_t = f |                     let ret_t = f | ||||||
|                         .ret |                         .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
 |                     // Update typing to be more accurate
 | ||||||
|                     function_call.return_type = ret_t.clone(); |                     function_call.return_type = ret_t.clone(); | ||||||
|                     Ok(ret_t.resolve_ref(typerefs)) |                     Ok(ret_t.resolve_ref(typerefs)) | ||||||
| @ -576,7 +576,7 @@ impl Expression { | |||||||
|             ExprKind::If(IfExpression(cond, lhs, rhs)) => { |             ExprKind::If(IfExpression(cond, lhs, rhs)) => { | ||||||
|                 let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool)); |                 let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool)); | ||||||
|                 let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1); |                 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
 |                 // Typecheck then/else return types and make sure they are the
 | ||||||
|                 // same, if else exists.
 |                 // same, if else exists.
 | ||||||
| @ -596,7 +596,7 @@ impl Expression { | |||||||
| 
 | 
 | ||||||
|                 // Make sure then and else -blocks have the same return type
 |                 // Make sure then and else -blocks have the same return type
 | ||||||
|                 let collapsed = then_ret_t |                 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)))?; |                     .or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?; | ||||||
| 
 | 
 | ||||||
|                 if let Some(rhs) = rhs.as_mut() { |                 if let Some(rhs) = rhs.as_mut() { | ||||||
| @ -632,7 +632,7 @@ impl Expression { | |||||||
|                 match expr_t { |                 match expr_t { | ||||||
|                     TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => { |                     TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => { | ||||||
|                         let ty = state.or_else( |                         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), |                             TypeKind::Vague(Vague::Unknown), | ||||||
|                             self.1, |                             self.1, | ||||||
|                         ); |                         ); | ||||||
| @ -660,7 +660,7 @@ impl Expression { | |||||||
|                         let mut iter = expr_types.iter_mut(); |                         let mut iter = expr_types.iter_mut(); | ||||||
|                         if let Some(first) = iter.next() { |                         if let Some(first) = iter.next() { | ||||||
|                             for other in iter { |                             for other in iter { | ||||||
|                                 state.ok(first.collapse_into(other), self.1); |                                 state.ok(first.narrow_into(other), self.1); | ||||||
|                             } |                             } | ||||||
|                             Ok(TypeKind::Array( |                             Ok(TypeKind::Array( | ||||||
|                                 Box::new(first.clone()), |                                 Box::new(first.clone()), | ||||||
| @ -696,7 +696,7 @@ impl Expression { | |||||||
|                     if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) { |                     if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) { | ||||||
|                         // Make sure they are the same
 |                         // Make sure they are the same
 | ||||||
|                         let true_ty = state.or_else( |                         let true_ty = state.or_else( | ||||||
|                             expr_field_ty.collapse_into(&expected_ty), |                             expr_field_ty.narrow_into(&expected_ty), | ||||||
|                             TypeKind::Vague(Vague::Unknown), |                             TypeKind::Vague(Vague::Unknown), | ||||||
|                             self.1, |                             self.1, | ||||||
|                         ); |                         ); | ||||||
| @ -736,7 +736,7 @@ impl Expression { | |||||||
|                         state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1); |                         state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1); | ||||||
| 
 | 
 | ||||||
|                     // Make sure both are the same type, report error if not
 |                     // 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)) |                 Ok(TypeKind::CustomType(type_key)) | ||||||
|             } |             } | ||||||
| @ -762,7 +762,7 @@ impl Expression { | |||||||
| 
 | 
 | ||||||
|                 // Update typing to be more accurate
 |                 // Update typing to be more accurate
 | ||||||
|                 var_ref.0 = state.or_else( |                 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), |                     TypeKind::Vague(Vague::Unknown), | ||||||
|                     var_ref.2, |                     var_ref.2, | ||||||
|                 ); |                 ); | ||||||
| @ -786,7 +786,7 @@ impl Expression { | |||||||
| 
 | 
 | ||||||
|                 // Update typing to be more accurate
 |                 // Update typing to be more accurate
 | ||||||
|                 let TypeKind::Borrow(inner, mutable) = state.or_else( |                 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), |                     TypeKind::Vague(Vague::Unknown), | ||||||
|                     var_ref.2, |                     var_ref.2, | ||||||
|                 ) else { |                 ) else { | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ use std::{ | |||||||
|     rc::Rc, |     rc::Rc, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::mir::{BinaryOperator, TypeKind, VagueType}; | use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}; | ||||||
| 
 | 
 | ||||||
| use super::{ | use super::{ | ||||||
|     super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, |     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
 |     /// Resolve current type in a weak manner, not resolving any Arrays or
 | ||||||
|     /// further inner types
 |     /// further inner types
 | ||||||
|     pub fn resolve_weak(&self) -> Option<TypeKind> { |     pub fn resolve_weak(&self) -> Option<TypeKind> { | ||||||
|         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.
 |     /// 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<RefCell<usize>>; | type TypeIdRef = Rc<RefCell<usize>>; | ||||||
| 
 | 
 | ||||||
|  | #[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<TypeKind> { | ||||||
|  |         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)] | #[derive(Debug, Default)] | ||||||
| pub struct TypeRefs { | pub struct TypeRefs { | ||||||
|     /// Simple list of types that variables can refrence
 |     /// Simple list of types that variables can refrence
 | ||||||
|     pub(super) hints: RefCell<Vec<TypeKind>>, |     pub(super) hints: RefCell<Vec<TypeRefKind>>, | ||||||
|     /// Indirect ID-references, referring to hints-vec
 |     /// Indirect ID-references, referring to hints-vec
 | ||||||
|     pub(super) type_refs: RefCell<Vec<TypeIdRef>>, |     pub(super) type_refs: RefCell<Vec<TypeIdRef>>, | ||||||
|  |     binop_types: BinopMap, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl std::fmt::Display for TypeRefs { | impl std::fmt::Display for TypeRefs { | ||||||
| @ -74,7 +108,7 @@ impl std::fmt::Display for TypeRefs { | |||||||
|                 "{:<3} = {:<3} = {:?} = {}", |                 "{:<3} = {:<3} = {:?} = {}", | ||||||
|                 i, |                 i, | ||||||
|                 unsafe { *self.recurse_type_ref(idx).borrow() }, |                 unsafe { *self.recurse_type_ref(idx).borrow() }, | ||||||
|                 self.retrieve_type(idx), |                 self.retrieve_wide_type(idx), | ||||||
|                 TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self) |                 TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self) | ||||||
|             )?; |             )?; | ||||||
|         } |         } | ||||||
| @ -87,7 +121,9 @@ impl TypeRefs { | |||||||
|         let idx = self.hints.borrow().len(); |         let idx = self.hints.borrow().len(); | ||||||
|         let typecell = Rc::new(RefCell::new(idx)); |         let typecell = Rc::new(RefCell::new(idx)); | ||||||
|         self.type_refs.borrow_mut().push(typecell.clone()); |         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 |         typecell | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -103,7 +139,7 @@ impl TypeRefs { | |||||||
|             .borrow_mut() |             .borrow_mut() | ||||||
|             .iter() |             .iter() | ||||||
|             .enumerate() |             .enumerate() | ||||||
|             .find(|(_, t)| *t == ty) |             .find(|(_, t)| t == &&TypeRefKind::Direct(ty.clone())) | ||||||
|             .map(|(i, _)| i) |             .map(|(i, _)| i) | ||||||
|         { |         { | ||||||
|             Some(Rc::new(RefCell::new(idx))) |             Some(Rc::new(RefCell::new(idx))) | ||||||
| @ -124,16 +160,13 @@ impl TypeRefs { | |||||||
|         return refs.get_unchecked(idx).clone(); |         return refs.get_unchecked(idx).clone(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> { |     pub fn retrieve_wide_type(&self, idx: usize) -> Option<TypeKind> { | ||||||
|         let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; |         let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; | ||||||
|         self.hints |         self.hints | ||||||
|             .borrow() |             .borrow() | ||||||
|             .get(inner_idx) |             .get(inner_idx) | ||||||
|             .cloned() |             .cloned() | ||||||
|             .map(|t| match t { |             .map(|t| t.widen(self)) | ||||||
|                 TypeKind::Vague(VagueType::TypeRef(id)) => self.retrieve_type(id), |  | ||||||
|                 _ => Some(t), |  | ||||||
|             }) |  | ||||||
|             .flatten() |             .flatten() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -203,7 +236,27 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|         unsafe { |         unsafe { | ||||||
|             let mut hints = self.types.hints.borrow_mut(); |             let mut hints = self.types.hints.borrow_mut(); | ||||||
|             let existing = hints.get_unchecked_mut(*hint.0.borrow()); |             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)) |             Some(TypeRef(hint.0.clone(), self)) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -215,7 +268,9 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|                 .hints |                 .hints | ||||||
|                 .borrow() |                 .borrow() | ||||||
|                 .get_unchecked(*hint2.0.borrow()) |                 .get_unchecked(*hint2.0.borrow()) | ||||||
|                 .clone(); |                 .clone() | ||||||
|  |                 .widen(self.types) | ||||||
|  |                 .unwrap(); | ||||||
|             self.narrow_to_type(&hint1, &ty)?; |             self.narrow_to_type(&hint1, &ty)?; | ||||||
|             for idx in self.types.type_refs.borrow_mut().iter_mut() { |             for idx in self.types.type_refs.borrow_mut().iter_mut() { | ||||||
|                 if *idx == hint2.0 && idx != &hint1.0 { |                 if *idx == hint2.0 && idx != &hint1.0 { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user