mirror of https://github.com/golang/go.git
go/types: first cut at supporting range over generic variables
TODO - some channel errors are not reported for generic variables - error messages should be better Change-Id: Ie388d6811b605645ea092481eee3a850c7ceb77b
This commit is contained in:
parent
c8947e760e
commit
172f10b1e2
|
|
@ -14,6 +14,7 @@ TODO
|
|||
----------------------------------------------------------------------------------------------------
|
||||
KNOWN ISSUES
|
||||
|
||||
- iteration over generic variables doesn't report certain channel errors (see TODOs in code)
|
||||
- cannot handle mutually recursive parameterized interfaces using themselves as type bounds
|
||||
- contract instantiation requires the type arguments to be type parameters from the type of function
|
||||
type parameter list or enclosing contract
|
||||
|
|
|
|||
|
|
@ -751,43 +751,24 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
// determine key/value types
|
||||
var key, val Type
|
||||
if x.mode != invalid {
|
||||
switch typ := x.typ.Underlying().(type) {
|
||||
case *Basic:
|
||||
if isString(typ) {
|
||||
key = Typ[Int]
|
||||
val = universeRune // use 'rune' name
|
||||
}
|
||||
case *Array:
|
||||
key = Typ[Int]
|
||||
val = typ.elem
|
||||
case *Slice:
|
||||
key = Typ[Int]
|
||||
val = typ.elem
|
||||
case *Pointer:
|
||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||
key = Typ[Int]
|
||||
val = typ.elem
|
||||
}
|
||||
case *Map:
|
||||
key = typ.key
|
||||
val = typ.elem
|
||||
case *Chan:
|
||||
key = typ.elem
|
||||
val = Typ[Invalid]
|
||||
typ := x.typ.Underlying()
|
||||
// TODO(gri) these tests need to be done also for type parameter channel types
|
||||
// => move into rangeTypes and return an error message instead
|
||||
if typ, _ := typ.(*Chan); typ != nil {
|
||||
if typ.dir == SendOnly {
|
||||
check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
|
||||
check.softErrorf(x.pos(), "cannot range over send-only channel %s", &x)
|
||||
// ok to continue
|
||||
}
|
||||
if s.Value != nil {
|
||||
check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
|
||||
check.softErrorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
check.errorf(x.pos(), "cannot range over %s", &x)
|
||||
// ok to continue
|
||||
key, val = rangeTypes(typ, isVarName(s.Key), isVarName(s.Value))
|
||||
if key == nil {
|
||||
check.softErrorf(x.pos(), "cannot range over %s", &x)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
|
||||
// check assignment to/declaration of iteration variables
|
||||
|
|
@ -869,3 +850,49 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
check.error(s.Pos(), "invalid statement")
|
||||
}
|
||||
}
|
||||
|
||||
func isVarName(x ast.Expr) bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
ident, _ := unparen(x).(*ast.Ident)
|
||||
return ident == nil || ident.Name != "_"
|
||||
}
|
||||
|
||||
func rangeTypes(typ Type, wantKey, wantVal bool) (Type, Type) {
|
||||
switch typ := typ.(type) {
|
||||
case *Basic:
|
||||
if isString(typ) {
|
||||
return Typ[Int], universeRune // use 'rune' name
|
||||
}
|
||||
case *Array:
|
||||
return Typ[Int], typ.elem
|
||||
case *Slice:
|
||||
return Typ[Int], typ.elem
|
||||
case *Pointer:
|
||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||
return Typ[Int], typ.elem
|
||||
}
|
||||
case *Map:
|
||||
return typ.key, typ.elem
|
||||
case *Chan:
|
||||
// TODO(gri) we need to move the additional channel checks here
|
||||
return typ.elem, Typ[Invalid]
|
||||
case *TypeParam:
|
||||
first := true
|
||||
var key, val Type
|
||||
if typ.Interface().is(func(t Type) bool {
|
||||
k, v := rangeTypes(t, true, true)
|
||||
if first {
|
||||
key, val = k, v
|
||||
first = false
|
||||
return true
|
||||
}
|
||||
// TODO(gri) if we fail we should return an explanatory error message
|
||||
return (!wantKey || Identical(key, k)) && (!wantVal || Identical(val, v))
|
||||
}) {
|
||||
return key, val
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,25 +27,34 @@ type II interface{
|
|||
var _ I = II(nil)
|
||||
*/
|
||||
|
||||
contract C(A, B) {
|
||||
A a()
|
||||
B b()
|
||||
func _(type T interface{})(x T) {
|
||||
for range x /* ERROR cannot range */ {}
|
||||
}
|
||||
|
||||
//func fa(type A, B, C) (A, B, C)
|
||||
//func fb(type A, B, C ABC) (A, B, C)
|
||||
//func fc(type A, B, C ABC(A, B, C)) (A, B, C)
|
||||
func fd(type A, B, X C(B, A)) ()
|
||||
func _(type T interface{ type string, []string })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i }
|
||||
for i, e := range x /* ERROR cannot range */ { _ = i } // different element types
|
||||
for _, e := range x /* ERROR cannot range */ {} // different element types
|
||||
var e rune
|
||||
_ = e
|
||||
for _, (e) = range x /* ERROR cannot range */ {} // different element types
|
||||
}
|
||||
|
||||
type tA struct{}; func (tA) a()
|
||||
type tB struct{}; func (tB) b()
|
||||
|
||||
func _() {
|
||||
//var a tA
|
||||
//var b tB
|
||||
//fa(a, b, 0)
|
||||
//(a, b, 0)
|
||||
//(a, b, 0)
|
||||
//fd(a, b, 0)
|
||||
fd(tA /* ERROR does not satisfy */ , tB, int)()
|
||||
}
|
||||
func _(type T interface{ type string, []rune, map[int]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x { _ = i; _ = e }
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, []rune, map[string]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x /* ERROR cannot range */ { _ = e } // different key types
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, chan int })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,40 @@ func _(type T interface{ type map[int]int })(x T) { _ = cap(x /* ERROR invalid a
|
|||
func _(type T interface{ type chan int })(x T) { _ = cap(x) }
|
||||
func _(type T interface{ type []byte, chan int })(x T) { _ = cap(x) }
|
||||
|
||||
// range iteration
|
||||
|
||||
func _(type T interface{})(x T) {
|
||||
for range x /* ERROR cannot range */ {}
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, []string })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i }
|
||||
for i, e := range x /* ERROR cannot range */ { _ = i } // different element types
|
||||
for _, e := range x /* ERROR cannot range */ {} // different element types
|
||||
var e rune
|
||||
_ = e
|
||||
for _, (e) = range x /* ERROR cannot range */ {} // different element types
|
||||
}
|
||||
|
||||
|
||||
func _(type T interface{ type string, []rune, map[int]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x { _ = i; _ = e }
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, []rune, map[string]rune })(x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x /* ERROR cannot range */ { _ = e } // different key types
|
||||
}
|
||||
|
||||
func _(type T interface{ type string, chan int })(x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
|
||||
}
|
||||
|
||||
// type inference checks
|
||||
|
||||
var _ = new() /* ERROR cannot infer T */
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
|
||||
// Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
|
||||
// declarations and then squash that scope into the parent scope (and report any redeclarations at
|
||||
// at that time).
|
||||
// that time).
|
||||
scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)")
|
||||
recvList, _ := check.collectParams(scope, recvPar, false)
|
||||
params, variadic := check.collectParams(scope, ftyp.Params, true)
|
||||
|
|
|
|||
Loading…
Reference in New Issue