go/types: use Interface.is for generic variable indexing/len/cap (cleanup)

Interface.is already takes care of iterating through all types of
a generic type bound; use it instead of writing custom loops each
time.

Change-Id: Ie0f91b27e5a7b65ea85a8c3847a954db1e9f24fe
This commit is contained in:
Robert Griesemer 2020-01-08 09:31:22 -08:00
parent 1a2a175a8e
commit 3c2505cae9
2 changed files with 41 additions and 50 deletions

View File

@ -176,28 +176,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
case *TypeParam:
if types := t.Interface().allTypes; len(types) > 0 {
mode = value // assume we're ok
L:
for _, t := range types {
switch t.(type) {
case *Basic:
if !isString(t) || id != _Len {
mode = invalid
break L
}
case *Array, *Slice, *Chan:
// ok
case *Map:
if id != _Len {
mode = invalid
break L
}
default:
mode = invalid
break L
if t.Interface().is(func(t Type) bool {
switch t.(type) {
case *Basic:
if isString(t) && id == _Len {
return true
}
case *Array, *Slice, *Chan:
return true
case *Map:
if id == _Len {
return true
}
}
return false
}) {
mode = value
}
}

View File

@ -1363,40 +1363,37 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
return expression
case *TypeParam:
if types := typ.Interface().allTypes; len(types) > 0 {
// A generic variable can be indexed if all types
// in its type bound support indexing and have the
// same element type.
var elem Type
for _, t := range types {
var e Type
switch t := t.(type) {
case *Basic:
if isString(t) {
e = universeByte
}
case *Array:
e = t.elem
case *Pointer:
if t, _ := t.base.Underlying().(*Array); t != nil {
e = t.elem
}
case *Slice:
e = t.elem
case *Map:
// A generic variable can be indexed if all types
// in its type bound support indexing and have the
// same element type.
var elem Type
if typ.Interface().is(func(t Type) bool {
var e Type
switch t := t.(type) {
case *Basic:
if isString(t) {
e = universeByte
}
case *Array:
e = t.elem
case *Pointer:
if t, _ := t.base.Underlying().(*Array); t != nil {
e = t.elem
}
if e == nil || elem != nil && e != elem {
elem = nil
break
}
case *Slice:
e = t.elem
case *Map:
e = t.elem
}
if e != nil && (e == elem || elem == nil) {
elem = e
return true
}
if elem != nil {
valid = true
x.mode = variable
x.typ = elem
}
return false
}) {
valid = true
x.mode = variable
x.typ = elem
}
}