You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -24,18 +29,17 @@ Introducing `where` clauses allows a programmer to state the constraints *after*
24
29
25
30
void resolve<T, U, V>(ResolutionContext<U> context, List<T> stuffToResolve, out V destination)
26
31
where T : IResolvable,
27
-
U : IResolver<T>,
28
-
V : IResolveDestination<T>
32
+
where U : IResolver<T>,
33
+
where V : IResolveDestination<T>
29
34
{ ... }
30
35
31
36
This latter form makes it easier to quickly glean the overall shape of the function signature.
32
37
33
-
A second important benefit of `where` clauses is that they open the door to expressing more complicated constraints on and between type parameters.
34
-
While this document does not propose to allow any new forms of constraints right away, we can imagine things like allowing constraints on *associated types*, e.g.:
38
+
A second important benefit of `where` clauses is that they open the door to expressing more complicated constraints on and between type parameters, such as allowing constraints on *associated types*, e.g.:
35
39
36
40
void writePackedData<T, U>(T src, out U dst)
37
41
where T : IPackable,
38
-
T.Packed : IWritable<U>
42
+
where T.Packed : IWritable<U>
39
43
{ .. }
40
44
41
45
Related Work
@@ -92,46 +96,63 @@ Proposed Approach
92
96
93
97
For any kind of declaration that Slang allows to have generic parameters, we will allow a `where` clause to appear after the *header* of that declaration.
94
98
A `where` clause consists of the (contextual) keyword `where`, following by a comma-separated list of *constraints*:
95
-
96
-
struct MyStuff<T> : Base, IFoo
97
-
where T : IFoo,
98
-
T : IBar
99
+
```csharp
100
+
structMyStuff<T, U> : IFoo
101
+
whereT : IFoo, IBar
102
+
whereT : IBaz
103
+
whereU : IArray<T>
99
104
{ ... }
100
-
105
+
```
101
106
A `where` clause is only allowed after the header of a declaration that has one or more generic parameters.
102
107
103
108
Each constraint must take the form of one of the type parameters from the immediately enclosing generic parameter list, followed by a colon (`:`), and then followed by a type expression that names an interface or a conjunction of interfaces.
104
109
Multiple constraints can be defined for the same parameter.
105
110
106
111
We haven't previously defined what the header of a declaration is, so we briefly illustrate what we mean by showing where the split between the header and the *body* of a declaration is for each of the major kinds of declarations that are supported. In each case a comment `/****/` is placed between the header and body:
107
112
108
-
// variables:
109
-
let v : Int /****/ = 99;
110
-
var v : Int /****/ = 99;
111
-
Int v /****/ = 99;
112
-
113
-
// simple type declarations:
114
-
typealias X : IFoo /****/ = Y;
115
-
associatedtype X : IFoo /****/;
116
-
117
-
// functions and other callables:
118
-
Int f(Float y) /****/ { ... }
119
-
func f(Float y) -> Int /****/ { ... }
120
-
init(Float y) /****/ { ... }
121
-
subscript(Int idx) -> Float /****/ { ... }
122
-
123
-
// properties
124
-
property p : Int /****/ { ... }
125
-
126
-
// aggregates
127
-
extension Int : IFoo /****/ { ... }
128
-
struct Thing : Base /****/ { ... }
129
-
class Thing : Base /****/ { ... }
130
-
interface IThing : IBase /****/ { ... }
131
-
enum Stuff : Int /****/ { ... }
132
-
113
+
```csharp
114
+
// variables:
115
+
letv:Int/****/=99;
116
+
varv:Int/****/=99;
117
+
Intv/****/=99;
118
+
119
+
// simple type declarations:
120
+
typealiasX:IFoo/****/=Y;
121
+
associatedtypeX:IFoo/****/;
122
+
123
+
// functions and other callables:
124
+
Intf(Floaty) /****/ { ... }
125
+
funcf(Floaty) -> Int/****/ { ... }
126
+
init(Floaty) /****/ { ... }
127
+
subscript(Intidx) -> Float/****/ { ... }
128
+
129
+
// properties
130
+
propertyp:Int/****/ { ... }
131
+
132
+
// aggregates
133
+
extensionInt:IFoo/****/ { ... }
134
+
structThing : Base/****/ { ... }
135
+
classThing : Base/****/ { ... }
136
+
interfaceIThing : IBase/****/ { ... }
137
+
enumStuff : Int/****/ { ... }
138
+
```
133
139
In practice, the body of a declaration starts at the `=` for declarations with an initial-value expression, at the opening `{` for declarations with a `{}`-enclosed body, or at the closing `;` for any other declarations.
134
140
141
+
With introduction of `where` clauses, we can extend type system to allow more kinds of type constraints. In this proposal,
142
+
we allow type constraints followed by `where` to be one of:
143
+
- Type conformance constraint, in the form of `T : IBase`
144
+
- Type equality constraint, in the form of `T == X`
145
+
146
+
In both cases, the left hand side of a constraint can be a simple generic type parameter, or any types that are dependent on some
147
+
generic type parameter. For example, the following is allowed:
148
+
```csharp
149
+
interfaceIFoo { associatedtype A; }
150
+
structS<T, U>
151
+
whereT : IFoo
152
+
where T.A == U
153
+
{}
154
+
```
155
+
135
156
Detailed Explanation
136
157
--------------------
137
158
@@ -241,37 +262,18 @@ Alternatives Considered
241
262
There really aren't any compelling alternatives to `where` clauses among the languages that Slang takes design influence from.
242
263
We could try to design something to solve the same problems from first principles, but the hypothetical benefits of doing so are unclear.
243
264
244
-
When it comes to the syntactic details, we could consider allowing for *multiple*`where` clauses (matching the C# syntax) as an alternative to the comma-separated list:
265
+
When it comes to the syntactic details, we could consider disallow type lists in the right hand side of a conformance constraint, and return allow multiple constraints to be separated with comma and sharing with one `where` keyword:
245
266
246
267
struct MyStuff<T> : Base, IFoo
247
-
where T : IFoo
248
-
where T : IBar
268
+
where T : IFoo,
269
+
T : IBar
249
270
{ ... }
250
271
251
-
This alternative form may result in more compact and tidy diffs when editing the constraints on declarations, at the cost of repeating the `where` keyword many times.
272
+
This alternative form may result in more compact code without needing duplicated `where` clause, but may be harder to achieve tidy diffs when editing the constraints on declarations.
252
273
253
274
Future Directions
254
275
-----------------
255
276
256
-
### Allow more general types on the left-hand side of `:`
257
-
258
-
There are many cases where it would be helpful to be able to introduce constraints on associated types.
259
-
As a contrived example:
260
-
261
-
interface IPrintable { ... }
262
-
interface ISequence
263
-
{
264
-
associatedtype Element;
265
-
...
266
-
}
267
-
extention<T> T : IPrintable
268
-
where T : ISequence,
269
-
T.Element : IPrintable
270
-
{ ... }
271
-
272
-
In this example, an `extension` is used to declare that sequences are printable if their elements are printable.
273
-
274
-
275
277
### Allow more general types on the right-hand side of `:`
276
278
277
279
Currently, the only constraints allowed using `:` have a concrete (non-`interface`) type on the left-hand side, and an `interface` (or conjunction of interfaces) on the right-hand side.
@@ -284,30 +286,6 @@ In the context of `class`-based hierarchies, we can also consider having constra
284
286
where T : Base
285
287
{ ... }
286
288
287
-
### Equality Constraints
288
-
289
-
One future direction that we already intend to pursue is allowing exact equality constraints.
290
-
The primary use case envisioned for equality constraints is to express restrictions on associated types of type parameters.
291
-
As a contrived example:
292
-
293
-
interface IProducer
294
-
{
295
-
associatedtype Element;
296
-
// ...
297
-
}
298
-
interface IConsumer
299
-
{
300
-
associatedtype Element;
301
-
// ...
302
-
}
303
-
void runPipeline<P, C>(P producer, C consumer)
304
-
where P : IProducer,
305
-
C : IConsumer,
306
-
P.Element == C.Element
307
-
{ ... }
308
-
309
-
An equality constraint could either constrain an associated type to be equal to some concrete type, or to some other associated type.
310
-
311
289
### Allow `where` clauses on non-generic declarations
312
290
313
291
We could consider allowing `where` clauses to appear on any declaration nested under a generic, such that those declarations are only usable when certain additinal constraints are met.
Each member in a `ConstantBuffer` will be emitted as `uniform` parameter.
137
+
Each member in a `ConstantBuffer` will be emitted as `uniform` parameter in a uniform block.
138
138
StructuredBuffer and ByteAddressBuffer are translated to a shader storage buffer with `readonly` layout.
139
139
RWStructuredBuffer and RWByteAddressBuffer are translated to a shader storage buffer with `read-write` layout.
140
140
RasterizerOrderedStructuredBuffer and RasterizerOrderedByteAddressBuffer will use an extension, `SPV_EXT_fragment_shader_interlock`.
@@ -156,6 +156,34 @@ It is similar to `ConstantBuffer` in HLSL, and `ParameterBlock` can include not
156
156
When both ordinary data fields and resource typed fields exist in a parameter block, all ordinary data fields will be grouped together into a uniform buffer and appear as a binding 0 of the resulting descriptor set.
157
157
158
158
159
+
Push Constants
160
+
---------------------
161
+
162
+
By default, a `uniform` parameter defined in the parameter list of an entrypoint function is translated to a push constant in SPIRV, if the type of the parameter is ordinary data type (no resources/textures).
163
+
All `uniform` parameter defined in global scope are grouped together and placed in a default constant bbuffer. You can make a global uniform parameter laid out as a push constant by using the `[vk::push_constant]` attribute
164
+
on the uniform parameter.
165
+
166
+
Specialization Constants
167
+
------------------------
168
+
169
+
You can specify a global constant to translate into a SPIRV specialization constant with the `[SpecializationConstant]` attribute.
170
+
For example:
171
+
```csharp
172
+
[SpecializationConstant]
173
+
constintmyConst=1; // Maps to a SPIRV specialization constant
174
+
```
175
+
176
+
By default, Slang will automatically assign `constant_id` number for specialization constants. If you wish to explicitly specify them, use `[vk::constant_id]` attribute:
177
+
```csharp
178
+
[vk::constant_id(1)]
179
+
constintmyConst=1;
180
+
```
181
+
182
+
Alternatively, the GLSL `layout` syntax is also supported by Slang:
<lidata-link="interfaces-generics#extending-a-type-with-additional-interface-conformances"><span>Extending a Type with Additional Interface Conformances</span></li>
85
85
<lidata-link="interfaces-generics#is-and-as-operator"><span>`is` and `as` Operator</span></li>
0 commit comments