From 3ff922e12babe9209957f5937f62ccff188b17da Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 2 Nov 2025 13:20:36 +0100 Subject: [PATCH] - Missing imports allowed if module `@if` evaluates to false #2251. --- releasenotes.md | 3 +- src/compiler/compiler_internal.h | 3 +- src/compiler/parse_expr.c | 4 +-- src/compiler/sema_passes.c | 30 ++++++++++++++++++- .../import/import_fail_and_cond_if.c3 | 12 ++++++++ .../import/import_fail_but_not_used_unit.c3 | 10 +++++++ 6 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 test/test_suite/import/import_fail_and_cond_if.c3 create mode 100644 test/test_suite/import/import_fail_but_not_used_unit.c3 diff --git a/releasenotes.md b/releasenotes.md index beb10c1d7..bad198367 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -3,7 +3,8 @@ ## 0.7.8 Change list ### Changes / improvements -- Improve multiline string parser inside compiler #2552 +- Improve multiline string parser inside compiler #2552. +- Missing imports allowed if module `@if` evaluates to false #2251. ### Fixes - `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 0c0d03a3e..ae87fac5c 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -627,7 +627,7 @@ typedef struct }; } DefineDecl; -typedef union +typedef struct { Path *alias_path; Module *module; @@ -1741,6 +1741,7 @@ struct CompilationUnit_ Decl **global_decls; Decl **global_cond_decls; Decl *main_function; + Decl *error_import; HTable local_symbols; int lambda_count; TypeInfo **check_type_variable_array; diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 272ba60c4..e8000f096 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1065,7 +1065,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left, SourceSpan lhs_start) /** * subscript ::= '[' range_expr ']' */ -static Expr *parse_subscript_expr(ParseContext *c, Expr *left, SourceSpan lhs_start) +static Expr *parse_subscript_expr(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED) { ASSERT(left && expr_ok(left)); advance_and_verify(c, TOKEN_LBRACKET); @@ -1644,7 +1644,7 @@ EXIT: PRINT_ERROR_AT(expr_int, "Integer type suffix should be i8, i16, i32, i64 or i128."); return poisoned_expr; } - const char *suffix; + const char *suffix; // NOLINT if (bit_suffix) { switch (type_bits) diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 232a2e3f9..e431b8c28 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -59,7 +59,6 @@ void sema_analyse_pass_module_hierarchy(Module *module) sema_analyze_stage(parent_module, ANALYSIS_MODULE_HIERARCHY); } - void sema_analysis_pass_process_imports(Module *module) { DEBUG_LOG("Pass: Importing dependencies for files in module '%s'.", module->name->module); @@ -99,6 +98,12 @@ void sema_analysis_pass_process_imports(Module *module) // 5. Do we find it? if (!import_module) { + if (unit->if_attr) + { + unit->error_import = import; + import_module = compiler_find_or_create_module(path, NULL); + goto FOUND_MODULE; + } PRINT_ERROR_AT(import, "No module named '%s' could be found, did you type the name right?", path->module); decl_poison(import); continue; @@ -112,6 +117,7 @@ void sema_analysis_pass_process_imports(Module *module) continue; } +FOUND_MODULE: // 7. Assign the module. DEBUG_LOG("* Import of %s.", path->module); import->import.module = import_module; @@ -125,9 +131,16 @@ NEXT:; // 5. Do we find it? if (!import_module) { + if (unit->if_attr) + { + unit->error_import = alias_module; + import_module = compiler_find_or_create_module(path, NULL); + goto FOUND_ALIAS; + } PRINT_ERROR_AT(path, "No module named '%s' could be found, did you type the name right?", path->module); continue; } +FOUND_ALIAS: alias_module->module_alias_decl.module = import_module; alias_module->resolve_status = RESOLVE_DONE; for (unsigned i = 0; i < idx; i++) @@ -515,6 +528,21 @@ CHECK_LINK: } RELEASE_CONTEXT: sema_context_destroy(&context); + if (unit->error_import) + { + Decl *import = unit->error_import; + switch (import->decl_kind) + { + case DECL_IMPORT: + PRINT_ERROR_AT(import, "No module named '%s' could be found, did you type the name right?", import->import.path->module); + continue; + case DECL_ALIAS_PATH: + PRINT_ERROR_AT(import->module_alias_decl.alias_path, "No module named '%s' could be found, did you type the name right?", import->module_alias_decl.alias_path->module); + continue; + default: + UNREACHABLE_VOID; + } + } register_global_decls(unit, unit->global_decls); // There may be includes, add those. sema_process_includes(unit); diff --git a/test/test_suite/import/import_fail_and_cond_if.c3 b/test/test_suite/import/import_fail_and_cond_if.c3 new file mode 100644 index 000000000..0ca257030 --- /dev/null +++ b/test/test_suite/import/import_fail_and_cond_if.c3 @@ -0,0 +1,12 @@ +module test; +const int FOO = 5; +fn int main() +{ + return 0; +} + +module foo @if(!$feature(XYZ)); +alias bar = module thirdparty; // #error: No module named 'thirdparty' could be found, did you type the name right? + +module foo @if(!$feature(XYZ)); +import testme; // #error: No module named 'testme' could be found \ No newline at end of file diff --git a/test/test_suite/import/import_fail_but_not_used_unit.c3 b/test/test_suite/import/import_fail_but_not_used_unit.c3 new file mode 100644 index 000000000..8755e932e --- /dev/null +++ b/test/test_suite/import/import_fail_but_not_used_unit.c3 @@ -0,0 +1,10 @@ +module test; +const int FOO = 5; +fn int main() +{ + return 0; +} + +module foo @if($feature(XYZ)); +alias bar = module thirdparty; +import testme; \ No newline at end of file