Fix triple-importing
This commit is contained in:
		
							parent
							
								
									8a178387ca
								
							
						
					
					
						commit
						1c3386bc9a
					
				
							
								
								
									
										5
									
								
								examples/triple_import_main.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/triple_import_main.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | 
 | ||||||
|  | import triple_import_vec2::Vec2; | ||||||
|  | import triple_import_ship::Ship; | ||||||
|  | 
 | ||||||
|  | fn main() -> i32 { return 0; } | ||||||
							
								
								
									
										3
									
								
								examples/triple_import_ship.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								examples/triple_import_ship.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | 
 | ||||||
|  | import triple_import_vec2::Vec2; | ||||||
|  | struct Ship { position: Vec2 } | ||||||
							
								
								
									
										2
									
								
								examples/triple_import_vec2.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								examples/triple_import_vec2.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | 
 | ||||||
|  | struct Vec2 { x: f32, y: f32 } | ||||||
| @ -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); | ||||||
|  | |||||||
| @ -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(), | ||||||
|  | |||||||
| @ -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(), | ||||||
|                     ))) |                     ))) | ||||||
|  | |||||||
| @ -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 ¤t_extern_types { |                 for extern_type in ¤t_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() | ||||||
|  | |||||||
| @ -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"); |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user