diff options
| author | Julius Ikkala <julius.ikkala@gmail.com> | 2025-06-28 05:39:24 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-28 02:39:24 +0000 |
| commit | 7349dc5cff49cf22c82eb912813e47f30cd7a757 (patch) | |
| tree | 4d7b3e14f119e7bb48623e52c890b461fd3d9701 /tests/language-feature | |
| parent | a13dda4f214274a10d39f37c79622fc3e62da310 (diff) | |
Minimal optional constraints (#7422)
* Parse optional witness syntax
* Allow failing optional constraint
* Make `is` work with optional constraint
* Allow using optional constraint in checked if statements
* Fix tests
* Make it work with structs
* Fix MSVC build error
* Disallow using `as` with optional constraints
* Update test to match split is/as errors
* Add tests
* Fix uninitialized variables in tests
* Add tests of incorrect uses & fix related bugs
* Mention optional constraints in docs
* format code
* Fix type unification with NoneWitness
* Fix formatting
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Co-authored-by: Nathan V. Morrical <natemorrical@gmail.com>
Diffstat (limited to 'tests/language-feature')
6 files changed, 203 insertions, 2 deletions
diff --git a/tests/language-feature/generics/where-optional-1.slang b/tests/language-feature/generics/where-optional-1.slang new file mode 100644 index 000000000..da4bdaacb --- /dev/null +++ b/tests/language-feature/generics/where-optional-1.slang @@ -0,0 +1,11 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): +interface IThing +{ + void thing(); +} + +void f<T>(T t) where optional T: IThing +{ + // Unchecked optional constraint is an error. + t.thing(); // CHECK: error 30403 +} diff --git a/tests/language-feature/generics/where-optional-2.slang b/tests/language-feature/generics/where-optional-2.slang new file mode 100644 index 000000000..67679bd8d --- /dev/null +++ b/tests/language-feature/generics/where-optional-2.slang @@ -0,0 +1,63 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -cpu -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<int> outputBuffer; + +interface IThing +{ + [mutating] + int thing(int index); +} + +struct MyThing: IThing +{ + int val; + + [mutating] + int thing(int index) + { + val++; + outputBuffer[index] = val; + return val; + } +} + +struct NotMyThing +{ + int val; +} + +void f<T>(inout T t, int index) where optional T: IThing +{ + if (T is IThing) + { + outputBuffer[index+1] = 2 * t.thing(index); + } + else + { + outputBuffer[index] = 0; + outputBuffer[index+1] = 0; + } +} + +[numthreads(1, 1, 1)] +void computeMain(int3 dispatchThreadID: SV_DispatchThreadID) +{ + MyThing mt = MyThing(0); + NotMyThing nt = NotMyThing(1); + + // CHECK: 1 + // CHECK-NEXT: 2 + f<MyThing>(mt, 0); + // CHECK-NEXT: 0 + // CHECK-NEXT: 0 + f<NotMyThing>(nt, 2); + // CHECK: 2 + // CHECK-NEXT: 4 + f(mt, 4); + // CHECK-NEXT: 0 + // CHECK-NEXT: 0 + f(nt, 6); +} diff --git a/tests/language-feature/generics/where-optional-3.slang b/tests/language-feature/generics/where-optional-3.slang new file mode 100644 index 000000000..f8b3a4907 --- /dev/null +++ b/tests/language-feature/generics/where-optional-3.slang @@ -0,0 +1,95 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -cpu -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<int> outputBuffer; + +interface IReleaseable +{ + [mutating] + void release(); +} + +struct Container<K, V> + where optional K : IReleaseable + where optional V : IReleaseable +{ + K k[2]; + V v[2]; + + [mutating] + void erase(int index) + { + if (K is IReleaseable) + k[index].release(); + if (V is IReleaseable) + v[index].release(); + } +} + +struct HeavyEntry: IReleaseable +{ + int index; + int value; + + [mutating] + void release() + { + outputBuffer[index] = value; + } +}; + +struct LightEntry +{ + int value; +}; + +[numthreads(1, 1, 1)] +void computeMain(int3 dispatchThreadID: SV_DispatchThreadID) +{ + { // Neither is IReleaseable + var c = Container<LightEntry, LightEntry>(); + c.k[0] = LightEntry(1); + c.k[1] = LightEntry(2); + c.v[0] = LightEntry(3); + c.v[1] = LightEntry(4); + c.erase(0); + c.erase(1); + } + { // K is IReleaseable + var c = Container<HeavyEntry, LightEntry>(); + c.k[0] = HeavyEntry(0,1); + c.k[1] = HeavyEntry(1,2); + c.v[0] = LightEntry(3); + c.v[1] = LightEntry(4); + // CHECK: 1 + c.erase(0); + // CHECK-NEXT: 2 + c.erase(1); + } + { // V is IReleaseable + var c = Container<LightEntry, HeavyEntry>(); + c.k[0] = LightEntry(1); + c.k[1] = LightEntry(2); + c.v[0] = HeavyEntry(2,3); + c.v[1] = HeavyEntry(3,4); + // CHECK-NEXT: 3 + c.erase(0); + // CHECK-NEXT: 4 + c.erase(1); + } + { // K and V are IReleaseable + var c = Container<HeavyEntry, HeavyEntry>(); + c.k[0] = HeavyEntry(4,5); + c.k[1] = HeavyEntry(6,7); + c.v[0] = HeavyEntry(5,6); + c.v[1] = HeavyEntry(7,8); + // CHECK-NEXT: 5 + // CHECK-NEXT: 6 + c.erase(0); + // CHECK-NEXT: 7 + // CHECK-NEXT: 8 + c.erase(1); + } +} diff --git a/tests/language-feature/generics/where-optional-4.slang b/tests/language-feature/generics/where-optional-4.slang new file mode 100644 index 000000000..6d72186d9 --- /dev/null +++ b/tests/language-feature/generics/where-optional-4.slang @@ -0,0 +1,15 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): +interface IThing +{ + void thing(); +} + +void g<T>(T t) where T: IThing +{ +} + +void f<T>(T t) where optional T: IThing +{ + // Error: cannot upgrade optional to non-optional witness in unchecked context. + g<T>(t); // CHECK: error 38029 +} diff --git a/tests/language-feature/generics/where-optional-5.slang b/tests/language-feature/generics/where-optional-5.slang new file mode 100644 index 000000000..3ce8041ad --- /dev/null +++ b/tests/language-feature/generics/where-optional-5.slang @@ -0,0 +1,17 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): +interface IThing +{ + void thing(); +} + +void f<T, U>(T t, U u) + where optional T: IThing + where optional U: IThing +{ + // Error: cannot upgrade optional to non-optional witness in unchecked context. + if (U is IThing) + { + // U being IThing doesn't justify using T as such! + t.thing(); // CHECK: error 30403 + } +} diff --git a/tests/language-feature/interface-as-rhs-error.slang b/tests/language-feature/interface-as-rhs-error.slang index 9ad71afde..7293b5134 100644 --- a/tests/language-feature/interface-as-rhs-error.slang +++ b/tests/language-feature/interface-as-rhs-error.slang @@ -21,13 +21,13 @@ struct AnotherType // These should produce errors - interface types as RHS bool testIsOperatorWithInterface<T>() { - //CHECK: ([[# @LINE+1]]): error 30301: 'is' and 'as' operators do not support interface types as the right-hand side + //CHECK: ([[# @LINE+1]]): error 30301: cannot use 'is' operator with an interface type as the right-hand side return (T is IMyInterface); } void testAsOperatorWithInterface<T>(T value) { - //CHECK: ([[# @LINE+1]]): error 30301: 'is' and 'as' operators do not support interface types as the right-hand side + //CHECK: ([[# @LINE+1]]): error 30302: cannot use 'as' operator with an interface type as the right-hand side let result = value as IMyInterface; } |
