Add function double-definition checking
This commit is contained in:
parent
954f3438d3
commit
89002f34e4
@ -129,7 +129,9 @@ pub fn perform_all_passes<'map>(
|
|||||||
dbg!(&context);
|
dbg!(&context);
|
||||||
|
|
||||||
for module in &mut context.modules {
|
for module in &mut context.modules {
|
||||||
module.1.functions.extend(form_intrinsics());
|
for intrinsic in form_intrinsics() {
|
||||||
|
module.1.functions.insert(0, intrinsic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -26,8 +26,8 @@ pub enum ErrorKind {
|
|||||||
FunctionNotDefined(String),
|
FunctionNotDefined(String),
|
||||||
#[error("Expected a return type of {0}, got {1} instead")]
|
#[error("Expected a return type of {0}, got {1} instead")]
|
||||||
ReturnTypeMismatch(TypeKind, TypeKind),
|
ReturnTypeMismatch(TypeKind, TypeKind),
|
||||||
#[error("Function already defined: {0}")]
|
#[error("Function {0} already defined {1}")]
|
||||||
FunctionAlreadyDefined(String),
|
FunctionAlreadyDefined(String, ErrorTypedefKind),
|
||||||
#[error("Variable already defined: {0}")]
|
#[error("Variable already defined: {0}")]
|
||||||
VariableAlreadyDefined(String),
|
VariableAlreadyDefined(String),
|
||||||
#[error("Variable {0} is not declared as mutable")]
|
#[error("Variable {0} is not declared as mutable")]
|
||||||
@ -80,6 +80,16 @@ pub struct TypeCheck<'t> {
|
|||||||
|
|
||||||
type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum ErrorTypedefKind {
|
||||||
|
#[error("locally")]
|
||||||
|
Local,
|
||||||
|
#[error("as an extern")]
|
||||||
|
Extern,
|
||||||
|
#[error("as an intrinsic")]
|
||||||
|
Intrinsic,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'t> Pass for TypeCheck<'t> {
|
impl<'t> Pass for TypeCheck<'t> {
|
||||||
type Data = ();
|
type Data = ();
|
||||||
type TError = ErrorKind;
|
type TError = ErrorKind;
|
||||||
@ -116,10 +126,9 @@ impl<'t> Pass for TypeCheck<'t> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seen = HashSet::new();
|
|
||||||
for typedef in defmap.values() {
|
for typedef in defmap.values() {
|
||||||
let mut curr = seen.clone();
|
let mut seen_types = HashSet::new();
|
||||||
curr.insert(typedef.name.clone());
|
seen_types.insert(typedef.name.clone());
|
||||||
check_typedefs_for_recursion(&defmap, typedef, HashSet::new(), &mut state);
|
check_typedefs_for_recursion(&defmap, typedef, HashSet::new(), &mut state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
//! 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::{convert::Infallible, iter};
|
use std::{collections::HashMap, 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::{Pass, PassResult, PassState},
|
||||||
typecheck::ErrorKind,
|
typecheck::{ErrorKind, ErrorTypedefKind},
|
||||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||||
Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||||
IfExpression, Module, ReturnKind, StmtKind,
|
IfExpression, Module, ReturnKind, StmtKind,
|
||||||
@ -33,6 +33,28 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
type TError = ErrorKind;
|
type TError = ErrorKind;
|
||||||
|
|
||||||
fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult {
|
fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult {
|
||||||
|
let mut seen_functions = HashMap::new();
|
||||||
|
for function in &mut module.functions {
|
||||||
|
if let Some(kind) = seen_functions.get(&function.name) {
|
||||||
|
state.note_errors(
|
||||||
|
&vec![ErrorKind::FunctionAlreadyDefined(
|
||||||
|
function.name.clone(),
|
||||||
|
*kind,
|
||||||
|
)],
|
||||||
|
function.signature(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
seen_functions.insert(
|
||||||
|
function.name.clone(),
|
||||||
|
match function.kind {
|
||||||
|
FunctionDefinitionKind::Local(..) => ErrorTypedefKind::Local,
|
||||||
|
FunctionDefinitionKind::Extern(..) => ErrorTypedefKind::Extern,
|
||||||
|
FunctionDefinitionKind::Intrinsic(..) => ErrorTypedefKind::Intrinsic,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for function in &mut module.functions {
|
for function in &mut module.functions {
|
||||||
let res = function.infer_types(&self.refs, &mut state.inner());
|
let res = function.infer_types(&self.refs, &mut state.inner());
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
|
Loading…
Reference in New Issue
Block a user