diff options
Diffstat (limited to 'src/go/types/index.go')
-rw-r--r-- | src/go/types/index.go | 154 |
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. |