go/types: implement len/cap for arguments of type paramater type

Change-Id: Ieeaa41573e5ec10df46ab25ec0a3563e3ae5b32b
This commit is contained in:
Robert Griesemer 2020-01-07 21:55:00 -08:00
parent c49fde5b11
commit d2fce6bc64
3 changed files with 49 additions and 0 deletions

View File

@ -23,6 +23,8 @@ KNOWN ISSUES
----------------------------------------------------------------------------------------------------
OPEN QUESTIONS
- for len/cap(x) where x is of type parameter type and the bound contains arrays only, should the
result be a constant? (right now it is not)
- confirm that it's ok to use inference in missingMethod to compare parameterized methods
- now that we allow parenthesized embedded interfaces, should we allow parenthesized embedded fields?
(probably yes, for symmetry and consistency).

View File

@ -174,6 +174,31 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
if id == _Len {
mode = value
}
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 mode == invalid && typ != Typ[Invalid] {

View File

@ -79,6 +79,28 @@ func f3(type A, B, C)(A, struct{x B}, func(A, struct{x B}, *C)) int
var _ = f3(int, rune, bool)(1, struct{x rune}{}, nil)
// len/cap built-ins
func _(type T)(x T) { _ = len(x /* ERROR invalid argument */ ) }
func _(type T interface{ type int })(x T) { _ = len(x /* ERROR invalid argument */ ) }
func _(type T interface{ type string, []byte, int })(x T) { _ = len(x /* ERROR invalid argument */ ) }
func _(type T interface{ type string })(x T) { _ = len(x) }
func _(type T interface{ type [10]int })(x T) { _ = len(x) }
func _(type T interface{ type []byte })(x T) { _ = len(x) }
func _(type T interface{ type map[int]int })(x T) { _ = len(x) }
func _(type T interface{ type chan int })(x T) { _ = len(x) }
func _(type T interface{ type string, []byte, chan int })(x T) { _ = len(x) }
func _(type T)(x T) { _ = cap(x /* ERROR invalid argument */ ) }
func _(type T interface{ type int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
func _(type T interface{ type string, []byte, int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
func _(type T interface{ type string })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
func _(type T interface{ type [10]int })(x T) { _ = cap(x) }
func _(type T interface{ type []byte })(x T) { _ = cap(x) }
func _(type T interface{ type map[int]int })(x T) { _ = cap(x /* ERROR invalid argument */ ) }
func _(type T interface{ type chan int })(x T) { _ = cap(x) }
func _(type T interface{ type []byte, chan int })(x T) { _ = cap(x) }
// type inference checks
var _ = new() /* ERROR cannot infer T */