Compare commits

...

7 Commits

Author SHA1 Message Date
89002f34e4 Add function double-definition checking 2025-07-24 12:13:34 +03:00
954f3438d3 Codegen intrinsics 2025-07-24 11:56:44 +03:00
b793ef7526 Add intrinsic code generation part 1 2025-07-24 11:34:44 +03:00
5ff5651f5f Work on intrinsics, clean up code a bit 2025-07-24 11:29:58 +03:00
4f1dc5e59d Merge branch 'main' into intrinsicts 2025-07-24 11:18:33 +03:00
9ba091973a Update readme 2025-07-24 11:18:23 +03:00
4bef1c2379 Start implementing intrinsics 2025-07-24 01:39:49 +03:00
16 changed files with 185 additions and 76 deletions

View File

@ -47,7 +47,7 @@ Currently missing big features (TODOs) are:
- Debug Information (PARTIALLY DONE) - Debug Information (PARTIALLY DONE)
- Ability to specify types in literals and variable definitions - Ability to specify types in literals and variable definitions
- Intrinsic functions - Intrinsic functions
- Not-Unary - Not-Unary and NEQ-binary
Big features that I want later but are not necessary: Big features that I want later but are not necessary:
- Associated functions - Associated functions

View File

@ -7,7 +7,7 @@ import std::new_string;
import std::add_num_to_str; import std::add_num_to_str;
import std::concat_strings; import std::concat_strings;
fn main() -> i32 { fn main() -> u8 {
let mut test = from_str("hello"); let mut test = from_str("hello");
concat_strings(&mut test, from_str(" world")); concat_strings(&mut test, from_str(" world"));
@ -21,5 +21,5 @@ fn main() -> i32 {
free_string(&test); free_string(&test);
return 0; return addition(5, 3);
} }

View File

@ -155,7 +155,7 @@ impl Default for FunctionFlags {
FunctionFlags { FunctionFlags {
is_extern: false, is_extern: false,
is_main: false, is_main: false,
is_pub: true, is_pub: false,
is_imported: false, is_imported: false,
} }
} }

View File

