func LoadPackage(filenames []string) {
base.Timer.Start("fe", "parse")
- mode := syntax.CheckBranches | syntax.AllowGenerics
+ mode := syntax.CheckBranches
// Limit the number of simultaneously open files.
sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
t.Skip("skipping test in short mode")
}
- ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
+ ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches)
if ast != nil {
Fdump(testOut(), ast)
}
defer f.Close()
- var mode Mode
- if !strings.HasSuffix(filename, ".go117") {
- mode = AllowGenerics
- }
ParseFile(filename, func(err error) {
e, ok := err.(Error)
if !ok {
} else {
t.Errorf("%s:%s: unexpected error: %s", filename, orig, e.Msg)
}
- }, nil, mode)
+ }, nil, 0)
if *print {
fmt.Println()
p.indent = nil
}
-func (p *parser) allowGenerics() bool { return p.mode&AllowGenerics != 0 }
-
// takePragma returns the current parsed pragmas
// and clears them from the parser state.
func (p *parser) takePragma() Pragma {
d.Pragma = p.takePragma()
d.Name = p.name()
- if p.allowGenerics() && p.tok == _Lbrack {
+ if p.tok == _Lbrack {
// d.Name "[" ...
// array/slice type or type parameter list
pos := p.pos()
f.Name = p.name()
context := ""
- if f.Recv != nil && p.mode&AllowMethodTypeParams == 0 {
+ if f.Recv != nil {
context = "method" // don't permit (method) type parameters in funcType
}
f.TParamList, f.Type = p.funcType(context)
var i Expr
if p.tok != _Colon {
- if p.mode&AllowGenerics == 0 {
- p.xnest++
- i = p.expr()
- p.xnest--
- if p.got(_Rbrack) {
- // x[i]
- t := new(IndexExpr)
- t.pos = pos
- t.X = x
- t.Index = i
- x = t
- break
- }
- } else {
- var comma bool
- i, comma = p.typeList()
- if comma || p.tok == _Rbrack {
- p.want(_Rbrack)
- // x[i,] or x[i, j, ...]
- t := new(IndexExpr)
- t.pos = pos
- t.X = x
- t.Index = i
- x = t
- break
- }
+ var comma bool
+ i, comma = p.typeList()
+ if comma || p.tok == _Rbrack {
+ p.want(_Rbrack)
+ // x[i,] or x[i, j, ...]
+ t := new(IndexExpr)
+ t.pos = pos
+ t.X = x
+ t.Index = i
+ x = t
+ break
}
}
// x[i:...
// For better error message, don't simply use p.want(_Colon) here (issue #47704).
if !p.got(_Colon) {
- if p.mode&AllowGenerics == 0 {
- p.syntaxError("expecting : or ]")
- p.advance(_Colon, _Rbrack)
- } else {
- p.syntaxError("expecting comma, : or ]")
- p.advance(_Comma, _Colon, _Rbrack)
- }
+ p.syntaxError("expecting comma, : or ]")
+ p.advance(_Comma, _Colon, _Rbrack)
}
p.xnest++
t := new(SliceExpr)
typ.pos = p.pos()
var tparamList []*Field
- if p.allowGenerics() && p.got(_Lbrack) {
+ if p.got(_Lbrack) {
if context != "" {
// accept but complain
p.syntaxErrorAt(typ.pos, context+" must have no type parameters")
// InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem | TypeList ) ";" } "}" .
// TypeList = "type" Type { "," Type } .
-// TODO(gri) remove TypeList syntax if we accept #45346
func (p *parser) interfaceType() *InterfaceType {
if trace {
defer p.trace("interfaceType")()
switch p.tok {
case _Name:
f := p.methodDecl()
- if f.Name == nil && p.allowGenerics() {
+ if f.Name == nil {
f = p.embeddedElem(f)
}
typ.MethodList = append(typ.MethodList, f)
return false
case _Lparen:
- // TODO(gri) Need to decide how to adjust this restriction.
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
return false
case _Operator:
- if p.op == Tilde && p.allowGenerics() {
+ if p.op == Tilde {
typ.MethodList = append(typ.MethodList, p.embeddedElem(nil))
return false
}
default:
- if p.allowGenerics() {
- pos := p.pos()
- if t := p.typeOrNil(); t != nil {
- f := new(Field)
- f.pos = pos
- f.Type = t
- typ.MethodList = append(typ.MethodList, p.embeddedElem(f))
- return false
- }
+ pos := p.pos()
+ if t := p.typeOrNil(); t != nil {
+ f := new(Field)
+ f.pos = pos
+ f.Type = t
+ typ.MethodList = append(typ.MethodList, p.embeddedElem(f))
+ return false
}
}
- if p.allowGenerics() {
- p.syntaxError("expecting method or embedded element")
- p.advance(_Semi, _Rbrace)
- return false
- }
-
- p.syntaxError("expecting method or interface name")
+ p.syntaxError("expecting method or embedded element")
p.advance(_Semi, _Rbrace)
return false
})
// Careful dance: We don't know if we have an embedded instantiated
// type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
- if p.allowGenerics() && len(names) == 1 && p.tok == _Lbrack {
+ if len(names) == 1 && p.tok == _Lbrack {
typ = p.arrayOrTArgs()
if typ, ok := typ.(*IndexExpr); ok {
// embedded type T[P1, P2, ...]
_, f.Type = p.funcType(context)
case _Lbrack:
- if p.allowGenerics() {
- // Careful dance: We don't know if we have a generic method m[T C](x T)
- // or an embedded instantiated type T[P1, P2] (we accept generic methods
- // for generality and robustness of parsing).
+ // Careful dance: We don't know if we have a generic method m[T C](x T)
+ // or an embedded instantiated type T[P1, P2] (we accept generic methods
+ // for generality and robustness of parsing but complain with an error).
+ pos := p.pos()
+ p.next()
+
+ // Empty type parameter or argument lists are not permitted.
+ // Treat as if [] were absent.
+ if p.tok == _Rbrack {
+ // name[]
pos := p.pos()
p.next()
-
- // Empty type parameter or argument lists are not permitted.
- // Treat as if [] were absent.
- if p.tok == _Rbrack {
- // name[]
- pos := p.pos()
- p.next()
- if p.tok == _Lparen {
- // name[](
- p.errorAt(pos, "empty type parameter list")
- f.Name = name
- _, f.Type = p.funcType(context)
- } else {
- p.errorAt(pos, "empty type argument list")
- f.Type = name
- }
- break
- }
-
- // A type argument list looks like a parameter list with only
- // types. Parse a parameter list and decide afterwards.
- list := p.paramList(nil, nil, _Rbrack, false)
- if len(list) == 0 {
- // The type parameter list is not [] but we got nothing
- // due to other errors (reported by paramList). Treat
- // as if [] were absent.
- if p.tok == _Lparen {
- f.Name = name
- _, f.Type = p.funcType(context)
- } else {
- f.Type = name
- }
- break
- }
-
- // len(list) > 0
- if list[0].Name != nil {
- // generic method
+ if p.tok == _Lparen {
+ // name[](
+ p.errorAt(pos, "empty type parameter list")
f.Name = name
_, f.Type = p.funcType(context)
- // TODO(gri) Record list as type parameter list with f.Type
- // if we want to type-check the generic method.
- // For now, report an error so this is not a silent event.
- p.errorAt(pos, "interface method must have no type parameters")
- break
+ } else {
+ p.errorAt(pos, "empty type argument list")
+ f.Type = name
}
+ break
+ }
- // embedded instantiated type
- t := new(IndexExpr)
- t.pos = pos
- t.X = name
- if len(list) == 1 {
- t.Index = list[0].Type
+ // A type argument list looks like a parameter list with only
+ // types. Parse a parameter list and decide afterwards.
+ list := p.paramList(nil, nil, _Rbrack, false)
+ if len(list) == 0 {
+ // The type parameter list is not [] but we got nothing
+ // due to other errors (reported by paramList). Treat
+ // as if [] were absent.
+ if p.tok == _Lparen {
+ f.Name = name
+ _, f.Type = p.funcType(context)
} else {
- // len(list) > 1
- l := new(ListExpr)
- l.pos = list[0].Pos()
- l.ElemList = make([]Expr, len(list))
- for i := range list {
- l.ElemList[i] = list[i].Type
- }
- t.Index = l
+ f.Type = name
}
- f.Type = t
break
}
- fallthrough
+
+ // len(list) > 0
+ if list[0].Name != nil {
+ // generic method
+ f.Name = name
+ _, f.Type = p.funcType(context)
+ p.errorAt(pos, "interface method must have no type parameters")
+ break
+ }
+
+ // embedded instantiated type
+ t := new(IndexExpr)
+ t.pos = pos
+ t.X = name
+ if len(list) == 1 {
+ t.Index = list[0].Type
+ } else {
+ // len(list) > 1
+ l := new(ListExpr)
+ l.pos = list[0].Pos()
+ l.ElemList = make([]Expr, len(list))
+ for i := range list {
+ l.ElemList[i] = list[i].Type
+ }
+ t.Index = l
+ }
+ f.Type = t
default:
// embedded type
name = p.name()
}
- if p.allowGenerics() && p.tok == _Lbrack {
+ if p.tok == _Lbrack {
// name "[" ...
f.Type = p.arrayOrTArgs()
if typ, ok := f.Type.(*IndexExpr); ok {
x = s
}
- if p.allowGenerics() && p.tok == _Lbrack {
+ if p.tok == _Lbrack {
x = p.typeInstance(x)
}
)
func TestParse(t *testing.T) {
- ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
+ ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
}
func TestVerify(t *testing.T) {
- ast, err := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
+ ast, err := ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
if err != nil {
return // error already reported
}
if debug {
fmt.Printf("parsing %s\n", filename)
}
- ast, err := ParseFile(filename, nil, nil, AllowGenerics)
+ ast, err := ParseFile(filename, nil, nil, 0)
if err != nil {
t.Error(err)
return
t.Skip("skipping test in short mode")
}
- ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
+ ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
if ast != nil {
Fprint(testOut(), ast, LineForm)
func TestPrintString(t *testing.T) {
for _, test := range stringTests {
- ast, err := Parse(nil, strings.NewReader(test[0]), nil, nil, AllowGenerics)
+ ast, err := Parse(nil, strings.NewReader(test[0]), nil, nil, 0)
if err != nil {
t.Error(err)
continue
func TestShortString(t *testing.T) {
for _, test := range exprTests {
src := "package p; var _ = " + test[0]
- ast, err := Parse(nil, strings.NewReader(src), nil, nil, AllowGenerics)
+ ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0)
if err != nil {
t.Errorf("%s: %s", test[0], err)
continue
// Modes supported by the parser.
const (
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
- AllowGenerics
- AllowMethodTypeParams // does not support interface methods yet; ignored if AllowGenerics is not set
)
// Error describes a syntax error. Error implements the error interface.
package p
-// error messages for parser in generic mode
func _() {
_ = m[] // ERROR expecting operand
_ = m[x,]
+++ /dev/null
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package p
-
-// error messages for parser in non-generic mode
-func _() {
- _ = m[] // ERROR expecting operand
- _ = m[x,] // ERROR unexpected comma, expecting \: or \]
- _ = m[x /* ERROR unexpected a */ a b c d]
-}
-
-// test case from the issue
-func f(m map[int]int) int {
- return m[0 // ERROR expecting \: or \]
- ]
-}
type _ struct{ T[int] }
// interfaces
-type _ interface{
+type _ interface {
m()
~int
}
-type _ interface{
+type _ interface {
~int | ~float | ~string
~complex128
underlying(underlying underlying) underlying
}
-type _ interface{
+type _ interface {
T
T[int]
}
func _(T[P], T[P1, P2])
func _(a [N]T)
-type _ struct{
+type _ struct {
T[P]
T[P1, P2]
- f [N]
+ f[N]
}
-type _ interface{
+type _ interface {
m()
- // generic methods - disabled for now
- // m[] /* ERROR empty type parameter list */ ()
- // m[ /* ERROR cannot have type parameters */ P any](P)
-
// instantiated types
- // T[] /* ERROR empty type argument list */
+ T[ /* ERROR empty type argument list */ ]
T[P]
T[P1, P2]
}
func parseSrc(path, src string) (*syntax.File, error) {
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
- return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics|syntax.AllowMethodTypeParams)
+ return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, 0)
}
func pkgFor(path, source string, info *Info) (*Package, error) {
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
[]testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
},
- // we don't know how to translate these but we can type-check them
- {`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
- []testInst{{`m`, []string{`int`}, `func(int)`}},
- },
- {`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
- []testInst{{`m`, []string{`int`}, `func(int) int`}},
- },
- {`package q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`,
- []testInst{{`m`, []string{`int`}, `func(...int) int`}},
- },
- {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
- []testInst{{`m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
- },
- {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
- []testInst{{`m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
- },
-
- {`package r0; type T[P1 any] struct{}; func (_ T[P2]) m[Q any](Q) {}; func _[P3 any](x T[P3]) { x.m(42) }`,
- []testInst{
- {`T`, []string{`P2`}, `struct{}`},
- {`T`, []string{`P3`}, `struct{}`},
- {`m`, []string{`int`}, `func(int)`},
- },
- },
- // TODO(gri) record method type parameters in syntax.FuncType so we can check this
- // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
- // `x.m`,
- // []string{`float64`},
- // `func(float64)`,
- // },
{`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
[]testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
func parseGenericSrc(path, src string) (*syntax.File, error) {
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
- return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+ return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, 0)
}
func testBuiltinSignature(t *testing.T, name, src0, want string) {
t.Fatal(err)
}
- files, errlist := parseFiles(t, filenames, syntax.AllowGenerics|syntax.AllowMethodTypeParams)
+ files, errlist := parseFiles(t, filenames, 0)
pkgName := "<no package>"
if len(files) > 0 {
func checkMono(t *testing.T, body string) error {
src := "package x; import `unsafe`; var _ unsafe.Pointer;\n" + body
- file, err := syntax.Parse(syntax.NewFileBase("x.go"), strings.NewReader(src), nil, nil, syntax.AllowGenerics)
+ file, err := syntax.Parse(syntax.NewFileBase("x.go"), strings.NewReader(src), nil, nil, 0)
if err != nil {
t.Fatal(err)
}
var files []*syntax.File
for _, filename := range filenames {
errh := func(err error) { t.Error(err) }
- file, err := syntax.ParseFile(filename, errh, nil, syntax.AllowGenerics)
+ file, err := syntax.ParseFile(filename, errh, nil, 0)
if err != nil {
return
}
+++ /dev/null
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// If types2.Config.AcceptMethodTypeParams is set,
-// the type checker accepts methods that have their
-// own type parameter list.
-
-package p
-
-type S struct{}
-
-func (S) m[T any](v T) {}
-
-// TODO(gri) Once we collect interface method type parameters
-// in the parser, we can enable these tests again.
-/*
-type I interface {
- m[T any](v T)
-}
-
-type J interface {
- m[T any](v T)
-}
-
-var _ I = S{}
-var _ I = J(nil)
-
-type C interface{ n() }
-
-type Sc struct{}
-
-func (Sc) m[T C](v T)
-
-type Ic interface {
- m[T C](v T)
-}
-
-type Jc interface {
- m[T C](v T)
-}
-
-var _ Ic = Sc{}
-var _ Ic = Jc(nil)
-
-// TODO(gri) These should fail because the constraints don't match.
-var _ I = Sc{}
-var _ I = Jc(nil)
-
-var _ Ic = S{}
-var _ Ic = J(nil)
-*/
\ No newline at end of file
type T struct {}
func (T) m1() {}
-// The type checker accepts method type parameters if configured accordingly.
-func (T) m2[_ any]() {}
-func (T) m3[P any]() {}
+func (T) m2[ /* ERROR method must have no type parameters */ _ any]() {}
+func (T) m3[ /* ERROR method must have no type parameters */ P any]() {}
// type inference across parameterized types
m(S1[T]{x})
}
-// type parameters in methods (generalization)
-
-type R0 struct{}
-
-func (R0) _[T any](x T) {}
-func (R0 /* ERROR invalid receiver */ ) _[R0 any]() {} // scope of type parameters starts at "func"
-
-type R1[A, B any] struct{}
-
-func (_ R1[A, B]) m0(A, B)
-func (_ R1[A, B]) m1[T any](A, B, T) T { panic(0) }
-func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
-func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B) {}
-
-func _() {
- var r R1[int, string]
- r.m1[rune](42, "foo", 'a')
- r.m1[rune](42, "foo", 1.2 /* ERROR cannot use .* as rune .* \(truncated\) */)
- r.m1(42, "foo", 1.2) // using type inference
- var _ float64 = r.m1(42, "foo", 1.2)
-}
-
type I1[A any] interface {
m1(A)
}
// parse
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
src := "package p; type T interface" + body
- file, err := syntax.Parse(nil, strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+ file, err := syntax.Parse(nil, strings.NewReader(src), errh, nil, 0)
if err != nil {
t.Fatalf("%s: %v (invalid test case)", body, err)
}
m(S1[T]{x})
}
-// type parameters in methods (generalization)
-
-// Type Parameter lists are not allowed on methods, and are not produced by
-// go/parser. The test cases below are preserved for consistency with types2,
-// which produces an error but stores type parameters.
-// type R0 struct{}
-
-// func (R0) _[ /* ERROR methods cannot have type parameters */ T any](x T) {}
-// func (R0 /* ERROR invalid receiver */ ) _[ /* ERROR methods cannot have type parameters */ R0 any]() {} // scope of type parameters starts at "func"
-
-// type R1[A, B any] struct{}
-
-// func (_ R1[A, B]) m0(A, B)
-// func (_ R1[A, B]) m1[ /* ERROR methods cannot have type parameters */ T any](A, B, T) T { panic(0) }
-// func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
-// func (_ R1[A, B]) _[ /* ERROR methods cannot have type parameters */ A /* ERROR redeclared */ any](B) {}
-
-// func _() {
-// var r R1[int, string]
-// r.m1[rune](42, "foo", 'a')
-// r.m1[rune](42, "foo", 1.2 /* ERROR cannot use .* as rune .* \(truncated\) */)
-// r.m1(42, "foo", 1.2) // using type inference
-// var _ float64 = r.m1(42, "foo", 1.2)
-// }
-
type I1[A any] interface {
m1(A)
}