aboutsummaryrefslogtreecommitdiff
path: root/src/go/types/index.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/types/index.go')
-rw-r--r--src/go/types/index.go154
1 files changed, 70 insertions, 84 deletions
diff --git a/src/go/types/index.go b/src/go/types/index.go
index 2ba3475f89..a49bc5519c 100644
--- a/src/go/types/index.go
+++ b/src/go/types/index.go
@@ -15,25 +15,25 @@ import (
// If e is a valid function instantiation, indexExpr returns true.
// In that case x represents the uninstantiated function value and
// it is the caller's responsibility to instantiate the function.
-func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) {
+func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst bool) {
check.exprOrType(x, e.X)
switch x.mode {
case invalid:
- check.use(typeparams.UnpackExpr(e.Index)...)
+ check.use(e.Indices...)
return false
case typexpr:
// type instantiation
x.mode = invalid
- x.typ = check.varType(e)
+ x.typ = check.varType(e.Orig)
if x.typ != Typ[Invalid] {
x.mode = typexpr
}
return false
case value:
- if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
+ if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
// function instantiation
return true
}
@@ -41,7 +41,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool)
valid := false
length := int64(-1) // valid if >= 0
- switch typ := optype(x.typ).(type) {
+ switch typ := under(x.typ).(type) {
case *Basic:
if isString(typ) {
valid = true
@@ -80,7 +80,7 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool)
index := check.singleIndex(e)
if index == nil {
x.mode = invalid
- return
+ return false
}
var key operand
check.expr(&key, index)
@@ -88,88 +88,81 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool)
// ok to continue even if indexing failed - map element type is known
x.mode = mapindex
x.typ = typ.elem
- x.expr = e
- return
+ x.expr = e.Orig
+ return false
- case *_Sum:
- // A sum type can be indexed if all of the sum's types
- // support indexing and have the same index and element
- // type. Special rules apply for maps in the sum type.
- var tkey, telem Type // key is for map types only
- nmaps := 0 // number of map types in sum type
- if typ.is(func(t Type) bool {
- var e Type
- switch t := under(t).(type) {
+ case *TypeParam:
+ // TODO(gri) report detailed failure cause for better error messages
+ var tkey, telem Type // tkey != nil if we have maps
+ if typ.underIs(func(u Type) bool {
+ var key, elem Type
+ alen := int64(-1) // valid if >= 0
+ switch t := u.(type) {
case *Basic:
- if isString(t) {
- e = universeByte
+ if !isString(t) {
+ return false
}
+ elem = universeByte
case *Array:
- e = t.elem
+ elem = t.elem
+ alen = t.len
case *Pointer:
- if t := asArray(t.base); t != nil {
- e = t.elem
+ a, _ := under(t.base).(*Array)
+ if a == nil {
+ return false
}
+ elem = a.elem
+ alen = a.len
case *Slice:
- e = t.elem
+ elem = t.elem
case *Map:
- // If there are multiple maps in the sum type,
- // they must have identical key types.
- // TODO(gri) We may be able to relax this rule
- // but it becomes complicated very quickly.
- if tkey != nil && !Identical(t.key, tkey) {
+ key = t.key
+ elem = t.elem
+ default:
+ return false
+ }
+ assert(elem != nil)
+ if telem == nil {
+ // first type
+ tkey, telem = key, elem
+ length = alen
+ } else {
+ // all map keys must be identical (incl. all nil)
+ if !Identical(key, tkey) {
return false
}
- tkey = t.key
- e = t.elem
- nmaps++
- case *_TypeParam:
- check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
- case *instance:
- panic("unimplemented")
- }
- if e == nil || telem != nil && !Identical(e, telem) {
- return false
+ // all element types must be identical
+ if !Identical(elem, telem) {
+ return false
+ }
+ tkey, telem = key, elem
+ // track the minimal length for arrays
+ if alen >= 0 && alen < length {
+ length = alen
+ }
}
- telem = e
return true
}) {
- // If there are maps, the index expression must be assignable
- // to the map key type (as for simple map index expressions).
- if nmaps > 0 {
+ // For maps, the index expression must be assignable to the map key type.
+ if tkey != nil {
index := check.singleIndex(e)
if index == nil {
x.mode = invalid
- return
+ return false
}
var key operand
check.expr(&key, index)
check.assignment(&key, tkey, "map index")
// ok to continue even if indexing failed - map element type is known
-
- // If there are only maps, we are done.
- if nmaps == len(typ.types) {
- x.mode = mapindex
- x.typ = telem
- x.expr = e
- return
- }
-
- // Otherwise we have mix of maps and other types. For
- // now we require that the map key be an integer type.
- // TODO(gri) This is probably not good enough.
- valid = isInteger(tkey)
- // avoid 2nd indexing error if indexing failed above
- if !valid && key.mode == invalid {
- x.mode = invalid
- return
- }
- x.mode = value // map index expressions are not addressable
- } else {
- // no maps
- valid = true
- x.mode = variable
+ x.mode = mapindex
+ x.typ = telem
+ x.expr = e
+ return false
}
+
+ // no maps
+ valid = true
+ x.mode = variable
x.typ = telem
}
}
@@ -177,13 +170,13 @@ func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool)
if !valid {
check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x)
x.mode = invalid
- return
+ return false
}
index := check.singleIndex(e)
if index == nil {
x.mode = invalid
- return
+ return false
}
// In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0)
@@ -206,7 +199,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
valid := false
length := int64(-1) // valid if >= 0
- switch typ := optype(x.typ).(type) {
+ switch typ := under(x.typ).(type) {
case *Basic:
if isString(typ) {
if e.Slice3 {
@@ -246,8 +239,8 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
valid = true
// x.typ doesn't change
- case *_Sum, *_TypeParam:
- check.errorf(x, 0, "generic slice expressions not yet implemented")
+ case *TypeParam:
+ check.errorf(x, _Todo, "generic slice expressions not yet implemented")
x.mode = invalid
return
}
@@ -311,23 +304,16 @@ L:
// singleIndex returns the (single) index from the index expression e.
// If the index is missing, or if there are multiple indices, an error
// is reported and the result is nil.
-func (check *Checker) singleIndex(e *ast.IndexExpr) ast.Expr {
- index := e.Index
- if index == nil {
- check.invalidAST(e, "missing index for %s", e)
- return nil
- }
-
- indexes := typeparams.UnpackExpr(index)
- if len(indexes) == 0 {
- check.invalidAST(index, "index expression %v with 0 indices", index)
+func (check *Checker) singleIndex(expr *typeparams.IndexExpr) ast.Expr {
+ if len(expr.Indices) == 0 {
+ check.invalidAST(expr.Orig, "index expression %v with 0 indices", expr)
return nil
}
- if len(indexes) > 1 {
+ if len(expr.Indices) > 1 {
// TODO(rFindley) should this get a distinct error code?
- check.invalidOp(indexes[1], _InvalidIndex, "more than one index")
+ check.invalidOp(expr.Indices[1], _InvalidIndex, "more than one index")
}
- return indexes[0]
+ return expr.Indices[0]
}
// index checks an index expression for validity.