[tint][intrinsics] Add explicit template arguments
Re-introduce the <...> template syntax as a list of explicit template
arguments. These must be provided to match the overload.
Add the explicit-template overloads to the various intrinsic definition
files. The non-WGSL definition files probably don't need both implcit
and explicit overloads for many of these, but this keeps behaviour
consistent.
Change-Id: Ie8078db1ed578fa7c72890f9f47a9ebc8aee420e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/175244
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/tools/src/tint/intrinsic/ast/ast.go b/tools/src/tint/intrinsic/ast/ast.go
index 4059fec..7d4f336 100644
--- a/tools/src/tint/intrinsic/ast/ast.go
+++ b/tools/src/tint/intrinsic/ast/ast.go
@@ -146,13 +146,14 @@
// IntrinsicDecl describes a builtin or operator declaration
type IntrinsicDecl struct {
- Source tok.Source
- Kind IntrinsicKind
- Name string
- Attributes Attributes
- TemplateParams []TemplateParam
- Parameters Parameters
- ReturnType *TemplatedName
+ Source tok.Source
+ Kind IntrinsicKind
+ Name string
+ Attributes Attributes
+ ImplicitTemplateParams []TemplateParam
+ ExplicitTemplateParams []TemplateParam
+ Parameters Parameters
+ ReturnType *TemplatedName
}
// Format implements the fmt.Formatter interface
@@ -169,11 +170,16 @@
}
fmt.Fprintf(w, "%v", i.Name)
- if len(i.TemplateParams) > 0 {
+ if len(i.ExplicitTemplateParams) > 0 {
fmt.Fprintf(w, "<")
- formatList(w, i.TemplateParams)
+ formatList(w, i.ExplicitTemplateParams)
fmt.Fprintf(w, ">")
}
+ if len(i.ImplicitTemplateParams) > 0 {
+ fmt.Fprintf(w, "[")
+ formatList(w, i.ImplicitTemplateParams)
+ fmt.Fprintf(w, "]")
+ }
i.Parameters.Format(w, verb)
if i.ReturnType != nil {
fmt.Fprintf(w, " -> ")
@@ -379,7 +385,6 @@
}
}
-// formatList writes the comma separated list to w.
func formatList[T any](w fmt.State, list []T) {
for i, v := range list {
if i > 0 {
diff --git a/tools/src/tint/intrinsic/gen/gen.go b/tools/src/tint/intrinsic/gen/gen.go
index 0037252..79ff6c9 100644
--- a/tools/src/tint/intrinsic/gen/gen.go
+++ b/tools/src/tint/intrinsic/gen/gen.go
@@ -96,9 +96,12 @@
type Overload struct {
// Total number of parameters for the overload
NumParameters int
- // Total number of templates for the overload
+ // Total number of explicit templates for the overload
+ NumExplicitTemplates int
+ // Total number of explicit and implicit templates for the overload
NumTemplates int
// Index to the first template in IntrinsicTable.Templates
+ // This is a list of template starting with the explicit templates, then the implicit templates.
TemplatesOffset int
// Index to the first parameter in IntrinsicTable.Parameters
ParametersOffset int
@@ -163,8 +166,10 @@
// Map of TemplateParam to templatesBuilder
templateBuilders map[sem.TemplateParam]*templateBuilder
// Templates used by the overload
+ // This is a list of explicit template types followed by the implicit template types.
templates []Template
// Index to the first template in IntrinsicTable.Templates
+ // This is a list of template starting with the explicit templates, then the implicit templates.
templateOffset *int
// Builders for all parameters
parameterBuilders []parameterBuilder
@@ -217,11 +222,11 @@
// - b.constEvalFunctionOffset
func (b *overloadBuilder) processStage0() error {
// Calculate the template matcher indices
- for _, t := range b.overload.Templates {
+ for _, t := range b.overload.AllTemplates() {
b.templateBuilders[t] = &templateBuilder{matcherIndex: len(b.templateBuilders)}
}
- for _, t := range b.overload.Templates {
+ for _, t := range b.overload.AllTemplates() {
switch t := t.(type) {
case *sem.TemplateTypeParam:
if t.Type != nil {
@@ -279,7 +284,7 @@
// - b.parametersOffset
func (b *overloadBuilder) processStage1() error {
b.templates = []Template{}
- for _, t := range b.overload.Templates {
+ for _, t := range b.overload.AllTemplates() {
b.templates = append(b.templates, Template{
Name: t.GetName(),
Kind: t.TemplateKind(),
@@ -302,7 +307,8 @@
func (b *overloadBuilder) build() (Overload, error) {
return Overload{
NumParameters: len(b.parameterBuilders),
- NumTemplates: len(b.overload.Templates),
+ NumExplicitTemplates: len(b.overload.ExplicitTemplates),
+ NumTemplates: len(b.overload.ExplicitTemplates) + len(b.overload.ImplicitTemplates),
TemplatesOffset: loadOrMinusOne(b.templateOffset),
ParametersOffset: loadOrMinusOne(b.parametersOffset),
ConstEvalFunctionOffset: loadOrMinusOne(b.constEvalFunctionOffset),
diff --git a/tools/src/tint/intrinsic/gen/permutate.go b/tools/src/tint/intrinsic/gen/permutate.go
index 7d35a19..4a79968 100644
--- a/tools/src/tint/intrinsic/gen/permutate.go
+++ b/tools/src/tint/intrinsic/gen/permutate.go
@@ -63,9 +63,10 @@
// Permutation describes a single permutation of an overload
type Permutation struct {
- sem.Overload // The permuted overload signature
- Desc string // Description of the overload
- Hash string // Hash of the overload
+ sem.Overload // The permuted overload signature
+ ExplicitTemplateArgs []sem.FullyQualifiedName
+ Desc string // Description of the overload
+ Hash string // Hash of the overload
}
// Permute generates a set of permutations for the given intrinsic overload
@@ -114,14 +115,25 @@
o.ReturnType = &retTys[0]
}
+ explicitTemplateArgs := make([]sem.FullyQualifiedName, len(overload.ExplicitTemplates))
+ for i, t := range overload.ExplicitTemplates {
+ ty := state.templateTypes[t]
+ explicitTemplateArgs[i] = ty
+ o.ExplicitTemplates = append(o.ExplicitTemplates, &sem.TemplateTypeParam{
+ Name: t.GetName(),
+ Type: &ty,
+ })
+ }
+
desc := fmt.Sprint(o)
hash := sha256.Sum256([]byte(desc))
const hashLength = 6
shortHash := hex.EncodeToString(hash[:])[:hashLength]
out = append(out, Permutation{
- Overload: o,
- Desc: desc,
- Hash: shortHash,
+ Overload: o,
+ ExplicitTemplateArgs: explicitTemplateArgs,
+ Desc: desc,
+ Hash: shortHash,
})
// Check for hash collisions
@@ -157,7 +169,7 @@
}
}
- for _, t := range overload.Templates {
+ for _, t := range overload.AllTemplates() {
t := t // Capture iterator values for anonymous function
next := permute // Permutation chaining
switch t := t.(type) {
diff --git a/tools/src/tint/intrinsic/parser/parser.go b/tools/src/tint/intrinsic/parser/parser.go
index bd2f055..fb06b75 100644
--- a/tools/src/tint/intrinsic/parser/parser.go
+++ b/tools/src/tint/intrinsic/parser/parser.go
@@ -228,7 +228,7 @@
Attributes: decos,
Name: string(name.Runes),
}
- f.TemplateParams = p.intrinsicTemplateParams()
+ f.ExplicitTemplateParams, f.ImplicitTemplateParams = p.intrinsicTemplateParams()
f.Parameters = p.parameters()
if p.match(tok.Arrow) != nil {
ret := p.templatedName()
@@ -246,7 +246,7 @@
Attributes: decos,
Name: string(name.Runes),
}
- f.TemplateParams = p.intrinsicTemplateParams()
+ f.ExplicitTemplateParams, f.ImplicitTemplateParams = p.intrinsicTemplateParams()
f.Parameters = p.parameters()
if p.match(tok.Arrow) != nil {
ret := p.templatedName()
@@ -264,7 +264,7 @@
Attributes: decos,
Name: string(name.Runes),
}
- f.TemplateParams = p.intrinsicTemplateParams()
+ f.ExplicitTemplateParams, f.ImplicitTemplateParams = p.intrinsicTemplateParams()
f.Parameters = p.parameters()
if p.match(tok.Arrow) != nil {
ret := p.templatedName()
@@ -282,7 +282,7 @@
Attributes: decos,
Name: string(name.Runes),
}
- f.TemplateParams = p.intrinsicTemplateParams()
+ f.ExplicitTemplateParams, f.ImplicitTemplateParams = p.intrinsicTemplateParams()
f.Parameters = p.parameters()
if p.match(tok.Arrow) != nil {
ret := p.templatedName()
@@ -371,16 +371,20 @@
return t
}
-func (p *parser) intrinsicTemplateParams() []ast.TemplateParam {
- if p.match(tok.Lbracket) == nil {
- return nil
+func (p *parser) intrinsicTemplateParams() (explicit, implicit []ast.TemplateParam) {
+ if p.match(tok.Lt) != nil { // <...>
+ for p.err == nil && p.peekIs(0, tok.Identifier) {
+ explicit = append(explicit, p.templateParam())
+ }
+ p.expect(tok.Gt, "explicit template parameter list")
}
- out := []ast.TemplateParam{}
- for p.err == nil && p.peekIs(0, tok.Identifier) {
- out = append(out, p.templateParam())
+ if p.match(tok.Lbracket) != nil { // [...]
+ for p.err == nil && p.peekIs(0, tok.Identifier) {
+ implicit = append(implicit, p.templateParam())
+ }
+ p.expect(tok.Rbracket, "implicit template parameter list")
}
- p.expect(tok.Rbracket, "intrinsic template parameter list")
- return out
+ return explicit, implicit
}
func (p *parser) templateParam() ast.TemplateParam {
diff --git a/tools/src/tint/intrinsic/parser/parser_test.go b/tools/src/tint/intrinsic/parser/parser_test.go
index 9dec76b..21b4e92 100644
--- a/tools/src/tint/intrinsic/parser/parser_test.go
+++ b/tools/src/tint/intrinsic/parser/parser_test.go
@@ -251,12 +251,12 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "fn F[A : B<C> ]()",
+ "fn F<A : B<C> >()",
ast.AST{
Builtins: []ast.IntrinsicDecl{{
Kind: ast.Builtin,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -271,19 +271,102 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
+ "fn F<T>(a: X, b: Y<T>)",
+ ast.AST{
+ Builtins: []ast.IntrinsicDecl{{
+ Kind: ast.Builtin,
+ Name: "F",
+ ExplicitTemplateParams: []ast.TemplateParam{
+ {Name: "T"},
+ },
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "X"}},
+ {Name: "b", Type: ast.TemplatedName{
+ Name: "Y",
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
+ }},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
+ "fn F[A : B<C>]()",
+ ast.AST{
+ Builtins: []ast.IntrinsicDecl{{
+ Kind: ast.Builtin,
+ Name: "F",
+ ImplicitTemplateParams: []ast.TemplateParam{
+ {
+ Name: "A",
+ Type: ast.TemplatedName{
+ Name: "B",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "C"},
+ },
+ },
+ },
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
"fn F[T](a: X, b: Y<T>)",
ast.AST{
Builtins: []ast.IntrinsicDecl{{
Kind: ast.Builtin,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ImplicitTemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
{Name: "b", Type: ast.TemplatedName{
Name: "Y",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
+ }},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
+ "fn F<A>[B: C<D>]()",
+ ast.AST{
+ Builtins: []ast.IntrinsicDecl{{
+ Kind: ast.Builtin,
+ Name: "F",
+ ExplicitTemplateParams: []ast.TemplateParam{
+ {Name: "A"},
+ },
+ ImplicitTemplateParams: []ast.TemplateParam{
+ {
+ Name: "B",
+ Type: ast.TemplatedName{
+ Name: "C",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "D"},
+ },
+ },
+ },
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
+ "fn F[T](a: X, b: Y<T>)",
+ ast.AST{
+ Builtins: []ast.IntrinsicDecl{{
+ Kind: ast.Builtin,
+ Name: "F",
+ ImplicitTemplateParams: []ast.TemplateParam{
+ {Name: "T"},
+ },
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "X"}},
+ {Name: "b", Type: ast.TemplatedName{
+ Name: "Y",
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
}},
},
}},
@@ -308,7 +391,7 @@
Name: "F",
ReturnType: &ast.TemplatedName{
Name: "X",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
},
Parameters: ast.Parameters{},
}},
@@ -389,12 +472,51 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "op F[A : B<C> ]()",
+ "op F<A : B<C> >()",
ast.AST{
Operators: []ast.IntrinsicDecl{{
Kind: ast.Operator,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
+ {
+ Name: "A", Type: ast.TemplatedName{
+ Name: "B",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "C"},
+ },
+ },
+ },
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
+ "op F<T>(a: X, b: Y<T>)",
+ ast.AST{
+ Operators: []ast.IntrinsicDecl{{
+ Kind: ast.Operator,
+ Name: "F",
+ ExplicitTemplateParams: []ast.TemplateParam{
+ {Name: "T"},
+ },
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "X"}},
+ {Name: "b", Type: ast.TemplatedName{
+ Name: "Y",
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
+ }},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
+ "op F[A : B<C>]()",
+ ast.AST{
+ Operators: []ast.IntrinsicDecl{{
+ Kind: ast.Operator,
+ Name: "F",
+ ImplicitTemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -414,20 +536,43 @@
Operators: []ast.IntrinsicDecl{{
Kind: ast.Operator,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ImplicitTemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
{Name: "b", Type: ast.TemplatedName{
Name: "Y",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
}},
},
}},
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
+ "op F<A : B<C> >[D]()",
+ ast.AST{
+ Operators: []ast.IntrinsicDecl{{
+ Kind: ast.Operator,
+ Name: "F",
+ ExplicitTemplateParams: []ast.TemplateParam{
+ {
+ Name: "A", Type: ast.TemplatedName{
+ Name: "B",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "C"},
+ },
+ },
+ },
+ },
+ ImplicitTemplateParams: []ast.TemplateParam{
+ {Name: "D"},
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ fileutils.ThisLine(),
"op F() -> X",
ast.AST{
Operators: []ast.IntrinsicDecl{{
@@ -446,7 +591,7 @@
Name: "F",
ReturnType: &ast.TemplatedName{
Name: "X",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
},
Parameters: ast.Parameters{},
}},
@@ -513,12 +658,12 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "ctor F[A : B<C> ]()",
+ "ctor F<A : B<C> >()",
ast.AST{
Constructors: []ast.IntrinsicDecl{{
Kind: ast.Constructor,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -533,19 +678,19 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "ctor F[T](a: X, b: Y<T>)",
+ "ctor F<T>(a: X, b: Y<T>)",
ast.AST{
Constructors: []ast.IntrinsicDecl{{
Kind: ast.Constructor,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
{Name: "b", Type: ast.TemplatedName{
Name: "Y",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
}},
},
}},
@@ -570,7 +715,7 @@
Name: "F",
ReturnType: &ast.TemplatedName{
Name: "X",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
},
Parameters: ast.Parameters{},
}},
@@ -637,12 +782,12 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "conv F[A : B<C> ]()",
+ "conv F<A : B<C> >()",
ast.AST{
Converters: []ast.IntrinsicDecl{{
Kind: ast.Converter,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -657,19 +802,19 @@
},
}, { ///////////////////////////////////////////////////////////////////
fileutils.ThisLine(),
- "conv F[T](a: X, b: Y<T>)",
+ "conv F<T>(a: X, b: Y<T>)",
ast.AST{
Converters: []ast.IntrinsicDecl{{
Kind: ast.Converter,
Name: "F",
- TemplateParams: []ast.TemplateParam{
+ ExplicitTemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
{Name: "b", Type: ast.TemplatedName{
Name: "Y",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
}},
},
}},
@@ -694,7 +839,7 @@
Name: "F",
ReturnType: &ast.TemplatedName{
Name: "X",
- TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ TemplateArgs: ast.TemplatedNames{{Name: "T"}},
},
Parameters: ast.Parameters{},
}},
diff --git a/tools/src/tint/intrinsic/resolver/resolve.go b/tools/src/tint/intrinsic/resolver/resolve.go
index 63e14df..abd5e44 100644
--- a/tools/src/tint/intrinsic/resolver/resolve.go
+++ b/tools/src/tint/intrinsic/resolver/resolve.go
@@ -328,11 +328,18 @@
}
// Resolve the declared template parameters
- templates, err := r.templateParams(&s, a.TemplateParams)
+ // Explicit template types can use implicit templates, so resolve implicit first
+ implicitTemplates, err := r.templateParams(&s, a.ImplicitTemplateParams)
if err != nil {
return err
}
- overload.Templates = templates
+ overload.ImplicitTemplates = implicitTemplates
+
+ explicitTemplates, err := r.templateParams(&s, a.ExplicitTemplateParams)
+ if err != nil {
+ return err
+ }
+ overload.ExplicitTemplates = explicitTemplates
// Process overload attributes
if stageDeco := a.Attributes.Take("stage"); stageDeco != nil {
@@ -401,8 +408,12 @@
// Append the overload to the intrinsic
intrinsic.Overloads = append(intrinsic.Overloads, overload)
+ for _, num := range overload.ExplicitTemplates.Numbers() {
+ return fmt.Errorf("%v explicit number template parameters are not supported", num.AST().Source)
+ }
+
// Update high-water mark of templates
- if n := len(overload.Templates); r.s.MaxTemplates < n {
+ if n := len(overload.AllTemplates()); r.s.MaxTemplates < n {
r.s.MaxTemplates = n
}
@@ -485,7 +496,9 @@
if err != nil {
return nil, err
}
- s.declare(param, ast.Source)
+ if err := s.declare(param, ast.Source); err != nil {
+ return nil, err
+ }
out = append(out, param)
}
return out, nil
diff --git a/tools/src/tint/intrinsic/resolver/resolver_test.go b/tools/src/tint/intrinsic/resolver/resolver_test.go
index c73fd4b..b5d3cb8 100644
--- a/tools/src/tint/intrinsic/resolver/resolver_test.go
+++ b/tools/src/tint/intrinsic/resolver/resolver_test.go
@@ -78,6 +78,11 @@
}, {
`
type f32
+fn f<T>(T) -> f32`,
+ success,
+ }, {
+ `
+type f32
fn f[N: num]()`,
success,
}, {
@@ -93,6 +98,16 @@
}, {
`
type f32
+fn f<T: f32>[N: num]()`,
+ success,
+ }, {
+ `
+type f32
+fn f[T: f32](T: f32) -> f32`,
+ success,
+ }, {
+ `
+type f32
type P<T>
match m: f32
fn f[T: m](P<T>) -> T`,
@@ -108,13 +123,6 @@
enum e { a b }
type T<E: e>
match m: e.a
-fn f[E: m](T<E>)`,
- success,
- }, {
- `
-enum e { a b }
-type T<E: e>
-match m: e.a
fn f(T<m>)`,
success,
}, {
@@ -158,6 +166,15 @@
success,
}, {
`
+type a
+type b
+type c
+match S: a | b | c
+type V<N: num, T>
+fn f<I: V<N, T> >[N: num, T: S, U: S](V<N, U>) -> I`,
+ success,
+ }, {
+ `
type f32
op -(f32)`,
success,
@@ -540,6 +557,28 @@
`
@must_use fn f()`,
`file.txt:1:2 @must_use can only be used on a function with a return type`,
+ }, {
+ `
+type f32
+fn f<N: num>()`,
+ `file.txt:2:6 explicit number template parameters are not supported`,
+ }, {
+ `
+enum e { a b c }
+fn f<N: e>()`,
+ `file.txt:2:6 explicit number template parameters are not supported`,
+ }, {
+ `
+enum e { a b }
+type T<E: e>
+match m: e.a
+fn f<E: m>(T<E>)`,
+ `file.txt:4:6 explicit number template parameters are not supported`,
+ }, {
+ `
+fn f<T>[T]()`,
+ `file.txt:1:6 'T' already declared
+First declared here: file.txt:1:9`,
},
} {
diff --git a/tools/src/tint/intrinsic/sem/sem.go b/tools/src/tint/intrinsic/sem/sem.go
index 4b9d8f3..e3ee74c 100644
--- a/tools/src/tint/intrinsic/sem/sem.go
+++ b/tools/src/tint/intrinsic/sem/sem.go
@@ -258,7 +258,8 @@
type Overload struct {
Decl ast.IntrinsicDecl
Intrinsic *Intrinsic
- Templates IntrinsicTemplates
+ ExplicitTemplates IntrinsicTemplates
+ ImplicitTemplates IntrinsicTemplates
ReturnType *FullyQualifiedName
Parameters []Parameter
CanBeUsedInStage StageUses
@@ -267,6 +268,11 @@
ConstEvalFunction string // Name of the function used to evaluate the intrinsic at shader creation time
}
+// AllTemplates returns the combined list of explicit and implicit templates
+func (o *Overload) AllTemplates() IntrinsicTemplates {
+ return append(append([]TemplateParam{}, o.ExplicitTemplates...), o.ImplicitTemplates...)
+}
+
// StageUses describes the stages an overload can be used in
type StageUses struct {
Vertex bool
@@ -298,11 +304,16 @@
fmt.Fprintf(w, "op ")
}
fmt.Fprintf(w, "%v", o.Intrinsic.Name)
- if len(o.Templates) > 0 {
+ if len(o.ExplicitTemplates) > 0 {
fmt.Fprintf(w, "<")
- formatList(w, o.Templates)
+ formatList(w, o.ExplicitTemplates)
fmt.Fprintf(w, ">")
}
+ if len(o.ImplicitTemplates) > 0 {
+ fmt.Fprintf(w, "[")
+ formatList(w, o.ImplicitTemplates)
+ fmt.Fprintf(w, "]")
+ }
fmt.Fprint(w, "(")
for i, p := range o.Parameters {
if i > 0 {
@@ -407,7 +418,6 @@
// GetName returns the name of the TemplateNumberParam
func (t *TemplateNumberParam) GetName() string { return t.Name }
-// formatList writes the comma separated list to w.
func formatList[T any](w fmt.State, list []T) {
for i, v := range list {
if i > 0 {