Implement typechecking and inference logic for binops
This commit is contained in:
		
							parent
							
								
									2cb61de294
								
							
						
					
					
						commit
						7ba3204803
					
				| @ -1,8 +1,10 @@ | |||||||
|  | use std::marker::PhantomData; | ||||||
|  | 
 | ||||||
| use reid_lib::{builder::InstructionValue, Instr}; | use reid_lib::{builder::InstructionValue, Instr}; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     codegen::{ErrorKind, StackValueKind}, |     codegen::{ErrorKind, StackValueKind}, | ||||||
|     mir::{BinopDefinition, FunctionDefinition, TypeKind}, |     mir::{BinaryOperator, BinopDefinition, FunctionDefinition, FunctionDefinitionKind, TypeKind}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use super::scope::{Scope, StackValue}; | use super::scope::{Scope, StackValue}; | ||||||
| @ -16,6 +18,72 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> { | |||||||
| pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { | pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { | ||||||
|     let mut intrinsics = Vec::new(); |     let mut intrinsics = Vec::new(); | ||||||
| 
 | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U32), | ||||||
|  |         op: BinaryOperator::Add, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U32), | ||||||
|  |         return_type: TypeKind::U32, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Add(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U16), | ||||||
|  |         op: BinaryOperator::Add, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U16), | ||||||
|  |         return_type: TypeKind::U16, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Add(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U32), | ||||||
|  |         op: BinaryOperator::Mult, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U32), | ||||||
|  |         return_type: TypeKind::U32, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Mul(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U16), | ||||||
|  |         op: BinaryOperator::Mult, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U16), | ||||||
|  |         return_type: TypeKind::U16, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Mul(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U32), | ||||||
|  |         op: BinaryOperator::Minus, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U32), | ||||||
|  |         return_type: TypeKind::U32, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Sub(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     intrinsics.push(BinopDefinition { | ||||||
|  |         lhs: ("lhs".to_owned(), TypeKind::U16), | ||||||
|  |         op: BinaryOperator::Minus, | ||||||
|  |         rhs: ("rhs".to_owned(), TypeKind::U16), | ||||||
|  |         return_type: TypeKind::U16, | ||||||
|  |         fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr( | ||||||
|  |             |scope, lhs, rhs| scope.block.build(Instr::Sub(lhs, rhs)).unwrap(), | ||||||
|  |         ))), | ||||||
|  |         meta: Default::default(), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     intrinsics |     intrinsics | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -23,56 +91,99 @@ pub trait IntrinsicFunction: std::fmt::Debug { | |||||||
|     fn codegen<'ctx, 'a>( |     fn codegen<'ctx, 'a>( | ||||||
|         &self, |         &self, | ||||||
|         scope: &mut Scope<'ctx, 'a>, |         scope: &mut Scope<'ctx, 'a>, | ||||||
|         params: &[InstructionValue], |         params: &[&StackValue], | ||||||
|     ) -> Result<StackValue, ErrorKind>; |     ) -> Result<StackValue, ErrorKind>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Clone)] | ||||||
| pub struct IntrinsicIAdd(TypeKind); | pub struct IntrinsicSimpleInstr<T>(T) | ||||||
|  | where | ||||||
|  |     T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; | ||||||
| 
 | 
 | ||||||
