]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.unified] cmd/compile: write iface conversion RTTI into unified IR
authorMatthew Dempsky <mdempsky@google.com>
Sat, 23 Jul 2022 07:46:10 +0000 (00:46 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 28 Jul 2022 07:31:29 +0000 (07:31 +0000)
This CL changes convRTTI into a serialization method too, like the
previous CL's rtype method. And again, currently this just builds on
the existing type serialization logic, but will eventually be changed
to use dictionary lookups where appropriate.

Change-Id: I551aef8ade24b08dc6206f06ace86d91e665f5c1
Reviewed-on: https://go-review.googlesource.com/c/go/+/419457
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>

src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/writer.go
src/internal/pkgbits/sync.go

index 6692446792d5a4e46c89d1407f95586cc46ed945..afc2705909bb59a388910513087745439ffc3d99 100644 (file)
@@ -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)
 
index 5dd252a2a5a59b1d85170b677147015d860aa1e7..d96ba0202febc3faab950e7b0aafd01686693a62 100644 (file)
@@ -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)
 
index 54e478d9320763fd6417293f54c95d856eec871d..a17a0088f759aee53b762707df9f99037e49a0ff 100644 (file)
@@ -113,4 +113,5 @@ const (
 
        SyncMultiExpr
        SyncRType
+       SyncConvRTTI
 )