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