mirror of
https://github.com/golang/go
synced 2024-09-04 15:34:21 +00:00
[dev.typeparams] cmd/compile: handle derived types that are converted to interfaces
Up to this point, we were only handling typeparams that were converted to empty or non-empty interfaces. But we have a dictionary entry for each derived type (i.e. type derived from typeparams) as well. So, when doing a conversion, look for the source type in both the type params and derived types of the generic info, and then use the appropriate dictionary entry. Added some cases to ifaceconv.go (e.g. converting []T to an empty interface). Change-Id: I7bbad0128bec20ccccd93ae1d65c1ffd44ca79a0 Reviewed-on: https://go-review.googlesource.com/c/go/+/333011 Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
b614c05a15
commit
501725032c
|
@ -979,21 +979,14 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDictionaryType returns a *runtime._type from the dictionary corresponding to the input type.
|
// getDictionaryType returns a *runtime._type from the dictionary entry i
|
||||||
// The input type must be a type parameter (TODO: or a local derived type).
|
// (which refers to a type param or a derived type that uses type params).
|
||||||
func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node {
|
func (subst *subster) getDictionaryType(pos src.XPos, i int) ir.Node {
|
||||||
tparams := subst.ts.Tparams
|
if i < 0 || i >= subst.info.startSubDict {
|
||||||
var i = 0
|
base.Fatalf(fmt.Sprintf("bad dict index %d", i))
|
||||||
for i = range tparams {
|
|
||||||
if t == tparams[i] {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i == len(tparams) {
|
|
||||||
base.Fatalf(fmt.Sprintf("couldn't find type param %+v", t))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := getDictionaryEntry(pos, subst.info.dictParam, i, len(tparams))
|
r := getDictionaryEntry(pos, subst.info.dictParam, i, subst.info.startSubDict)
|
||||||
// change type of retrieved dictionary entry to *byte, which is the
|
// change type of retrieved dictionary entry to *byte, which is the
|
||||||
// standard typing of a *runtime._type in the compiler
|
// standard typing of a *runtime._type in the compiler
|
||||||
typed(types.Types[types.TUINT8].PtrTo(), r)
|
typed(types.Types[types.TUINT8].PtrTo(), r)
|
||||||
|
@ -1134,11 +1127,12 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||||
// type argument.
|
// type argument.
|
||||||
m = transformConvCall(call)
|
m = transformConvCall(call)
|
||||||
if m.Op() == ir.OCONVIFACE {
|
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
|
||||||
// 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.
|
||||||
// we need the type before the type parameter -> type argument substitution.
|
srcType := x.(*ir.CallExpr).Args[0].Type()
|
||||||
|
if ix := subst.findDictType(srcType); ix >= 0 {
|
||||||
c := m.(*ir.ConvExpr)
|
c := m.(*ir.ConvExpr)
|
||||||
m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType)
|
m = subst.convertUsingDictionary(c.Pos(), c.X, c.Type(), srcType, ix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1240,8 +1234,9 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||||
x := x.(*ir.ConvExpr)
|
x := x.(*ir.ConvExpr)
|
||||||
// Note: x's argument is still typed as a type parameter.
|
// Note: x's argument is still typed as a type parameter.
|
||||||
// m's argument now has an instantiated type.
|
// m's argument now has an instantiated type.
|
||||||
if t := x.X.Type(); t.IsTypeParam() {
|
t := x.X.Type()
|
||||||
m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t)
|
if ix := subst.findDictType(t); ix >= 0 {
|
||||||
|
m = subst.convertUsingDictionary(x.Pos(), m.(*ir.ConvExpr).X, m.Type(), t, ix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
@ -1250,18 +1245,31 @@ 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.
|
// findDictType looks for type t in the typeparams or derived types in the generic
|
||||||
func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type) ir.Node {
|
// function info subst.info.gfInfo. This will indicate the dictionary entry with the
|
||||||
// TODO: handle converting from derived types. For now, just from naked
|
// correct concrete type for the associated instantiated function.
|
||||||
// type parameters.
|
func (subst *subster) findDictType(t *types.Type) int {
|
||||||
if !src.IsTypeParam() {
|
for i, dt := range subst.info.gfInfo.tparams {
|
||||||
base.Fatalf("source must be a type parameter %+v", src)
|
if dt == t {
|
||||||
|
return i
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for i, dt := range subst.info.gfInfo.derivedTypes {
|
||||||
|
if types.Identical(dt, t) {
|
||||||
|
return i + len(subst.info.gfInfo.tparams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertUsingDictionary converts value v from instantiated type src (which is index
|
||||||
|
// 'ix' in the instantiation's dictionary) to an interface type dst.
|
||||||
|
func (subst *subster) convertUsingDictionary(pos src.XPos, v ir.Node, dst, src *types.Type, ix int) ir.Node {
|
||||||
if !dst.IsInterface() {
|
if !dst.IsInterface() {
|
||||||
base.Fatalf("can only convert type parameters to interfaces %+v -> %+v", src, dst)
|
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.
|
// Load the actual runtime._type of the type parameter from the dictionary.
|
||||||
rt := subst.getDictionaryType(pos, src)
|
rt := subst.getDictionaryType(pos, ix)
|
||||||
|
|
||||||
// Convert value to an interface type, so the data field is what we want.
|
// Convert value to an interface type, so the data field is what we want.
|
||||||
if !v.Type().IsInterface() {
|
if !v.Type().IsInterface() {
|
||||||
|
|
|
@ -18,6 +18,13 @@ func f[T any](x T) interface{} {
|
||||||
var i interface{} = x
|
var i interface{} = x
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fs[T any](x T) interface{} {
|
||||||
|
y := []T{x}
|
||||||
|
var i interface{} = y
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
func g[T any](x T) E {
|
func g[T any](x T) E {
|
||||||
var i E = x
|
var i E = x
|
||||||
return i
|
return i
|
||||||
|
@ -46,10 +53,18 @@ func j[T C](t T) C {
|
||||||
return C(t) // explicit conversion
|
return C(t) // explicit conversion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func js[T any](x T) interface{} {
|
||||||
|
y := []T{x}
|
||||||
|
return interface{}(y)
|
||||||
|
}
|
||||||
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
if got, want := fs[int](7), []int{7}; got.([]int)[0] != want[0] {
|
||||||
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
|
}
|
||||||
if got, want := g[int](7), 7; got != want {
|
if got, want := g[int](7), 7; got != want {
|
||||||
panic(fmt.Sprintf("got %d want %d", got, want))
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
}
|
}
|
||||||
|
@ -62,4 +77,7 @@ func main() {
|
||||||
if got, want := j[myInt](7).foo(), 8; got != want {
|
if got, want := j[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 := js[int](7), []int{7}; got.([]int)[0] != want[0] {
|
||||||
|
panic(fmt.Sprintf("got %d want %d", got, want))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue