diff options
author | Keith Randall <khr@golang.org> | 2021-04-16 14:06:50 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2021-06-02 20:23:12 +0000 |
commit | 7b876def6c4936cfae774d3007f8265876a9fbf7 (patch) | |
tree | 74d0b022c50ea68dfe1dbe4dbded11161ebaedaa /src/cmd/compile/internal/noder/transform.go | |
parent | aa9cfdf775692a9fa6cc4ea9768415d73323c0cc (diff) | |
download | go-7b876def6c4936cfae774d3007f8265876a9fbf7.tar.gz go-7b876def6c4936cfae774d3007f8265876a9fbf7.zip |
[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>
Diffstat (limited to 'src/cmd/compile/internal/noder/transform.go')
-rw-r--r-- | src/cmd/compile/internal/noder/transform.go | 72 |
1 files changed, 49 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 2859089e69..90d38fe514 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -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 { - return - } - t := list[0].Type() - if t == nil || !t.IsFuncArgStruct() { + // 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 } - // 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 |