yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Harsh Aggarwal (NVIDIA)Fix #6544: Properly format nested type names in extensions (#6769)b78a8ba00

master
8.6 KiB357 linesraw
1// extension-full-name.slang
2//DIAGNOSTIC_TEST:SIMPLE:-target hlsl
3
4// Define a generic type with a nested struct
5struct GenericType<T>
6{
7    T value;
8
9    struct InnerType
10    {
11        T innerValue;
12    }
13
14    InnerType inner;
15}
16
17// Define a non-generic type
18struct NonGenericType
19{
20    float value;
21
22    struct InnerType
23    {
24        float innerValue;
25    }
26
27    InnerType inner;
28}
29
30// Add an extension to the generic type
31extension GenericType<half>
32{
33    // Type in extension
34    struct State
35    {
36        half value;
37        half factor;
38    }
39
40    // Function in extension
41    State
42    createState()
43    {
44        State state;
45        state.value = value;
46        state.factor = 1.0h;
47        return state;
48    }
49
50    // Value/field in extension
51    static State defaultState;
52}
53
54// Add an extension to a nested type inside a generic type
55extension GenericType<float>.InnerType
56{
57    struct Options
58    {
59        float min;
60        float max;
61    }
62
63    Options
64    getOptions()
65    {
66        Options opts;
67        opts.min = 0;
68        opts.max = innerValue;
69        return opts;
70    }
71
72    static Options defaultOptions;
73}
74
75// Add an extension to the non-generic type
76extension NonGenericType
77{
78    // Type in extension
79    struct Config
80    {
81        float threshold;
82        float scale;
83    }
84
85    // Function in extension
86    Config
87    createConfig()
88    {
89        Config config;
90        config.threshold = 0.5;
91        config.scale = 2.0;
92        return config;
93    }
94
95    // Value/field in extension
96    static Config defaultConfig;
97}
98
99// Add nested types and extensions
100struct Container
101{
102    struct Nested
103    {
104        float value;
105
106        struct DeepNested
107        {
108            int count;
109        }
110
111        DeepNested deep;
112    }
113
114    Nested nested;
115}
116
117// Extension for deeply nested type
118extension Container.Nested.DeepNested
119{
120    struct Record
121    {
122        int id;
123        float value;
124    }
125
126    Record
127    createRecord(int newId)
128    {
129        Record r;
130        r.id = newId;
131        r.value = 0;
132        return r;
133    }
134
135    static Record defaultRecord;
136}
137
138extension Container.Nested
139{
140    // Type in nested extension
141    struct Settings
142    {
143        float value;
144        float threshold;
145    }
146
147    // Function in nested extension
148    Settings
149    createSettings()
150    {
151        Settings settings;
152        settings.value = value;
153        settings.threshold = 0.1;
154        return settings;
155    }
156
157    // Value/field in nested extension
158    static Settings defaultSettings;
159}
160
161[shader("compute")][numthreads(1, 1, 1)] void main(uint3 dispatchThreadID
162                                                   : SV_DispatchThreadID)
163{
164    // Test array extensions with constraints
165    testArrayExtension();
166
167    // Test namespace extensions
168    testNamespaceExtensions();
169
170    // Type instantiation tests
171    GenericType<half>.State state1;
172    GenericType<float>.InnerType.Options options1;
173    NonGenericType.Config config1;
174    Container.Nested.Settings settings1;
175    Container.Nested.DeepNested.Record record1;
176
177    // Initialize extension types with struct literals
178    state1 = {1.0h, 2.0h};  // Valid struct initialization
179    options1 = {0.0, 1.0};  // Valid struct initialization
180    config1 = {0.1, 0.5};   // Valid struct initialization
181    settings1 = {0.2, 0.3}; // Valid struct initialization
182    record1 = {1, 2.5};     // Valid struct initialization
183
184    // Extension type mismatches - assign value type to extension type
185    state1 = 0;    // Error: expected expr of type 'GenericType<half>.State', got 'int'
186    options1 = 0;  // Error: expected expr of type 'GenericType<float>.InnerType.Options', got 'int'
187    config1 = 0;   // Error: expected expr of type 'NonGenericType.Config', got 'int'
188    settings1 = 0; // Error: expected expr of type 'Container.Nested.Settings', got 'int'
189    record1 = 0;   // Error: expected expr of type 'Container.Nested.DeepNested.Record', got 'int'
190
191    // Extension type mismatches - assign wrong extension types
192    GenericType<int>.InnerType intInner;
193    GenericType<float>.InnerType floatInner;
194
195    // This should fail due to different generic parameters
196    floatInner.Options floatOpts =
197        intInner.getOptions(); // This won't compile as intInner doesn't have getOptions
198
199    // Extension member access - valid cases
200    state1.value = 1.0h;       // Valid
201    state1.factor = 2.0h;      // Valid
202    options1.min = 0.0;        // Valid
203    options1.max = 1.0;        // Valid
204    config1.threshold = 0.5;   // Valid
205    config1.scale = 2.0;       // Valid
206    settings1.value = 0.1;     // Valid
207    settings1.threshold = 0.2; // Valid
208    record1.id = 100;          // Valid
209    record1.value = 3.14;      // Valid
210
211    // Extension function calls
212    GenericType<half> halfType;
213    NonGenericType nonGenType;
214    Container.Nested nested;
215    Container.Nested.DeepNested deepNested;
216    GenericType<float>.InnerType floatInnerType;
217
218    state1 = halfType.createState();        // Valid
219    config1 = nonGenType.createConfig();    // Valid
220    settings1 = nested.createSettings();    // Valid
221    record1 = deepNested.createRecord(42);  // Valid
222    options1 = floatInnerType.getOptions(); // Valid
223
224    // Type mismatches - function return values
225    options1 =
226        halfType
227            .createState(); // Error: expected expr of type 'GenericType<float>.InnerType.Options',
228                            // got 'GenericType<half>.State'
229    state1 = nonGenType.createConfig(); // Error: expected expr of type 'GenericType<half>.State',
230                                        // got 'NonGenericType.Config'
231    config1 = nested.createSettings();  // Error: expected expr of type 'NonGenericType.Config', got
232                                        // 'Container.Nested.Settings'
233}
234
235// Define an interface for constraint
236interface IFoo
237{
238    float getValue();
239}
240
241// Struct that implements IFoo
242struct Bar : IFoo
243{
244    float value;
245
246    float getValue() { return value; }
247}
248
249// Struct that doesn't implement IFoo
250struct Baz
251{
252    float value;
253}
254
255// Extension with constrained generic type parameter
256extension<T : IFoo, let N : int> Array<T, N>
257{
258    // Add a struct type inside the extension
259    struct DataStats
260    {
261        float average;
262        float maximum;
263        float minimum;
264    }
265
266    // Add a function that uses the struct type
267    DataStats computeStats()
268    {
269        DataStats stats;
270        stats.average = 0;
271        stats.maximum = -1e38;
272        stats.minimum = 1e38;
273
274        for(int i = 0; i < N; i++)
275        {
276            float val = this[i].getValue();
277            stats.average += val;
278            stats.maximum = max(stats.maximum, val);
279            stats.minimum = min(stats.minimum, val);
280        }
281
282        if(N > 0)
283            stats.average /= float(N);
284
285        return stats;
286    }
287
288    // Add a field
289    static DataStats defaultStats;
290}
291
292void testArrayExtension()
293{
294    // Create an array of a type that implements IFoo
295    Bar barArray[3] = { {1.0}, {2.0}, {3.0} };
296
297    // Create an array of a type that doesn't implement IFoo
298    Baz bazArray[3] = { {1.0}, {2.0}, {3.0} };
299
300    // This should work - using the extension on a valid type
301    Array<Bar, 3>.DataStats barStats;
302    barStats = barArray.computeStats(); // Valid
303
304    // Type mismatch errors
305    barStats = 0; // Error: expected expr of type 'Bar[3].DataStats', got 'int'
306
307    // This won't compile - Baz doesn't implement IFoo
308    //Array<Baz, 3>.DataStats bazStats;  // This should fail because Baz doesn't implement IFoo
309    //bazStats = bazArray.computeStats(); // This also won't compile
310
311    // Type mismatch between different extension instantiations
312    Array<Bar, 2>.DataStats bar2Stats;
313    bar2Stats = barArray.computeStats(); // Error: expected expr of type 'Bar[2].DataStats', got 'Bar[3].DataStats'
314}
315
316// Test namespace extensions
317// Define a simple base struct
318struct SimpleBase
319{
320    float value;
321}
322
323// Define a namespace with an extension
324namespace TestNamespace
325{
326    extension SimpleBase
327    {
328        struct NamedConfig
329        {
330            float factor;
331        }
332
333        NamedConfig createConfig()
334        {
335            NamedConfig config;
336            config.factor = value * 2.0;
337            return config;
338        }
339    }
340}
341
342// Test function for namespace extensions
343void testNamespaceExtensions()
344{
345    // Need to use the namespace to access the extension methods
346    using namespace TestNamespace;
347
348    SimpleBase base;
349    base.value = 5.0;
350
351    // The type is just "SimpleBase.NamedConfig", not "TestNamespace.SimpleBase.NamedConfig"
352    SimpleBase.NamedConfig config;
353    config.factor = 2.0;
354
355    // Generate a type error to check the output format
356    config = 0; // Error: expected expr of type 'SimpleBase.NamedConfig', got 'int'
357}