@ -18,11 +18,16 @@ pub struct Allocator {
pub struct AllocatorScope<'ctx, 'a> { pub struct AllocatorScope<'ctx, 'a> {
pub(super) block: &'a mut Block<'ctx>, pub(super) block: &'a mut Block<'ctx>,
pub(super) module_id: SourceModuleId, pub(super) module_id: SourceModuleId,
pub(super) types: &'a HashMap<TypeValue, TypeDefinition>,
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>, pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
} }
impl Allocator { impl Allocator {
pub fn empty() -> Allocator {
Allocator {
allocations: Vec::new(),
}
}
pub fn from(func: &FunctionDefinition, scope: &mut AllocatorScope) -> Allocator { pub fn from(func: &FunctionDefinition, scope: &mut AllocatorScope) -> Allocator {
func.allocate(scope) func.allocate(scope)
} }
@ -44,22 +49,21 @@ impl mir::FunctionDefinition {
fn allocate<'ctx, 'a>(&self, scope: &mut AllocatorScope<'ctx, 'a>) -> Allocator { fn allocate<'ctx, 'a>(&self, scope: &mut AllocatorScope<'ctx, 'a>) -> Allocator {
let mut allocated = Vec::new(); let mut allocated = Vec::new();
match &self.kind { match &self.kind {
crate::mir::FunctionDefinitionKind::Local(block, _) => { mir::FunctionDefinitionKind::Local(block, _) => {
for param in &self.parameters { for param in &self.parameters {
let allocation = scope let allocation = scope
.block .block
.build_named( .build_named(
param.0.clone(), param.0.clone(),
reid_lib::Instr::Alloca( reid_lib::Instr::Alloca(param.1.get_type(scope.type_values)),
param.1.get_type(scope.type_values, scope.types),
),
) )
.unwrap(); .unwrap();
allocated.push(Allocation(param.0.clone(), param.1.clone(), allocation)); allocated.push(Allocation(param.0.clone(), param.1.clone(), allocation));
} }
allocated.extend(block.allocate(scope)); allocated.extend(block.allocate(scope));
} }
crate::mir::FunctionDefinitionKind::Extern(_) => {} mir::FunctionDefinitionKind::Extern(_) => {}
mir::FunctionDefinitionKind::Intrinsic(_) => {}
} }
Allocator { Allocator {
@ -95,11 +99,7 @@ impl mir::Statement {
.block .block
.build_named( .build_named(
named_variable_ref.1.clone(), named_variable_ref.1.clone(),
reid_lib::Instr::Alloca( reid_lib::Instr::Alloca(named_variable_ref.0.get_type(scope.type_values)),
named_variable_ref
.0
.get_type(scope.type_values, scope.types),
),
) )
.unwrap(); .unwrap();
allocated.push(Allocation( allocated.push(Allocation(

View File

@ -50,7 +50,6 @@ impl ast::Module {
block.into_mir(module_id), block.into_mir(module_id),
(*range).as_meta(module_id), (*range).as_meta(module_id),
), ),
source: module_id,
}; };
functions.push(def); functions.push(def);
} }
@ -71,7 +70,6 @@ impl ast::Module {
.map(|p| (p.0, p.1 .0.into_mir(module_id))) .map(|p| (p.0, p.1 .0.into_mir(module_id)))
.collect(), .collect(),
kind: mir::FunctionDefinitionKind::Extern(false), kind: mir::FunctionDefinitionKind::Extern(false),
source: module_id,
}; };
functions.push(def); functions.push(def);
} }

View File

@ -275,7 +275,7 @@ impl mir::Module {
// TODO: Reorder custom-type definitions such that // TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this // inner types get evaluated first. Otherwise this
// will cause a panic! // will cause a panic!
.map(|StructField(_, t, _)| t.get_type(&type_values, &types)) .map(|StructField(_, t, _)| t.get_type(&type_values))
.collect(), .collect(),
))) )))
} }
@ -291,14 +291,14 @@ impl mir::Module {
let param_types: Vec<Type> = function let param_types: Vec<Type> = function
.parameters .parameters
.iter() .iter()
.map(|(_, p)| p.get_type(&type_values, &types)) .map(|(_, p)| p.get_type(&type_values))
.collect(); .collect();
let is_main = self.is_main && function.name == "main"; let is_main = self.is_main && function.name == "main";
let func = match &function.kind { let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => module.function( mir::FunctionDefinitionKind::Local(_, _) => module.function(
&function.name, &function.name,
function.return_type.get_type(&type_values, &types), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
is_pub: function.is_pub || is_main, is_pub: function.is_pub || is_main,
@ -309,7 +309,7 @@ impl mir::Module {
), ),
mir::FunctionDefinitionKind::Extern(imported) => module.function( mir::FunctionDefinitionKind::Extern(imported) => module.function(
&function.name, &function.name,
function.return_type.get_type(&type_values, &types), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
is_extern: true, is_extern: true,
@ -317,6 +317,14 @@ impl mir::Module {
..FunctionFlags::default() ..FunctionFlags::default()
}, },
), ),
mir::FunctionDefinitionKind::Intrinsic(_) => module.function(
&function.name,
function.return_type.get_type(&type_values),
param_types,
FunctionFlags {
..FunctionFlags::default()
},
),
}; };
functions.insert(function.name.clone(), StackFunction { ir: func }); functions.insert(function.name.clone(), StackFunction { ir: func });
@ -333,7 +341,6 @@ impl mir::Module {
&mut AllocatorScope { &mut AllocatorScope {
block: &mut entry, block: &mut entry,
module_id: self.module_id, module_id: self.module_id,
types: &types,
type_values: &type_values, type_values: &type_values,
}, },
); );
@ -470,6 +477,26 @@ impl mir::Module {
} }
} }
mir::FunctionDefinitionKind::Extern(_) => {} mir::FunctionDefinitionKind::Extern(_) => {}
mir::FunctionDefinitionKind::Intrinsic(kind) => {
let entry = function.ir.block("entry");
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function,
block: entry,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values: Default::default(),
debug: None,
allocator: Rc::new(RefCell::new(Allocator::empty())),
};
kind.codegen(&mut scope)?
}
} }
} }
@ -694,7 +721,7 @@ impl mir::Expression {
format!("{}", varref.1), format!("{}", varref.1),
Instr::Load( Instr::Load(
v.0.instr(), v.0.instr(),
inner.get_type(scope.type_values, scope.types), inner.get_type(scope.type_values),
), ),
) )
.unwrap(), .unwrap(),
@ -800,7 +827,7 @@ impl mir::Expression {
.known() .known()
.expect("function return type unknown"); .expect("function return type unknown");
let ret_type = ret_type_kind.get_type(scope.type_values, scope.types); let ret_type = ret_type_kind.get_type(scope.type_values);
let params = try_all( let params = try_all(
call.parameters call.parameters
@ -903,10 +930,7 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
"load", "load",
Instr::Load( Instr::Load(kind.instr(), inner.get_type(scope.type_values)),
kind.instr(),
inner.get_type(scope.type_values, scope.types),
),
) )
.unwrap(); .unwrap();
( (
@ -962,10 +986,7 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
"array.load", "array.load",
Instr::Load( Instr::Load(ptr, contained_ty.get_type(scope.type_values)),
ptr,
contained_ty.get_type(scope.type_values, scope.types),
),
) )
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location), .maybe_location(&mut scope.block, location),
@ -1003,7 +1024,7 @@ impl mir::Expression {
.unwrap_or(TypeKind::Void); .unwrap_or(TypeKind::Void);
let array_ty = Type::Array( let array_ty = Type::Array(
Box::new(elem_ty_kind.get_type(scope.type_values, scope.types)), Box::new(elem_ty_kind.get_type(scope.type_values)),
instr_list.len() as u64, instr_list.len() as u64,
); );
let array_name = format!("{}.{}", elem_ty_kind, instr_list.len()); let array_name = format!("{}.{}", elem_ty_kind, instr_list.len());
@ -1086,10 +1107,7 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
load_n, load_n,
Instr::Load( Instr::Load(value, type_kind.get_type(scope.type_values)),
value,
type_kind.get_type(scope.type_values, scope.types),
),
) )
.unwrap(), .unwrap(),
), ),
@ -1180,10 +1198,7 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
format!("{}.deref", varref.1), format!("{}.deref", varref.1),
Instr::Load( Instr::Load(v.0.instr(), ptr_inner.get_type(scope.type_values)),
v.0.instr(),
ptr_inner.get_type(scope.type_values, scope.types),
),
) )
.unwrap(); .unwrap();
@ -1198,7 +1213,7 @@ impl mir::Expression {
format!("{}.deref.inner", varref.1), format!("{}.deref.inner", varref.1),
Instr::Load( Instr::Load(
var_ptr_instr, var_ptr_instr,
inner.get_type(scope.type_values, scope.types), inner.get_type(scope.type_values),
), ),
) )
.unwrap(), .unwrap(),
@ -1236,7 +1251,7 @@ impl mir::Expression {
.build(Instr::BitCast( .build(Instr::BitCast(
val.instr(), val.instr(),
Type::Ptr(Box::new( Type::Ptr(Box::new(
type_kind.get_type(scope.type_values, scope.types), type_kind.get_type(scope.type_values),
)), )),
)) ))
.unwrap(), .unwrap(),
@ -1254,7 +1269,7 @@ impl mir::Expression {
.block .block
.build(Instr::BitCast( .build(Instr::BitCast(
val.instr(), val.instr(),
type_kind.get_type(scope.type_values, scope.types), type_kind.get_type(scope.type_values),
)) ))
.unwrap(), .unwrap(),
), ),
@ -1263,10 +1278,10 @@ impl mir::Expression {
_ => { _ => {
let cast_instr = val let cast_instr = val
.1 .1
.get_type(scope.type_values, scope.types) .get_type(scope.type_values)
.cast_instruction( .cast_instruction(
val.instr(), val.instr(),
&type_kind.get_type(scope.type_values, scope.types), &type_kind.get_type(scope.type_values),
) )
.unwrap(); .unwrap();
@ -1438,11 +1453,7 @@ impl mir::Literal {
} }
impl TypeKind { impl TypeKind {
pub(super) fn get_type( pub(super) fn get_type(&self, type_vals: &HashMap<CustomTypeKey, TypeValue>) -> Type {
&self,
type_vals: &HashMap<CustomTypeKey, TypeValue>,
typedefs: &HashMap<TypeValue, TypeDefinition>,
) -> Type {
match &self { match &self {
TypeKind::I8 => Type::I8, TypeKind::I8 => Type::I8,
TypeKind::I16 => Type::I16, TypeKind::I16 => Type::I16,
@ -1463,24 +1474,16 @@ impl TypeKind {
TypeKind::F80 => Type::F80, TypeKind::F80 => Type::F80,
TypeKind::F128PPC => Type::F128PPC, TypeKind::F128PPC => Type::F128PPC,
TypeKind::Char => Type::U8, TypeKind::Char => Type::U8,
TypeKind::Array(elem_t, len) => { TypeKind::Array(elem_t, len) => Type::Array(Box::new(elem_t.get_type(type_vals)), *len),
Type::Array(Box::new(elem_t.get_type(type_vals, typedefs)), *len)
}
TypeKind::Void => Type::Void, TypeKind::Void => Type::Void,
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"), TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
TypeKind::CustomType(n) => { TypeKind::CustomType(n) => {
let type_val = type_vals.get(n).unwrap().clone(); let type_val = type_vals.get(n).unwrap().clone();
Type::CustomType(type_val) Type::CustomType(type_val)
} }
TypeKind::UserPtr(type_kind) => { TypeKind::UserPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))),
Type::Ptr(Box::new(type_kind.get_type(type_vals, typedefs))) TypeKind::CodegenPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))),
} TypeKind::Borrow(type_kind, _) => Type::Ptr(Box::new(type_kind.get_type(type_vals))),
TypeKind::CodegenPtr(type_kind) => {
Type::Ptr(Box::new(type_kind.get_type(type_vals, typedefs)))
}
TypeKind::Borrow(type_kind, _) => {
Type::Ptr(Box::new(type_kind.get_type(type_vals, typedefs)))
}
} }
} }
} }

