Fix triple-importing

This commit is contained in:
Sofia 2025-08-04 23:46:46 +03:00
parent 8a178387ca
commit 1c3386bc9a
8 changed files with 86 additions and 198 deletions

View File

@ -0,0 +1,5 @@
import triple_import_vec2::Vec2;
import triple_import_ship::Ship;
fn main() -> i32 { return 0; }

View File

@ -0,0 +1,3 @@
import triple_import_vec2::Vec2;
struct Ship { position: Vec2 }

View File

@ -0,0 +1,2 @@
struct Vec2 { x: f32, y: f32 }

View File

@ -743,7 +743,6 @@ pub fn analyze_block(
analyze_expr(context, source_module, expression, scope); analyze_expr(context, source_module, expression, scope);
} }
mir::StmtKind::While(WhileStatement { condition, block, .. }) => { mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
dbg!(condition);
analyze_expr(context, source_module, condition, scope); analyze_expr(context, source_module, condition, scope);
analyze_block(context, source_module, block, scope); analyze_block(context, source_module, block, scope);
} }
@ -852,8 +851,8 @@ pub fn analyze_expr(
analyze_expr(context, source_module, expr, scope); analyze_expr(context, source_module, expr, scope);
} }
} }
mir::ExprKind::Struct(struct_name, items) => { mir::ExprKind::Struct(key, items) => {
let struct_type = TypeKind::CustomType(CustomTypeKey(struct_name.clone(), source_module.module_id)); let struct_type = TypeKind::CustomType(key.clone());
let struct_idx = scope let struct_idx = scope
.token_idx(&expr.1, |t| matches!(t, Token::Identifier(_))) .token_idx(&expr.1, |t| matches!(t, Token::Identifier(_)))
.unwrap_or(expr.1.range.end); .unwrap_or(expr.1.range.end);

View File

@ -703,7 +703,6 @@ impl IntrinsicFunction for IntrinsicMemcpy {
.unwrap(); .unwrap();
let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap(); let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap();
dbg!(self.0.size_of(&scope.type_map) / 8);
let params = vec![ let params = vec![
dest.instr(), dest.instr(),
src.instr(), src.instr(),

View File

@ -1,4 +1,8 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
use allocator::{Allocator, AllocatorScope}; use allocator::{Allocator, AllocatorScope};
use intrinsics::*; use intrinsics::*;
@ -180,7 +184,40 @@ impl mir::Module {
let mut typedefs = self.typedefs.clone(); let mut typedefs = self.typedefs.clone();
typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module)); typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module));
for typedef in typedefs { // Since we know by this point that no types are recursive, we can
// somewhat easily sort the type-definitions such that we can process
// the ones with no depencencies first, and later the ones that depend
// on the earlier ones.
let mut typekeys_seen = HashSet::new();
let mut typedefs_sorted = Vec::new();
let mut typedefs_left = typedefs.clone();
typedefs_left.reverse();
while let Some(typedef) = typedefs_left.pop() {
match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
let mut is_ok = true;
for field in fields {
match &field.1 {
TypeKind::CustomType(type_key) => {
if !typekeys_seen.contains(type_key) {
is_ok = false;
break;
}
}
_ => {}
}
}
if is_ok {
typekeys_seen.insert(CustomTypeKey(typedef.name.clone(), typedef.source_module));
typedefs_sorted.push(typedef);
} else {
typedefs_left.insert(0, typedef.clone());
}
}
};
}
for typedef in typedefs_sorted {
let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module); let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module);
type_map.insert(type_key.clone(), typedef.clone()); type_map.insert(type_key.clone(), typedef.clone());
@ -190,9 +227,6 @@ impl mir::Module {
typedef.name.clone(), typedef.name.clone(),
fields fields
.iter() .iter()
// TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this
// will cause a panic!
.map(|StructField(_, t, _)| t.get_type(&type_values)) .map(|StructField(_, t, _)| t.get_type(&type_values))
.collect(), .collect(),
))) )))

View File

