Skip to content

Commit

Permalink
[dev.unified] cmd/compile: write iface conversion RTTI into unified IR
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mdempsky committed Jul 28, 2022
1 parent 9b70178 commit 9279817
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 63 deletions.
100 changes: 40 additions & 60 deletions src/cmd/compile/internal/noder/reader.go
Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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.
Expand All @@ -1857,41 +1832,14 @@ 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)
}
return typecheck.Expr(n)
}
}

// 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()
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)

Expand Down
78 changes: 75 additions & 3 deletions src/cmd/compile/internal/noder/writer.go
Expand Up @@ -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
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -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())
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions src/internal/pkgbits/sync.go
Expand Up @@ -113,4 +113,5 @@ const (

SyncMultiExpr
SyncRType
SyncConvRTTI
)

0 comments on commit 9279817

Please sign in to comment.