Skip to content

Commit 52400c8

Browse files
committed
feat(typechecker): 增强类型检查逻辑,支持模块间枚举有效载荷的 ABI 稳定性
1 parent 1be36ea commit 52400c8

8 files changed

Lines changed: 346 additions & 53 deletions

File tree

compiler/driver/src/pipeline.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ pub fn check(path: &std::path::Path, opts: &CompilerOptions) -> CompileResult {
3434
let _sem = semantic::analyze_program(&module, &arena, &module_of_item, &mut diags);
3535
semantic::resolve_imports_program(&module, &mut arena, &module_of_item, &mut diags);
3636
let names = semantic::resolve_names_program(&module, &arena, &module_of_item, &mut diags);
37-
let tc_out = typechecker::check_program(&module, &arena, &module_of_item, &names, &mut diags);
37+
let tc_out = typechecker::check_program(
38+
&module,
39+
&arena,
40+
&module_of_item,
41+
&entry_module,
42+
&names,
43+
&mut diags,
44+
);
3845
borrow_checker::check_module(&module, &arena, &mut diags);
3946

4047
if diags.has_errors() {

compiler/driver/tests/compile_fail.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,62 @@ fn per_module_llvm_ir_units_split_definitions_and_declarations() {
700700
);
701701
}
702702

703+
#[test]
704+
fn per_module_llvm_ir_units_preserve_enum_payload_abi_across_modules() {
705+
let path = fixture("ok_enum_payload_across_modules.w");
706+
let opts = CompilerOptions {
707+
emit_llvm_ir_units: true,
708+
..Default::default()
709+
};
710+
711+
let result = whatever_driver::check(&path, &opts);
712+
assert!(
713+
result.ok,
714+
"expected fixture to pass, got:\n{}",
715+
result.rendered_diags
716+
);
717+
718+
let units = result
719+
.llvm_ir_units
720+
.expect("emit_llvm_ir_units should produce per-module LLVM IR units");
721+
let entry = units
722+
.get("ok_enum_payload_across_modules")
723+
.expect("expected entry module unit: ok_enum_payload_across_modules");
724+
let eabi = units.get("eabi").expect("expected module unit: eabi");
725+
726+
assert!(
727+
entry.contains("declare") && entry.contains("@eabi__takes"),
728+
"expected entry unit to declare eabi::takes, got:\n{entry}"
729+
);
730+
assert!(
731+
entry.contains("call") && entry.contains("@eabi__takes"),
732+
"expected entry unit to call eabi::takes, got:\n{entry}"
733+
);
734+
assert!(
735+
!entry.contains("define ccc i32 @eabi__takes"),
736+
"expected entry unit to not define eabi::takes, got:\n{entry}"
737+
);
738+
739+
assert!(
740+
eabi.contains("define ccc") && eabi.contains("@eabi__takes"),
741+
"expected eabi unit to define eabi::takes, got:\n{eabi}"
742+
);
743+
assert!(
744+
!eabi.contains("declare i32 @eabi__takes"),
745+
"expected eabi unit to not declare eabi::takes (it defines it), got:\n{eabi}"
746+
);
747+
748+
// Shape-level ABI stability: both units should agree on the enum representation.
749+
assert!(
750+
entry.contains("{ i32, i1, i32 }"),
751+
"expected entry unit to contain enum repr shape, got:\n{entry}"
752+
);
753+
assert!(
754+
eabi.contains("{ i32, i1, i32 }"),
755+
"expected eabi unit to contain enum repr shape, got:\n{eabi}"
756+
);
757+
}
758+
703759
fn tool_available(tool: &str) -> bool {
704760
std::process::Command::new(tool)
705761
.arg("--version")
@@ -769,6 +825,52 @@ fn separate_compilation_emits_per_module_objects_when_clang_is_available() {
769825
assert!(foo_o.exists(), "expected foo object to exist: {foo_o:?}");
770826
}
771827

828+
#[test]
829+
fn separate_compilation_emits_per_module_objects_for_enum_payload_when_clang_is_available() {
830+
// Strong regression for cross-module ABI: compiles per-module objects.
831+
if !tool_available("clang") {
832+
eprintln!(
833+
"skipping: clang not found in PATH (install LLVM/Clang to enable separate-compilation object emission regression)"
834+
);
835+
return;
836+
}
837+
838+
let path = fixture("ok_enum_payload_across_modules.w");
839+
let out_dir = unique_temp_out_dir("separate_compilation_enum_payload_emits_objects");
840+
841+
let opts = CompilerOptions {
842+
emit_object: true,
843+
link_executable: false,
844+
separate_compilation: true,
845+
codegen_tool: Some("clang".to_string()),
846+
output_dir: Some(out_dir.clone()),
847+
..Default::default()
848+
};
849+
850+
let result = whatever_driver::check(&path, &opts);
851+
assert!(
852+
result.ok,
853+
"expected fixture to pass, got:\n{}",
854+
result.rendered_diags
855+
);
856+
857+
let entry_ll = out_dir.join("ok_enum_payload_across_modules.ll");
858+
let entry_o = out_dir.join("ok_enum_payload_across_modules.o");
859+
let eabi_ll = out_dir.join("eabi.ll");
860+
let eabi_o = out_dir.join("eabi.o");
861+
862+
assert!(
863+
entry_ll.exists(),
864+
"expected entry ll to exist: {entry_ll:?}"
865+
);
866+
assert!(
867+
entry_o.exists(),
868+
"expected entry object to exist: {entry_o:?}"
869+
);
870+
assert!(eabi_ll.exists(), "expected eabi ll to exist: {eabi_ll:?}");
871+
assert!(eabi_o.exists(), "expected eabi object to exist: {eabi_o:?}");
872+
}
873+
772874
#[test]
773875
fn separate_compilation_links_executable_when_toolchain_is_available() {
774876
// Strong regression: exercises the link stage.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
enum E { A(bool, i32), B }
2+
3+
fn make() -> E {
4+
E::A(true, 7)
5+
}
6+
7+
fn takes(e: E) -> i32 {
8+
match e {
9+
E::A(b, n) => n,
10+
E::B => 0,
11+
}
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use eabi::E;
2+
use eabi::make;
3+
use eabi::takes;
4+
5+
fn main() -> i32 {
6+
let v: E = make();
7+
takes(v)
8+
}

0 commit comments

Comments
 (0)