]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] Parse a generic type arg for generic function call
authorDan Scales <danscales@google.com>
Sat, 30 Jan 2021 16:43:58 +0000 (08:43 -0800)
committerDan Scales <danscales@google.com>
Mon, 1 Feb 2021 22:05:52 +0000 (22:05 +0000)
Will now run "go tool compile -G=2 -W=2" on a simple generic function
with one type parameter and a call to that function with one explicit
type argument. Next change will handle multiple type arguments.

Change-Id: Ia7d17ea2a02bf99bd50e673ac80ae4aad4c48440
Reviewed-on: https://go-review.googlesource.com/c/go/+/288432
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/helpers.go
src/cmd/compile/internal/noder/irgen.go
src/cmd/compile/internal/noder/types.go

index 9212c672132a40d056a6b24599406d4c5369ede9..79b94638e88bd84212a6f3c4b4b51d75c5e18c07 100644 (file)
@@ -93,9 +93,16 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
        case *syntax.AssertExpr:
                return Assert(pos, g.expr(expr.X), g.typeExpr(expr.Type))
        case *syntax.CallExpr:
-               return Call(pos, g.expr(expr.Fun), g.exprs(expr.ArgList), expr.HasDots)
+               def := g.info.Inferred[expr]
+               if len(def.Targs) > 0 {
+                       panic("Inferred type arguments not handled yet")
+               }
+               return Call(pos, g.typ(typ), g.expr(expr.Fun), g.exprs(expr.ArgList), expr.HasDots)
        case *syntax.IndexExpr:
-               return Index(pos, g.expr(expr.X), g.expr(expr.Index))
+               if _, ok := expr.Index.(*syntax.ListExpr); ok {
+                       panic("more than one type argument")
+               }
+               return Index(pos, g.typ(typ), g.expr(expr.X), g.expr(expr.Index))
        case *syntax.ParenExpr:
                return g.expr(expr.X) // skip parens; unneeded after parse+typecheck
        case *syntax.SelectorExpr:
index a851844dede2445178b2749ebbe18bcfe65a901d..2a6f30e026e82f828d296b67f099ecb6941cd469 100644 (file)
@@ -79,18 +79,18 @@ func Binary(pos src.XPos, op ir.Op, x, y ir.Node) ir.Node {
        }
 }
 
-func Call(pos src.XPos, fun ir.Node, args []ir.Node, dots bool) ir.Node {
+func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
        // TODO(mdempsky): This should not be so difficult.
-
-       n := ir.NewCallExpr(pos, ir.OCALL, fun, nil, args)
-       n.IsDDD = dots
-
-       // Actually a type conversion.
        if fun.Op() == ir.OTYPE {
+               // Actually a type conversion, not a function call.
+               n := ir.NewCallExpr(pos, ir.OCALL, fun, nil, args)
                return typecheck.Expr(n)
        }
 
        if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
+               // Call to a builtin function.
+               n := ir.NewCallExpr(pos, ir.OCALL, fun, nil, args)
+               n.IsDDD = dots
                switch fun.BuiltinOp {
                case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN:
                        return typecheck.Stmt(n)
@@ -116,7 +116,46 @@ func Call(pos src.XPos, fun ir.Node, args []ir.Node, dots bool) ir.Node {
                }
        }
 
-       typecheck.Call(n)
+       var targs []ir.Node
+       if indexExpr, ok := fun.(*ir.IndexExpr); ok {
+               if indexExpr.Index.Op() == ir.OTYPE {
+                       // Called function is an instantiated generic function
+                       // TODO this handles just one type argument for now
+                       fun = indexExpr.X
+                       targs = make([]ir.Node, 1, 1)
+                       targs[0] = indexExpr.Index
+               }
+       }
+
+       n := ir.NewCallExpr(pos, ir.OCALL, fun, targs, args)
+       n.IsDDD = dots
+
+       if targs == nil {
+               // If no type params, still do normal typechecking, since we're
+               // still missing some things done by tcCall below (mainly
+               // typecheckargs and typecheckaste).
+               typecheck.Call(n)
+               return n
+       }
+
+       n.Use = ir.CallUseExpr
+       if fun.Type().NumResults() == 0 {
+               n.Use = ir.CallUseStmt
+       }
+
+       // Rewrite call node depending on use.
+       switch fun.Op() {
+       case ir.ODOTINTER:
+               n.SetOp(ir.OCALLINTER)
+
+       case ir.ODOTMETH:
+               n.SetOp(ir.OCALLMETH)
+
+       default:
+               n.SetOp(ir.OCALLFUNC)
+       }
+
+       typed(typ, n)
        return n
 }
 
@@ -195,8 +234,13 @@ func method(typ *types.Type, index int) *types.Field {
        return types.ReceiverBaseType(typ).Methods().Index(index)
 }
 
-func Index(pos src.XPos, x, index ir.Node) ir.Node {
-       // TODO(mdempsky): Avoid typecheck.Expr.
+func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
+       if index.Op() == ir.OTYPE {
+               n := ir.NewIndexExpr(pos, x, index)
+               typed(typ, n)
+               return n
+       }
+       // TODO(mdempsky): Avoid typecheck.Expr (which will call tcIndex)
        return typecheck.Expr(ir.NewIndexExpr(pos, x, index))
 }
 
index 5456005598e187a8af7640621a39313168ace29d..1cef98742d5b34ea4def3b7acbf65d1437880543 100644 (file)
@@ -62,6 +62,7 @@ func check2(noders []*noder) {
                Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
                Implicits:  make(map[syntax.Node]types2.Object),
                Scopes:     make(map[syntax.Node]*types2.Scope),
+               Inferred:   make(map[syntax.Expr]types2.Inferred),
                // expand as needed
        }
        pkg, err := conf.Check(base.Ctxt.Pkgpath, files, &info)
index b4ad9cfc5b8c94fbbe01cf6be842ec4b9e073700..1e7196985822aa66f5d3296a0ad06b1be8fbb671 100644 (file)
@@ -39,7 +39,7 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
                // Ensure we calculate the size for all concrete types seen by
                // the frontend. This is another heavy hammer for something that
                // should really be the backend's responsibility instead.
-               if !res.IsUntyped() {
+               if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() {
                        types.CheckSize(res)
                }
        }
@@ -106,6 +106,22 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                tp.SetSym(g.sym(typ.Obj()))
                return tp
 
+       case *types2.Tuple:
+               // Tuples are used for the type of a function call (i.e. the
+               // return value of the function).
+               if typ == nil {
+                       return (*types.Type)(nil)
+               }
+               fields := make([]*types.Field, typ.Len())
+               for i := range fields {
+                       fields[i] = g.param(typ.At(i))
+               }
+               t := types.NewStruct(types.LocalPkg, fields)
+               types.CheckSize(t)
+               // Can only set after doing the types.CheckSize()
+               t.StructType().Funarg = types.FunargResults
+               return t
+
        default:
                base.FatalfAt(src.NoXPos, "unhandled type: %v (%T)", typ, typ)
                panic("unreachable")