]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/syntax: better error message when type parameters are not permitted
authorRobert Griesemer <gri@golang.org>
Wed, 3 Nov 2021 21:58:59 +0000 (14:58 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 4 Nov 2021 00:29:42 +0000 (00:29 +0000)
Fixes #48382.

Change-Id: I215896a4429839c41c9136b6922b1b748ed47734
Reviewed-on: https://go-review.googlesource.com/c/go/+/361259
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/testdata/issue48382.go2 [new file with mode: 0644]

index 9f02cb6c2ca1a11a1f91e2f8697ce657485e1465..770175fe54f8d2b5aee7071e924d37cea019a2df 100644 (file)
@@ -708,15 +708,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        }
 
        f.Name = p.name()
-       if p.allowGenerics() && p.got(_Lbrack) {
-               if p.tok == _Rbrack {
-                       p.syntaxError("empty type parameter list")
-                       p.next()
-               } else {
-                       f.TParamList = p.paramList(nil, _Rbrack, true)
-               }
-       }
-       f.Type = p.funcType()
+       f.TParamList, f.Type = p.funcType("")
        if p.tok == _Lbrace {
                f.Body = p.funcBody()
        }
@@ -944,7 +936,7 @@ func (p *parser) operand(keep_parens bool) Expr {
        case _Func:
                pos := p.pos()
                p.next()
-               ftyp := p.funcType()
+               _, ftyp := p.funcType("function literal")
                if p.tok == _Lbrace {
                        p.xnest++
 
@@ -1284,7 +1276,8 @@ func (p *parser) typeOrNil() Expr {
        case _Func:
                // fntype
                p.next()
-               return p.funcType()
+               _, t := p.funcType("function type")
+               return t
 
        case _Lbrack:
                // '[' oexpr ']' ntype
@@ -1357,18 +1350,34 @@ func (p *parser) typeInstance(typ Expr) Expr {
        return x
 }
 
-func (p *parser) funcType() *FuncType {
+// If context != "", type parameters are not permitted.
+func (p *parser) funcType(context string) ([]*Field, *FuncType) {
        if trace {
                defer p.trace("funcType")()
        }
 
        typ := new(FuncType)
        typ.pos = p.pos()
+
+       var tparamList []*Field
+       if p.allowGenerics() && p.got(_Lbrack) {
+               if context != "" {
+                       // accept but complain
+                       p.syntaxErrorAt(typ.pos, context+" cannot have type parameters")
+               }
+               if p.tok == _Rbrack {
+                       p.syntaxError("empty type parameter list")
+                       p.next()
+               } else {
+                       tparamList = p.paramList(nil, _Rbrack, true)
+               }
+       }
+
        p.want(_Lparen)
        typ.ParamList = p.paramList(nil, _Rparen, false)
        typ.ResultList = p.funcResult()
 
-       return typ
+       return tparamList, typ
 }
 
 // "[" has already been consumed, and pos is its position.
@@ -1697,11 +1706,13 @@ func (p *parser) methodDecl() *Field {
                // already progressed, no need to advance
        }
 
+       const context = "interface method"
+
        switch p.tok {
        case _Lparen:
                // method
                f.Name = name
-               f.Type = p.funcType()
+               _, f.Type = p.funcType(context)
 
        case _Lbrack:
                if p.allowGenerics() {
@@ -1721,7 +1732,7 @@ func (p *parser) methodDecl() *Field {
                                        // name[](
                                        p.errorAt(pos, "empty type parameter list")
                                        f.Name = name
-                                       f.Type = p.funcType()
+                                       _, f.Type = p.funcType(context)
                                } else {
                                        p.errorAt(pos, "empty type argument list")
                                        f.Type = name
@@ -1738,7 +1749,7 @@ func (p *parser) methodDecl() *Field {
                                // as if [] were absent.
                                if p.tok == _Lparen {
                                        f.Name = name
-                                       f.Type = p.funcType()
+                                       _, f.Type = p.funcType(context)
                                } else {
                                        f.Type = name
                                }
@@ -1749,7 +1760,7 @@ func (p *parser) methodDecl() *Field {
                        if list[0].Name != nil {
                                // generic method
                                f.Name = name
-                               f.Type = p.funcType()
+                               _, 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.
diff --git a/src/cmd/compile/internal/syntax/testdata/issue48382.go2 b/src/cmd/compile/internal/syntax/testdata/issue48382.go2
new file mode 100644 (file)
index 0000000..1e8f4b0
--- /dev/null
@@ -0,0 +1,15 @@
+// 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
+
+type _ func /* ERROR function type cannot have type parameters */ [ /* ERROR empty type parameter list */ ]()
+type _ func /* ERROR function type cannot have type parameters */ [ x /* ERROR missing type constraint */ ]()
+type _ func /* ERROR function type cannot have type parameters */ [P any]()
+
+var _ = func /* ERROR function literal cannot have type parameters */ [P any]() {}
+
+type _ interface{
+        m /* ERROR interface method cannot have type parameters */ [P any]()
+}