Add function double-definition checking

This commit is contained in:
Sofia 2025-07-24 12:13:34 +03:00
parent 954f3438d3
commit 89002f34e4
3 changed files with 41 additions and 8 deletions

View File

@ -129,7 +129,9 @@ pub fn perform_all_passes<'map>(
dbg!(&context);
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)]

View File

@ -26,8 +26,8 @@ pub enum ErrorKind {
FunctionNotDefined(String),
#[error("Expected a return type of {0}, got {1} instead")]
ReturnTypeMismatch(TypeKind, TypeKind),
#[error("Function already defined: {0}")]
FunctionAlreadyDefined(String),
#[error("Function {0} already defined {1}")]
FunctionAlreadyDefined(String, ErrorTypedefKind),
#[error("Variable already defined: {0}")]
VariableAlreadyDefined(String),
#[error("Variable {0} is not declared as mutable")]
@ -80,6 +80,16 @@ pub struct TypeCheck<'t> {
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> {
type Data = ();
type TError = ErrorKind;
@ -116,10 +126,9 @@ impl<'t> Pass for TypeCheck<'t> {
}
}
let seen = HashSet::new();
for typedef in defmap.values() {
let mut curr = seen.clone();
curr.insert(typedef.name.clone());
let mut seen_types = HashSet::new();
seen_types.insert(typedef.name.clone());
check_typedefs_for_recursion(&defmap, typedef, HashSet::new(), &mut state);
}

View File

@ -4,13 +4,13 @@
//! 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::{convert::Infallible, iter};
use std::{collections::HashMap, convert::Infallible, iter};
use crate::{mir::TypeKind, util::try_all};
use super::{
pass::{Pass, PassResult, PassState},
typecheck::ErrorKind,
typecheck::{ErrorKind, ErrorTypedefKind},
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
IfExpression, Module, ReturnKind, StmtKind,
@ -33,6 +33,28 @@ impl<'t> Pass for TypeInference<'t> {
type TError = ErrorKind;
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 {
let res = function.infer_types(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());