mirror of
https://github.com/golang/go
synced 2024-11-16 21:04:45 -07:00
[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>
This commit is contained in:
parent
5fa6bbc669
commit
6a5f7e8498
@ -838,7 +838,15 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||||||
case ir.OTYPE:
|
case ir.OTYPE:
|
||||||
// Transform the conversion, now that we know the
|
// Transform the conversion, now that we know the
|
||||||
// type argument.
|
// 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:
|
case ir.OMETHVALUE:
|
||||||
// Redo the transformation of OXDOT, now that we
|
// Redo the transformation of OXDOT, now that we
|
||||||
@ -919,30 +927,10 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||||||
|
|
||||||
case ir.OCONVIFACE:
|
case ir.OCONVIFACE:
|
||||||
x := x.(*ir.ConvExpr)
|
x := x.(*ir.ConvExpr)
|
||||||
// TODO: handle converting from derived types. For now, just from naked
|
// Note: x's argument is still typed as a type parameter.
|
||||||
// type parameters.
|
// m's argument now has an instantiated type.
|
||||||
if x.X.Type().IsTypeParam() {
|
if t := x.X.Type(); t.IsTypeParam() {
|
||||||
// Load the actual runtime._type of the type parameter from the dictionary.
|
m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t)
|
||||||
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.)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
@ -951,6 +939,47 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||||||
return edit(n)
|
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 {
|
func (subst *subster) namelist(l []*ir.Name) []*ir.Name {
|
||||||
s := make([]*ir.Name, len(l))
|
s := make([]*ir.Name, len(l))
|
||||||
for i, n := range l {
|
for i, n := range l {
|
||||||
|
@ -38,10 +38,14 @@ func h[T C](x T) interface{foo() int} {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
func i[T C](x T) C {
|
func i[T C](x T) C {
|
||||||
var i C = x
|
var i C = x // conversion in assignment
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func j[T C](t T) C {
|
||||||
|
return C(t) // explicit conversion
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if got, want := f[int](7), 7; got != want {
|
if got, want := f[int](7), 7; got != want {
|
||||||
panic(fmt.Sprintf("got %d want %d", got, want))
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
@ -55,4 +59,7 @@ func main() {
|
|||||||
if got, want := i[myInt](7).foo(), 8; got != want {
|
if got, want := i[myInt](7).foo(), 8; got != want {
|
||||||
panic(fmt.Sprintf("got %d want %d", got, want))
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
}
|
}
|
||||||
|
if got, want := j[myInt](7).foo(), 8; got != want {
|
||||||
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user