go/types: report error if type list contains duplicate entries

Passes all.bash.

Change-Id: I9a795c931100af662c9c62223d4e4ca0103d2af3
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/765675
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2020-06-08 16:21:30 -07:00
parent 61c4506052
commit 7307dda747
3 changed files with 40 additions and 18 deletions

View File

@ -149,7 +149,6 @@ func _(type T)(r R2(T, int), p *R2(string, T)) {
}
// An interface can (explicitly) declare at most one type list.
// Only the first respective error is reported.
type _ interface {
m0()
type int, string, bool
@ -157,7 +156,20 @@ type _ interface {
m1()
m2()
type /* ERROR multiple type lists */ complex64, complex128
type /* ERROR multiple type lists */ bool
type /* ERROR multiple type lists */ rune
}
// Interface type lists may contain each type at most once.
// (If there are multiple lists, we assume the author intended
// for them to be all in a single list, and we report the error
// as well.)
type _ interface {
type int, int /* ERROR duplicate type int */
type /* ERROR multiple type lists */ int /* ERROR duplicate type int */
}
type _ interface {
type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int}
}
// Embedding of interfaces with type lists leads to interfaces

View File

@ -362,12 +362,9 @@ func typeSet(list []Type) []Type {
// Quadratic algorithm, but probably good enough for now.
// TODO(gri) we need a fast quick type ID/hash for all types.
result := make([]Type, 0, len(list)) // assume types are unique
L:
for _, t := range list {
for _, e := range result {
if Identical(t, e) {
continue L // t already in result
}
if contains(result, t) {
continue
}
result = append(result, t)
}

View File

@ -933,11 +933,8 @@ func intersect(x, y Type) (r Type) {
// TODO(gri) fix this
var rtypes []Type
for _, x := range xtypes {
for _, y := range ytypes {
if Identical(x, y) {
rtypes = append(rtypes, x)
break
}
if contains(ytypes, x) {
rtypes = append(rtypes, x)
}
}
@ -1106,21 +1103,37 @@ func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []
}
typ := check.typ(texpr)
// A type constraint may be a predeclared type or a
// composite type composed only of predeclared types.
// TODO(gri) should we keep this restriction?
// composite type composed of only predeclared types.
var why string
if !check.typeConstraint(typ, &why) {
check.errorf(texpr.Pos(), "invalid type constraint %s (%s)", typ, why)
continue
}
// add type
// add type if not already in list
// Overall, this produces a quadratic algorithm,
// but probably good enough for now.
// TODO(gri) fix this
if contains(list, typ) {
check.errorf(texpr.Pos(), "duplicate type %s in type list", typ)
continue
}
list = append(list, typ)
}
return list
}
// TODO(gri) does this simply check for the absence of defined types?
// (if so, should choose a better name)
// contains reports whether typ is in list
func contains(list []Type, typ Type) bool {
for _, e := range list {
if Identical(typ, e) {
return true
}
}
return false
}
// typeConstraint checks that typ may be used in a type list.
// For now this just checks for the absence of defined (*Named) types.
func (check *Checker) typeConstraint(typ Type, why *string) bool {
switch t := typ.(type) {
case *Basic:
@ -1165,7 +1178,7 @@ func (check *Checker) typeConstraint(typ Type, why *string) bool {
case *Chan:
return check.typeConstraint(t.elem, why)
case *Named:
*why = check.sprintf("%s is not a type literal", t)
*why = check.sprintf("contains defined type %s", t)
return false
case *TypeParam:
// ok, e.g.: func f (type T interface { type T }) ()