mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] cmd/compile: add dictionary argument to generic functions
When converting from a generic function to a concrete implementation,
add a dictionary argument to the generic function (both an actual
argument at each callsite, and a formal argument of each
implementation).
The dictionary argument comes before all other arguments (including
any receiver).
The dictionary argument is checked for validity, but is otherwise unused.
Subsequent CLs will start using the dictionary for, e.g., converting a
value of generic type to interface{}.
Import/export required adding support for LINKSYMOFFSET, which is used
by the dictionary checking code.
Change-Id: I16a7a8d23c7bd6a897e0da87c69f273be9103bd7
Reviewed-on: https://go-review.googlesource.com/c/go/+/323272
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
aa9cfdf775
commit
7b876def6c
10 changed files with 688 additions and 113 deletions
|
|
@ -340,12 +340,12 @@ assignOK:
|
|||
}
|
||||
}
|
||||
|
||||
// Corresponds to typecheck.typecheckargs.
|
||||
// Corresponds to, but slightly more general than, typecheck.typecheckargs.
|
||||
func transformArgs(n ir.InitNode) {
|
||||
var list []ir.Node
|
||||
switch n := n.(type) {
|
||||
default:
|
||||
base.Fatalf("typecheckargs %+v", n.Op())
|
||||
base.Fatalf("transformArgs %+v", n.Op())
|
||||
case *ir.CallExpr:
|
||||
list = n.Args
|
||||
if n.IsDDD {
|
||||
|
|
@ -354,25 +354,31 @@ func transformArgs(n ir.InitNode) {
|
|||
case *ir.ReturnStmt:
|
||||
list = n.Results
|
||||
}
|
||||
if len(list) != 1 {
|
||||
|
||||
// Look to see if we have any multi-return functions as arguments.
|
||||
extra := 0
|
||||
for _, arg := range list {
|
||||
t := arg.Type()
|
||||
if t.IsFuncArgStruct() {
|
||||
num := t.Fields().Len()
|
||||
if num <= 1 {
|
||||
base.Fatalf("multi-return type with only %d parts", num)
|
||||
}
|
||||
extra += num - 1
|
||||
}
|
||||
}
|
||||
// If not, nothing to do.
|
||||
if extra == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
t := list[0].Type()
|
||||
if t == nil || !t.IsFuncArgStruct() {
|
||||
return
|
||||
}
|
||||
|
||||
// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
|
||||
// Rewrite f(..., g(), ...) into t1, ..., tN = g(); f(..., t1, ..., tN, ...).
|
||||
|
||||
// Save n as n.Orig for fmt.go.
|
||||
if ir.Orig(n) == n {
|
||||
n.(ir.OrigNode).SetOrig(ir.SepCopy(n))
|
||||
}
|
||||
|
||||
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
||||
as.Rhs.Append(list...)
|
||||
|
||||
// If we're outside of function context, then this call will
|
||||
// be executed during the generated init function. However,
|
||||
// init.go hasn't yet created it. Instead, associate the
|
||||
|
|
@ -382,27 +388,42 @@ func transformArgs(n ir.InitNode) {
|
|||
if static {
|
||||
ir.CurFunc = typecheck.InitTodoFunc
|
||||
}
|
||||
list = nil
|
||||
for _, f := range t.FieldSlice() {
|
||||
t := typecheck.Temp(f.Type)
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
|
||||
as.Lhs.Append(t)
|
||||
list = append(list, t)
|
||||
|
||||
// Expand multi-return function calls.
|
||||
// The spec only allows a multi-return function as an argument
|
||||
// if it is the only argument. This code must handle calls to
|
||||
// stenciled generic functions which have extra arguments
|
||||
// (like the dictionary) so it must handle a slightly more general
|
||||
// cases, like f(n, g()) where g is multi-return.
|
||||
newList := make([]ir.Node, 0, len(list)+extra)
|
||||
for _, arg := range list {
|
||||
t := arg.Type()
|
||||
if t.IsFuncArgStruct() {
|
||||
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{arg})
|
||||
for _, f := range t.FieldSlice() {
|
||||
t := typecheck.Temp(f.Type)
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
|
||||
as.Lhs.Append(t)
|
||||
newList = append(newList, t)
|
||||
}
|
||||
transformAssign(as, as.Lhs, as.Rhs)
|
||||
as.SetTypecheck(1)
|
||||
n.PtrInit().Append(as)
|
||||
} else {
|
||||
newList = append(newList, arg)
|
||||
}
|
||||
}
|
||||
|
||||
if static {
|
||||
ir.CurFunc = nil
|
||||
}
|
||||
|
||||
switch n := n.(type) {
|
||||
case *ir.CallExpr:
|
||||
n.Args = list
|
||||
n.Args = newList
|
||||
case *ir.ReturnStmt:
|
||||
n.Results = list
|
||||
n.Results = newList
|
||||
}
|
||||
|
||||
transformAssign(as, as.Lhs, as.Rhs)
|
||||
as.SetTypecheck(1)
|
||||
n.PtrInit().Append(as)
|
||||
}
|
||||
|
||||
// assignconvfn converts node n for assignment to type t. Corresponds to
|
||||
|
|
@ -562,6 +583,11 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
|
|||
|
||||
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
|
||||
n.SetOp(ir.OCALLPART)
|
||||
if len(n.X.Type().RParams()) > 0 || n.X.Type().IsPtr() && len(n.X.Type().Elem().RParams()) > 0 {
|
||||
// TODO: MethodValueWrapper needed for generics?
|
||||
// Or did we successfully desugar all that at stencil time?
|
||||
return n
|
||||
}
|
||||
n.SetType(typecheck.MethodValueWrapper(n).Type())
|
||||
}
|
||||
return n
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue