From 7a017d2ecd78b8eaf8c5d32841beeba2ccaf5406 Mon Sep 17 00:00:00 2001 From: Harold Brenes Date: Tue, 24 Mar 2026 15:37:04 -0400 Subject: [PATCH] Add test case for implicit cast pointer to offset zero subtype field proc param --- tests/issues/run.bat | 2 + tests/issues/run.sh | 7 +++ tests/issues/test_issue_xxxx.odin | 79 +++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/issues/test_issue_xxxx.odin diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 3db9d48c2..3c722ccc7 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -32,6 +32,8 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused ..\..\..\odin test ..\test_issue_6165.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_6240.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "3" || exit /b ..\..\..\odin build ..\test_issue_6401.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "3" || exit /b +..\..\..\odin test ..\test_issue_xxxx.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_xxxx.odin -define:TEST_EXPECT_FAILURE=true %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 01e6a6a28..67530a1d7 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -49,6 +49,13 @@ else echo "SUCCESSFUL 0/1" exit 1 fi +$ODIN test ../test_issue_xxxx.odin $COMMON +if [[ $($ODIN test ../test_issue_xxxx.odin -define:TEST_EXPECT_FAILURE=true $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi set +x popd diff --git a/tests/issues/test_issue_xxxx.odin b/tests/issues/test_issue_xxxx.odin new file mode 100644 index 000000000..4d20ef356 --- /dev/null +++ b/tests/issues/test_issue_xxxx.odin @@ -0,0 +1,79 @@ +// Tests PR #xxxx https://github.com/odin-lang/Odin/issues/xxxx +package test_issues + +TEST_EXPECT_FAILURE :: #config(TEST_EXPECT_FAILURE, false) + +// Interfaces +IFoo :: struct { + foo: proc(self: ^IFoo) -> string, +} + +IBar :: struct { + bar: proc(self: ^IBar) -> string, +} + + +// Virtual table holders +Foo :: struct { + using vt: IFoo, +} + +// This is OK, but be careful! +Foo_Bar :: struct #raw_union { + using vt_foo: IFoo, + using vt_bar: IBar, +} + +// Implementation via Foo +Foo_Impl :: IFoo { + foo = proc(self: ^Foo) -> string { + return "Foo" + }, +} + +// Implementations via Foo_Bar +Foo_Bar_Foo_Impl :: IFoo { + foo = proc(self: ^Foo_Bar) -> string { + return "Foo_Bar: Foo" + }, +} + +Foo_Bar_Bar_Impl :: IBar { + bar = proc(self: ^Foo_Bar) -> string { + return "Foo_Bar: Bar" + }, +} + +when TEST_EXPECT_FAILURE { + // Will not be allowed in to be used in an implementation: + // The interface and implementation do not share the same address. + Invalid_Foo :: struct { + x: int, + using vt: IFoo, + } + + Invalid_Foo_Impl :: IFoo { + // Will not compile: + foo = proc(self: ^Invalid_Foo) -> string { + return "" + }, + } +} + +import "core:testing" + +@test +test_const_array_fill_assignment :: proc(t: ^testing.T) { + foo := Foo { + vt = Foo_Impl, + } + testing.expect_value(t, foo->foo(), "Foo") + + foo_bar := Foo_Bar { + vt_foo = Foo_Bar_Foo_Impl, + } + testing.expect_value(t, foo_bar->foo(), "Foo_Bar: Foo") + + foo_bar.vt_bar = Foo_Bar_Bar_Impl + testing.expect_value(t, foo_bar->bar(), "Foo_Bar: Bar") +}