]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser: disallow parenthesizing embedded types in structs
authorRobert Griesemer <gri@golang.org>
Thu, 18 Aug 2022 03:11:57 +0000 (20:11 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 19 Aug 2022 17:46:01 +0000 (17:46 +0000)
This was never permitted in Go but the flexibility to do so
was introduced through the generics prototype code where we
experimented with parentheses to enclose type parameters.
Restore original (pre-generics) behavior.

Fixes #51655.

Change-Id: Ia7a4b2e393e0214a70e840c8663cf4474c5c754b
Reviewed-on: https://go-review.googlesource.com/c/go/+/424694
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/go/parser/parser.go
src/go/parser/short_test.go

index d4ad36dc672cf58091fd33d2cdfe749a4195508e..acb71ee9ac26e930ecb4f1fe2d6bca8e94f13727 100644 (file)
@@ -643,7 +643,8 @@ func (p *parser) parseFieldDecl() *ast.Field {
 
        var names []*ast.Ident
        var typ ast.Expr
-       if p.tok == token.IDENT {
+       switch p.tok {
+       case token.IDENT:
                name := p.parseIdent()
                if p.tok == token.PERIOD || p.tok == token.STRING || p.tok == token.SEMICOLON || p.tok == token.RBRACE {
                        // embedded type
@@ -670,11 +671,46 @@ func (p *parser) parseFieldDecl() *ast.Field {
                                typ = p.parseType()
                        }
                }
-       } else {
-               // embedded, possibly generic type
-               // (using the enclosing parentheses to distinguish it from a named field declaration)
-               // TODO(rFindley) confirm that this doesn't allow parenthesized embedded type
-               typ = p.parseType()
+       case token.MUL:
+               star := p.pos
+               p.next()
+               if p.tok == token.LPAREN {
+                       // *(T)
+                       p.error(p.pos, "cannot parenthesize embedded type")
+                       p.next()
+                       typ = p.parseQualifiedIdent(nil)
+                       // expect closing ')' but no need to complain if missing
+                       if p.tok == token.RPAREN {
+                               p.next()
+                       }
+               } else {
+                       // *T
+                       typ = p.parseQualifiedIdent(nil)
+               }
+               typ = &ast.StarExpr{Star: star, X: typ}
+
+       case token.LPAREN:
+               p.error(p.pos, "cannot parenthesize embedded type")
+               p.next()
+               if p.tok == token.MUL {
+                       // (*T)
+                       star := p.pos
+                       p.next()
+                       typ = &ast.StarExpr{Star: star, X: p.parseQualifiedIdent(nil)}
+               } else {
+                       // (T)
+                       typ = p.parseQualifiedIdent(nil)
+               }
+               // expect closing ')' but no need to complain if missing
+               if p.tok == token.RPAREN {
+                       p.next()
+               }
+
+       default:
+               pos := p.pos
+               p.errorExpected(pos, "field name or embedded type")
+               p.advance(exprEnd)
+               typ = &ast.BadExpr{From: pos, To: p.pos}
        }
 
        var tag *ast.BasicLit
index d117f0d3815aad7913b0eb71068e6276f84572a0..be8be6450c2f5dad5a2f624beae07dcdc01e4735 100644 (file)
@@ -52,9 +52,9 @@ var valids = []string{
        `package p; type T = int`,
        `package p; type (T = p.T; _ = struct{}; x = *T)`,
        `package p; type T (*int)`,
-       `package p; type _ struct{ ((int)) }`,
-       `package p; type _ struct{ (*(int)) }`,
-       `package p; type _ struct{ ([]byte) }`, // disallowed by type-checker
+       `package p; type _ struct{ int }`,
+       `package p; type _ struct{ pkg.T }`,
+       `package p; type _ struct{ *pkg.T }`,
        `package p; var _ = func()T(nil)`,
        `package p; func _(T (P))`,
        `package p; func _(T []E)`,
@@ -195,6 +195,12 @@ var invalids = []string{
        `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`,
        `package p; type _[A+B, /* ERROR "unexpected comma" */ ] int`,
 
+       `package p; type _ struct{ [ /* ERROR "expected '}', found '\['" */ ]byte }`,
+       `package p; type _ struct{ ( /* ERROR "cannot parenthesize embedded type" */ int) }`,
+       `package p; type _ struct{ ( /* ERROR "cannot parenthesize embedded type" */ []byte) }`,
+       `package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ int) }`,
+       `package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ []byte) }`,
+
        // TODO(rfindley): this error should be positioned on the ':'
        `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`,