tint: Add type constructors and converters support to intrinsic-gen
These are currently not used, but the first step towards moving type
constructors and converters over to using the intrinisc table.
This will simplify maintenance of type functions, and will greatly
simplify the [AbstractInt -> i32|u32] [AbstractFloat -> f32|f16] logic.
Bug: tint:1504
Change-Id: I15526670a6ff801e66551ab5adc37b1570ac49de
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90242
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/tools/src/cmd/intrinsic-gen/ast/ast.go b/tools/src/cmd/intrinsic-gen/ast/ast.go
index da78d96..75b74c7 100644
--- a/tools/src/cmd/intrinsic-gen/ast/ast.go
+++ b/tools/src/cmd/intrinsic-gen/ast/ast.go
@@ -25,11 +25,13 @@
// AST is the parsed syntax tree of the intrinsic definition file
type AST struct {
- Enums []EnumDecl
- Types []TypeDecl
- Matchers []MatcherDecl
- Builtins []IntrinsicDecl
- Operators []IntrinsicDecl
+ Enums []EnumDecl
+ Types []TypeDecl
+ Matchers []MatcherDecl
+ Builtins []IntrinsicDecl
+ Constructors []IntrinsicDecl
+ Converters []IntrinsicDecl
+ Operators []IntrinsicDecl
}
func (a AST) String() string {
@@ -50,6 +52,14 @@
fmt.Fprintf(&sb, "%v", b)
fmt.Fprintln(&sb)
}
+ for _, o := range a.Constructors {
+ fmt.Fprintf(&sb, "%v", o)
+ fmt.Fprintln(&sb)
+ }
+ for _, o := range a.Converters {
+ fmt.Fprintf(&sb, "%v", o)
+ fmt.Fprintln(&sb)
+ }
for _, o := range a.Operators {
fmt.Fprintf(&sb, "%v", o)
fmt.Fprintln(&sb)
@@ -103,7 +113,7 @@
m.Options.Format(w, verb)
}
-// IntrinsicKind is either a Builtin or Operator
+// IntrinsicKind is either a Builtin, Operator, Constructor or Converter
type IntrinsicKind string
const (
@@ -113,6 +123,12 @@
// Operator is a unary or binary operator.
// Declared with 'op'.
Operator IntrinsicKind = "operator"
+ // Constructor is a type constructor function.
+ // Declared with 'ctor'.
+ Constructor IntrinsicKind = "constructor"
+ // Converter is a type conversion function.
+ // Declared with 'conv'.
+ Converter IntrinsicKind = "converter"
)
// IntrinsicDecl describes a builtin or operator declaration
@@ -133,6 +149,10 @@
fmt.Fprintf(w, "fn ")
case Operator:
fmt.Fprintf(w, "op ")
+ case Constructor:
+ fmt.Fprintf(w, "ctor ")
+ case Converter:
+ fmt.Fprintf(w, "conv ")
}
fmt.Fprintf(w, "%v", i.Name)
i.TemplateParams.Format(w, verb)
diff --git a/tools/src/cmd/intrinsic-gen/gen/builtin_table.go b/tools/src/cmd/intrinsic-gen/gen/builtin_table.go
index 8d6e4da..502b690 100644
--- a/tools/src/cmd/intrinsic-gen/gen/builtin_table.go
+++ b/tools/src/cmd/intrinsic-gen/gen/builtin_table.go
@@ -37,14 +37,15 @@
NMatchers []sem.Named
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
- MatcherIndices []int // kMatcherIndices table content
- OpenTypes []OpenType // kOpenTypes table content
- OpenNumbers []OpenNumber // kOpenNumbers 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
+ MatcherIndices []int // kMatcherIndices table content
+ OpenTypes []OpenType // kOpenTypes table content
+ OpenNumbers []OpenNumber // kOpenNumbers 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 // kConstructorsAndConverters table content
}
// OpenType is used to create the C++ OpenTypeInfo structure
@@ -372,6 +373,7 @@
{s.Builtins, &b.Builtins},
{s.UnaryOperators, &b.UnaryOperators},
{s.BinaryOperators, &b.BinaryOperators},
+ {s.ConstructorsAndConverters, &b.ConstructorsAndConverters},
} {
out := make([]Intrinsic, len(intrinsics.in))
for i, f := range intrinsics.in {
diff --git a/tools/src/cmd/intrinsic-gen/lexer/lexer.go b/tools/src/cmd/intrinsic-gen/lexer/lexer.go
index aeffe04..a81875e 100644
--- a/tools/src/cmd/intrinsic-gen/lexer/lexer.go
+++ b/tools/src/cmd/intrinsic-gen/lexer/lexer.go
@@ -97,6 +97,8 @@
case l.match("op", tok.Operator):
case l.match("enum", tok.Enum):
case l.match("type", tok.Type):
+ case l.match("ctor", tok.Constructor):
+ case l.match("conv", tok.Converter):
case l.match("match", tok.Match):
case unicode.IsLetter(l.peek(0)) || l.peek(0) == '_':
l.tok(l.count(alphaNumericOrUnderscore), tok.Identifier)
diff --git a/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go b/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go
index 1c6a2ae..f17eb23 100644
--- a/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go
+++ b/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go
@@ -58,6 +58,12 @@
{"type", tok.Token{Kind: tok.Type, Runes: []rune("type"), Source: tok.Source{
S: loc(1, 1, 0), E: loc(1, 5, 4),
}}},
+ {"ctor", tok.Token{Kind: tok.Constructor, Runes: []rune("ctor"), Source: tok.Source{
+ S: loc(1, 1, 0), E: loc(1, 5, 4),
+ }}},
+ {"conv", tok.Token{Kind: tok.Converter, Runes: []rune("conv"), Source: tok.Source{
+ S: loc(1, 1, 0), E: loc(1, 5, 4),
+ }}},
{"enum", tok.Token{Kind: tok.Enum, Runes: []rune("enum"), Source: tok.Source{
S: loc(1, 1, 0), E: loc(1, 5, 4),
}}},
diff --git a/tools/src/cmd/intrinsic-gen/parser/parser.go b/tools/src/cmd/intrinsic-gen/parser/parser.go
index 48c8a94..a93d966 100644
--- a/tools/src/cmd/intrinsic-gen/parser/parser.go
+++ b/tools/src/cmd/intrinsic-gen/parser/parser.go
@@ -71,6 +71,12 @@
case tok.Operator:
out.Operators = append(out.Operators, p.operatorDecl(decorations))
decorations = nil
+ case tok.Constructor:
+ out.Constructors = append(out.Constructors, p.constructorDecl(decorations))
+ decorations = nil
+ case tok.Converter:
+ out.Converters = append(out.Converters, p.converterDecl(decorations))
+ decorations = nil
default:
p.err = fmt.Errorf("%v unexpected token '%v'", t.Source, t.Kind)
}
@@ -195,6 +201,47 @@
}
return f
}
+
+func (p *parser) constructorDecl(decos ast.Decorations) ast.IntrinsicDecl {
+ p.expect(tok.Constructor, "constructor declaration")
+ name := p.next()
+ f := ast.IntrinsicDecl{
+ Source: name.Source,
+ Kind: ast.Constructor,
+ Decorations: decos,
+ Name: string(name.Runes),
+ }
+ if p.peekIs(0, tok.Lt) {
+ f.TemplateParams = p.templateParams()
+ }
+ f.Parameters = p.parameters()
+ if p.match(tok.Arrow) != nil {
+ ret := p.templatedName()
+ f.ReturnType = &ret
+ }
+ return f
+}
+
+func (p *parser) converterDecl(decos ast.Decorations) ast.IntrinsicDecl {
+ p.expect(tok.Converter, "converter declaration")
+ name := p.next()
+ f := ast.IntrinsicDecl{
+ Source: name.Source,
+ Kind: ast.Converter,
+ Decorations: decos,
+ Name: string(name.Runes),
+ }
+ if p.peekIs(0, tok.Lt) {
+ f.TemplateParams = p.templateParams()
+ }
+ f.Parameters = p.parameters()
+ if p.match(tok.Arrow) != nil {
+ ret := p.templatedName()
+ f.ReturnType = &ret
+ }
+ return f
+}
+
func (p *parser) parameters() ast.Parameters {
l := ast.Parameters{}
p.expect(tok.Lparen, "function parameter list")
diff --git a/tools/src/cmd/intrinsic-gen/parser/parser_test.go b/tools/src/cmd/intrinsic-gen/parser/parser_test.go
index 9ea76c3..0c01f7c 100644
--- a/tools/src/cmd/intrinsic-gen/parser/parser_test.go
+++ b/tools/src/cmd/intrinsic-gen/parser/parser_test.go
@@ -370,6 +370,254 @@
},
Parameters: ast.Parameters{},
}},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F()",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "[[deco]] ctor F()",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ Decorations: ast.Decorations{
+ {Name: "deco", Values: []string{}},
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F(a)",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Type: ast.TemplatedName{Name: "a"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F(a: T)",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "T"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F(a, b)",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Type: ast.TemplatedName{Name: "a"}},
+ {Type: ast.TemplatedName{Name: "b"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F<A : B<C> >()",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ TemplateParams: ast.TemplateParams{
+ {
+ Name: "A", Type: ast.TemplatedName{
+ Name: "B",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "C"},
+ },
+ },
+ },
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F<T>(a: X, b: Y<T>)",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ TemplateParams: ast.TemplateParams{
+ {Name: "T"},
+ },
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "X"}},
+ {Name: "b", Type: ast.TemplatedName{
+ Name: "Y",
+ TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ }},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F() -> X",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ ReturnType: &ast.TemplatedName{Name: "X"},
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "ctor F() -> X<T>",
+ ast.AST{
+ Constructors: []ast.IntrinsicDecl{{
+ Kind: ast.Constructor,
+ Name: "F",
+ ReturnType: &ast.TemplatedName{
+ Name: "X",
+ TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F()",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "[[deco]] conv F()",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ Decorations: ast.Decorations{
+ {Name: "deco", Values: []string{}},
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F(a)",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Type: ast.TemplatedName{Name: "a"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F(a: T)",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "T"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F(a, b)",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ Parameters: ast.Parameters{
+ {Type: ast.TemplatedName{Name: "a"}},
+ {Type: ast.TemplatedName{Name: "b"}},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F<A : B<C> >()",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ TemplateParams: ast.TemplateParams{
+ {
+ Name: "A", Type: ast.TemplatedName{
+ Name: "B",
+ TemplateArgs: ast.TemplatedNames{
+ {Name: "C"},
+ },
+ },
+ },
+ },
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F<T>(a: X, b: Y<T>)",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ TemplateParams: ast.TemplateParams{
+ {Name: "T"},
+ },
+ Parameters: ast.Parameters{
+ {Name: "a", Type: ast.TemplatedName{Name: "X"}},
+ {Name: "b", Type: ast.TemplatedName{
+ Name: "Y",
+ TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ }},
+ },
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F() -> X",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ ReturnType: &ast.TemplatedName{Name: "X"},
+ Parameters: ast.Parameters{},
+ }},
+ },
+ }, { ///////////////////////////////////////////////////////////////////
+ utils.ThisLine(),
+ "conv F() -> X<T>",
+ ast.AST{
+ Converters: []ast.IntrinsicDecl{{
+ Kind: ast.Converter,
+ Name: "F",
+ ReturnType: &ast.TemplatedName{
+ Name: "X",
+ TemplateArgs: []ast.TemplatedName{{Name: "T"}},
+ },
+ Parameters: ast.Parameters{},
+ }},
}},
} {
got, err := parser.Parse(test.src, "file.txt")
diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolve.go b/tools/src/cmd/intrinsic-gen/resolver/resolve.go
index 52a8140..68b9dee 100644
--- a/tools/src/cmd/intrinsic-gen/resolver/resolve.go
+++ b/tools/src/cmd/intrinsic-gen/resolver/resolve.go
@@ -27,23 +27,25 @@
a *ast.AST
s *sem.Sem
- globals scope
- builtins map[string]*sem.Intrinsic
- unaryOperators map[string]*sem.Intrinsic
- binaryOperators map[string]*sem.Intrinsic
- enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
+ globals scope
+ builtins map[string]*sem.Intrinsic
+ unaryOperators map[string]*sem.Intrinsic
+ binaryOperators map[string]*sem.Intrinsic
+ constructorsAndConverters map[string]*sem.Intrinsic
+ enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
}
// Resolve processes the AST
func Resolve(a *ast.AST) (*sem.Sem, error) {
r := resolver{
- a: a,
- s: sem.New(),
- globals: newScope(nil),
- builtins: map[string]*sem.Intrinsic{},
- unaryOperators: map[string]*sem.Intrinsic{},
- binaryOperators: map[string]*sem.Intrinsic{},
- enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
+ a: a,
+ s: sem.New(),
+ globals: newScope(nil),
+ builtins: map[string]*sem.Intrinsic{},
+ unaryOperators: map[string]*sem.Intrinsic{},
+ binaryOperators: map[string]*sem.Intrinsic{},
+ constructorsAndConverters: map[string]*sem.Intrinsic{},
+ enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
}
// Declare and resolve all the enumerators
for _, e := range a.Enums {
@@ -85,6 +87,21 @@
}
}
+ // Declare and resolve type constructors and converters
+ for _, c := range a.Constructors {
+ if err := r.intrinsic(c, r.constructorsAndConverters, &r.s.ConstructorsAndConverters); err != nil {
+ return nil, err
+ }
+ }
+ for _, c := range a.Converters {
+ if len(c.Parameters) != 1 {
+ return nil, fmt.Errorf("%v conversions must have a single parameter", c.Source)
+ }
+ if err := r.intrinsic(c, r.constructorsAndConverters, &r.s.ConstructorsAndConverters); err != nil {
+ return nil, err
+ }
+ }
+
// Calculate the unique parameter names
r.s.UniqueParameterNames = r.calculateUniqueParameterNames()
@@ -440,6 +457,8 @@
return &sem.TemplateEnumParam{Name: a.Name, Enum: r.Enum, Matcher: r}, nil
case *sem.TypeMatcher:
return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
+ case *sem.Type:
+ return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
default:
return nil, fmt.Errorf("%v invalid template parameter type '%v'", a.Source, a.Type.Name)
}
@@ -525,6 +544,7 @@
r.s.Builtins,
r.s.UnaryOperators,
r.s.BinaryOperators,
+ r.s.ConstructorsAndConverters,
} {
for _, i := range intrinsics {
for _, o := range i.Overloads {
diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
index 9f3aac0..7ce9236 100644
--- a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
+++ b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
@@ -142,6 +142,40 @@
fn f(T< T<f32> >)`,
success,
}, {
+ `
+type f32
+op -(f32)`,
+ success,
+ }, {
+ `
+type f32
+type T<x>
+op +(T<f32>, T<f32>)`,
+ success,
+ }, {
+ `
+type f32
+ctor f32(f32)`,
+ success,
+ }, {
+ `
+type f32
+type T<x>
+ctor f32(T<f32>)`,
+ success,
+ }, {
+ `
+type f32
+type i32
+conv f32(i32)`,
+ success,
+ }, {
+ `
+type f32
+type T<x>
+conv f32(T<f32>)`,
+ success,
+ }, {
`enum E {A A}`,
`
file.txt:1:6 'A' already declared
@@ -363,6 +397,125 @@
`file.txt:4:16 cannot use template enum 'E' as template number`,
}, {
`
+type i
+enum e { a }
+ctor F(i) -> e`,
+ `file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`,
+ }, {
+ `
+type T<x>
+ctor F(T<u>)`,
+ `file.txt:2:10 cannot resolve 'u'`,
+ }, {
+ `
+type x
+ctor F<T>(T<x>)`,
+ `file.txt:2:11 'T' template parameters do not accept template arguments`,
+ }, {
+ `
+type A<N: num>
+type B
+ctor F(A<B>)`,
+ `file.txt:3:10 cannot use type 'B' as template number`,
+ }, {
+ `
+type A<N>
+enum E { b }
+ctor F(A<b>)`,
+ `file.txt:3:10 cannot use enum entry 'E.b' as template type`,
+ }, {
+ `
+type T
+type P<N: num>
+match m: T
+ctor F(P<m>)`,
+ `file.txt:4:10 cannot use type matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { b }
+ctor F(P<E>)`,
+ `file.txt:3:10 cannot use enum 'E' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+ctor F(P<m>)`,
+ `file.txt:4:10 cannot use enum matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+ctor F<M: m>(P<M>)`,
+ `file.txt:4:16 cannot use template enum 'E' as template number`,
+ }, {
+ `
+conv F()`,
+ `file.txt:1:6 conversions must have a single parameter`,
+ }, {
+ `
+type i
+conv F(i, i, i)`,
+ `file.txt:2:6 conversions must have a single parameter`,
+ }, {
+ `
+type i
+enum e { a }
+conv F(i) -> e`,
+ `file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`,
+ }, {
+ `
+type T<x>
+conv F(T<u>)`,
+ `file.txt:2:10 cannot resolve 'u'`,
+ }, {
+ `
+type x
+conv F<T>(T<x>)`,
+ `file.txt:2:11 'T' template parameters do not accept template arguments`,
+ }, {
+ `
+type A<N: num>
+type B
+conv F(A<B>)`,
+ `file.txt:3:10 cannot use type 'B' as template number`,
+ }, {
+ `
+type A<N>
+enum E { b }
+conv F(A<b>)`,
+ `file.txt:3:10 cannot use enum entry 'E.b' as template type`,
+ }, {
+ `
+type T
+type P<N: num>
+match m: T
+conv F(P<m>)`,
+ `file.txt:4:10 cannot use type matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { b }
+conv F(P<E>)`,
+ `file.txt:3:10 cannot use enum 'E' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+conv F(P<m>)`,
+ `file.txt:4:10 cannot use enum matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+conv F<M: m>(P<M>)`,
+ `file.txt:4:16 cannot use template enum 'E' as template number`,
+ }, {
+ `
enum E { a }
type T<X: a>`,
`file.txt:2:8 invalid template parameter type 'a'`,
diff --git a/tools/src/cmd/intrinsic-gen/sem/sem.go b/tools/src/cmd/intrinsic-gen/sem/sem.go
index 33abb42..f61f218 100644
--- a/tools/src/cmd/intrinsic-gen/sem/sem.go
+++ b/tools/src/cmd/intrinsic-gen/sem/sem.go
@@ -22,13 +22,14 @@
// Sem is the root of the semantic tree
type Sem struct {
- Enums []*Enum
- Types []*Type
- TypeMatchers []*TypeMatcher
- EnumMatchers []*EnumMatcher
- Builtins []*Intrinsic
- UnaryOperators []*Intrinsic
- BinaryOperators []*Intrinsic
+ Enums []*Enum
+ Types []*Type
+ TypeMatchers []*TypeMatcher
+ EnumMatchers []*EnumMatcher
+ Builtins []*Intrinsic
+ UnaryOperators []*Intrinsic
+ BinaryOperators []*Intrinsic
+ ConstructorsAndConverters []*Intrinsic
// Maximum number of open-types used across all builtins
MaxOpenTypes int
// Maximum number of open-numbers used across all builtins
diff --git a/tools/src/cmd/intrinsic-gen/tok/tok.go b/tools/src/cmd/intrinsic-gen/tok/tok.go
index f152527..c5def48 100644
--- a/tools/src/cmd/intrinsic-gen/tok/tok.go
+++ b/tools/src/cmd/intrinsic-gen/tok/tok.go
@@ -30,6 +30,8 @@
Match Kind = "match"
Function Kind = "fn"
Operator Kind = "op"
+ Constructor Kind = "ctor"
+ Converter Kind = "conv"
Type Kind = "type"
Enum Kind = "enum"
And Kind = "&"