aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2024-11-25 13:08:34 -0800
committerGopher Robot <gobot@golang.org>2025-02-03 14:04:09 -0800
commitad7b46ee4ac1cee5095d64b01e8cf7fcda8bee5e (patch)
treeb6196aa1649255d39cae4f3f4e1719f67d341a76 /src/cmd
parentd96fd2e758d79a60f2c3df46e9b15e9ad084a5cb (diff)
downloadgo-ad7b46ee4ac1cee5095d64b01e8cf7fcda8bee5e.tar.xz
go/parser, go/types, syntax, types2: report invalid uses of ... by parsers
Check correct use of ...'s in parameter lists in parsers. This allows the type checkers to assume correct ASTs with respect to ... use. Adjust some error messages: if a ... is used in a result parameter list, the error is now more accurate. Eliminate a now unused error code. Change-Id: I66058e114e84805e24c59e570604b607ef5ff1fe Reviewed-on: https://go-review.googlesource.com/c/go/+/631135 Reviewed-by: Robert Griesemer <gri@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Bypass: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/syntax/parser.go36
-rw-r--r--src/cmd/compile/internal/types2/expr.go5
-rw-r--r--src/cmd/compile/internal/types2/signature.go2
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go6
4 files changed, 32 insertions, 17 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index 14a737c414..8278685943 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -650,7 +650,7 @@ func (p *parser) typeDecl(group *Group) Decl {
// d.Name "[" pname ...
// d.Name "[" pname ptype ...
// d.Name "[" pname ptype "," ...
- d.TParamList = p.paramList(pname, ptype, _Rbrack, true) // ptype may be nil
+ d.TParamList = p.paramList(pname, ptype, _Rbrack, true, false) // ptype may be nil
d.Alias = p.gotAssign()
d.Type = p.typeOrNil()
} else {
@@ -800,7 +800,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
var context string
if p.got(_Lparen) {
context = "method"
- rcvr := p.paramList(nil, nil, _Rparen, false)
+ rcvr := p.paramList(nil, nil, _Rparen, false, false)
switch len(rcvr) {
case 0:
p.error("method has no receiver")
@@ -1469,12 +1469,12 @@ func (p *parser) funcType(context string) ([]*Field, *FuncType) {
p.syntaxError("empty type parameter list")
p.next()
} else {
- tparamList = p.paramList(nil, nil, _Rbrack, true)
+ tparamList = p.paramList(nil, nil, _Rbrack, true, false)
}
}
p.want(_Lparen)
- typ.ParamList = p.paramList(nil, nil, _Rparen, false)
+ typ.ParamList = p.paramList(nil, nil, _Rparen, false, true)
typ.ResultList = p.funcResult()
return tparamList, typ
@@ -1582,7 +1582,7 @@ func (p *parser) funcResult() []*Field {
}
if p.got(_Lparen) {
- return p.paramList(nil, nil, _Rparen, false)
+ return p.paramList(nil, nil, _Rparen, false, false)
}
pos := p.pos()
@@ -1793,7 +1793,7 @@ func (p *parser) methodDecl() *Field {
// 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)
+ list := p.paramList(nil, nil, _Rbrack, false, false)
if len(list) == 0 {
// The type parameter list is not [] but we got nothing
// due to other errors (reported by paramList). Treat
@@ -1962,10 +1962,11 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
p.next()
t.Elem = p.typeOrNil()
if t.Elem == nil {
- t.Elem = p.badExpr()
+ f.Type = p.badExpr()
p.syntaxError("... is missing type")
+ } else {
+ f.Type = t
}
- f.Type = t
return f
}
@@ -1995,7 +1996,7 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
// If name != nil, it is the first name after "(" or "[".
// If typ != nil, name must be != nil, and (name, typ) is the first field in the list.
// In the result list, either all fields have a name, or no field has a name.
-func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool) (list []*Field) {
+func (p *parser) paramList(name *Name, typ Expr, close token, requireNames, dddok bool) (list []*Field) {
if trace {
defer p.trace("paramList")()
}
@@ -2109,6 +2110,23 @@ func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool)
}
}
+ // check use of ...
+ first := true // only report first occurrence
+ for i, f := range list {
+ if t, _ := f.Type.(*DotsType); t != nil && (!dddok || i+1 < len(list)) {
+ if first {
+ first = false
+ if dddok {
+ p.errorAt(t.pos, "can only use ... with final parameter")
+ } else {
+ p.errorAt(t.pos, "invalid use of ...")
+ }
+ }
+ // use T instead of invalid ...T
+ f.Type = t.Elem
+ }
+ }
+
return
}
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index 2bf42d1c6f..28a5d78872 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -1016,9 +1016,8 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
check.ident(x, e, nil, false)
case *syntax.DotsType:
- // dots are handled explicitly where they are legal
- // (array composite literals and parameter lists)
- check.error(e, BadDotDotDotSyntax, "invalid use of '...'")
+ // dots are handled explicitly where they are valid
+ check.error(e, InvalidSyntaxTree, "invalid use of ...")
goto Error
case *syntax.BasicLit:
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index de4f1eaa20..622eb1383d 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -344,7 +344,7 @@ func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (name
if variadicOk && i == len(list)-1 {
variadic = true
} else {
- check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list")
+ check.error(t, InvalidSyntaxTree, "invalid use of ...")
// ignore ... and continue
}
}
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index e9b5ca9aa6..0964c53fe0 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -321,10 +321,8 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
return typ
case *syntax.DotsType:
- // dots are handled explicitly where they are legal
- // (array composite literals and parameter lists)
- check.error(e, InvalidDotDotDot, "invalid use of '...'")
- check.use(e.Elem)
+ // dots are handled explicitly where they are valid
+ check.error(e, InvalidSyntaxTree, "invalid use of ...")
case *syntax.StructType:
typ := new(Struct)