aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2021-06-08 15:58:16 -0700
committerKeith Randall <khr@golang.org>2021-06-29 21:50:53 +0000
commit6a5f7e8498b7cd53bb5461fbf777aa83aea067a8 (patch)
tree6faf2e23ce7e8205af1a6f1db64f4d334639ccca /src/cmd
parent5fa6bbc669c22f05deb421c324b90b30ae3caa08 (diff)
downloadgo-6a5f7e8498b7cd53bb5461fbf777aa83aea067a8.tar.xz
[dev.typeparams] cmd/compile: use dictionary entries for more conversion cases
This CL handles I(x) where I is an interface type and x has typeparam type. Change-Id: Ib99de2b741d588947f5e0164255f6365e98acd8a Reviewed-on: https://go-review.googlesource.com/c/go/+/326189 Trust: Keith Randall <khr@golang.org> Trust: Dan Scales <danscales@google.com> Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/noder/stencil.go79
1 files changed, 54 insertions, 25 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 49781ddc07..29ee863a71 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -838,7 +838,15 @@ func (subst *subster) node(n ir.Node) ir.Node {
case ir.OTYPE:
// Transform the conversion, now that we know the
// type argument.
- m = transformConvCall(m.(*ir.CallExpr))
+ m = transformConvCall(call)
+ if m.Op() == ir.OCONVIFACE {
+ if srcType := x.(*ir.CallExpr).Args[0].Type(); srcType.IsTypeParam() { // TODO: or derived type
+ // Note: srcType uses x.Args[0], not m.X or call.Args[0], because
+ // we need the type before the type parameter -> type argument substitution.
+ c := m.(*ir.ConvExpr)
+ m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType)
+ }
+ }
case ir.OMETHVALUE:
// Redo the transformation of OXDOT, now that we
@@ -919,30 +927,10 @@ func (subst *subster) node(n ir.Node) ir.Node {
case ir.OCONVIFACE:
x := x.(*ir.ConvExpr)
- // TODO: handle converting from derived types. For now, just from naked
- // type parameters.
- if x.X.Type().IsTypeParam() {
- // Load the actual runtime._type of the type parameter from the dictionary.
- rt := subst.getDictionaryType(m.Pos(), x.X.Type())
-
- // At this point, m is an interface type with a data word we want.
- // But the type word represents a gcshape type, which we don't want.
- // Replace with the instantiated type loaded from the dictionary.
- m = ir.NewUnaryExpr(m.Pos(), ir.OIDATA, m)
- typed(types.Types[types.TUNSAFEPTR], m)
- m = ir.NewBinaryExpr(m.Pos(), ir.OEFACE, rt, m)
- if !x.Type().IsEmptyInterface() {
- // We just built an empty interface{}. Type it as such,
- // then assert it to the required non-empty interface.
- typed(types.NewInterface(types.LocalPkg, nil), m)
- m = ir.NewTypeAssertExpr(m.Pos(), m, nil)
- }
- typed(x.Type(), m)
- // TODO: we're throwing away the type word of the original version
- // of m here (it would be OITAB(m)), which probably took some
- // work to generate. Can we avoid generating it at all?
- // (The linker will throw them away if not needed, so it would just
- // save toolchain work, not binary size.)
+ // Note: x's argument is still typed as a type parameter.
+ // m's argument now has an instantiated type.
+ if t := x.X.Type(); t.IsTypeParam() {
+ m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t)
}
}
return m
@@ -951,6 +939,47 @@ func (subst *subster) node(n ir.Node) ir.Node {
return edit(n)
}
+// convertUsingDictionary converts value v from generic type src to an interface type dst.
+func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type) ir.Node {
+ // TODO: handle converting from derived types. For now, just from naked
+ // type parameters.
+ if !src.IsTypeParam() {
+ base.Fatalf("source must be a type parameter %+v", src)
+ }
+ if !dst.IsInterface() {
+ base.Fatalf("can only convert type parameters to interfaces %+v -> %+v", src, dst)
+ }
+ // Load the actual runtime._type of the type parameter from the dictionary.
+ rt := subst.getDictionaryType(pos, src)
+
+ // Convert value to an interface type, so the data field is what we want.
+ if !v.Type().IsInterface() {
+ v = ir.NewConvExpr(v.Pos(), ir.OCONVIFACE, nil, v)
+ typed(types.NewInterface(types.LocalPkg, nil), v)
+ }
+
+ // At this point, v is an interface type with a data word we want.
+ // But the type word represents a gcshape type, which we don't want.
+ // Replace with the instantiated type loaded from the dictionary.
+ data := ir.NewUnaryExpr(pos, ir.OIDATA, v)
+ typed(types.Types[types.TUNSAFEPTR], data)
+ var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data)
+ if !dst.IsEmptyInterface() {
+ // We just built an empty interface{}. Type it as such,
+ // then assert it to the required non-empty interface.
+ typed(types.NewInterface(types.LocalPkg, nil), i)
+ i = ir.NewTypeAssertExpr(pos, i, nil)
+ }
+ typed(dst, i)
+ // TODO: we're throwing away the type word of the original version
+ // of m here (it would be OITAB(m)), which probably took some
+ // work to generate. Can we avoid generating it at all?
+ // (The linker will throw them away if not needed, so it would just
+ // save toolchain work, not binary size.)
+ return i
+
+}
+
func (subst *subster) namelist(l []*ir.Name) []*ir.Name {
s := make([]*ir.Name, len(l))
for i, n := range l {