57
reid/src/intrinsics.rs Normal file
View File

@ -0,0 +1,57 @@
use reid_lib::Instr;
use crate::{
codegen::{ErrorKind, Scope},
mir::{FunctionDefinition, FunctionDefinitionKind, TypeKind},
};
#[derive(Debug, Clone, Copy)]
pub enum InstrinsicKind {
IAdd,
}
fn intrinsic(
name: &str,
ret_ty: TypeKind,
params: Vec<(&str, TypeKind)>,
kind: InstrinsicKind,
) -> FunctionDefinition {
FunctionDefinition {
name: name.into(),
is_pub: false,
is_imported: false,
return_type: ret_ty,
parameters: params.into_iter().map(|(n, ty)| (n.into(), ty)).collect(),
kind: FunctionDefinitionKind::Intrinsic(kind),
}
}
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
let mut intrinsics = Vec::new();
intrinsics.push(intrinsic(
"addition",
TypeKind::U8,
vec![("lhs".into(), TypeKind::U8), ("rhs".into(), TypeKind::U8)],
InstrinsicKind::IAdd,
));
intrinsics
}
impl InstrinsicKind {
pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Result<(), ErrorKind> {
match self {
InstrinsicKind::IAdd => {
let lhs = scope.block.build(Instr::Param(0)).unwrap();
let rhs = scope.block.build(Instr::Param(1)).unwrap();
let add = scope.block.build(Instr::Add(lhs, rhs)).unwrap();
scope
.block
.terminate(reid_lib::TerminatorKind::Ret(add))
.unwrap()
}
}
Ok(())
}
}

