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:
}
}
-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)
}
}
- 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
}
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))
}
// 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)
}
}
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")