[tint][intrinsics] Simplify intrinsic table
* Combine the type and number matcher index tables. The usage knows which
kind of matcher is needed.
* Combine the type and number template structures.
* Change the template matcher from a single matcher index, to a list of
matchers. This allows templates to match using other templates.
* Remove the validation forbidding the direct use of a matcher in a
parameter. While this is discouraged for WGSL due to readability of
diagnostics messages, there's no reason this couldn't be used to
simplify other definition files.
Change-Id: I86897d49297c3d4b960e1f73c465103593a445d4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/175242
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/tools/src/cmd/gen/templates/templates.go b/tools/src/cmd/gen/templates/templates.go
index ebe6652..783b4ed 100644
--- a/tools/src/cmd/gen/templates/templates.go
+++ b/tools/src/cmd/gen/templates/templates.go
@@ -249,7 +249,11 @@
return nil, err
}
}
- return i.cachedPermuter.Permute(overload)
+ out, err := i.cachedPermuter.Permute(overload)
+ if err != nil {
+ return nil, fmt.Errorf("while permuting '%v'\n%w", overload, err)
+ }
+ return out, nil
}
// Cache for objects that are expensive to build, and can be reused between templates.
diff --git a/tools/src/template/template.go b/tools/src/template/template.go
index fcd14a1..5af3ef6 100644
--- a/tools/src/template/template.go
+++ b/tools/src/template/template.go
@@ -159,7 +159,7 @@
}
if err != nil {
- return "", fmt.Errorf("while evaluating '%v': %v", template, err)
+ return "", fmt.Errorf("while evaluating '%v' with args '%v'\n%v", template, args, err)
}
return sb.String(), nil
}
diff --git a/tools/src/tint/intrinsic/ast/ast.go b/tools/src/tint/intrinsic/ast/ast.go
index 350009a..4059fec 100644
--- a/tools/src/tint/intrinsic/ast/ast.go
+++ b/tools/src/tint/intrinsic/ast/ast.go
@@ -150,7 +150,7 @@
Kind IntrinsicKind
Name string
Attributes Attributes
- TemplateParams TemplateParams
+ TemplateParams []TemplateParam
Parameters Parameters
ReturnType *TemplatedName
}
@@ -167,8 +167,13 @@
case Converter:
fmt.Fprintf(w, "conv ")
}
+
fmt.Fprintf(w, "%v", i.Name)
- i.TemplateParams.Format(w, verb)
+ if len(i.TemplateParams) > 0 {
+ fmt.Fprintf(w, "<")
+ formatList(w, i.TemplateParams)
+ fmt.Fprintf(w, ">")
+ }
i.Parameters.Format(w, verb)
if i.ReturnType != nil {
fmt.Fprintf(w, " -> ")
@@ -238,12 +243,7 @@
// Format implements the fmt.Formatter interface
func (l TemplatedNames) Format(w fmt.State, verb rune) {
- for i, n := range l {
- if i > 0 {
- fmt.Fprintf(w, ", ")
- }
- n.Format(w, verb)
- }
+ formatList(w, l)
}
// TemplatedName is an identifier with optional templated arguments
@@ -274,12 +274,7 @@
// Format implements the fmt.Formatter interface
func (l MemberNames) Format(w fmt.State, verb rune) {
- for i, n := range l {
- if i > 0 {
- fmt.Fprintf(w, ", ")
- }
- n.Format(w, verb)
- }
+ formatList(w, l)
}
// MemberName is two identifiers separated by a dot (Owner.Member)
@@ -299,7 +294,7 @@
Source tok.Source
Attributes Attributes
Name string
- TemplateParams TemplateParams
+ TemplateParams []TemplateParam
}
// Format implements the fmt.Formatter interface
@@ -309,25 +304,9 @@
fmt.Fprintf(w, " type %v", p.Name)
}
fmt.Fprintf(w, "type %v", p.Name)
- p.TemplateParams.Format(w, verb)
-}
-
-// TemplateParams is a list of TemplateParam
-// Example:
-//
-// <A, B : TyB>
-type TemplateParams []TemplateParam
-
-// Format implements the fmt.Formatter interface
-func (p TemplateParams) Format(w fmt.State, verb rune) {
- if len(p) > 0 {
+ if len(p.TemplateParams) > 0 {
fmt.Fprintf(w, "<")
- for i, tp := range p {
- if i > 0 {
- fmt.Fprintf(w, ", ")
- }
- tp.Format(w, verb)
- }
+ formatList(w, p.TemplateParams)
fmt.Fprintf(w, ">")
}
}
@@ -395,12 +374,17 @@
fmt.Fprintf(w, "%v", d.Name)
if len(d.Values) > 0 {
fmt.Fprintf(w, "(")
- for i, v := range d.Values {
- if i > 0 {
- fmt.Fprint(w, ", ")
- }
- fmt.Fprintf(w, "%v", v)
- }
+ formatList(w, d.Values)
fmt.Fprintf(w, ")")
}
}
+
+// 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 {
+ fmt.Fprint(w, ", ")
+ }
+ fmt.Fprintf(w, "%v", v)
+ }
+}
diff --git a/tools/src/tint/intrinsic/gen/gen.go b/tools/src/tint/intrinsic/gen/gen.go
index 7a98730..0037252 100644
--- a/tools/src/tint/intrinsic/gen/gen.go
+++ b/tools/src/tint/intrinsic/gen/gen.go
@@ -54,35 +54,30 @@
NMatchers []sem.Named
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
- TypeMatcherIndices []int // kTypeMatcherIndices table content
- NumberMatcherIndices []int // kNumberMatcherIndices table content
- TemplateTypes []TemplateType // kTemplateTypes table content
- TemplateNumbers []TemplateNumber // kTemplateNumbers table content
- Parameters []Parameter // kParameters table content
- Overloads []Overload // kOverloads table content
- Builtins []Intrinsic // kBuiltins table content
- UnaryOperators []Intrinsic // kUnaryOperators table content
- BinaryOperators []Intrinsic // kBinaryOperators table content
- ConstructorsAndConverters []Intrinsic // kInitializersAndConverters table content
- ConstEvalFunctions []string // kConstEvalFunctions table content
+ MatcherIndices []int // kMatcherIndices table content
+ Templates []Template // kTemplates table content
+ Parameters []Parameter // kParameters table content
+ Overloads []Overload // kOverloads table content
+ Builtins []Intrinsic // kBuiltins table content
+ UnaryOperators []Intrinsic // kUnaryOperators table content
+ BinaryOperators []Intrinsic // kBinaryOperators table content
+ ConstructorsAndConverters []Intrinsic // kInitializersAndConverters table content
+ ConstEvalFunctions []string // kConstEvalFunctions table content
}
-// TemplateType is used to create the C++ TemplateTypeInfo structure
-type TemplateType struct {
+// Template is used to create the C++ TemplateInfo structure
+type Template struct {
// Name of the template type (e.g. 'T')
Name string
- // Optional type matcher constraint.
- // Either an index in Matchers::type, or -1
- MatcherIndex int
-}
-// TemplateNumber is used to create the C++ TemplateNumberInfo structure
-type TemplateNumber struct {
- // Name of the template number (e.g. 'N')
- Name string
- // Optional type matcher constraint.
- // Either an index in Matchers::type, or -1
- MatcherIndex int
+ // Kind of the template
+ Kind sem.TemplateKind
+
+ // Index into IntrinsicTable.MatcherIndices, beginning the list of matchers required to match
+ // the parameter type.
+ // The matcher indices index into IntrinsicTable::TMatchers and IntrinsicTable::NMatchers.
+ // These indices are consumed by the matchers themselves.
+ MatcherIndicesOffset int
}
// Parameter is used to create the C++ ParameterInfo structure
@@ -90,41 +85,28 @@
// The parameter usage (parameter name)
Usage string
- // Index into IntrinsicTable.TypeMatcherIndices, beginning the list of matchers
- // required to match the parameter type.
- // The matcher indices index into IntrinsicTable::TMatchers.
+ // Index into IntrinsicTable.MatcherIndices, beginning the list of matchers required to match
+ // the parameter type.
+ // The matcher indices index into IntrinsicTable::TMatchers and IntrinsicTable::NMatchers.
// These indices are consumed by the matchers themselves.
- TypeMatcherIndicesOffset int
-
- // Index into IntrinsicTable.NumberMatcherIndices.
- // The matcher indices index into IntrinsicTable::NMatchers.
- // These indices are consumed by the matchers themselves.
- NumberMatcherIndicesOffset int
+ MatcherIndicesOffset int
}
// Overload is used to create the C++ OverloadInfo structure
type Overload struct {
// Total number of parameters for the overload
NumParameters int
- // Total number of template types for the overload
- NumTemplateTypes int
- // Total number of template numbers for the overload
- NumTemplateNumbers int
- // Index to the first template type in IntrinsicTable.TemplateTypes
- TemplateTypesOffset int
- // Index to the first template number in IntrinsicTable.TemplateNumbers
- TemplateNumbersOffset int
+ // Total number of templates for the overload
+ NumTemplates int
+ // Index to the first template in IntrinsicTable.Templates
+ TemplatesOffset int
// Index to the first parameter in IntrinsicTable.Parameters
ParametersOffset int
- // Index into IntrinsicTable.TypeMatcherIndices, beginning the list of matchers
+ // Index into IntrinsicTable.matcherIndices, beginning the list of matchers
// required to match the return type.
// The matcher indices index into IntrinsicTable::TMatchers.
// These indices are consumed by the matchers themselves.
- ReturnTypeMatcherIndicesOffset int
- // Index into IntrinsicTable.NumberMatcherIndices.
- // The matcher indices index into IntrinsicTable::NMatchers.
- // These indices are consumed by the matchers themselves.
- ReturnNumberMatcherIndicesOffset int
+ ReturnMatcherIndicesOffset int
// Index into IntrinsicTable.ConstEvalFunctions.
ConstEvalFunctionOffset int
// StageUses describes the stages an overload can be used in
@@ -153,10 +135,8 @@
// Lookup tables.
// These are packed (compressed) once all the entries have been added.
lut struct {
- typeMatcherIndices lut.LUT[int]
- numberMatcherIndices lut.LUT[int]
- templateTypes lut.LUT[TemplateType]
- templateNumbers lut.LUT[TemplateNumber]
+ matcherIndices lut.LUT[int]
+ templates lut.LUT[Template]
constEvalFunctionIndices lut.LUT[string]
parameters lut.LUT[Parameter]
overloads lut.LUT[Overload]
@@ -164,9 +144,15 @@
}
type parameterBuilder struct {
- usage string
- typeMatcherIndicesOffset *int
- numberMatcherIndicesOffset *int
+ usage string
+ matcherIndicesOffset *int
+}
+
+type templateBuilder struct {
+ // The index of the template in kTypeMatchers / kNumberMatchers
+ matcherIndex int
+ // The matcher indices for this template type / number
+ constraintIndicesOffset *int
}
// Helper for building a single overload
@@ -174,39 +160,31 @@
*IntrinsicTableBuilder
// The overload being built
overload *sem.Overload
- // Maps TemplateParam to index in templateTypes
- templateTypeIndex map[sem.TemplateParam]int
- // Maps TemplateParam to index in templateNumbers
- templateNumberIndex map[sem.TemplateParam]int
- // Template types used by the overload
- templateTypes []TemplateType
- // Index to the first template type in IntrinsicTable.TemplateTypes
- templateTypesOffset *int
- // Template numbers used by the overload
- templateNumbers []TemplateNumber
- // Index to the first template number in IntrinsicTable.TemplateNumbers
- templateNumbersOffset *int
+ // Map of TemplateParam to templatesBuilder
+ templateBuilders map[sem.TemplateParam]*templateBuilder
+ // Templates used by the overload
+ templates []Template
+ // Index to the first template in IntrinsicTable.Templates
+ templateOffset *int
// Builders for all parameters
parameterBuilders []parameterBuilder
// Index to the first parameter in IntrinsicTable.Parameters
parametersOffset *int
// Index into IntrinsicTable.ConstEvalFunctions
constEvalFunctionOffset *int
- // Index into IntrinsicTable.TypeMatcherIndices, beginning the list of
+ // Index into IntrinsicTable.matcherIndices, beginning the list of
// matchers required to match the return type.
// The matcher indices index into IntrinsicTable::TMatchers.
// These indices are consumed by the matchers themselves.
- returnTypeMatcherIndicesOffset *int
- // Index into IntrinsicTable.NumberMatcherIndices.
- // The matcher indices index into IntrinsicTable::NMatchers.
- // These indices are consumed by the matchers themselves.
- returnNumberMatcherIndicesOffset *int
+ returnMatcherIndicesOffset *int
}
// layoutMatchers assigns each of the TMatchers and NMatchers a unique index.
func (b *IntrinsicTableBuilder) layoutMatchers(s *sem.Sem) {
- // First MaxTemplateTypes of TMatchers are template types
- b.TMatchers = make([]sem.Named, s.MaxTemplateTypes)
+ // First MaxTemplates of TMatchers and NMatchers are template types
+ b.TMatchers = make([]sem.Named, s.MaxTemplates)
+ b.NMatchers = make([]sem.Named, s.MaxTemplates)
+
for _, m := range s.Types {
b.TMatcherIndex[m] = len(b.TMatchers)
b.TMatchers = append(b.TMatchers, m)
@@ -215,9 +193,6 @@
b.TMatcherIndex[m] = len(b.TMatchers)
b.TMatchers = append(b.TMatchers, m)
}
-
- // First MaxTemplateNumbers of NMatchers are template numbers
- b.NMatchers = make([]sem.Named, s.MaxTemplateNumbers)
for _, m := range s.EnumMatchers {
b.NMatcherIndex[m] = len(b.NMatchers)
b.NMatchers = append(b.NMatchers, m)
@@ -228,8 +203,7 @@
return &overloadBuilder{
IntrinsicTableBuilder: b,
overload: o,
- templateTypeIndex: map[sem.TemplateParam]int{},
- templateNumberIndex: map[sem.TemplateParam]int{},
+ templateBuilders: map[sem.TemplateParam]*templateBuilder{},
}
}
@@ -237,77 +211,55 @@
// Preconditions:
// - Must be called before any LUTs are compacted.
// Populates:
-// - b.templateTypes
-// - b.templateTypesOffset
-// - b.templateNumbers
-// - b.templateNumbersOffset
+// - b.templateBuilders
// - b.parameterBuilders
-// - b.returnTypeMatcherIndicesOffset
-// - b.returnNumberMatcherIndicesOffset
+// - b.returnMatcherIndicesOffset
// - b.constEvalFunctionOffset
func (b *overloadBuilder) processStage0() error {
- b.templateTypes = make([]TemplateType, len(b.overload.TemplateTypes))
- for i, t := range b.overload.TemplateTypes {
- b.templateTypeIndex[t] = i
- matcherIndex := -1
- if t.Type != nil {
- tys, nums, err := b.matcherIndices(t.Type)
- if err != nil {
- return err
- }
- if len(tys) != 1 || len(nums) != 0 {
- panic("unexpected result of matcherIndices()")
- }
- matcherIndex = tys[0]
- }
- b.templateTypes[i] = TemplateType{
- Name: t.Name,
- MatcherIndex: matcherIndex,
- }
+ // Calculate the template matcher indices
+ for _, t := range b.overload.Templates {
+ b.templateBuilders[t] = &templateBuilder{matcherIndex: len(b.templateBuilders)}
}
- b.templateTypesOffset = b.lut.templateTypes.Add(b.templateTypes)
- b.templateNumbers = make([]TemplateNumber, len(b.overload.TemplateNumbers))
- for i, t := range b.overload.TemplateNumbers {
- b.templateNumberIndex[t] = i
- matcherIndex := -1
- if e, ok := t.(*sem.TemplateEnumParam); ok && e.Matcher != nil {
- tys, nums, err := b.matcherIndices(e.Matcher)
- if err != nil {
- return err
+ for _, t := range b.overload.Templates {
+ switch t := t.(type) {
+ case *sem.TemplateTypeParam:
+ if t.Type != nil {
+ indices, err := b.collectMatcherIndices(*t.Type)
+ if err != nil {
+ return err
+ }
+ b.templateBuilders[t].constraintIndicesOffset = b.lut.matcherIndices.Add(indices)
}
- if len(tys) != 0 || len(nums) != 1 {
- panic("unexpected result of matcherIndices()")
+ case *sem.TemplateEnumParam:
+ if t.Matcher != nil {
+ index, err := b.matcherIndex(t.Matcher)
+ if err != nil {
+ return err
+ }
+ b.templateBuilders[t].constraintIndicesOffset = b.lut.matcherIndices.Add([]int{index})
}
- matcherIndex = nums[0]
- }
- b.templateNumbers[i] = TemplateNumber{
- Name: t.GetName(),
- MatcherIndex: matcherIndex,
}
}
- b.templateNumbersOffset = b.lut.templateNumbers.Add(b.templateNumbers)
if b.overload.ReturnType != nil {
- typeIndices, numberIndices, err := b.collectMatcherIndices(*b.overload.ReturnType)
+ indices, err := b.collectMatcherIndices(*b.overload.ReturnType)
if err != nil {
return err
}
- b.returnTypeMatcherIndicesOffset = b.lut.typeMatcherIndices.Add(typeIndices)
- b.returnNumberMatcherIndicesOffset = b.lut.numberMatcherIndices.Add(numberIndices)
+ b.returnMatcherIndicesOffset = b.lut.matcherIndices.Add(indices)
}
b.parameterBuilders = make([]parameterBuilder, len(b.overload.Parameters))
for i, p := range b.overload.Parameters {
- typeIndices, numberIndices, err := b.collectMatcherIndices(p.Type)
+ matcherIndices, err := b.collectMatcherIndices(p.Type)
if err != nil {
return err
}
b.parameterBuilders[i] = parameterBuilder{
- usage: p.Name,
- typeMatcherIndicesOffset: b.lut.typeMatcherIndices.Add(typeIndices),
- numberMatcherIndicesOffset: b.lut.numberMatcherIndices.Add(numberIndices),
+ usage: p.Name,
+ matcherIndicesOffset: b.lut.matcherIndices.Add(matcherIndices),
}
}
@@ -320,19 +272,27 @@
// processStage1 builds the Parameters used by the overload
// Must only be called after the following LUTs have been compacted:
-// - b.lut.typeMatcherIndices
-// - b.lut.numberMatcherIndices
-// - b.lut.templateTypes
-// - b.lut.templateNumbers
+// - b.lut.matcherIndices
// Populates:
+// - b.templates
+// - b.templateOffset
// - b.parametersOffset
func (b *overloadBuilder) processStage1() error {
+ b.templates = []Template{}
+ for _, t := range b.overload.Templates {
+ b.templates = append(b.templates, Template{
+ Name: t.GetName(),
+ Kind: t.TemplateKind(),
+ MatcherIndicesOffset: loadOrMinusOne(b.templateBuilders[t].constraintIndicesOffset),
+ })
+ }
+ b.templateOffset = b.lut.templates.Add(b.templates)
+
parameters := make([]Parameter, len(b.parameterBuilders))
for i, pb := range b.parameterBuilders {
parameters[i] = Parameter{
- Usage: pb.usage,
- TypeMatcherIndicesOffset: loadOrMinusOne(pb.typeMatcherIndicesOffset),
- NumberMatcherIndicesOffset: loadOrMinusOne(pb.numberMatcherIndicesOffset),
+ Usage: pb.usage,
+ MatcherIndicesOffset: loadOrMinusOne(pb.matcherIndicesOffset),
}
}
b.parametersOffset = b.lut.parameters.Add(parameters)
@@ -341,53 +301,40 @@
func (b *overloadBuilder) build() (Overload, error) {
return Overload{
- NumParameters: len(b.parameterBuilders),
- NumTemplateTypes: len(b.templateTypes),
- NumTemplateNumbers: len(b.templateNumbers),
- TemplateTypesOffset: loadOrMinusOne(b.templateTypesOffset),
- TemplateNumbersOffset: loadOrMinusOne(b.templateNumbersOffset),
- ParametersOffset: loadOrMinusOne(b.parametersOffset),
- ConstEvalFunctionOffset: loadOrMinusOne(b.constEvalFunctionOffset),
- ReturnTypeMatcherIndicesOffset: loadOrMinusOne(b.returnTypeMatcherIndicesOffset),
- ReturnNumberMatcherIndicesOffset: loadOrMinusOne(b.returnNumberMatcherIndicesOffset),
- CanBeUsedInStage: b.overload.CanBeUsedInStage,
- MustUse: b.overload.MustUse,
- IsDeprecated: b.overload.IsDeprecated,
- Kind: string(b.overload.Decl.Kind),
+ NumParameters: len(b.parameterBuilders),
+ NumTemplates: len(b.overload.Templates),
+ TemplatesOffset: loadOrMinusOne(b.templateOffset),
+ ParametersOffset: loadOrMinusOne(b.parametersOffset),
+ ConstEvalFunctionOffset: loadOrMinusOne(b.constEvalFunctionOffset),
+ ReturnMatcherIndicesOffset: loadOrMinusOne(b.returnMatcherIndicesOffset),
+ CanBeUsedInStage: b.overload.CanBeUsedInStage,
+ MustUse: b.overload.MustUse,
+ IsDeprecated: b.overload.IsDeprecated,
+ Kind: string(b.overload.Decl.Kind),
}, nil
}
// matcherIndex returns the matcher indices into IntrinsicTable.TMatcher and
// IntrinsicTable.NMatcher, respectively for the given named entity.
-func (b *overloadBuilder) matcherIndices(n sem.Named) (types, numbers []int, err error) {
+func (b *overloadBuilder) matcherIndex(n sem.Named) (int, error) {
switch n := n.(type) {
case *sem.Type, *sem.TypeMatcher:
if i, ok := b.TMatcherIndex[n]; ok {
- return []int{i}, nil, nil
+ return i, nil
}
- return nil, nil, fmt.Errorf("matcherIndex missing entry for %v %T", n.GetName(), n)
- case *sem.TemplateTypeParam:
- if i, ok := b.templateTypeIndex[n]; ok {
- return []int{i}, nil, nil
- }
- return nil, nil, fmt.Errorf("templateTypeIndex missing entry for %v %T", n.Name, n)
+ return -1, fmt.Errorf("TMatcherIndex missing entry for %v %T", n.GetName(), n)
case *sem.EnumMatcher:
if i, ok := b.NMatcherIndex[n]; ok {
- return nil, []int{i}, nil
+ return i, nil
}
- return nil, nil, fmt.Errorf("matcherIndex missing entry for %v %T", n.GetName(), n)
- case *sem.TemplateEnumParam:
- if i, ok := b.templateNumberIndex[n]; ok {
- return nil, []int{i}, nil
+ return -1, fmt.Errorf("NMatcherIndex missing entry for %v %T", n.GetName(), n)
+ case sem.TemplateParam:
+ if b, ok := b.templateBuilders[n]; ok {
+ return b.matcherIndex, nil
}
- return nil, nil, fmt.Errorf("templateNumberIndex missing entry for %v %T", n, n)
- case *sem.TemplateNumberParam:
- if i, ok := b.templateNumberIndex[n]; ok {
- return nil, []int{i}, nil
- }
- return nil, nil, fmt.Errorf("templateNumberIndex missing entry for %v %T", n, n)
+ return -1, fmt.Errorf("templatesBuilders missing entry for %v %T", n.GetName(), n)
default:
- return nil, nil, fmt.Errorf("overload.matcherIndices() does not handle %v %T", n, n)
+ return -1, fmt.Errorf("overload.matcherIndices() does not handle %v %T", n, n)
}
}
@@ -408,25 +355,24 @@
// Would return the matcher indices:
//
// A, B, C, D, E, F, G, H, I
-func (b *overloadBuilder) collectMatcherIndices(fqn sem.FullyQualifiedName) (tys, nums []int, err error) {
- tys, nums, err = b.matcherIndices(fqn.Target)
+func (b *overloadBuilder) collectMatcherIndices(fqn sem.FullyQualifiedName) ([]int, error) {
+ base, err := b.matcherIndex(fqn.Target)
if err != nil {
- return nil, nil, err
+ return nil, err
}
+ indices := []int{base}
for _, arg := range fqn.TemplateArguments {
- typeIndices, numberIndices, err := b.collectMatcherIndices(arg.(sem.FullyQualifiedName))
+ subIndices, err := b.collectMatcherIndices(arg.(sem.FullyQualifiedName))
if err != nil {
- return nil, nil, err
+ return nil, err
}
- tys = append(tys, typeIndices...)
- nums = append(nums, numberIndices...)
+ indices = append(indices, subIndices...)
}
- return tys, nums, nil
+ return indices, nil
}
// BuildIntrinsicTable builds the IntrinsicTable from the semantic info
func BuildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
-
b := IntrinsicTableBuilder{
IntrinsicTable: IntrinsicTable{
Sem: s,
@@ -460,35 +406,32 @@
}
// Perform the 'stage-0' processing of the overloads
- b.lut.typeMatcherIndices = lut.New[int]()
- b.lut.numberMatcherIndices = lut.New[int]()
- b.lut.templateTypes = lut.New[TemplateType]()
- b.lut.templateNumbers = lut.New[TemplateNumber]()
+ b.lut.matcherIndices = lut.New[int]()
b.lut.constEvalFunctionIndices = lut.New[string]()
for _, b := range overloadBuilders {
- b.processStage0()
+ if err := b.processStage0(); err != nil {
+ return nil, fmt.Errorf("while processing stage 0 of '%v'\n%w", b.overload, err)
+ }
}
- // Compact type and number LUTs
- b.TypeMatcherIndices = b.lut.typeMatcherIndices.Compact()
- b.NumberMatcherIndices = b.lut.numberMatcherIndices.Compact()
- b.TemplateTypes = b.lut.templateTypes.Compact()
- b.TemplateNumbers = b.lut.templateNumbers.Compact()
- b.ConstEvalFunctions = b.lut.constEvalFunctionIndices.Compact()
// Clear the compacted LUTs to prevent use-after-compaction
- b.lut.typeMatcherIndices = nil
- b.lut.numberMatcherIndices = nil
- b.lut.templateTypes = nil
- b.lut.templateNumbers = nil
+ b.MatcherIndices = b.lut.matcherIndices.Compact()
+ b.ConstEvalFunctions = b.lut.constEvalFunctionIndices.Compact()
+ b.lut.matcherIndices = nil
b.lut.constEvalFunctionIndices = nil
+ b.lut.templates = lut.New[Template]()
// Perform the 'stage-1' processing of the overloads
b.lut.parameters = lut.New[Parameter]()
for _, b := range overloadBuilders {
- b.processStage1()
+ if err := b.processStage1(); err != nil {
+ return nil, fmt.Errorf("while processing stage 1 of '%v'\n%w", b.overload, err)
+ }
}
b.Parameters = b.lut.parameters.Compact()
+ b.Templates = b.lut.templates.Compact()
b.lut.parameters = nil
+ b.lut.templates = nil
// Build the Intrinsics
b.lut.overloads = lut.New[Overload]()
diff --git a/tools/src/tint/intrinsic/gen/permutate.go b/tools/src/tint/intrinsic/gen/permutate.go
index 47d7aa8..7d35a19 100644
--- a/tools/src/tint/intrinsic/gen/permutate.go
+++ b/tools/src/tint/intrinsic/gen/permutate.go
@@ -63,7 +63,7 @@
// Permutation describes a single permutation of an overload
type Permutation struct {
- sem.Overload // The permutated overload signature
+ sem.Overload // The permuted overload signature
Desc string // Description of the overload
Hash string // Hash of the overload
}
@@ -82,9 +82,10 @@
// Map of hash to permutation description. Used to detect collisions.
hashes := map[string]string{}
- // permutate appends a permutation to out.
- // permutate may be chained to generate N-dimensional permutations.
- permutate := func() error {
+ // permute appends a permutation to out.
+ // permute may be chained to generate N-dimensional permutations.
+ permute := func() error {
+ // Generate an overload with the templated types replaced with the permuted types.
o := sem.Overload{
Decl: overload.Decl,
Intrinsic: overload.Intrinsic,
@@ -103,15 +104,16 @@
})
}
if overload.ReturnType != nil {
- retTys, err := state.permutateFQN(*overload.ReturnType)
+ retTys, err := state.permuteFQN(*overload.ReturnType)
if err != nil {
- return fmt.Errorf("while permutating return type: %w", err)
+ return fmt.Errorf("while permuting return type: %w", err)
}
if len(retTys) != 1 {
return fmt.Errorf("result type not pinned")
}
o.ReturnType = &retTys[0]
}
+
desc := fmt.Sprint(o)
hash := sha256.Sum256([]byte(desc))
const hashLength = 6
@@ -136,9 +138,9 @@
}
for i, param := range overload.Parameters {
i, param := i, param // Capture iterator values for anonymous function
- next := permutate // Permutation chaining
- permutate = func() error {
- permutations, err := state.permutateFQN(param.Type)
+ next := permute // Permutation chaining
+ permute = func() error {
+ permutations, err := state.permuteFQN(param.Type)
if err != nil {
return fmt.Errorf("while processing parameter %v: %w", i, err)
}
@@ -154,22 +156,24 @@
return nil
}
}
- for _, t := range overload.TemplateParams {
- next := permutate // Permutation chaining
+
+ for _, t := range overload.Templates {
+ t := t // Capture iterator values for anonymous function
+ next := permute // Permutation chaining
switch t := t.(type) {
case *sem.TemplateTypeParam:
- types := p.allTypes
- if t.Type != nil {
- var err error
- types, err = state.permutateFQN(sem.FullyQualifiedName{Target: t.Type})
- if err != nil {
- return nil, fmt.Errorf("while permutating template types: %w", err)
+ permute = func() error {
+ types := p.allTypes
+ if t.Type != nil {
+ var err error
+ types, err = state.permuteFQN(*t.Type)
+ if err != nil {
+ return fmt.Errorf("while permuting template types: %w", err)
+ }
}
- }
- if len(types) == 0 {
- return nil, fmt.Errorf("template type %v has no permutations", t.Name)
- }
- permutate = func() error {
+ if len(types) == 0 {
+ return fmt.Errorf("template type %v has no permutations", t.Name)
+ }
for _, ty := range types {
state.templateTypes[t] = ty
if err := next(); err != nil {
@@ -182,17 +186,17 @@
var permutations []sem.FullyQualifiedName
var err error
if t.Matcher != nil {
- permutations, err = state.permutateFQN(sem.FullyQualifiedName{Target: t.Matcher})
+ permutations, err = state.permuteFQN(sem.FullyQualifiedName{Target: t.Matcher})
} else {
- permutations, err = state.permutateFQN(sem.FullyQualifiedName{Target: t.Enum})
+ permutations, err = state.permuteFQN(sem.FullyQualifiedName{Target: t.Enum})
}
if err != nil {
- return nil, fmt.Errorf("while permutating template numbers: %w", err)
+ return nil, fmt.Errorf("while permuting template numbers: %w", err)
}
if len(permutations) == 0 {
return nil, fmt.Errorf("template type %v has no permutations", t.Name)
}
- permutate = func() error {
+ permute = func() error {
for _, n := range permutations {
state.templateNumbers[t] = n
if err := next(); err != nil {
@@ -204,7 +208,7 @@
case *sem.TemplateNumberParam:
// Currently all open numbers are used for vector / matrices
permutations := []int{2, 3, 4}
- permutate = func() error {
+ permute = func() error {
for _, n := range permutations {
state.templateNumbers[t] = n
if err := next(); err != nil {
@@ -216,7 +220,7 @@
}
}
- if err := permutate(); err != nil {
+ if err := permute(); err != nil {
return nil, fmt.Errorf("%v %v %w\nState: %v", overload.Decl.Source, overload.Decl, err, state)
}
@@ -243,18 +247,18 @@
return sb.String()
}
-func (s *permutationState) permutateFQN(in sem.FullyQualifiedName) ([]sem.FullyQualifiedName, error) {
+func (s *permutationState) permuteFQN(in sem.FullyQualifiedName) ([]sem.FullyQualifiedName, error) {
args := append([]any{}, in.TemplateArguments...)
out := []sem.FullyQualifiedName{}
- // permutate appends a permutation to out.
- // permutate may be chained to generate N-dimensional permutations.
- var permutate func() error
+ // permute appends a permutation to out.
+ // permute may be chained to generate N-dimensional permutations.
+ var permute func() error
switch target := in.Target.(type) {
case *sem.Type:
- permutate = func() error {
- // Inner-most permutate lambda.
+ permute = func() error {
+ // Inner-most permute lambda.
// Append a the current permutation to out
out = append(out, sem.FullyQualifiedName{Target: in.Target, TemplateArguments: args})
// Clone the argument list, for the next permutation to use.
@@ -263,7 +267,7 @@
}
case sem.TemplateParam:
if ty, ok := s.templateTypes[target]; ok {
- permutate = func() error {
+ permute = func() error {
out = append(out, ty)
return nil
}
@@ -271,14 +275,14 @@
return nil, fmt.Errorf("'%v' was not found in templateTypes", target.GetName())
}
case *sem.TypeMatcher:
- permutate = func() error {
+ permute = func() error {
for _, ty := range target.Types {
out = append(out, sem.FullyQualifiedName{Target: ty})
}
return nil
}
case *sem.EnumMatcher:
- permutate = func() error {
+ permute = func() error {
for _, o := range target.Options {
if !o.IsInternal {
out = append(out, sem.FullyQualifiedName{Target: o})
@@ -287,7 +291,7 @@
return nil
}
case *sem.Enum:
- permutate = func() error {
+ permute = func() error {
for _, e := range target.Entries {
if !e.IsInternal {
out = append(out, sem.FullyQualifiedName{Target: e})
@@ -300,8 +304,8 @@
}
for i, arg := range in.TemplateArguments {
- i := i // Capture iterator value for anonymous functions
- next := permutate // Permutation chaining
+ i := i // Capture iterator value for anonymous functions
+ next := permute // Permutation chaining
switch arg := arg.(type) {
case sem.FullyQualifiedName:
switch target := arg.Target.(type) {
@@ -314,14 +318,14 @@
return nil, fmt.Errorf("'%v' was not found in templateTypes or templateNumbers", target.GetName())
}
default:
- perms, err := s.permutateFQN(arg)
+ perms, err := s.permuteFQN(arg)
if err != nil {
return nil, fmt.Errorf("while processing template argument %v: %v", i, err)
}
if len(perms) == 0 {
return nil, fmt.Errorf("template argument %v has no permutations", i)
}
- permutate = func() error {
+ permute = func() error {
for _, f := range perms {
args[i] = f
if err := next(); err != nil {
@@ -332,11 +336,11 @@
}
}
default:
- return nil, fmt.Errorf("permutateFQN() unhandled template argument type: %T", arg)
+ return nil, fmt.Errorf("permuteFQN() unhandled template argument type: %T", arg)
}
}
- if err := permutate(); err != nil {
+ if err := permute(); err != nil {
return nil, fmt.Errorf("while processing fully qualified name '%v': %w", in.Target.GetName(), err)
}
diff --git a/tools/src/tint/intrinsic/parser/parser.go b/tools/src/tint/intrinsic/parser/parser.go
index cacbb13..86379d4 100644
--- a/tools/src/tint/intrinsic/parser/parser.go
+++ b/tools/src/tint/intrinsic/parser/parser.go
@@ -368,8 +368,8 @@
return m
}
-func (p *parser) templateParams() ast.TemplateParams {
- t := ast.TemplateParams{}
+func (p *parser) templateParams() []ast.TemplateParam {
+ t := []ast.TemplateParam{}
p.expect(tok.Lt, "template parameter list")
for p.err == nil && p.peekIs(0, tok.Identifier) {
t = append(t, p.templateParam())
diff --git a/tools/src/tint/intrinsic/parser/parser_test.go b/tools/src/tint/intrinsic/parser/parser_test.go
index 93a9fc1..76ed5cd 100644
--- a/tools/src/tint/intrinsic/parser/parser_test.go
+++ b/tools/src/tint/intrinsic/parser/parser_test.go
@@ -85,7 +85,7 @@
ast.AST{
Types: []ast.TypeDecl{{
Name: "T",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{Name: "A"},
{Name: "B"},
{Name: "C"},
@@ -256,7 +256,7 @@
Builtins: []ast.IntrinsicDecl{{
Kind: ast.Builtin,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -276,7 +276,7 @@
Builtins: []ast.IntrinsicDecl{{
Kind: ast.Builtin,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
@@ -394,7 +394,7 @@
Operators: []ast.IntrinsicDecl{{
Kind: ast.Operator,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -414,7 +414,7 @@
Operators: []ast.IntrinsicDecl{{
Kind: ast.Operator,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
@@ -518,7 +518,7 @@
Constructors: []ast.IntrinsicDecl{{
Kind: ast.Constructor,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -538,7 +538,7 @@
Constructors: []ast.IntrinsicDecl{{
Kind: ast.Constructor,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
@@ -642,7 +642,7 @@
Converters: []ast.IntrinsicDecl{{
Kind: ast.Converter,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
@@ -662,7 +662,7 @@
Converters: []ast.IntrinsicDecl{{
Kind: ast.Converter,
Name: "F",
- TemplateParams: ast.TemplateParams{
+ TemplateParams: []ast.TemplateParam{
{Name: "T"},
},
Parameters: ast.Parameters{
diff --git a/tools/src/tint/intrinsic/resolver/resolve.go b/tools/src/tint/intrinsic/resolver/resolve.go
index 3cf5ece..63e14df 100644
--- a/tools/src/tint/intrinsic/resolver/resolve.go
+++ b/tools/src/tint/intrinsic/resolver/resolve.go
@@ -320,19 +320,19 @@
// Create a new scope for resolving template parameters
s := newScope(&r.globals)
+ // Construct the semantic overload
+ overload := &sem.Overload{
+ Decl: a,
+ Intrinsic: intrinsic,
+ Parameters: make([]sem.Parameter, len(a.Parameters)),
+ }
+
// Resolve the declared template parameters
- templateParams, err := r.templateParams(&s, a.TemplateParams)
+ templates, err := r.templateParams(&s, a.TemplateParams)
if err != nil {
return err
}
-
- // Construct the semantic overload
- overload := &sem.Overload{
- Decl: a,
- Intrinsic: intrinsic,
- Parameters: make([]sem.Parameter, len(a.Parameters)),
- TemplateParams: templateParams,
- }
+ overload.Templates = templates
// Process overload attributes
if stageDeco := a.Attributes.Take("stage"); stageDeco != nil {
@@ -401,23 +401,9 @@
// Append the overload to the intrinsic
intrinsic.Overloads = append(intrinsic.Overloads, overload)
- // Sort the template parameters by resolved type. Append these to
- // sem.Overload.TemplateTypes or sem.Overload.TemplateNumbers based on their kind.
- for _, param := range templateParams {
- switch param := param.(type) {
- case *sem.TemplateTypeParam:
- overload.TemplateTypes = append(overload.TemplateTypes, param)
- case *sem.TemplateEnumParam, *sem.TemplateNumberParam:
- overload.TemplateNumbers = append(overload.TemplateNumbers, param)
- }
- }
-
- // Update high-water marks of template types and numbers
- if r.s.MaxTemplateTypes < len(overload.TemplateTypes) {
- r.s.MaxTemplateTypes = len(overload.TemplateTypes)
- }
- if r.s.MaxTemplateNumbers < len(overload.TemplateNumbers) {
- r.s.MaxTemplateNumbers = len(overload.TemplateNumbers)
+ // Update high-water mark of templates
+ if n := len(overload.Templates); r.s.MaxTemplates < n {
+ r.s.MaxTemplates = n
}
// Resolve the parameters
@@ -476,9 +462,6 @@
if err != nil {
return sem.FullyQualifiedName{}, err
}
- if _, ok := target.(*sem.TypeMatcher); ok {
- return sem.FullyQualifiedName{}, fmt.Errorf("%v type matcher cannot be used directly here. Use a matcher constrained template argument", arg.Source)
- }
fqn := sem.FullyQualifiedName{
Target: target,
TemplateArguments: make([]interface{}, len(arg.TemplateArgs)),
@@ -493,12 +476,12 @@
return fqn, nil
}
-// templateParams() resolves the ast.TemplateParams into list of sem.TemplateParam.
+// templateParams() resolves the ast.TemplateParams list into a sem.TemplateParam list.
// Each sem.TemplateParam is registered with the scope s.
-func (r *resolver) templateParams(s *scope, l ast.TemplateParams) ([]sem.TemplateParam, error) {
- out := []sem.TemplateParam{}
+func (r *resolver) templateParams(s *scope, l []ast.TemplateParam) ([]sem.TemplateParam, error) {
+ out := make([]sem.TemplateParam, 0, len(l))
for _, ast := range l {
- param, err := r.templateParam(ast)
+ param, err := r.templateParam(s, ast)
if err != nil {
return nil, err
}
@@ -510,25 +493,25 @@
// templateParams() resolves the ast.TemplateParam into sem.TemplateParam, which
// is either a sem.TemplateEnumParam or a sem.TemplateTypeParam.
-func (r *resolver) templateParam(a ast.TemplateParam) (sem.TemplateParam, error) {
+func (r *resolver) templateParam(s *scope, a ast.TemplateParam) (sem.TemplateParam, error) {
if a.Type.Name == "num" {
- return &sem.TemplateNumberParam{Name: a.Name}, nil
+ return &sem.TemplateNumberParam{Name: a.Name, ASTParam: a}, nil
}
if a.Type.Name != "" {
- resolved, err := r.lookupNamed(&r.globals, a.Type)
+ resolved, err := r.fullyQualifiedName(s, a.Type)
if err != nil {
return nil, err
}
- switch r := resolved.(type) {
+ switch r := resolved.Target.(type) {
case *sem.Enum:
- return &sem.TemplateEnumParam{Name: a.Name, Enum: r}, nil
+ return &sem.TemplateEnumParam{Name: a.Name, ASTParam: a, Enum: r}, nil
case *sem.EnumMatcher:
- return &sem.TemplateEnumParam{Name: a.Name, Enum: r.Enum, Matcher: r}, nil
+ return &sem.TemplateEnumParam{Name: a.Name, ASTParam: a, Enum: r.Enum, Matcher: r}, nil
case *sem.TypeMatcher:
- return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
+ return &sem.TemplateTypeParam{Name: a.Name, ASTParam: a, Type: &resolved}, nil
case *sem.Type:
- return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
+ return &sem.TemplateTypeParam{Name: a.Name, ASTParam: a, Type: &resolved}, nil
default:
return nil, fmt.Errorf("%v invalid template parameter type '%v'", a.Source, a.Type.Name)
}
@@ -708,7 +691,7 @@
switch n := n.(type) {
case *sem.TemplateTypeParam:
if n.Type != nil {
- return n.Type
+ return n.Type.Target.(sem.ResolvableType)
}
return anyType
case *sem.Type:
diff --git a/tools/src/tint/intrinsic/resolver/resolver_test.go b/tools/src/tint/intrinsic/resolver/resolver_test.go
index 273a09a..294691a 100644
--- a/tools/src/tint/intrinsic/resolver/resolver_test.go
+++ b/tools/src/tint/intrinsic/resolver/resolver_test.go
@@ -196,6 +196,20 @@
@must_use fn f() -> f32`,
success,
}, {
+ `
+type f32
+type P<T>
+match m: f32
+fn f(m)`,
+ success,
+ }, {
+ `
+type f32
+type P<T>
+match m: f32
+fn f(P<m>)`,
+ success,
+ }, {
`enum E {A A}`,
`
file.txt:1:11 duplicate enum entry 'A'
@@ -524,20 +538,6 @@
`file.txt:4:16 cannot use template enum 'E' as template number`,
}, {
`
-type f32
-type P<T>
-match m: f32
-fn f(m)`,
- `file.txt:4:6 type matcher cannot be used directly here. Use a matcher constrained template argument`,
- }, {
- `
-type f32
-type P<T>
-match m: f32
-fn f(P<m>)`,
- `file.txt:4:8 type matcher cannot be used directly here. Use a matcher constrained template argument`,
- }, {
- `
@must_use fn f()`,
`file.txt:1:2 @must_use can only be used on a function with a return type`,
},
diff --git a/tools/src/tint/intrinsic/sem/sem.go b/tools/src/tint/intrinsic/sem/sem.go
index e440e01..4b9d8f3 100644
--- a/tools/src/tint/intrinsic/sem/sem.go
+++ b/tools/src/tint/intrinsic/sem/sem.go
@@ -46,9 +46,7 @@
BinaryOperators []*Intrinsic
ConstructorsAndConverters []*Intrinsic
// Maximum number of template types used across all builtins
- MaxTemplateTypes int
- // Maximum number of template numbers used across all builtins
- MaxTemplateNumbers int
+ MaxTemplates int
// The alphabetically sorted list of unique parameter names
UniqueParameterNames []string
}
@@ -161,22 +159,68 @@
Options []*EnumEntry
}
-// TemplateEnumParam is a template enum parameter
-type TemplateEnumParam struct {
- Name string
- Enum *Enum
- Matcher *EnumMatcher // Optional
-}
+// TemplateKind is an enumerator of template kinds.
+type TemplateKind string
+
+const (
+ // A templated type
+ TypeTemplate TemplateKind = "Type"
+ // A templated number
+ NumberTemplate TemplateKind = "Number"
+)
// TemplateTypeParam is a template type parameter
type TemplateTypeParam struct {
- Name string
- Type ResolvableType
+ Name string
+ ASTParam ast.TemplateParam
+ Type *FullyQualifiedName
+}
+
+func (t *TemplateTypeParam) AST() ast.TemplateParam { return t.ASTParam }
+func (t *TemplateTypeParam) TemplateKind() TemplateKind { return TypeTemplate }
+
+// Format implements the fmt.Formatter interface
+func (t *TemplateTypeParam) Format(w fmt.State, verb rune) {
+ fmt.Fprint(w, t.Name)
+ if t.Type != nil {
+ fmt.Fprint(w, ": ")
+ fmt.Fprint(w, *t.Type)
+ }
+}
+
+// TemplateEnumParam is a template enum parameter
+type TemplateEnumParam struct {
+ Name string
+ ASTParam ast.TemplateParam
+ Enum *Enum
+ Matcher *EnumMatcher // Optional
+}
+
+func (t *TemplateEnumParam) AST() ast.TemplateParam { return t.ASTParam }
+func (t *TemplateEnumParam) TemplateKind() TemplateKind { return NumberTemplate }
+
+// Format implements the fmt.Formatter interface
+func (t *TemplateEnumParam) Format(w fmt.State, verb rune) {
+ fmt.Fprint(w, t.Name)
+ if t.Enum != nil {
+ fmt.Fprint(w, ": ")
+ fmt.Fprint(w, *t.Enum)
+ }
}
// TemplateNumberParam is a template type parameter
type TemplateNumberParam struct {
- Name string
+ Name string
+ ASTParam ast.TemplateParam
+}
+
+func (t *TemplateNumberParam) AST() ast.TemplateParam { return t.ASTParam }
+func (t *TemplateNumberParam) TemplateKind() TemplateKind { return NumberTemplate }
+
+// Format implements the fmt.Formatter interface
+func (t *TemplateNumberParam) Format(w fmt.State, verb rune) {
+ fmt.Fprint(w, t.Name)
+ fmt.Fprint(w, ": num")
}
// Intrinsic describes the overloads of a builtin or operator
@@ -185,13 +229,36 @@
Overloads []*Overload
}
+// IntrinsicTemplates is a list of TemplateParam, used by an Intrinsic.
+type IntrinsicTemplates []TemplateParam
+
+// Types() returns all the template type parameters
+func (t IntrinsicTemplates) Types() []*TemplateTypeParam {
+ out := []*TemplateTypeParam{}
+ for _, p := range t {
+ if ty, ok := p.(*TemplateTypeParam); ok {
+ out = append(out, ty)
+ }
+ }
+ return out
+}
+
+// Numbers() returns all the template number parameters.
+func (t IntrinsicTemplates) Numbers() []TemplateParam {
+ out := []TemplateParam{}
+ for _, p := range t {
+ if _, ok := p.(*TemplateTypeParam); !ok {
+ out = append(out, p)
+ }
+ }
+ return out
+}
+
// Overload describes a single overload of a builtin or operator
type Overload struct {
Decl ast.IntrinsicDecl
Intrinsic *Intrinsic
- TemplateParams []TemplateParam
- TemplateTypes []*TemplateTypeParam
- TemplateNumbers []TemplateParam
+ Templates IntrinsicTemplates
ReturnType *FullyQualifiedName
Parameters []Parameter
CanBeUsedInStage StageUses
@@ -231,14 +298,9 @@
fmt.Fprintf(w, "op ")
}
fmt.Fprintf(w, "%v", o.Intrinsic.Name)
- if len(o.TemplateParams) > 0 {
+ if len(o.Templates) > 0 {
fmt.Fprintf(w, "<")
- for i, t := range o.TemplateParams {
- if i > 0 {
- fmt.Fprint(w, ", ")
- }
- fmt.Fprintf(w, "%v", t)
- }
+ formatList(w, o.Templates)
fmt.Fprintf(w, ">")
}
fmt.Fprint(w, "(")
@@ -284,12 +346,7 @@
fmt.Fprint(w, f.Target.GetName())
if len(f.TemplateArguments) > 0 {
fmt.Fprintf(w, "<")
- for i, t := range f.TemplateArguments {
- if i > 0 {
- fmt.Fprint(w, ", ")
- }
- fmt.Fprintf(w, "%v", t)
- }
+ formatList(w, f.TemplateArguments)
fmt.Fprintf(w, ">")
}
}
@@ -297,13 +354,10 @@
// TemplateParam is a TemplateEnumParam, TemplateTypeParam or TemplateNumberParam
type TemplateParam interface {
Named
- isTemplateParam()
+ TemplateKind() TemplateKind
+ AST() ast.TemplateParam
}
-func (*TemplateEnumParam) isTemplateParam() {}
-func (*TemplateTypeParam) isTemplateParam() {}
-func (*TemplateNumberParam) isTemplateParam() {}
-
// ResolvableType is a Type, TypeMatcher or TemplateTypeParam
type ResolvableType interface {
Named
@@ -352,3 +406,13 @@
// 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 {
+ fmt.Fprint(w, ", ")
+ }
+ fmt.Fprintf(w, "%v", v)
+ }
+}