Check for existance of pre-existing binops
This commit is contained in:
		
							parent
							
								
									50af50c43f
								
							
						
					
					
						commit
						7c6de93b31
					
				| @ -1,7 +1,7 @@ | ||||
| //! This module contains relevant code for [`Pass`] and shared code between
 | ||||
| //! passes. Passes can be performed on Reid MIR to e.g. typecheck the code.
 | ||||
| 
 | ||||
| use std::collections::HashMap; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| use std::convert::Infallible; | ||||
| use std::error::Error as STDError; | ||||
| 
 | ||||
| @ -115,6 +115,7 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> { | ||||
| 
 | ||||
| #[derive(Clone, Default, Debug)] | ||||
| pub struct Scope<Data: Clone + Default> { | ||||
|     pub binops: Storage<ScopeBinopKey, ScopeBinopDef>, | ||||
|     pub function_returns: Storage<String, ScopeFunction>, | ||||
|     pub variables: Storage<String, ScopeVariable>, | ||||
|     pub types: Storage<CustomTypeKey, TypeDefinition>, | ||||
| @ -128,6 +129,7 @@ impl<Data: Clone + Default> Scope<Data> { | ||||
|         Scope { | ||||
|             function_returns: self.function_returns.clone(), | ||||
|             variables: self.variables.clone(), | ||||
|             binops: self.binops.clone(), | ||||
|             types: self.types.clone(), | ||||
|             return_type_hint: self.return_type_hint.clone(), | ||||
|             data: self.data.clone(), | ||||
| @ -162,6 +164,56 @@ pub struct ScopeVariable { | ||||
|     pub mutable: bool, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Eq)] | ||||
| pub struct ScopeBinopKey { | ||||
|     pub operators: (TypeKind, TypeKind), | ||||
|     pub commutative: CommutativeKind, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum CommutativeKind { | ||||
|     True, | ||||
|     False, | ||||
|     Any, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for ScopeBinopKey { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         if self.commutative != CommutativeKind::Any && other.commutative != CommutativeKind::Any { | ||||
|             if self.commutative != other.commutative { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         let operators_eq = self.operators == other.operators; | ||||
|         let swapped_ops_eq = | ||||
|             (self.operators.1.clone(), self.operators.0.clone()) == other.operators; | ||||
|         if self.commutative == CommutativeKind::True || other.commutative == CommutativeKind::True { | ||||
|             operators_eq || swapped_ops_eq | ||||
|         } else { | ||||
|             operators_eq | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::hash::Hash for ScopeBinopKey { | ||||
|     fn hash<H: std::hash::Hasher>(&self, state: &mut H) { | ||||
|         if self.commutative == CommutativeKind::True { | ||||
|             let mut sorted = vec![&self.operators.0, &self.operators.1]; | ||||
|             sorted.sort(); | ||||
|             sorted.hash(state); | ||||
|         } else { | ||||
|             self.operators.hash(state); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct ScopeBinopDef { | ||||
|     pub operators: (TypeKind, TypeKind), | ||||
|     pub commutative: bool, | ||||
|     pub return_ty: TypeKind, | ||||
| } | ||||
| 
 | ||||
| pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> { | ||||
|     state: &'st mut State<TError>, | ||||
|     pub scope: &'sc mut Scope<Data>, | ||||
| @ -301,6 +353,20 @@ impl Module { | ||||
|                 .ok(); | ||||
|         } | ||||
| 
 | ||||
|         for binop in &self.binop_defs { | ||||
|             scope.binops.set( | ||||
|                 ScopeBinopKey { | ||||
|                     operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), | ||||
|                     commutative: CommutativeKind::True, | ||||
|                 }, | ||||
|                 ScopeBinopDef { | ||||
|                     operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), | ||||
|                     commutative: true, | ||||
|                     return_ty: binop.return_ty.clone(), | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         for function in &self.functions { | ||||
|             scope | ||||
|                 .function_returns | ||||
|  | ||||
| @ -70,6 +70,8 @@ pub enum ErrorKind { | ||||
|     NotCastableTo(TypeKind, TypeKind), | ||||
|     #[error("Cannot divide by zero")] | ||||
|     DivideZero, | ||||
|     #[error("Binary operation between {0} and {1} is already defined!")] | ||||
|     BinaryOpAlreadyDefined(TypeKind, TypeKind), | ||||
| } | ||||
| 
 | ||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | ||||
|  | ||||
| @ -4,12 +4,16 @@ | ||||
| //! must then be passed through TypeCheck with the same [`TypeRefs`] in order to
 | ||||
| //! place the correct types from the IDs and check that there are no issues.
 | ||||
| 
 | ||||
| use std::{collections::HashMap, convert::Infallible, iter}; | ||||
| use std::{ | ||||
|     collections::{HashMap, HashSet}, | ||||
|     convert::Infallible, | ||||
|     iter, | ||||
| }; | ||||
| 
 | ||||
| use crate::{mir::TypeKind, util::try_all}; | ||||
| 
 | ||||
| use super::{ | ||||
|     pass::{Pass, PassResult, PassState}, | ||||
|     pass::{self, Pass, PassResult, PassState, ScopeBinopDef, ScopeBinopKey}, | ||||
|     typecheck::{ErrorKind, ErrorTypedefKind}, | ||||
|     typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, | ||||
|     BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, | ||||
| @ -55,6 +59,25 @@ impl<'t> Pass for TypeInference<'t> { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut seen_binops = HashSet::new(); | ||||
|         for binop in &module.binop_defs { | ||||
|             let binop_key = ScopeBinopKey { | ||||
|                 operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), | ||||
|                 commutative: pass::CommutativeKind::True, | ||||
|             }; | ||||
|             if seen_binops.contains(&binop_key) { | ||||
|                 state.note_errors( | ||||
|                     &vec![ErrorKind::BinaryOpAlreadyDefined( | ||||
|                         binop.lhs.1.clone(), | ||||
|                         binop.rhs.1.clone(), | ||||
|                     )], | ||||
|                     binop.signature(), | ||||
|                 ); | ||||
|             } else { | ||||
|                 seen_binops.insert(binop_key); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for binop in &mut module.binop_defs { | ||||
|             let res = binop.infer_types(&self.refs, &mut state.inner()); | ||||
|             state.ok(res, binop.block_meta()); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user