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
|
//! 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.
|
//! 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::convert::Infallible;
|
||||||
use std::error::Error as STDError;
|
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)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Scope<Data: Clone + Default> {
|
pub struct Scope<Data: Clone + Default> {
|
||||||
|
pub binops: Storage<ScopeBinopKey, ScopeBinopDef>,
|
||||||
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>,
|
||||||
@ -128,6 +129,7 @@ impl<Data: Clone + Default> Scope<Data> {
|
|||||||
Scope {
|
Scope {
|
||||||
function_returns: self.function_returns.clone(),
|
function_returns: self.function_returns.clone(),
|
||||||
variables: self.variables.clone(),
|
variables: self.variables.clone(),
|
||||||
|
binops: self.binops.clone(),
|
||||||
types: self.types.clone(),
|
types: self.types.clone(),
|
||||||
return_type_hint: self.return_type_hint.clone(),
|
return_type_hint: self.return_type_hint.clone(),
|
||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
@ -162,6 +164,56 @@ pub struct ScopeVariable {
|
|||||||
pub mutable: bool,
|
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> {
|
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>,
|
||||||
@ -301,6 +353,20 @@ impl Module {
|
|||||||
.ok();
|
.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 {
|
for function in &self.functions {
|
||||||
scope
|
scope
|
||||||
.function_returns
|
.function_returns
|
||||||
|
@ -70,6 +70,8 @@ pub enum ErrorKind {
|
|||||||
NotCastableTo(TypeKind, TypeKind),
|
NotCastableTo(TypeKind, TypeKind),
|
||||||
#[error("Cannot divide by zero")]
|
#[error("Cannot divide by zero")]
|
||||||
DivideZero,
|
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
|
/// 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
|
//! 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.
|
//! 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 crate::{mir::TypeKind, util::try_all};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pass::{Pass, PassResult, PassState},
|
pass::{self, Pass, PassResult, PassState, ScopeBinopDef, ScopeBinopKey},
|
||||||
typecheck::{ErrorKind, ErrorTypedefKind},
|
typecheck::{ErrorKind, ErrorTypedefKind},
|
||||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
|
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 {
|
for binop in &mut module.binop_defs {
|
||||||
let res = binop.infer_types(&self.refs, &mut state.inner());
|
let res = binop.infer_types(&self.refs, &mut state.inner());
|
||||||
state.ok(res, binop.block_meta());
|
state.ok(res, binop.block_meta());
|
||||||
|
Loading…
Reference in New Issue
Block a user