View File

@ -44,6 +44,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
use intrinsics::form_intrinsics;
use lexer::FullToken; use lexer::FullToken;
use mir::{ use mir::{
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs, linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
@ -56,6 +57,7 @@ mod allocator;
mod ast; mod ast;
mod codegen; mod codegen;
pub mod error_raporting; pub mod error_raporting;
pub mod intrinsics;
pub mod ld; pub mod ld;
mod lexer; mod lexer;
pub mod mir; pub mod mir;
@ -126,6 +128,12 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&context); dbg!(&context);
for module in &mut context.modules {
for intrinsic in form_intrinsics() {
module.1.functions.insert(0, intrinsic);
}
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{}", &context); println!("{}", &context);

View File

@ -108,12 +108,13 @@ impl Display for FunctionDefinition {
impl Display for FunctionDefinitionKind { impl Display for FunctionDefinitionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
write!(f, "{}", block)?; write!(f, "{}", block)?;
Ok(()) Ok(())
} }
Self::Extern(true) => write!(f, "<Imported Extern>"), FunctionDefinitionKind::Extern(true) => write!(f, "<Imported Extern>"),
Self::Extern(false) => write!(f, "<Linked Extern>"), FunctionDefinitionKind::Extern(false) => write!(f, "<Linked Extern>"),
FunctionDefinitionKind::Intrinsic(_) => write!(f, "<Intrinsic>"),
} }
} }
} }

View File

