diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 6692446792..afc2705909 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1406,15 +1406,11 @@ func (r *reader) forStmt(label *types.Sym) ir.Node { 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() @@ -1435,28 +1431,6 @@ func (r *reader) forStmt(label *types.Sym) ir.Node { 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() @@ -1841,6 +1815,7 @@ func (r *reader) expr() (res ir.Node) { 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. @@ -1857,7 +1832,7 @@ func (r *reader) expr() (res ir.Node) { } 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) } @@ -1865,33 +1840,6 @@ func (r *reader) expr() (res ir.Node) { } } -// 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() @@ -1917,7 +1865,7 @@ func (r *reader) multiExpr() []ir.Node { 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) } @@ -2057,12 +2005,44 @@ func (r *reader) exprs() []ir.Node { 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) diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 5dd252a2a5..d96ba0202f 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -123,8 +123,12 @@ func (pw *pkgWriter) unexpected(what string, p poser) { // 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 } @@ -361,7 +365,10 @@ func (pw *pkgWriter) pkgIdx(pkg *types2.Package) pkgbits.Index { // @@@ 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) { @@ -1304,6 +1311,34 @@ func (w *writer) forStmt(stmt *syntax.ForStmt) { 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) @@ -1315,6 +1350,30 @@ func (w *writer) forStmt(stmt *syntax.ForStmt) { 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()) @@ -1629,6 +1688,7 @@ func (w *writer) expr(expr syntax.Expr) { 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 } @@ -1763,6 +1823,7 @@ func (w *writer) multiExpr(pos poser, dstType func(int) types2.Type, exprs []syn w.p.fatalf(pos, "%v is not assignable to %v", src, dst) } w.typ(dst) + w.convRTTI(src, dst) } } return @@ -1789,6 +1850,7 @@ func (w *writer) implicitConvExpr(pos poser, dst types2.Type, expr syntax.Expr) w.Bool(true) // implicit w.typ(dst) w.pos(pos) + w.convRTTI(src, dst) // fallthrough } w.expr(expr) @@ -1883,11 +1945,21 @@ func (w *writer) exprs(exprs []syntax.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) diff --git a/src/internal/pkgbits/sync.go b/src/internal/pkgbits/sync.go index 54e478d932..a17a0088f7 100644 --- a/src/internal/pkgbits/sync.go +++ b/src/internal/pkgbits/sync.go @@ -113,4 +113,5 @@ const ( SyncMultiExpr SyncRType + SyncConvRTTI )