| impl IntrinsicFunction for IntrinsicIAdd { | impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T> | ||||||
|     fn codegen<'ctx, 'a>( | where | ||||||
|         &self, |     T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, | ||||||
|         scope: &mut Scope<'ctx, 'a>, | { | ||||||
|         params: &[InstructionValue], |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|     ) -> Result<StackValue, ErrorKind> { |         f.debug_tuple("IntrinsicSimpleInstr").finish() | ||||||
|         let lhs = params.get(0).unwrap(); |  | ||||||
|         let rhs = params.get(1).unwrap(); |  | ||||||
|         let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap(); |  | ||||||
|         Ok(StackValue(StackValueKind::Literal(add), self.0.clone())) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T> | ||||||
| pub struct IntrinsicUDiv(TypeKind); | where | ||||||
| 
 |     T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, | ||||||
| impl IntrinsicFunction for IntrinsicUDiv { | { | ||||||
|     fn codegen<'ctx, 'a>( |     fn codegen<'b, 'c>( | ||||||
|         &self, |         &self, | ||||||
|         scope: &mut Scope<'ctx, 'a>, |         scope: &mut Scope<'b, 'c>, | ||||||
|         params: &[InstructionValue], |         params: &[&StackValue], | ||||||
|     ) -> Result<StackValue, ErrorKind> { |     ) -> Result<StackValue, ErrorKind> { | ||||||
|         let lhs = params.get(0).unwrap(); |         let lhs = params.get(0).unwrap(); | ||||||
|         let rhs = params.get(1).unwrap(); |         let rhs = params.get(1).unwrap(); | ||||||
|         let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap(); |         let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); | ||||||
|         Ok(StackValue(StackValueKind::Literal(add), self.0.clone())) |         Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone())) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | // impl IntrinsicFunction for IntrinsicIAdd {
 | ||||||
| pub struct IntrinsicUMod(TypeKind); | //     fn codegen<'ctx, 'a>(
 | ||||||
|  | //         &self,
 | ||||||
|  | //         scope: &mut Scope<'ctx, 'a>,
 | ||||||
|  | //         params: &[InstructionValue],
 | ||||||
|  | //     ) -> Result<StackValue, ErrorKind> {
 | ||||||
|  | //         let lhs = params.get(0).unwrap();
 | ||||||
|  | //         let rhs = params.get(1).unwrap();
 | ||||||
|  | //         let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
 | ||||||
|  | //         Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
 | ||||||
|  | //     }
 | ||||||
|  | // }
 | ||||||
| 
 | 
 | ||||||
| impl IntrinsicFunction for IntrinsicUMod { | // #[derive(Debug, Clone)]
 | ||||||
|     fn codegen<'ctx, 'a>( | // pub struct IntrinsicIAdd(TypeKind);
 | ||||||
|         &self, | 
 | ||||||
|         scope: &mut Scope<'ctx, 'a>, | // impl IntrinsicFunction for IntrinsicIAdd {
 | ||||||
|         params: &[InstructionValue], | //     fn codegen<'ctx, 'a>(
 | ||||||
|     ) -> Result<StackValue, ErrorKind> { | //         &self,
 | ||||||
|         let lhs = params.get(0).unwrap(); | //         scope: &mut Scope<'ctx, 'a>,
 | ||||||
|         let rhs = params.get(1).unwrap(); | //         params: &[InstructionValue],
 | ||||||
|         let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap(); | //     ) -> Result<StackValue, ErrorKind> {
 | ||||||
|         let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap(); | //         let lhs = params.get(0).unwrap();
 | ||||||
|         let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap(); | //         let rhs = params.get(1).unwrap();
 | ||||||
|         Ok(StackValue(StackValueKind::Literal(sub), self.0.clone())) | //         let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
 | ||||||
|     } | //         Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
 | ||||||
| } | //     }
 | ||||||
|  | // }
 | ||||||
|  | 
 | ||||||
|  | // #[derive(Debug, Clone)]
 | ||||||
|  | // pub struct IntrinsicUDiv(TypeKind);
 | ||||||
|  | 
 | ||||||
|  | // impl IntrinsicFunction for IntrinsicUDiv {
 | ||||||
|  | //     fn codegen<'ctx, 'a>(
 | ||||||
|  | //         &self,
 | ||||||
|  | //         scope: &mut Scope<'ctx, 'a>,
 | ||||||
|  | //         params: &[InstructionValue],
 | ||||||
|  | //     ) -> Result<StackValue, ErrorKind> {
 | ||||||
|  | //         let lhs = params.get(0).unwrap();
 | ||||||
|  | //         let rhs = params.get(1).unwrap();
 | ||||||
|  | //         let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
 | ||||||
|  | //         Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
 | ||||||
|  | //     }
 | ||||||
|  | // }
 | ||||||
|  | 
 | ||||||
|  | // #[derive(Debug, Clone)]
 | ||||||
|  | // pub struct IntrinsicUMod(TypeKind);
 | ||||||
|  | 
 | ||||||
|  | // impl IntrinsicFunction for IntrinsicUMod {
 | ||||||
|  | //     fn codegen<'ctx, 'a>(
 | ||||||
|  | //         &self,
 | ||||||
|  | //         scope: &mut Scope<'ctx, 'a>,
 | ||||||
|  | //         params: &[InstructionValue],
 | ||||||
|  | //     ) -> Result<StackValue, ErrorKind> {
 | ||||||
|  | //         let lhs = params.get(0).unwrap();
 | ||||||
|  | //         let rhs = params.get(1).unwrap();
 | ||||||
|  | //         let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
 | ||||||
|  | //         let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
 | ||||||
|  | //         let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
 | ||||||
|  | //         Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
 | ||||||
|  | //     }
 | ||||||
|  | // }
 | ||||||
|  | |||||||
| @ -160,9 +160,7 @@ impl<'ctx> StackBinopDefinition<'ctx> { | |||||||
|                     self.return_ty.clone(), |                     self.return_ty.clone(), | ||||||
|                 )) |                 )) | ||||||
|             } |             } | ||||||
|             StackBinopFunctionKind::Intrinsic(fun) => { |             StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]), | ||||||
|                 fun.codegen(scope, &[lhs.instr(), rhs.instr()]) |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ | |||||||
| //! - Debug Symbols
 | //! - Debug Symbols
 | ||||||
| //! ```
 | //! ```
 | ||||||
| 
 | 
 | ||||||
| use std::path::PathBuf; | use std::{path::PathBuf, thread, time::Duration}; | ||||||
| 
 | 
 | ||||||
| use ast::{ | use ast::{ | ||||||
|     lexer::{self, FullToken, Token}, |     lexer::{self, FullToken, Token}, | ||||||
| @ -51,6 +51,7 @@ use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; | |||||||
| use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; | use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; | ||||||
| use mir::{ | use mir::{ | ||||||
|     linker::LinkerPass, |     linker::LinkerPass, | ||||||
|  |     pass::BinopMap, | ||||||
|     typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs}, |     typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs}, | ||||||
| }; | }; | ||||||
| use reid_lib::{compile::CompileOutput, Context}; | use reid_lib::{compile::CompileOutput, Context}; | ||||||
| @ -128,8 +129,22 @@ pub fn perform_all_passes<'map>( | |||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     dbg!(&context); |     dbg!(&context); | ||||||
| 
 | 
 | ||||||
|  |     let mut binops = BinopMap::default(); | ||||||
|     for module in &mut context.modules { |     for module in &mut context.modules { | ||||||
|         for intrinsic in form_intrinsic_binops() { |         for intrinsic in form_intrinsic_binops() { | ||||||
|  |             binops | ||||||
|  |                 .set( | ||||||
|  |                     mir::pass::ScopeBinopKey { | ||||||
|  |                         params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()), | ||||||
|  |                         operator: intrinsic.op, | ||||||
|  |                     }, | ||||||
|  |                     mir::pass::ScopeBinopDef { | ||||||
|  |                         hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()), | ||||||
|  |                         operator: intrinsic.op, | ||||||
|  |                         return_ty: intrinsic.return_type.clone(), | ||||||
|  |                     }, | ||||||
|  |                 ) | ||||||
|  |                 .ok(); | ||||||
|             module.1.binop_defs.insert(0, intrinsic); |             module.1.binop_defs.insert(0, intrinsic); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -162,7 +177,7 @@ pub fn perform_all_passes<'map>( | |||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let refs = TypeRefs::default(); |     let refs = TypeRefs::with_binops(binops); | ||||||
| 
 | 
 | ||||||
|     let state = context.pass(&mut TypeInference { refs: &refs })?; |     let state = context.pass(&mut TypeInference { refs: &refs })?; | ||||||
| 
 | 
 | ||||||
| @ -174,6 +189,8 @@ pub fn perform_all_passes<'map>( | |||||||
|     println!("{}", &context); |     println!("{}", &context); | ||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     dbg!(&state); |     dbg!(&state); | ||||||
|  |     dbg!("asd!"); | ||||||
|  |     thread::sleep(Duration::from_millis(100)); | ||||||
| 
 | 
 | ||||||
|     if !state.errors.is_empty() { |     if !state.errors.is_empty() { | ||||||
|         return Err(ReidError::from_kind( |         return Err(ReidError::from_kind( | ||||||
|  | |||||||
| @ -43,20 +43,6 @@ impl TypeKind { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn binop_type( |  | ||||||
|         lhs: &TypeKind, |  | ||||||
|         rhs: &TypeKind, |  | ||||||
|         binop: &ScopeBinopDef, |  | ||||||
|     ) -> Option<(TypeKind, TypeKind, TypeKind)> { |  | ||||||
|         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 { |  | ||||||
|             None |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Reverse of binop_type, where the given hint is the known required output
 |     /// Reverse of binop_type, where the given hint is the known required output
 | ||||||
|     /// type of the binop, and the output is the hint for the lhs/rhs type.
 |     /// type of the binop, and the output is the hint for the lhs/rhs type.
 | ||||||
|     pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { |     pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { | ||||||
|  | |||||||
| @ -119,6 +119,10 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> { | |||||||
|     pub fn find(&self, key: &Key) -> Option<(&Key, &T)> { |     pub fn find(&self, key: &Key) -> Option<(&Key, &T)> { | ||||||
|         self.0.iter().find(|(k, _)| *k == key) |         self.0.iter().find(|(k, _)| *k == key) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn filter(&self, key: &Key) -> Vec<(&Key, &T)> { | ||||||
|  |         self.0.iter().filter(|(k, _)| *k == key).collect() | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>; | pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>; | ||||||
| @ -195,8 +199,12 @@ impl PartialEq for ScopeBinopKey { | |||||||
|         if self.operator.is_commutative() != other.operator.is_commutative() { |         if self.operator.is_commutative() != other.operator.is_commutative() { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         let operators_eq = self.params == other.params; | 
 | ||||||
|         let swapped_ops_eq = (self.params.1.clone(), self.params.0.clone()) == other.params; |         let operators_eq = self.params.0.narrow_into(&other.params.0).is_ok() | ||||||
|  |             && self.params.1.narrow_into(&other.params.1).is_ok(); | ||||||
|  |         let swapped_ops_eq = self.params.0.narrow_into(&other.params.1).is_ok() | ||||||
|  |             && self.params.1.narrow_into(&other.params.0).is_ok(); | ||||||
|  | 
 | ||||||
|         if self.operator.is_commutative() { |         if self.operator.is_commutative() { | ||||||
|             operators_eq || swapped_ops_eq |             operators_eq || swapped_ops_eq | ||||||
|         } else { |         } else { | ||||||
| @ -226,27 +234,11 @@ pub struct ScopeBinopDef { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ScopeBinopDef { | impl ScopeBinopDef { | ||||||
|     pub fn binop_hint_old( |     pub fn narrow(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<(TypeKind, TypeKind, TypeKind)> { | ||||||
|         &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 lhs_ty = lhs.narrow_into(&self.hands.0); | ||||||
|         let rhs_ty = rhs.narrow_into(&self.hands.1); |         let rhs_ty = rhs.narrow_into(&self.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)) |             Some((lhs_ty, rhs_ty, self.return_ty.clone())) | ||||||
|         } 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 { |         } else { | ||||||
|             None |             None | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -453,73 +453,93 @@ impl Expression { | |||||||
|                 let rhs_res = rhs.typecheck(state, &typerefs, None); |                 let rhs_res = rhs.typecheck(state, &typerefs, None); | ||||||
|                 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 cloned = state.scope.binops.clone(); |                 if let Some(binop) = state | ||||||
|                 let mut iter = cloned.iter(); |                     .scope | ||||||
|                 let operator = loop { |                     .binops | ||||||
|                     let Some((_, binop)) = iter.next() else { |                     .find(&pass::ScopeBinopKey { | ||||||
|                         break None; |                         params: (lhs_type.clone(), rhs_type.clone()), | ||||||
|                     }; |                         operator: *op, | ||||||
|                     if binop.operator != *op { |                     }) | ||||||
|                         continue; |                     .map(|v| (v.1.clone())) | ||||||
|                     } |                 { | ||||||
|                     if let Some(hint_t) = hint_t { |                     dbg!(&lhs, &rhs); | ||||||
|                         if binop.return_ty == *hint_t { |                     dbg!(&lhs_type.resolve_ref(typerefs)); | ||||||
|                             if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) { |                     dbg!(&rhs_type.resolve_ref(typerefs)); | ||||||
|                                 break Some(binop); |                     lhs.typecheck(state, &typerefs, Some(&binop.hands.0))?; | ||||||
|                             } |                     rhs.typecheck(state, &typerefs, Some(&binop.hands.1))?; | ||||||
|                         } else { |                     Ok(binop.narrow(&lhs_type, &rhs_type).unwrap().2) | ||||||
|                             continue; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) { |  | ||||||
|                         break Some(binop); |  | ||||||
|                     } |  | ||||||
|                 }; |  | ||||||
| 
 |  | ||||||
|                 if let Some(operator) = operator { |  | ||||||
|                     // Re-typecheck with found operator hints
 |  | ||||||
|                     let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two( |  | ||||||
|                         (&lhs_type, &rhs_type), |  | ||||||
|                         (&operator.hands.0, &operator.hands.1), |  | ||||||
|                     ) |  | ||||||
|                     .unwrap(); |  | ||||||
|                     let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty)); |  | ||||||
|                     let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty)); |  | ||||||
|                     state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); |  | ||||||
|                     state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); |  | ||||||
|                     Ok(operator.return_ty.clone()) |  | ||||||
|                 } else { |                 } else { | ||||||
|                     // Re-typecheck with typical everyday binop
 |                     Err(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type)) | ||||||
|                     let lhs_res = lhs.typecheck( |  | ||||||
|                         state, |  | ||||||
|                         &typerefs, |  | ||||||
|                         hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(), |  | ||||||
|                     ); |  | ||||||
|                     let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); |  | ||||||
|                     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.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()?) |  | ||||||
|                         { |  | ||||||
|                             if lhs_val < rhs_val { |  | ||||||
|                                 return Err(ErrorKind::NegativeUnsignedValue(lhs_type)); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     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(); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     both_t |  | ||||||
|                         .simple_binop_type(op) |  | ||||||
|                         .ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type)) |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 // let cloned = state.scope.binops.clone();
 | ||||||
|  |                 // let mut iter = cloned.iter();
 | ||||||
|  |                 // let operator = loop {
 | ||||||
|  |                 //     let Some((_, binop)) = iter.next() else {
 | ||||||
|  |                 //         break None;
 | ||||||
|  |                 //     };
 | ||||||
|  |                 //     if binop.operator != *op {
 | ||||||
|  |                 //         continue;
 | ||||||
|  |                 //     }
 | ||||||
|  |                 //     if let Some(hint_t) = hint_t {
 | ||||||
|  |                 //         if binop.return_ty == *hint_t {
 | ||||||
|  |                 //             if let Some(_) = TypeKind::narrow_to_binop(&lhs_type, &rhs_type, binop)
 | ||||||
|  |                 //             {
 | ||||||
|  |                 //                 break Some(binop);
 | ||||||
|  |                 //             }
 | ||||||
|  |                 //         } else {
 | ||||||
|  |                 //             continue;
 | ||||||
|  |                 //         }
 | ||||||
|  |                 //     }
 | ||||||
|  |                 //     if let Some(_) = TypeKind::narrow_to_binop(&lhs_type, &rhs_type, binop) {
 | ||||||
|  |                 //         break Some(binop);
 | ||||||
|  |                 //     }
 | ||||||
|  |                 // };
 | ||||||
|  | 
 | ||||||
|  |                 // if let Some(operator) = operator {
 | ||||||
|  |                 //     // Re-typecheck with found operator hints
 | ||||||
|  |                 //     let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two(
 | ||||||
|  |                 //         (&lhs_type, &rhs_type),
 | ||||||
|  |                 //         (&operator.hands.0, &operator.hands.1),
 | ||||||
|  |                 //     )
 | ||||||
|  |                 //     .unwrap();
 | ||||||
|  |                 //     let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty));
 | ||||||
|  |                 //     let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty));
 | ||||||
|  |                 //     state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
 | ||||||
|  |                 //     state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
 | ||||||
|  |                 //     Ok(operator.return_ty.clone())
 | ||||||
|  |                 // } else {
 | ||||||
|  |                 //     // Re-typecheck with typical everyday binop
 | ||||||
|  |                 //     let lhs_res = lhs.typecheck(
 | ||||||
|  |                 //         state,
 | ||||||
|  |                 //         &typerefs,
 | ||||||
|  |                 //         hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(),
 | ||||||
|  |                 //     );
 | ||||||
|  |                 //     let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
 | ||||||
|  |                 //     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.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()?)
 | ||||||
|  |                 //         {
 | ||||||
|  |                 //             if lhs_val < rhs_val {
 | ||||||
|  |                 //                 return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
 | ||||||
|  |                 //             }
 | ||||||
|  |                 //         }
 | ||||||
|  |                 //     }
 | ||||||
|  | 
 | ||||||
|  |                 //     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();
 | ||||||
|  |                 //     }
 | ||||||
|  | 
 | ||||||
|  |                 //     both_t
 | ||||||
|  |                 //         .simple_binop_type(op)
 | ||||||
|  |                 //         .ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
 | ||||||
|  |                 // }
 | ||||||
|             } |             } | ||||||
|             ExprKind::FunctionCall(function_call) => { |             ExprKind::FunctionCall(function_call) => { | ||||||
|                 let true_function = state |                 let true_function = state | ||||||
| @ -809,6 +829,7 @@ impl Literal { | |||||||
|     /// Try to coerce this literal, ie. convert it to a more specific type in
 |     /// Try to coerce this literal, ie. convert it to a more specific type in
 | ||||||
|     /// regards to the given hint if any.
 |     /// regards to the given hint if any.
 | ||||||
|     fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> { |     fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> { | ||||||
|  |         dbg!(&self, &hint); | ||||||
|         if let Some(hint) = &hint { |         if let Some(hint) = &hint { | ||||||
|             use Literal as L; |             use Literal as L; | ||||||
|             use VagueLiteral as VagueL; |             use VagueLiteral as VagueL; | ||||||
|  | |||||||
| @ -322,37 +322,25 @@ impl Expression { | |||||||
|                 let mut lhs_ref = lhs.infer_types(state, type_refs)?; |                 let mut lhs_ref = lhs.infer_types(state, type_refs)?; | ||||||
|                 let mut rhs_ref = rhs.infer_types(state, type_refs)?; |                 let mut rhs_ref = rhs.infer_types(state, type_refs)?; | ||||||
| 
 | 
 | ||||||
|                 if let Ok(binop) = type_refs |                 let binops = type_refs.available_binops(op, &mut lhs_ref, &mut rhs_ref); | ||||||
|                     .binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops) | 
 | ||||||
|                     .ok_or(ErrorKind::TypesIncompatible( |                 if binops.len() > 0 { | ||||||
|  |                     let binop = unsafe { binops.get_unchecked(0) }; | ||||||
|  |                     let mut widened_lhs = binop.hands.0.clone(); | ||||||
|  |                     let mut widened_rhs = binop.hands.1.clone(); | ||||||
|  |                     for binop in binops.iter().skip(1) { | ||||||
|  |                         widened_lhs = widened_lhs.widen_into(&binop.hands.0); | ||||||
|  |                         widened_rhs = widened_rhs.widen_into(&binop.hands.1); | ||||||
|  |                     } | ||||||
|  |                     lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap()); | ||||||
|  |                     rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap()); | ||||||
|  |                     Ok(type_refs.from_binop(*op, &lhs_ref, &rhs_ref)) | ||||||
|  |                 } else { | ||||||
|  |                     Err(ErrorKind::InvalidBinop( | ||||||
|  |                         *op, | ||||||
|                         lhs_ref.resolve_deep().unwrap(), |                         lhs_ref.resolve_deep().unwrap(), | ||||||
|                         rhs_ref.resolve_deep().unwrap(), |                         rhs_ref.resolve_deep().unwrap(), | ||||||
|                     )) |                     )) | ||||||
|                 { |  | ||||||
|                     Ok(binop) |  | ||||||
|                 } else { |  | ||||||
|                     let typeref = state.or_else( |  | ||||||
|                         lhs_ref.narrow(&rhs_ref).ok_or(ErrorKind::InvalidBinop( |  | ||||||
|                             *op, |  | ||||||
|                             lhs_ref.resolve_deep().unwrap(), |  | ||||||
|                             rhs_ref.resolve_deep().unwrap(), |  | ||||||
|                         )), |  | ||||||
|                         type_refs.from_type(&Vague(Unknown)).unwrap(), |  | ||||||
|                         self.1, |  | ||||||
|                     ); |  | ||||||
|                     Ok(type_refs |  | ||||||
|                         .from_type( |  | ||||||
|                             &typeref |  | ||||||
|                                 .resolve_deep() |  | ||||||
|                                 .unwrap() |  | ||||||
|                                 .simple_binop_type(op) |  | ||||||
|                                 .ok_or(ErrorKind::InvalidBinop( |  | ||||||
|                                     *op, |  | ||||||
|                                     lhs_ref.resolve_deep().unwrap(), |  | ||||||
|                                     rhs_ref.resolve_deep().unwrap(), |  | ||||||
|                                 ))?, |  | ||||||
|                         ) |  | ||||||
|                         .unwrap()) |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ExprKind::FunctionCall(function_call) => { |             ExprKind::FunctionCall(function_call) => { | ||||||
|  | |||||||
| @ -4,7 +4,10 @@ use std::{ | |||||||
|     rc::Rc, |     rc::Rc, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}; | use crate::{ | ||||||
|  |     ast::BinopDefinition, | ||||||
|  |     mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| use super::{ | use super::{ | ||||||
|     super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, |     super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, | ||||||
| @ -64,33 +67,33 @@ pub enum TypeRefKind { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TypeRefKind { | impl TypeRefKind { | ||||||
|     pub fn widen(&self, types: &TypeRefs) -> Option<TypeKind> { |     pub fn widen(&self, types: &TypeRefs) -> TypeKind { | ||||||
|         match self { |         match self { | ||||||
|             TypeRefKind::BinOp(op, lhs, rhs) => { |             TypeRefKind::BinOp(op, lhs, rhs) => { | ||||||
|                 let mut binops = types |                 let mut binops = types | ||||||
|                     .binop_types |                     .binop_types | ||||||
|                     .iter() |                     .iter() | ||||||
|                     .filter(|b| b.1.operator == *op) |                     .filter(|b| b.1.operator == *op) | ||||||
|                     .map(|b| b.1.binop_ret_ty(&lhs, &rhs)) |                     .map(|b| b.1.narrow(&lhs, &rhs).map(|b| b.2)) | ||||||
|                     .filter_map(|s| s); |                     .filter_map(|s| s); | ||||||
|                 if let Some(mut ty) = binops.next() { |                 if let Some(mut ty) = binops.next() { | ||||||
|                     while let Some(other) = binops.next() { |                     while let Some(other) = binops.next() { | ||||||
|                         ty = ty.widen_into(&other); |                         ty = ty.widen_into(&other); | ||||||
|                     } |                     } | ||||||
|                     Some(ty) |                     ty | ||||||
|                 } else { |                 } else { | ||||||
|                     None |                     TypeKind::Vague(VagueType::Unknown) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             TypeRefKind::Direct(ty) => match ty { |             TypeRefKind::Direct(ty) => match ty { | ||||||
|                 TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id), |                 TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id).unwrap(), | ||||||
|                 _ => Some(ty.clone()), |                 _ => ty.clone(), | ||||||
|             }, |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Default)] | #[derive(Default, Debug)] | ||||||
| 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<TypeRefKind>>, |     pub(super) hints: RefCell<Vec<TypeRefKind>>, | ||||||
| @ -117,6 +120,14 @@ impl std::fmt::Display for TypeRefs { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TypeRefs { | impl TypeRefs { | ||||||
|  |     pub fn with_binops(binops: BinopMap) -> TypeRefs { | ||||||
|  |         TypeRefs { | ||||||
|  |             hints: Default::default(), | ||||||
|  |             type_refs: Default::default(), | ||||||
|  |             binop_types: binops, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn new(&self, ty: &TypeKind) -> TypeIdRef { |     pub fn new(&self, ty: &TypeKind) -> TypeIdRef { | ||||||
|         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)); | ||||||
| @ -127,6 +138,16 @@ impl TypeRefs { | |||||||
|         typecell |         typecell | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn binop(&self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeIdRef { | ||||||
|  |         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(TypeRefKind::BinOp(op, lhs.as_type(), rhs.as_type())); | ||||||
|  |         typecell | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> { |     pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> { | ||||||
|         if ty.known().is_err() { |         if ty.known().is_err() { | ||||||
|             // Only do this for non-vague types that can not be further narrowed
 |             // Only do this for non-vague types that can not be further narrowed
 | ||||||
| @ -167,7 +188,6 @@ impl TypeRefs { | |||||||
|             .get(inner_idx) |             .get(inner_idx) | ||||||
|             .cloned() |             .cloned() | ||||||
|             .map(|t| t.widen(self)) |             .map(|t| t.widen(self)) | ||||||
|             .flatten() |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -232,6 +252,15 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|         Some(TypeRef(idx, self)) |         Some(TypeRef(idx, self)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn from_binop( | ||||||
|  |         &'outer self, | ||||||
|  |         op: BinaryOperator, | ||||||
|  |         lhs: &TypeRef, | ||||||
|  |         rhs: &TypeRef, | ||||||
|  |     ) -> TypeRef<'outer> { | ||||||
|  |         TypeRef(self.types.binop(op, lhs, rhs), self) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> { |     fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> { | ||||||
|         unsafe { |         unsafe { | ||||||
|             let mut hints = self.types.hints.borrow_mut(); |             let mut hints = self.types.hints.borrow_mut(); | ||||||
| @ -269,8 +298,7 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|                 .borrow() |                 .borrow() | ||||||
|                 .get_unchecked(*hint2.0.borrow()) |                 .get_unchecked(*hint2.0.borrow()) | ||||||
|                 .clone() |                 .clone() | ||||||
|                 .widen(self.types) |                 .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 { | ||||||
| @ -297,47 +325,36 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|             .or(self.outer.map(|o| o.find_var(name)).flatten()) |             .or(self.outer.map(|o| o.find_var(name)).flatten()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn binop( |     pub fn available_binops( | ||||||
|         &'outer self, |         &'outer self, | ||||||
|         op: &BinaryOperator, |         op: &BinaryOperator, | ||||||
|         lhs: &mut TypeRef<'outer>, |         lhs: &mut TypeRef<'outer>, | ||||||
|         rhs: &mut TypeRef<'outer>, |         rhs: &mut TypeRef<'outer>, | ||||||
|         binops: &Storage<ScopeBinopKey, ScopeBinopDef>, |     ) -> Vec<ScopeBinopDef> { | ||||||
|     ) -> Option<TypeRef<'outer>> { |         let mut applying_binops = Vec::new(); | ||||||
|         if lhs.resolve_deep().unwrap().known().is_err() |         for (_, binop) in self.types.binop_types.iter() { | ||||||
|             && rhs.resolve_deep().unwrap().known().is_err() |  | ||||||
|         { |  | ||||||
|             return self.from_type(&TypeKind::Vague(VagueType::Unknown)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         let mut iter = binops.iter(); |  | ||||||
|         loop { |  | ||||||
|             let Some((_, binop)) = iter.next() else { |  | ||||||
|                 break None; |  | ||||||
|             }; |  | ||||||
|             if binop.operator != *op { |             if binop.operator != *op { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             if let Some(ret) = try_binop(lhs, rhs, binop) { |             if let Some(_) = check_binop(lhs, rhs, binop) { | ||||||
|                 break Some(ret); |                 applying_binops.push(binop.clone()); | ||||||
|  |                 continue; | ||||||
|             } |             } | ||||||
|             if binop.operator.is_commutative() { |             if binop.operator.is_commutative() { | ||||||
|                 if let Some(ret) = try_binop(rhs, lhs, binop) { |                 if let Some(_) = check_binop(lhs, rhs, binop) { | ||||||
|                     return Some(ret); |                     applying_binops.push(binop.clone()); | ||||||
|  |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         applying_binops | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn try_binop<'o>( | fn check_binop<'o>( | ||||||
|     lhs: &mut TypeRef<'o>, |     lhs: &mut TypeRef<'o>, | ||||||
|     rhs: &mut TypeRef<'o>, |     rhs: &mut TypeRef<'o>, | ||||||
|     binop: &ScopeBinopDef, |     binop: &ScopeBinopDef, | ||||||
| ) -> Option<TypeRef<'o>> { | ) -> Option<(TypeKind, TypeKind, TypeKind)> { | ||||||
|     let (lhs_ty, rhs_ty, ret_ty) = |     binop.narrow(&lhs.resolve_deep()?, &rhs.resolve_deep()?) | ||||||
|         TypeKind::binop_type(&lhs.resolve_deep()?, &rhs.resolve_deep()?, binop)?; |  | ||||||
|     lhs.narrow(&lhs.1.from_type(&lhs_ty).unwrap()).unwrap(); |  | ||||||
|     rhs.narrow(&rhs.1.from_type(&rhs_ty).unwrap()).unwrap(); |  | ||||||
|     lhs.1.from_type(&ret_ty) |  | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user