@ -675,6 +675,8 @@ pub enum EqualsIssue {
AlreadyExtern(String, Metadata), AlreadyExtern(String, Metadata),
#[error("Function {0} is already imported from another module")] #[error("Function {0} is already imported from another module")]
ConflictWithImport(String), ConflictWithImport(String),
#[error("Function is defined as an intrinsic")]
ExistsAsIntrinsic,
} }
impl FunctionDefinition { impl FunctionDefinition {
@ -701,6 +703,7 @@ impl FunctionDefinition {
} }
} }
} }
FunctionDefinitionKind::Intrinsic(_) => Err(EqualsIssue::ExistsAsIntrinsic),
} }
} }
} }

View File

@ -331,7 +331,6 @@ impl<'map> Pass for LinkerPass<'map> {
return_type, return_type,
parameters: param_tys, parameters: param_tys,
kind: super::FunctionDefinitionKind::Extern(true), kind: super::FunctionDefinitionKind::Extern(true),
source: imported_mod_id,
}); });
} }
} }

View File

@ -5,6 +5,7 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use crate::{ use crate::{
intrinsics::InstrinsicKind,
lexer::{FullToken, Position}, lexer::{FullToken, Position},
token_stream::TokenRange, token_stream::TokenRange,
}; };
@ -293,7 +294,6 @@ pub struct FunctionDefinition {
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<(String, TypeKind)>, pub parameters: Vec<(String, TypeKind)>,
pub kind: FunctionDefinitionKind, pub kind: FunctionDefinitionKind,
pub source: SourceModuleId,
} }
#[derive(Debug)] #[derive(Debug)]
@ -302,6 +302,8 @@ pub enum FunctionDefinitionKind {
Local(Block, Metadata), Local(Block, Metadata),
/// True = imported from other module, False = Is user defined extern /// True = imported from other module, False = Is user defined extern
Extern(bool), Extern(bool),
/// Intrinsic definition, defined within the compiler
Intrinsic(InstrinsicKind),
} }
impl FunctionDefinition { impl FunctionDefinition {
@ -309,6 +311,7 @@ impl FunctionDefinition {
match &self.kind { match &self.kind {
FunctionDefinitionKind::Local(block, _) => block.meta.clone(), FunctionDefinitionKind::Local(block, _) => block.meta.clone(),
FunctionDefinitionKind::Extern(_) => Metadata::default(), FunctionDefinitionKind::Extern(_) => Metadata::default(),
FunctionDefinitionKind::Intrinsic(_) => Metadata::default(),
} }
} }
@ -316,6 +319,7 @@ impl FunctionDefinition {
match &self.kind { match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => metadata.clone(), FunctionDefinitionKind::Local(_, metadata) => metadata.clone(),
FunctionDefinitionKind::Extern(_) => Metadata::default(), FunctionDefinitionKind::Extern(_) => Metadata::default(),
FunctionDefinitionKind::Intrinsic(_) => Metadata::default(),
} }
} }
} }

View File

@ -352,6 +352,7 @@ impl FunctionDefinition {
block.pass(pass, state, scope, mod_id)?; block.pass(pass, state, scope, mod_id)?;
} }
FunctionDefinitionKind::Extern(_) => {} FunctionDefinitionKind::Extern(_) => {}
FunctionDefinitionKind::Intrinsic(..) => {}
}; };
Ok(()) Ok(())
} }

View File

@ -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);
} }
@ -196,6 +205,9 @@ impl FunctionDefinition {
FunctionDefinitionKind::Extern(_) => { FunctionDefinitionKind::Extern(_) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))) Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
} }
FunctionDefinitionKind::Intrinsic(..) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
}
}; };
match inferred { match inferred {

View File

@ -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());
@ -69,6 +91,7 @@ impl FunctionDefinition {
} }
} }
FunctionDefinitionKind::Extern(_) => {} FunctionDefinitionKind::Extern(_) => {}
FunctionDefinitionKind::Intrinsic(_) => {}
}; };
Ok(()) Ok(())

View File

@ -98,7 +98,7 @@ fn float_compiles_well() {
} }
#[test] #[test]
fn hello_world_compiles_well() { fn hello_world_compiles_well() {
test(include_str!("../../examples/hello_world.reid"), "test", 0); test(include_str!("../../examples/hello_world.reid"), "test", 8);
} }
#[test] #[test]
fn mutable_compiles_well() { fn mutable_compiles_well() {