cmd/compile/internal/syntax: better error message for missing type constraint

For #43527.

Change-Id: I8c706e68572286d5675383eb2dfd75b5618b646b
Reviewed-on: https://go-review.googlesource.com/c/go/+/348730
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-09-08 21:30:01 -07:00
parent e1c3f2158f
commit 73483df406
4 changed files with 44 additions and 11 deletions

View File

@ -1908,8 +1908,9 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
defer p.trace("paramList")() defer p.trace("paramList")()
} }
var named int // number of parameters that have an explicit name and type/bound var named int // number of parameters that have an explicit name and type
p.list(_Comma, close, func() bool { var typed int // number of parameters that have an explicit type
end := p.list(_Comma, close, func() bool {
par := p.paramDeclOrNil(name) par := p.paramDeclOrNil(name)
name = nil // 1st name was consumed if present name = nil // 1st name was consumed if present
if par != nil { if par != nil {
@ -1919,6 +1920,9 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
if par.Name != nil && par.Type != nil { if par.Name != nil && par.Type != nil {
named++ named++
} }
if par.Type != nil {
typed++
}
list = append(list, par) list = append(list, par)
} }
return false return false
@ -1940,9 +1944,10 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
} else if named != len(list) { } else if named != len(list) {
// some named => all must have names and types // some named => all must have names and types
var pos Pos // left-most error position (or unknown) var pos Pos // left-most error position (or unknown)
var typ Expr var typ Expr // current type (from right to left)
for i := len(list) - 1; i >= 0; i-- { 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 typ = par.Type
if par.Name == nil { if par.Name == nil {
pos = typ.Pos() pos = typ.Pos()
@ -1961,7 +1966,12 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
if pos.IsKnown() { if pos.IsKnown() {
var msg string var msg string
if requireNames { if requireNames {
if named == typed {
pos = end // position error at closing ]
msg = "missing type constraint"
} else {
msg = "type parameters must be named" msg = "type parameters must be named"
}
} else { } else {
msg = "mixed named and unnamed parameters" msg = "mixed named and unnamed parameters"
} }

View File

@ -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{}]() {}

View File

@ -4,8 +4,8 @@
package p package p
type t[ /* ERROR type parameters must be named */ a, b] struct{} type t[a, b /* ERROR missing type constraint */ ] struct{}
type t[a t, b t, /* ERROR type parameters must be named */ c] struct{} type t[a t, b t, c /* ERROR missing type constraint */ ] struct{}
type t struct { type t struct {
t [n]byte t [n]byte
t[a] t[a]
@ -18,5 +18,5 @@ type t interface {
} }
func f[ /* ERROR empty type parameter list */ ]() func f[ /* ERROR empty type parameter list */ ]()
func f[ /* ERROR type parameters must be named */ a, b]() func f[a, b /* ERROR missing type constraint */ ]()
func f[a t, b t, /* ERROR type parameters must be named */ c]() func f[a t, b t, c /* ERROR missing type constraint */ ]()

View File

@ -5,4 +5,4 @@
package p package p
// don't crash // don't crash
func T /* ERROR missing */ [P /* ERROR named */ ] m /* ERROR m */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */ func T /* ERROR missing */ [P] /* ERROR missing */ m /* ERROR unexpected */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */