diff --git a/releasenotes.md b/releasenotes.md index 34905dca2..a5fde39d0 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -41,6 +41,7 @@ - Assert when struct size would exceed 4 GB. - Assert when encountering a malformed module alias. - Assert when encountering a test function with raw vaarg parameters. +- `foo.x` was not always handled correctly when `foo` was optional. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 58c0f063e..8bff9f8c4 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -6592,7 +6592,7 @@ CHECK_DEEPER: if (missing_ref) goto MISSING_REF; RETURN_SEMA_ERROR(expr, "The method '%s' has private visibility.", kw); } - Type *parent_type = parent->type->canonical; + Type *parent_type = type_no_optional(parent->type)->canonical; ASSERT(type_is_user_defined(parent_type)); if (missing_ref && parent_type->decl->unit->module->stage < ANALYSIS_POST_REGISTER) { diff --git a/test/test_suite/any/interface_fault.c3 b/test/test_suite/any/interface_fault.c3 new file mode 100644 index 000000000..60e77ebb5 --- /dev/null +++ b/test/test_suite/any/interface_fault.c3 @@ -0,0 +1,7 @@ +interface Foo { } +fn int main() +{ + Foo? v; + v.nope(); // #error: The 'Foo' interface has no method 'nope', did you spell it correctly + return 0; +} diff --git a/test/test_suite/any/interface_through_fault.c3t b/test/test_suite/any/interface_through_fault.c3t new file mode 100644 index 000000000..d0c59a866 --- /dev/null +++ b/test/test_suite/any/interface_through_fault.c3t @@ -0,0 +1,89 @@ +// #target: macos-x64 +module test; +interface Foo { fn int test(); } + +fn int int.test(&self) @dynamic => *self + 1; + +fn int main() +{ + Foo? v = (Foo)&&2; + int x = v.test()!!; + return x; +} + +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %v = alloca %any, align 8 + %v.f = alloca i64, align 8 + %taddr = alloca i32, align 4 + %x = alloca i32, align 4 + %error_var = alloca i64, align 8 + %.inlinecache = alloca ptr, align 8 + %.cachedtype = alloca ptr, align 8 + %varargslots = alloca [1 x %any], align 16 + %indirectarg = alloca %"any[]", align 8 + store ptr null, ptr %.cachedtype, align 8 + store i32 2, ptr %taddr, align 4 + %0 = insertvalue %any undef, ptr %taddr, 0 + %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %1, ptr %v, align 8 + store i64 0, ptr %v.f, align 8 + %optval = load i64, ptr %v.f, align 8 + %not_err = icmp eq i64 %optval, 0 + %2 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %2, label %after_check, label %assign_optional + +assign_optional: ; preds = %entry + store i64 %optval, ptr %error_var, align 8 + br label %panic_block + +after_check: ; preds = %entry + %ptradd = getelementptr inbounds i8, ptr %v, i64 8 + %3 = load i64, ptr %ptradd, align 8 + %4 = inttoptr i64 %3 to ptr + %5 = load ptr, ptr %.cachedtype, align 8 + %6 = icmp eq ptr %4, %5 + br i1 %6, label %cache_hit, label %cache_miss + +cache_miss: ; preds = %after_check + %7 = call ptr @.dyn_search(ptr %4, ptr @"$sel.test") + store ptr %7, ptr %.inlinecache, align 8 + store ptr %4, ptr %.cachedtype, align 8 + br label %9 + +cache_hit: ; preds = %after_check + %8 = load ptr, ptr %.inlinecache, align 8 + br label %9 + +9: ; preds = %cache_hit, %cache_miss + %fn_phi = phi ptr [ %8, %cache_hit ], [ %7, %cache_miss ] + %10 = icmp eq ptr %fn_phi, null + br i1 %10, label %missing_function, label %match + +missing_function: ; preds = %9 + %11 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %11(ptr @.panic_msg, i64 41, ptr @.file, i64 26, ptr @.func, i64 4, i32 9) #2 + unreachable + +match: ; preds = %9 + %12 = load ptr, ptr %v, align 8 + %13 = call i32 %fn_phi(ptr %12) + br label %noerr_block + +panic_block: ; preds = %assign_optional + %14 = insertvalue %any undef, ptr %error_var, 0 + %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.fault" to i64), 1 + store %any %15, ptr %varargslots, align 16 + %16 = insertvalue %"any[]" undef, ptr %varargslots, 0 + %"$$temp" = insertvalue %"any[]" %16, i64 1, 1 + store %"any[]" %"$$temp", ptr %indirectarg, align 8 + call void @std.core.builtin.panicf + unreachable + +noerr_block: ; preds = %match + store i32 %13, ptr %x, align 4 + %17 = load i32, ptr %x, align 4 + ret i32 %17 +}