mirror of
https://github.com/golang/go
synced 2024-11-22 21:00:04 -07:00
[dev.typeparams] cmd/compile: handle dictionaries for top-level instantiations
There's no outer function in these cases, so we won't be reading the dictionary as a subdictionary from the outer scope's dictionary. It will always be a compile-time constant. Change-Id: I754b126652a6ffb62255734d53fcec29d77cfa9e Reviewed-on: https://go-review.googlesource.com/c/go/+/324949 Trust: Keith Randall <khr@golang.org> Trust: Dan Scales <danscales@google.com> Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
parent
de61465156
commit
bad388744b
@ -144,13 +144,19 @@ func (g *irgen) stencil() {
|
||||
// call.
|
||||
if closureRequired {
|
||||
var edit func(ir.Node) ir.Node
|
||||
var outer *ir.Func
|
||||
if f, ok := decl.(*ir.Func); ok {
|
||||
outer = f
|
||||
}
|
||||
edit = func(x ir.Node) ir.Node {
|
||||
ir.EditChildren(x, edit)
|
||||
switch {
|
||||
case x.Op() == ir.OFUNCINST:
|
||||
return g.buildClosure(decl.(*ir.Func), x)
|
||||
// TODO: only set outer!=nil if this instantiation uses
|
||||
// a type parameter from outer. See comment in buildClosure.
|
||||
return g.buildClosure(outer, x)
|
||||
case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0: // TODO: test for ptr-to-method case
|
||||
return g.buildClosure(decl.(*ir.Func), x)
|
||||
return g.buildClosure(outer, x)
|
||||
}
|
||||
return x
|
||||
}
|
||||
@ -170,7 +176,8 @@ func (g *irgen) stencil() {
|
||||
}
|
||||
|
||||
// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR
|
||||
// of generic type. outer is the containing function.
|
||||
// of generic type. outer is the containing function (or nil if closure is
|
||||
// in a global assignment instead of a function).
|
||||
func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||
pos := x.Pos()
|
||||
var target *ir.Func // target instantiated function/method
|
||||
@ -276,19 +283,25 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||
fn.SetIsHiddenClosure(true)
|
||||
|
||||
// This is the dictionary we want to use.
|
||||
// Note: for now this is a compile-time constant, so we don't really need a closure
|
||||
// to capture it (a wrapper function would work just as well). But eventually it
|
||||
// will be a read of a subdictionary from the parent dictionary.
|
||||
dictVar := ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum))
|
||||
g.dnum++
|
||||
dictVar.Class = ir.PAUTO
|
||||
typed(types.Types[types.TUINTPTR], dictVar)
|
||||
dictVar.Curfn = outer
|
||||
dictAssign := ir.NewAssignStmt(pos, dictVar, dictValue)
|
||||
dictAssign.SetTypecheck(1)
|
||||
dictVar.Defn = dictAssign
|
||||
outer.Dcl = append(outer.Dcl, dictVar)
|
||||
|
||||
// It may be a constant, or it may be a dictionary acquired from the outer function's dictionary.
|
||||
// For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
|
||||
// read from the outer function's dictionary.
|
||||
var dictVar *ir.Name
|
||||
var dictAssign *ir.AssignStmt
|
||||
if outer != nil {
|
||||
// Note: for now this is a compile-time constant, so we don't really need a closure
|
||||
// to capture it (a wrapper function would work just as well). But eventually it
|
||||
// will be a read of a subdictionary from the parent dictionary.
|
||||
dictVar = ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum))
|
||||
g.dnum++
|
||||
dictVar.Class = ir.PAUTO
|
||||
typed(types.Types[types.TUINTPTR], dictVar)
|
||||
dictVar.Curfn = outer
|
||||
dictAssign = ir.NewAssignStmt(pos, dictVar, dictValue)
|
||||
dictAssign.SetTypecheck(1)
|
||||
dictVar.Defn = dictAssign
|
||||
outer.Dcl = append(outer.Dcl, dictVar)
|
||||
}
|
||||
// assign the receiver to a temporary.
|
||||
var rcvrVar *ir.Name
|
||||
var rcvrAssign ir.Node
|
||||
@ -335,6 +348,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||
sym := typecheck.ClosureName(outer)
|
||||
sym.SetFunc(true)
|
||||
fn.Nname = ir.NewNameAt(pos, sym)
|
||||
fn.Nname.Class = ir.PFUNC
|
||||
fn.Nname.Func = fn
|
||||
fn.Nname.Defn = fn
|
||||
typed(closureType, fn.Nname)
|
||||
@ -343,8 +357,18 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||
// Build body of closure. This involves just calling the wrapped function directly
|
||||
// with the additional dictionary argument.
|
||||
|
||||
// First, capture the dictionary variable for use in the closure.
|
||||
dict2Var := ir.CaptureName(pos, fn, dictVar)
|
||||
// First, figure out the dictionary argument.
|
||||
var dict2Var ir.Node
|
||||
if outer != nil {
|
||||
// If there's an outer function, the dictionary value will be read from
|
||||
// the dictionary of the outer function.
|
||||
// TODO: only use a subdictionary if any of the instantiating types
|
||||
// depend on the type params of the outer function.
|
||||
dict2Var = ir.CaptureName(pos, fn, dictVar)
|
||||
} else {
|
||||
// No outer function, instantiating types are known concrete types.
|
||||
dict2Var = dictValue
|
||||
}
|
||||
// Also capture the receiver variable.
|
||||
var rcvr2Var *ir.Name
|
||||
if rcvrValue != nil {
|
||||
@ -376,13 +400,19 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
||||
typecheck.Stmt(innerCall)
|
||||
ir.CurFunc = nil
|
||||
fn.Body = []ir.Node{innerCall}
|
||||
if outer == nil {
|
||||
g.target.Decls = append(g.target.Decls, fn)
|
||||
}
|
||||
|
||||
// We're all done with the captured dictionary (and receiver, for method values).
|
||||
ir.FinishCaptureNames(pos, outer, fn)
|
||||
|
||||
// Make a closure referencing our new internal function.
|
||||
c := ir.NewClosureExpr(pos, fn)
|
||||
init := []ir.Node{dictAssign}
|
||||
var init []ir.Node
|
||||
if outer != nil {
|
||||
init = append(init, dictAssign)
|
||||
}
|
||||
if rcvrValue != nil {
|
||||
init = append(init, rcvrAssign)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ func main() {
|
||||
methodExpressions()
|
||||
methodValues()
|
||||
interfaceMethods()
|
||||
globals()
|
||||
}
|
||||
|
||||
func g0[T any](x T) {
|
||||
@ -98,3 +99,30 @@ func interfaceMethods() {
|
||||
is7(y.(interface{g1()int}).g1())
|
||||
is77(y.(interface{g2()(int,int)}).g2())
|
||||
}
|
||||
|
||||
// Also check for instantiations outside functions.
|
||||
var gg0 = g0[int]
|
||||
var gg1 = g1[int]
|
||||
var gg2 = g2[int]
|
||||
|
||||
var hh0 = s[int].g0
|
||||
var hh1 = s[int].g1
|
||||
var hh2 = s[int].g2
|
||||
|
||||
var xtop = s[int]{a:7}
|
||||
var ii0 = x.g0
|
||||
var ii1 = x.g1
|
||||
var ii2 = x.g2
|
||||
|
||||
func globals() {
|
||||
gg0(7)
|
||||
is7(gg1(7))
|
||||
is77(gg2(7))
|
||||
x := s[int]{a:7}
|
||||
hh0(x)
|
||||
is7(hh1(x))
|
||||
is77(hh2(x))
|
||||
ii0()
|
||||
is7(ii1())
|
||||
is77(ii2())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user