p.next()
}
-func (p *parser) allowGenerics() bool { return p.mode&typeparams.DisallowParsing == 0 }
-func (p *parser) allowTypeSets() bool { return p.mode&typeparams.DisallowTypeSets == 0 }
-
// ----------------------------------------------------------------------------
// Parsing support
}
typ := p.parseTypeName(ident)
- if p.tok == token.LBRACK && p.allowGenerics() {
+ if p.tok == token.LBRACK {
typ = p.parseTypeInstance(typ)
}
// list such as T[P,]? (We do in parseTypeInstance).
lbrack := p.expect(token.LBRACK)
var args []ast.Expr
- var firstComma token.Pos
- // TODO(rfindley): consider changing parseRhsOrType so that this function variable
- // is not needed.
- argparser := p.parseRhsOrType
- if !p.allowGenerics() {
- argparser = p.parseRhs
- }
if p.tok != token.RBRACK {
p.exprLev++
- args = append(args, argparser())
+ args = append(args, p.parseRhsOrType())
for p.tok == token.COMMA {
- if !firstComma.IsValid() {
- firstComma = p.pos
- }
p.next()
- args = append(args, argparser())
+ args = append(args, p.parseRhsOrType())
}
p.exprLev--
}
// x [P]E
return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
}
- if !p.allowGenerics() {
- p.error(rbrack, "missing element type in array type expression")
- return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
- }
- }
-
- if !p.allowGenerics() {
- p.error(firstComma, "expected ']', found ','")
- return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
}
// x[P], x[P1, P2], ...
// Type parameters are the only parameter list closed by ']'.
tparams := closing == token.RBRACK
// Type set notation is ok in type parameter lists.
- typeSetsOK := tparams && p.allowTypeSets()
+ typeSetsOK := tparams
pos := p.pos
if name0 != nil {
defer un(trace(p, "Parameters"))
}
- if p.allowGenerics() && acceptTParams && p.tok == token.LBRACK {
+ if acceptTParams && p.tok == token.LBRACK {
opening := p.pos
p.next()
// [T any](params) syntax
x := p.parseTypeName(nil)
if ident, _ := x.(*ast.Ident); ident != nil {
switch {
- case p.tok == token.LBRACK && p.allowGenerics():
+ case p.tok == token.LBRACK:
// generic method or embedded instantiated type
lbrack := p.pos
p.next()
} else {
// embedded, possibly instantiated type
typ = x
- if p.tok == token.LBRACK && p.allowGenerics() {
+ if p.tok == token.LBRACK {
// embedded instantiated interface
typ = p.parseTypeInstance(typ)
}
switch {
case p.tok == token.IDENT:
f := p.parseMethodSpec()
- if f.Names == nil && p.allowGenerics() {
+ if f.Names == nil {
f.Type = p.embeddedElem(f.Type)
}
p.expectSemi()
f.Comment = p.lineComment
list = append(list, f)
- case p.tok == token.TILDE && p.allowGenerics():
+ case p.tok == token.TILDE:
typ := p.embeddedElem(nil)
p.expectSemi()
comment := p.lineComment
list = append(list, &ast.Field{Type: typ, Comment: comment})
- case p.allowGenerics():
+ default:
if t := p.tryIdentOrType(); t != nil {
typ := p.embeddedElem(t)
p.expectSemi()
} else {
break parseElements
}
- default:
- break parseElements
}
}
}
func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
- assert(p.allowGenerics(), "parseTypeInstance while not parsing type params")
if p.trace {
defer un(trace(p, "TypeInstance"))
}
switch p.tok {
case token.IDENT:
typ := p.parseTypeName(nil)
- if p.tok == token.LBRACK && p.allowGenerics() {
+ if p.tok == token.LBRACK {
typ = p.parseTypeInstance(typ)
}
return typ
var args []ast.Expr
var index [N]ast.Expr
var colons [N - 1]token.Pos
- var firstComma token.Pos
if p.tok != token.COLON {
// We can't know if we have an index expression or a type instantiation;
// so even if we see a (named) type we are not going to be in type context.
}
}
case token.COMMA:
- firstComma = p.pos
// instance expression
args = append(args, index[0])
for p.tok == token.COMMA {
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
}
- if !p.allowGenerics() {
- p.error(firstComma, "expected ']' or ':', found ','")
- return &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
- }
-
// instance expression
return typeparams.PackIndexExpr(x, lbrack, args, rbrack)
}
name := p.parseIdent()
spec := &ast.TypeSpec{Doc: doc, Name: name}
- if p.tok == token.LBRACK && p.allowGenerics() {
+ if p.tok == token.LBRACK {
// spec.Name "[" ...
// array/slice type or type parameter list
lbrack := p.pos
package parser
-import (
- "go/internal/typeparams"
- "testing"
-)
+import "testing"
var valids = []string{
"package p\n",
`package p; type _ struct{ f [n]E }`,
`package p; type _ struct{ f [a+b+c+d]E }`,
`package p; type I1 interface{}; type I2 interface{ I1 }`,
-}
-// validWithTParamsOnly holds source code examples that are valid if
-// parseTypeParams is set, but invalid if not. When checking with the
-// parseTypeParams set, errors are ignored.
-var validWithTParamsOnly = []string{
- `package p; type _ []T[ /* ERROR "expected ';', found '\['" */ int]`,
- `package p; type T[P any /* ERROR "expected ']', found any" */ ] struct { P }`,
- `package p; type T[P comparable /* ERROR "expected ']', found comparable" */ ] struct { P }`,
- `package p; type T[P comparable /* ERROR "expected ']', found comparable" */ [P]] struct { P }`,
- `package p; type T[P1, /* ERROR "unexpected comma" */ P2 any] struct { P1; f []P2 }`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()()`,
+ // generic code
+ `package p; type _ []T[int]`,
+ `package p; type T[P any] struct { P }`,
+ `package p; type T[P comparable] struct { P }`,
+ `package p; type T[P comparable[P]] struct { P }`,
+ `package p; type T[P1, P2 any] struct { P1; f []P2 }`,
+ `package p; func _[T any]()()`,
`package p; func _(T (P))`,
- `package p; func f[ /* ERROR "expected '\(', found '\['" */ A, B any](); func _() { _ = f[int, int] }`,
- `package p; func _(x /* ERROR "mixed named and unnamed parameters" */ T[P1, P2, P3])`,
- `package p; func _(x /* ERROR "mixed named and unnamed parameters" */ p.T[Q])`,
- `package p; func _(p.T[ /* ERROR "missing ',' in parameter list" */ Q])`,
- `package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {},] struct{}`,
- `package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {}] struct{}`,
- `package p; type _[A, /* ERROR "unexpected comma" */ B any,] struct{}`,
- `package p; type _[A, /* ERROR "unexpected comma" */ B any] struct{}`,
- `package p; type _[A any /* ERROR "expected ']', found any" */,] struct{}`,
- `package p; type _[A any /* ERROR "expected ']', found any" */ ]struct{}`,
- `package p; type _[A any /* ERROR "expected ']', found any" */ ] struct{ A }`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any](x T)`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 any](x T)`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
-
- `package p; type _[A, /* ERROR "unexpected comma" */ B any] interface { _(a A) B }`,
- `package p; type _[A, /* ERROR "unexpected comma" */ B C[A, B]] interface { _(a A) B }`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 interface{}](x T1) T2`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
- `package p; var _ = [ /* ERROR "expected expression" */ ]T[int]{}`,
- `package p; var _ = [ /* ERROR "expected expression" */ 10]T[int]{}`,
- `package p; var _ = func /* ERROR "expected expression" */ ()T[int]{}`,
- `package p; var _ = map /* ERROR "expected expression" */ [T[int]]T[int]{}`,
- `package p; var _ = chan /* ERROR "expected expression" */ T[int](x)`,
- `package p; func _(_ T[ /* ERROR "missing ',' in parameter list" */ P], T P) T[P]`,
- `package p; var _ T[ /* ERROR "expected ';', found '\['" */ chan int]`,
-
- // TODO(rfindley) this error message could be improved.
- `package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[P]) _(x T)`,
- `package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[ P, Q]) _(x T)`,
-
- `package p; func (R[P] /* ERROR "missing element type" */ ) _()`,
- `package p; func _(T[P] /* ERROR "missing element type" */ )`,
- `package p; func _(T[P1, /* ERROR "expected ']', found ','" */ P2, P3 ])`,
- `package p; func _(T[P] /* ERROR "missing element type" */ ) T[P]`,
- `package p; type _ struct{ T[P] /* ERROR "missing element type" */ }`,
- `package p; type _ struct{ T[struct /* ERROR "expected expression" */ {a, b, c int}] }`,
- `package p; type _ interface{int| /* ERROR "expected ';'" */ float32; bool; m(); string;}`,
- `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2 interface{ I1[int] }`,
- `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2[T any] interface{ I1[T] }`,
- `package p; type _ interface { N[ /* ERROR "expected ';', found '\['" */ T] }`,
- `package p; type T[P any /* ERROR "expected ']'" */ ] = T0`,
+ `package p; func f[A, B any](); func _() { _ = f[int, int] }`,
+ `package p; func _(x T[P1, P2, P3])`,
+ `package p; func _(x p.T[Q])`,
+ `package p; func _(p.T[Q])`,
+ `package p; type _[A interface{},] struct{}`,
+ `package p; type _[A interface{}] struct{}`,
+ `package p; type _[A, B any,] struct{}`,
+ `package p; type _[A, B any] struct{}`,
+ `package p; type _[A any,] struct{}`,
+ `package p; type _[A any]struct{}`,
+ `package p; type _[A any] struct{ A }`,
+ `package p; func _[T any]()`,
+ `package p; func _[T any](x T)`,
+ `package p; func _[T1, T2 any](x T)`,
+ `package p; func _[A, B any](a A) B`,
+ `package p; func _[A, B C](a A) B`,
+ `package p; func _[A, B C[A, B]](a A) B`,
+
+ `package p; type _[A, B any] interface { _(a A) B }`,
+ `package p; type _[A, B C[A, B]] interface { _(a A) B }`,
+ `package p; func _[T1, T2 interface{}](x T1) T2`,
+ `package p; func _[T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
+ `package p; var _ = []T[int]{}`,
+ `package p; var _ = [10]T[int]{}`,
+ `package p; var _ = func()T[int]{}`,
+ `package p; var _ = map[T[int]]T[int]{}`,
+ `package p; var _ = chan T[int](x)`,
+ `package p; func _(_ T[P], T P) T[P]`,
+ `package p; var _ T[chan int]`,
+
+ `package p; func (_ R[P]) _(x T)`,
+ `package p; func (_ R[ P, Q]) _(x T)`,
+
+ `package p; func (R[P]) _()`,
+ `package p; func _(T[P])`,
+ `package p; func _(T[P1, P2, P3 ])`,
+ `package p; func _(T[P]) T[P]`,
+ `package p; type _ struct{ T[P]}`,
+ `package p; type _ struct{ T[struct{a, b, c int}] }`,
+ `package p; type _ interface{int|float32; bool; m(); string;}`,
+ `package p; type I1[T any] interface{}; type I2 interface{ I1[int] }`,
+ `package p; type I1[T any] interface{}; type I2[T any] interface{ I1[T] }`,
+ `package p; type _ interface { N[T] }`,
+ `package p; type T[P any] = T0`,
}
func TestValid(t *testing.T) {
- t.Run("no tparams", func(t *testing.T) {
- for _, src := range valids {
- checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
- }
- })
- t.Run("tparams", func(t *testing.T) {
- for _, src := range valids {
- checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
- }
- for _, src := range validWithTParamsOnly {
- checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
- }
- })
+ for _, src := range valids {
+ checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
+ }
}
// TestSingle is useful to track down a problem with a single short test program.
// issue 13475
`package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
`package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
-}
-
-// invalidNoTParamErrs holds invalid source code examples annotated with the
-// error messages produced when ParseTypeParams is not set.
-var invalidNoTParamErrs = []string{
- `package p; type _[_ any /* ERROR "expected ']', found any" */ ] int; var _ = T[]{}`,
- `package p; type T[P any /* ERROR "expected ']', found any" */ ] = T0`,
- `package p; var _ func[ /* ERROR "expected '\(', found '\['" */ T any](T)`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ ]()`,
- `package p; type _[A, /* ERROR "unexpected comma" */] struct{ A }`,
- `package p; func _[ /* ERROR "expected '\(', found '\['" */ type P, *Q interface{}]()`,
-
- `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
- `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
- `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
-
- `package p; func(*T[ /* ERROR "missing ',' in parameter list" */ e, e]) _()`,
-}
-// invalidTParamErrs holds invalid source code examples annotated with the
-// error messages produced when ParseTypeParams is set.
-var invalidTParamErrs = []string{
+ // generic code
`package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`,
`package p; var _ func[ /* ERROR "must have no type parameters" */ T any](T)`,
`package p; func _[]/* ERROR "empty type parameter list" */()`,
}
func TestInvalid(t *testing.T) {
- t.Run("no tparams", func(t *testing.T) {
- for _, src := range invalids {
- checkErrors(t, src, src, DeclarationErrors|AllErrors|typeparams.DisallowParsing, true)
- }
- for _, src := range validWithTParamsOnly {
- checkErrors(t, src, src, DeclarationErrors|AllErrors|typeparams.DisallowParsing, true)
- }
- for _, src := range invalidNoTParamErrs {
- checkErrors(t, src, src, DeclarationErrors|AllErrors|typeparams.DisallowParsing, true)
- }
- })
- t.Run("tparams", func(t *testing.T) {
- for _, src := range invalids {
- checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
- }
- for _, src := range invalidTParamErrs {
- checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
- }
- })
+ for _, src := range invalids {
+ checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+ }
}