From 7307dda747a135ed6e25d344cb4c6b66b552f752 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 8 Jun 2020 16:21:30 -0700 Subject: [PATCH] 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 --- src/go/types/testdata/typeinst2.go2 | 16 +++++++++++-- src/go/types/type.go | 7 ++---- src/go/types/typexpr.go | 35 ++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index b31694c34d..6ff9b6510a 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -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 diff --git a/src/go/types/type.go b/src/go/types/type.go index 3130511b63..08b416165e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -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) } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 79ecb6cc00..5fea20f8f7 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -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 }) ()