aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/syntax')
-rw-r--r--src/cmd/compile/internal/syntax/parser.go36
-rw-r--r--src/cmd/compile/internal/syntax/testdata/issue43527.go223
-rw-r--r--src/cmd/compile/internal/syntax/testdata/tparams.go210
3 files changed, 53 insertions, 16 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index e89796cb31..82cb06b180 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -276,7 +276,9 @@ func (p *parser) syntaxErrorAt(pos Pos, msg string) {
}
// tokstring returns the English word for selected punctuation tokens
-// for more readable error messages.
+// for more readable error messages. Use tokstring (not tok.String())
+// for user-facing (error) messages; use tok.String() for debugging
+// output.
func tokstring(tok token) string {
switch tok {
case _Comma:
@@ -1839,7 +1841,7 @@ func (p *parser) embeddedTerm() Expr {
}
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) paramDeclOrNil(name *Name) *Field {
+func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
if trace {
defer p.trace("paramDecl")()
}
@@ -1893,8 +1895,8 @@ func (p *parser) paramDeclOrNil(name *Name) *Field {
return f
}
- p.syntaxError("expecting )")
- p.advance(_Comma, _Rparen)
+ p.syntaxError("expecting " + tokstring(follow))
+ p.advance(_Comma, follow)
return nil
}
@@ -1908,9 +1910,10 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
defer p.trace("paramList")()
}
- var named int // number of parameters that have an explicit name and type/bound
- p.list(_Comma, close, func() bool {
- par := p.paramDeclOrNil(name)
+ var named int // number of parameters that have an explicit name and type
+ var typed int // number of parameters that have an explicit type
+ end := p.list(_Comma, close, func() bool {
+ par := p.paramDeclOrNil(name, close)
name = nil // 1st name was consumed if present
if par != nil {
if debug && par.Name == nil && par.Type == nil {
@@ -1919,6 +1922,9 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
if par.Name != nil && par.Type != nil {
named++
}
+ if par.Type != nil {
+ typed++
+ }
list = append(list, par)
}
return false
@@ -1939,10 +1945,11 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
}
} else if named != len(list) {
// some named => all must have names and types
- var pos Pos // left-most error position (or unknown)
- var typ Expr
+ var pos Pos // left-most error position (or unknown)
+ var typ Expr // current type (from right to left)
for i := len(list) - 1; i >= 0; i-- {
- if par := list[i]; par.Type != nil {
+ par := list[i]
+ if par.Type != nil {
typ = par.Type
if par.Name == nil {
pos = typ.Pos()
@@ -1961,7 +1968,12 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
if pos.IsKnown() {
var msg string
if requireNames {
- msg = "type parameters must be named"
+ if named == typed {
+ pos = end // position error at closing ]
+ msg = "missing type constraint"
+ } else {
+ msg = "type parameters must be named"
+ }
} else {
msg = "mixed named and unnamed parameters"
}
@@ -2201,7 +2213,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS
if p.tok != _Semi {
// accept potential varDecl but complain
if p.got(_Var) {
- p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", keyword.String()))
+ p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", tokstring(keyword)))
}
init = p.simpleStmt(nil, keyword)
// If we have a range clause, we are done (can only happen for keyword == _For).
diff --git a/src/cmd/compile/internal/syntax/testdata/issue43527.go2 b/src/cmd/compile/internal/syntax/testdata/issue43527.go2
new file mode 100644
index 0000000000..dd2c9b1272
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/issue43527.go2
@@ -0,0 +1,23 @@
+// 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 (
+ // 0 and 1-element []-lists are syntactically valid
+ _[A, B /* ERROR missing type constraint */ ] int
+ _[A, /* ERROR type parameters must be named */ interface{}] int
+ _[A, B, C /* ERROR missing type constraint */ ] int
+ _[A B, C /* ERROR missing type constraint */ ] int
+ _[A B, /* ERROR type parameters must be named */ interface{}] int
+ _[A B, /* ERROR type parameters must be named */ interface{}, C D] int
+ _[A B, /* ERROR type parameters must be named */ interface{}, C, D] int
+ _[A B, /* ERROR type parameters must be named */ interface{}, C, interface{}] int
+ _[A B, C interface{}, D, /* ERROR type parameters must be named */ interface{}] int
+)
+
+// function type parameters use the same parsing routine - just have a couple of tests
+
+func _[A, B /* ERROR missing type constraint */ ]() {}
+func _[A, /* ERROR type parameters must be named */ interface{}]() {}
diff --git a/src/cmd/compile/internal/syntax/testdata/tparams.go2 b/src/cmd/compile/internal/syntax/testdata/tparams.go2
index 42031c3277..80e155bfe0 100644
--- a/src/cmd/compile/internal/syntax/testdata/tparams.go2
+++ b/src/cmd/compile/internal/syntax/testdata/tparams.go2
@@ -4,8 +4,8 @@
package p
-type t[ /* ERROR type parameters must be named */ a, b] struct{}
-type t[a t, b t, /* ERROR type parameters must be named */ c] struct{}
+type t[a, b /* ERROR missing type constraint */ ] struct{}
+type t[a t, b t, c /* ERROR missing type constraint */ ] struct{}
type t struct {
t [n]byte
t[a]
@@ -18,5 +18,7 @@ type t interface {
}
func f[ /* ERROR empty type parameter list */ ]()
-func f[ /* ERROR type parameters must be named */ a, b]()
-func f[a t, b t, /* ERROR type parameters must be named */ c]()
+func f[a, b /* ERROR missing type constraint */ ]()
+func f[a t, b t, c /* ERROR missing type constraint */ ]()
+
+func f[a b, /* ERROR expecting ] */ 0] ()