if rang.X.Type().IsMap() {
rang.RType = r.rtype(pos)
}
- {
- keyType, valueType := rangeTypes(pos, rang.X.Type())
-
- if rang.Key != nil {
- rang.KeyTypeWord, rang.KeySrcRType = convRTTI(pos, rang.Key.Type(), keyType)
- }
- if rang.Value != nil {
- rang.ValueTypeWord, rang.ValueSrcRType = convRTTI(pos, rang.Value.Type(), valueType)
- }
+ if rang.Key != nil && !ir.IsBlank(rang.Key) {
+ rang.KeyTypeWord, rang.KeySrcRType = r.convRTTI(pos)
+ }
+ if rang.Value != nil && !ir.IsBlank(rang.Value) {
+ rang.ValueTypeWord, rang.ValueSrcRType = r.convRTTI(pos)
}
rang.Body = r.blockStmt()
return stmt
}
-// rangeTypes returns the types of values produced by ranging over a
-// value of type typ.
-func rangeTypes(pos src.XPos, typ *types.Type) (key, value *types.Type) {
- switch typ.Kind() {
- default:
- base.FatalfAt(pos, "unexpected range type: %v", typ)
- panic("unreachable")
- case types.TPTR: // must be pointer to array
- typ = typ.Elem()
- base.AssertfAt(typ.Kind() == types.TARRAY, pos, "want array type, have %v", typ)
- fallthrough
- case types.TARRAY, types.TSLICE:
- return types.Types[types.TINT], typ.Elem()
- case types.TSTRING:
- return types.Types[types.TINT], types.RuneType
- case types.TMAP:
- return typ.Key(), typ.Elem()
- case types.TCHAN:
- return typ.Elem(), nil
- }
-}
-
func (r *reader) ifStmt() ir.Node {
r.Sync(pkgbits.SyncIfStmt)
r.openScope()
implicit := r.Bool()
typ := r.typ()
pos := r.pos()
+ typeWord, srcRType := r.convRTTI(pos)
x := r.expr()
// TODO(mdempsky): Stop constructing expressions of untyped type.
}
n := ir.NewConvExpr(pos, ir.OCONV, typ, x)
- n.TypeWord, n.SrcRType = convRTTI(pos, typ, x.Type())
+ n.TypeWord, n.SrcRType = typeWord, srcRType
if implicit {
n.SetImplicit(true)
}
}
}
-// convRTTI returns the TypeWord and SrcRType expressions appropriate
-// for a conversion from src to dst.
-func convRTTI(pos src.XPos, dst, src *types.Type) (typeWord, srcRType ir.Node) {
- if !dst.IsInterface() {
- return
- }
-
- // See reflectdata.ConvIfaceTypeWord.
- switch {
- case dst.IsEmptyInterface():
- if !src.IsInterface() {
- typeWord = reflectdata.TypePtrAt(pos, src) // direct eface construction
- }
- case !src.IsInterface():
- typeWord = reflectdata.ITabAddrAt(pos, src, dst) // direct iface construction
- default:
- typeWord = reflectdata.TypePtrAt(pos, dst) // convI2I
- }
-
- // See reflectdata.ConvIfaceSrcRType.
- if !src.IsInterface() {
- srcRType = reflectdata.TypePtrAt(pos, src)
- }
-
- return
-}
-
func (r *reader) optExpr() ir.Node {
if r.Bool() {
return r.expr()
res := ir.Node(tmp)
if r.Bool() {
n := ir.NewConvExpr(pos, ir.OCONV, r.typ(), res)
- n.TypeWord, n.SrcRType = convRTTI(pos, n.Type(), n.X.Type())
+ n.TypeWord, n.SrcRType = r.convRTTI(pos)
n.SetImplicit(true)
res = typecheck.Expr(n)
}
return nodes
}
+// rtype returns an expression of type *runtime._type.
func (r *reader) rtype(pos src.XPos) ir.Node {
r.Sync(pkgbits.SyncRType)
// TODO(mdempsky): For derived types, use dictionary instead.
return reflectdata.TypePtrAt(pos, r.typ())
}
+// convRTTI returns expressions appropriate for populating an
+// ir.ConvExpr's TypeWord and SrcRType fields, respectively.
+func (r *reader) convRTTI(pos src.XPos) (typeWord, srcRType ir.Node) {
+ r.Sync(pkgbits.SyncConvRTTI)
+ src := r.typ()
+ dst := r.typ()
+
+ if !dst.IsInterface() {
+ return
+ }
+
+ // See reflectdata.ConvIfaceTypeWord.
+ switch {
+ case dst.IsEmptyInterface():
+ if !src.IsInterface() {
+ typeWord = reflectdata.TypePtrAt(pos, src) // direct eface construction
+ }
+ case !src.IsInterface():
+ typeWord = reflectdata.ITabAddrAt(pos, src, dst) // direct iface construction
+ default:
+ typeWord = reflectdata.TypePtrAt(pos, dst) // convI2I
+ }
+
+ // See reflectdata.ConvIfaceSrcRType.
+ if !src.IsInterface() {
+ srcRType = reflectdata.TypePtrAt(pos, src)
+ }
+
+ return
+}
+
func (r *reader) exprType(nilOK bool) ir.Node {
r.Sync(pkgbits.SyncExprType)
// typeOf returns the Type of the given value expression.
func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type {
tv, ok := pw.info.Types[expr]
- assert(ok)
- assert(tv.IsValue())
+ if !ok {
+ pw.fatalf(expr, "missing Types entry: %v", syntax.String(expr))
+ }
+ if !tv.IsValue() {
+ pw.fatalf(expr, "expected value: %v", syntax.String(expr))
+ }
return tv.Type
}
// @@@ Types
-var anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
+var (
+ anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
+ runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName)
+)
// typ writes a use of the given type into the bitstream.
func (w *writer) typ(typ types2.Type) {
if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap {
w.rtype(xtyp)
}
+ {
+ lhs := unpackListExpr(rang.Lhs)
+ assign := func(i int, src types2.Type) {
+ if i >= len(lhs) {
+ return
+ }
+ dst := unparen(lhs[i])
+ if name, ok := dst.(*syntax.Name); ok && name.Value == "_" {
+ return
+ }
+
+ var dstType types2.Type
+ if rang.Def {
+ // For `:=` assignments, the LHS names only appear in Defs,
+ // not Types (as used by typeOf).
+ dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type()
+ } else {
+ dstType = w.p.typeOf(dst)
+ }
+
+ w.convRTTI(src, dstType)
+ }
+
+ keyType, valueType := w.p.rangeTypes(rang.X)
+ assign(0, keyType)
+ assign(1, valueType)
+ }
+
} else {
w.pos(stmt)
w.stmt(stmt.Init)
w.closeAnotherScope()
}
+// rangeTypes returns the types of values produced by ranging over
+// expr.
+func (pw *pkgWriter) rangeTypes(expr syntax.Expr) (key, value types2.Type) {
+ typ := pw.typeOf(expr)
+ switch typ := types2.CoreType(typ).(type) {
+ case *types2.Pointer: // must be pointer to array
+ return types2.Typ[types2.Int], types2.CoreType(typ.Elem()).(*types2.Array).Elem()
+ case *types2.Array:
+ return types2.Typ[types2.Int], typ.Elem()
+ case *types2.Slice:
+ return types2.Typ[types2.Int], typ.Elem()
+ case *types2.Basic:
+ if typ.Info()&types2.IsString != 0 {
+ return types2.Typ[types2.Int], runeTypeName.Type()
+ }
+ case *types2.Map:
+ return typ.Key(), typ.Elem()
+ case *types2.Chan:
+ return typ.Elem(), nil
+ }
+ pw.fatalf(expr, "unexpected range type: %v", typ)
+ panic("unreachable")
+}
+
func (w *writer) ifStmt(stmt *syntax.IfStmt) {
w.Sync(pkgbits.SyncIfStmt)
w.openScope(stmt.Pos())
w.Bool(false) // explicit
w.typ(tv.Type)
w.pos(expr)
+ w.convRTTI(w.p.typeOf(expr.ArgList[0]), tv.Type)
w.expr(expr.ArgList[0])
break
}
w.p.fatalf(pos, "%v is not assignable to %v", src, dst)
}
w.typ(dst)
+ w.convRTTI(src, dst)
}
}
return
w.Bool(true) // implicit
w.typ(dst)
w.pos(pos)
+ w.convRTTI(src, dst)
// fallthrough
}
w.expr(expr)
}
}
+// rtype writes information so that the reader can construct an
+// expression of type *runtime._type representing typ.
func (w *writer) rtype(typ types2.Type) {
w.Sync(pkgbits.SyncRType)
w.typ(typ)
}
+// convRTTI writes information so that the reader can construct
+// expressions for converting from src to dst.
+func (w *writer) convRTTI(src, dst types2.Type) {
+ w.Sync(pkgbits.SyncConvRTTI)
+ w.typ(src)
+ w.typ(dst)
+}
+
func (w *writer) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) {
base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface)