From c71444e7a0c3d1c4f371af48e3804fe7da5ce62b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 16 Sep 2025 14:10:23 +0200 Subject: [PATCH] Compile time switch over type would not correctly compare function pointer types. --- lib/std/core/builtin.c3 | 2 +- releasenotes.md | 1 + src/compiler/types.c | 4 + test/test_suite/compile_time/ct_switch_fn.c3t | 92 +++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 test/test_suite/compile_time/ct_switch_fn.c3t diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 553e47ab5..8c52ea71f 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -108,7 +108,7 @@ macro anycast(any v, $Type) @builtin return ($Type*)v.ptr; } -macro bool @assignable_to(#foo, $Type) @const @builtin @deprecated("use '$define($Type x = #foo)'") => $defined(*&&($Type){} = #foo); +macro bool @assignable_to(#foo, $Type) @const @builtin @deprecated("use '$defined($Type x = #foo)'") => $defined(*&&($Type){} = #foo); macro @addr(#val) @builtin { diff --git a/releasenotes.md b/releasenotes.md index 9194b3b37..540ac56ab 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -22,6 +22,7 @@ - `??` with void results on both sides cause a compiler crash #2472. - Stack object size limit error on a static object. #2476 - Compiler segfault when modifying variable using an inline assembly block inside defer #2450. +- Compile time switch over type would not correctly compare function pointer types. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface diff --git a/src/compiler/types.c b/src/compiler/types.c index 51bdfa04e..a178b45da 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1598,6 +1598,10 @@ bool type_is_subtype(Type *type, Type *possible_subtype) { possible_subtype = possible_subtype->canonical; if (type == possible_subtype) return true; + if (type->type_kind == TYPE_FUNC_PTR && possible_subtype->type_kind == TYPE_FUNC_PTR) + { + return type->pointer->function.prototype->raw_type == possible_subtype->pointer->function.prototype->raw_type; + } possible_subtype = type_find_parent_type(possible_subtype); } return false; diff --git a/test/test_suite/compile_time/ct_switch_fn.c3t b/test/test_suite/compile_time/ct_switch_fn.c3t new file mode 100644 index 000000000..01df5bb88 --- /dev/null +++ b/test/test_suite/compile_time/ct_switch_fn.c3t @@ -0,0 +1,92 @@ +// #target: macos-x64 +module test; +import std; + +alias Foo = fn void(); + +macro @test(#foo) +{ + $switch $typeof(#foo): + $case Foo: + io::printn("Hello"); + $default: + io::printn($typeof(#foo).nameof); + $endswitch +} +fn void tester() {} +fn int main(String[] args) +{ + @test(&tester); + return 0; +} +/* #expect: test.ll + +define i32 @test.main(ptr %0, i64 %1) #0 { +entry: + %args = alloca %"char[][]", align 8 + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + store ptr %0, ptr %args, align 8 + %ptradd = getelementptr inbounds i8, ptr %args, i64 8 + store i64 %1, ptr %ptradd, align 8 + %2 = call ptr @std.io.stdout() + %3 = call i64 @std.io.File.write(ptr %retparam, ptr %2, ptr @.str, i64 5) + %not_err = icmp eq i64 %3, 0 + %4 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %4, label %after_check, label %assign_optional + +assign_optional: ; preds = %entry + store i64 %3, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %5 = load i64, ptr %retparam, align 8 + store i64 %5, ptr %len, align 8 + %6 = call i64 @std.io.File.write_byte(ptr %2, i8 zeroext 10) + %not_err3 = icmp eq i64 %6, 0 + %7 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %7, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %6, ptr %error_var2, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + br label %voiderr + +noerr_block7: ; preds = %after_check5 + %8 = call i64 @std.io.File.flush(ptr %2) + %not_err9 = icmp eq i64 %8, 0 + %9 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) + br i1 %9, label %after_check11, label %assign_optional10 + +assign_optional10: ; preds = %noerr_block7 + store i64 %8, ptr %error_var8, align 8 + br label %guard_block12 + +after_check11: ; preds = %noerr_block7 + br label %noerr_block13 + +guard_block12: ; preds = %assign_optional10 + br label %voiderr + +noerr_block13: ; preds = %after_check11 + %10 = load i64, ptr %len, align 8 + %add = add i64 %10, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block + ret i32 0 +}