@ -111,11 +111,12 @@ impl<'map> Pass for LinkerPass<'map> {
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect(); let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
let mut already_imported_types = HashSet::<CustomTypeKey>::new(); let mut still_required_types = HashSet::<CustomTypeKey>::new();
let mut already_imported_binops = HashSet::<BinopKey>::new();
while let Some(module) = modules_to_process.pop() { while let Some(module) = modules_to_process.pop() {
let mut extern_types = HashMap::new(); let mut extern_types = HashMap::new();
let mut already_imported_binops = HashSet::<BinopKey>::new();
let mut already_imported_types = HashSet::<CustomTypeKey>::new();
let mut importer_module = module.borrow_mut(); let mut importer_module = module.borrow_mut();
for import in importer_module.imports.clone() { for import in importer_module.imports.clone() {
@ -208,7 +209,7 @@ impl<'map> Pass for LinkerPass<'map> {
let Some((import_name, _)) = path.get(1) else { let Some((import_name, _)) = path.get(1) else {
continue; continue;
}; };
let import_id = imported.module_id; let imported_id = imported.module_id;
let mut imported_types = Vec::new(); let mut imported_types = Vec::new();
@ -351,7 +352,7 @@ 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: Some(import_id), source: Some(imported_id),
signature_meta: func.signature_meta, signature_meta: func.signature_meta,
}, },
)); ));
@ -367,6 +368,13 @@ impl<'map> Pass for LinkerPass<'map> {
let mut seen = HashSet::new(); let mut seen = HashSet::new();
let mut current_extern_types = HashSet::new(); let mut current_extern_types = HashSet::new();
seen.extend(imported_types.clone().iter().map(|t| t.0.clone())); seen.extend(imported_types.clone().iter().map(|t| t.0.clone()));
for ty in still_required_types.clone() {
if ty.1 == imported_id && !seen.contains(&ty) {
imported_types.push((ty, false));
}
}
current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone())); current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone()));
for extern_type in &current_extern_types { for extern_type in &current_extern_types {
extern_types.insert(extern_type.0.clone(), extern_type.1); extern_types.insert(extern_type.0.clone(), extern_type.1);
@ -378,10 +386,16 @@ impl<'map> Pass for LinkerPass<'map> {
for typekey in imported_types.clone() { for typekey in imported_types.clone() {
let typedef = imported_mod_typedefs let typedef = imported_mod_typedefs
.iter() .iter()
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey.0) .find(|ty| CustomTypeKey(ty.name.clone(), ty.source_module) == typekey.0)
.unwrap(); .unwrap();
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id); let inner = find_inner_types(typedef, seen.clone(), imported_mod_typedefs);
seen.extend(inner.iter().cloned()); for ty in inner {
if ty.1 == imported_id && imported_mod_typedefs.iter().find(|t| t.name == ty.0).is_some() {
seen.insert(ty);
} else {
still_required_types.insert(ty);
}
}
} }
// TODO: Unable to import same-named type from multiple places.. // TODO: Unable to import same-named type from multiple places..
@ -573,28 +587,31 @@ fn import_type(ty: &TypeKind, usable_import: bool) -> Vec<(CustomTypeKey, bool)>
fn find_inner_types( fn find_inner_types(
typedef: &TypeDefinition, typedef: &TypeDefinition,
mut seen: HashSet<CustomTypeKey>, mut seen: HashSet<CustomTypeKey>,
mod_id: SourceModuleId, typedefs: &Vec<TypeDefinition>,
) -> Vec<CustomTypeKey> { ) -> Vec<CustomTypeKey> {
match &typedef.kind { match &typedef.kind {
crate::mir::TypeDefinitionKind::Struct(struct_type) => { crate::mir::TypeDefinitionKind::Struct(struct_type) => {
let typenames = struct_type let typekeys = struct_type
.0 .0
.iter() .iter()
.filter(|t| matches!(t.1, TypeKind::CustomType(..))) .filter_map(|t| match &t.1 {
.map(|t| match &t.1 { TypeKind::CustomType(key) => Some(key),
TypeKind::CustomType(CustomTypeKey(t, _)) => t, _ => None,
_ => panic!(),
}) })
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for typename in typenames { for typekey in typekeys {
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) { if seen.contains(&typekey) {
continue; continue;
} }
let inner = find_inner_types(typedef, seen.clone(), mod_id); seen.insert(typekey.clone());
seen.insert(CustomTypeKey(typename, mod_id)); if typekey.1 == typedef.source_module {
seen.extend(inner); if let Some(inner) = typedefs.iter().find(|t| t.name == typekey.0) {
let ret = find_inner_types(inner, seen.clone(), typedefs);
seen.extend(ret);
}
}
} }
seen.into_iter().collect() seen.into_iter().collect()

View File

@ -1,171 +0,0 @@
use std::{path::PathBuf, process::Command, time::SystemTime};
use reid::{
compile_module,
ld::LDRunner,
mir::{self},
parse_module, perform_all_passes,
};
use reid_lib::{compile::CompileOutput, Context};
use util::assert_err;
mod util;
fn test_compile(source: &str, name: &str) -> CompileOutput {
assert_err(assert_err(std::panic::catch_unwind(|| {
let mut map = Default::default();
let (id, tokens) = assert_err(parse_module(source, name, None, &mut map, None));
let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e));
let mut mir_context = mir::Context::from(vec![module], Default::default());
assert_err(perform_all_passes(&mut mir_context, &mut map));
let context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
let codegen = assert_err(mir_context.codegen(&context));
Ok::<_, ()>(codegen.compile(None, Vec::new()).output())
})))
}
fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
assert_err(assert_err(std::panic::catch_unwind(|| {
let output = test_compile(source, name);
let time = SystemTime::now();
let in_path = PathBuf::from(format!(
"/tmp/temp-{}.o",
time.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos()
));
std::fs::write(&in_path, &output.obj_buffer).expect("Could not write OBJ-file!");
let out_path = in_path.with_extension("out");
LDRunner::from_command("ld")
.with_library("c")
.invoke(&in_path, &out_path);
std::fs::remove_file(in_path).unwrap();
let executed = Command::new(&out_path).output();
std::fs::remove_file(out_path).unwrap();
if let Some(expected_exit_code) = expected_exit_code {
assert_eq!(expected_exit_code, executed.unwrap().status.code().unwrap());
}
Ok::<(), ()>(())
})))
}
#[test]
fn arithmetic_compiles_well() {
test(include_str!("../../examples/arithmetic.reid"), "test", Some(48));
}
#[test]
fn array_structs_compiles_well() {
test(include_str!("../../examples/array_structs.reid"), "test", Some(5));
}
#[test]
fn array_compiles_well() {
test(include_str!("../../examples/array.reid"), "test", Some(3));
}
#[test]
fn borrow_compiles_well() {
test(include_str!("../../examples/borrow.reid"), "test", Some(17));
}
#[test]
fn borrow_hard_compiles_well() {
test(include_str!("../../examples/borrow_hard.reid"), "test", Some(17));
}
#[test]
fn cast_compiles_well() {
test(include_str!("../../examples/cast.reid"), "test", Some(6));
}
#[test]
fn char_compiles_well() {
test(include_str!("../../examples/char.reid"), "test", Some(98));
}
#[test]
fn div_mod_compiles_well() {
test(include_str!("../../examples/div_mod.reid"), "test", Some(12));
}
#[test]
fn fibonacci_compiles_well() {
test(include_str!("../../examples/fibonacci.reid"), "test", Some(1));
}
#[test]
fn float_compiles_well() {
test(include_str!("../../examples/float.reid"), "test", Some(1));
}
#[test]
fn hello_world_compiles_well() {
test(include_str!("../../examples/hello_world.reid"), "test", None);
}
#[test]
fn hello_world_harder_compiles_well() {
test(include_str!("../../examples/hello_world_harder.reid"), "test", None);
}
#[test]
fn mutable_compiles_well() {
test(include_str!("../../examples/mutable.reid"), "test", Some(21));
}
#[test]
fn ptr_compiles_well() {
test(include_str!("../../examples/ptr.reid"), "test", Some(5));
}
#[test]
fn std_test_compiles_well() {
test(include_str!("../../examples/std_test.reid"), "test", Some(3));
}
#[test]
fn strings_compiles_well() {
test(include_str!("../../examples/strings.reid"), "test", Some(5));
}
#[test]
fn struct_compiles_well() {
test(include_str!("../../examples/struct.reid"), "test", Some(17));
}
#[test]
fn loops_compiles_well() {
test(include_str!("../../examples/loops.reid"), "test", Some(10));
}
#[test]
fn ptr_hard_compiles_well() {
test(include_str!("../../examples/ptr_hard.reid"), "test", Some(0));
}
#[test]
fn loop_hard_compiles_well() {
test(include_str!("../../examples/loop_hard.reid"), "test", Some(0));
}
#[test]
fn custom_binop_compiles_well() {
test(include_str!("../../examples/custom_binop.reid"), "test", Some(21));
}
#[test]
fn array_short_compiles_well() {
test(include_str!("../../examples/array_short.reid"), "test", Some(5));
}
#[test]
fn imported_type_compiles_well() {
test(include_str!("../../examples/imported_type.reid"), "test", Some(0));
}
#[test]
fn associated_functions() {
test(
include_str!("../../examples/associated_functions.reid"),
"test",
Some(4),
);
}
#[test]
fn mutable_inner_functions() {
test(include_str!("../../examples/mutable_inner.reid"), "test", Some(0));
}
#[test]
fn cpu_raytracer_compiles() {
test_compile(include_str!("../../examples/cpu_raytracer.reid"), "test");
}