aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder')
-rw-r--r--src/cmd/compile/internal/noder/expr.go2
-rw-r--r--src/cmd/compile/internal/noder/helpers.go56
-rw-r--r--src/cmd/compile/internal/noder/stencil.go23
-rw-r--r--src/cmd/compile/internal/noder/stmt.go29
4 files changed, 86 insertions, 24 deletions
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go
index 989ebf236e..1ca5552879 100644
--- a/src/cmd/compile/internal/noder/expr.go
+++ b/src/cmd/compile/internal/noder/expr.go
@@ -135,7 +135,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
index := g.expr(expr.Index)
if index.Op() != ir.OTYPE {
// This is just a normal index expression
- return Index(pos, g.expr(expr.X), index)
+ return Index(pos, g.typ(typ), g.expr(expr.X), index)
}
// This is generic function instantiation with a single type
targs = []ir.Node{index}
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index cf7a3e22b3..1210d4b58c 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -83,11 +83,12 @@ func Binary(pos src.XPos, op ir.Op, x, y ir.Node) 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, args)
+ n.IsDDD = dots
+
if fun.Op() == ir.OTYPE {
// Actually a type conversion, not a function call.
- n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
- if fun.Type().Kind() == types.TTYPEPARAM {
+ if fun.Type().HasTParam() || args[0].Type().HasTParam() {
// For type params, don't typecheck until we actually know
// the type.
return typed(typ, n)
@@ -96,9 +97,34 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
}
if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
- // Call to a builtin function.
- n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
- n.IsDDD = dots
+ // For Builtin ops, we currently stay with using the old
+ // typechecker to transform the call to a more specific expression
+ // and possibly use more specific ops. However, for a bunch of the
+ // ops, we delay doing the old typechecker if any of the args have
+ // type params, for a variety of reasons:
+ //
+ // OMAKE: hard to choose specific ops OMAKESLICE, etc. until arg type is known
+ // OREAL/OIMAG: can't determine type float32/float64 until arg type know
+ // OLEN/OCAP: old typechecker will complain if arg is not obviously a slice/array.
+ // OAPPEND: old typechecker will complain if arg is not obviously slice, etc.
+ //
+ // We will eventually break out the transforming functionality
+ // needed for builtin's, and call it here or during stenciling, as
+ // appropriate.
+ switch fun.BuiltinOp {
+ case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND:
+ hasTParam := false
+ for _, arg := range args {
+ if arg.Type().HasTParam() {
+ hasTParam = true
+ break
+ }
+ }
+ if hasTParam {
+ return typed(typ, n)
+ }
+ }
+
switch fun.BuiltinOp {
case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN:
return typecheck.Stmt(n)
@@ -124,9 +150,6 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
}
}
- n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
- n.IsDDD = dots
-
if fun.Op() == ir.OXDOT {
if !fun.(*ir.SelectorExpr).X.Type().HasTParam() {
base.FatalfAt(pos, "Expecting type param receiver in %v", fun)
@@ -230,9 +253,18 @@ 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 (which will call tcIndex)
- return typecheck.Expr(ir.NewIndexExpr(pos, x, index))
+func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
+ n := ir.NewIndexExpr(pos, x, index)
+ // TODO(danscales): Temporary fix. Need to separate out the
+ // transformations done by the old typechecker (in tcIndex()), to be
+ // called here or after stenciling.
+ if x.Type().HasTParam() && x.Type().Kind() != types.TMAP &&
+ x.Type().Kind() != types.TSLICE && x.Type().Kind() != types.TARRAY {
+ // Old typechecker will complain if arg is not obviously a slice/array/map.
+ typed(typ, n)
+ return n
+ }
+ return typecheck.Expr(n)
}
func Slice(pos src.XPos, x, low, high, max ir.Node) ir.Node {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 64b3a942e2..55aee9b6ff 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -330,8 +330,13 @@ func (subst *subster) node(n ir.Node) ir.Node {
m.SetIsClosureVar(true)
}
t := x.Type()
- newt := subst.typ(t)
- m.SetType(newt)
+ if t == nil {
+ assert(name.BuiltinOp != 0)
+ } else {
+ newt := subst.typ(t)
+ m.SetType(newt)
+ }
+ m.BuiltinOp = name.BuiltinOp
m.Curfn = subst.newf
m.Class = name.Class
m.Func = name.Func
@@ -396,11 +401,23 @@ func (subst *subster) node(n ir.Node) ir.Node {
// that the OXDOT was resolved.
call.SetTypecheck(0)
typecheck.Call(call)
+ } else if name := call.X.Name(); name != nil {
+ switch name.BuiltinOp {
+ case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND:
+ // Call old typechecker (to do any
+ // transformations) now that we know the
+ // type of the args.
+ m.SetTypecheck(0)
+ m = typecheck.Expr(m)
+ default:
+ base.FatalfAt(call.Pos(), "Unexpected builtin op")
+ }
+
} else if call.X.Op() != ir.OFUNCINST {
// A call with an OFUNCINST will get typechecked
// in stencil() once we have created & attached the
// instantiation to be called.
- base.FatalfAt(call.Pos(), "Expecting OCALLPART or OTYPE or OFUNCINST with CALL")
+ base.FatalfAt(call.Pos(), "Expecting OCALLPART or OTYPE or OFUNCINST or builtin with CALL")
}
}
diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go
index 1775116f41..31c6bfe5c8 100644
--- a/src/cmd/compile/internal/noder/stmt.go
+++ b/src/cmd/compile/internal/noder/stmt.go
@@ -28,7 +28,11 @@ func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
// TODO(mdempsky): Remove dependency on typecheck.
- return typecheck.Stmt(g.stmt0(stmt))
+ n := g.stmt0(stmt)
+ if n != nil {
+ n.SetTypecheck(1)
+ }
+ return n
}
func (g *irgen) stmt0(stmt syntax.Stmt) ir.Node {
@@ -46,17 +50,20 @@ func (g *irgen) stmt0(stmt syntax.Stmt) ir.Node {
}
return x
case *syntax.SendStmt:
- return ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
+ n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
+ // Need to do the AssignConv() in tcSend().
+ return typecheck.Stmt(n)
case *syntax.DeclStmt:
return ir.NewBlockStmt(g.pos(stmt), g.decls(stmt.DeclList))
case *syntax.AssignStmt:
if stmt.Op != 0 && stmt.Op != syntax.Def {
op := g.op(stmt.Op, binOps[:])
+ // May need to insert ConvExpr nodes on the args in tcArith
if stmt.Rhs == nil {
- return IncDec(g.pos(stmt), op, g.expr(stmt.Lhs))
+ return typecheck.Stmt(IncDec(g.pos(stmt), op, g.expr(stmt.Lhs)))
}
- return ir.NewAssignOpStmt(g.pos(stmt), op, g.expr(stmt.Lhs), g.expr(stmt.Rhs))
+ return typecheck.Stmt(ir.NewAssignOpStmt(g.pos(stmt), op, g.expr(stmt.Lhs), g.expr(stmt.Rhs)))
}
names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
@@ -65,25 +72,31 @@ func (g *irgen) stmt0(stmt syntax.Stmt) ir.Node {
if len(lhs) == 1 && len(rhs) == 1 {
n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
n.Def = initDefn(n, names)
- return n
+ // Need to set Assigned in checkassign for maps
+ return typecheck.Stmt(n)
}
n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
n.Def = initDefn(n, names)
- return n
+ // Need to do tcAssignList().
+ return typecheck.Stmt(n)
case *syntax.BranchStmt:
return ir.NewBranchStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), branchOps[:]), g.name(stmt.Label))
case *syntax.CallStmt:
return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
case *syntax.ReturnStmt:
- return ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
+ n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
+ // Need to do typecheckaste() for multiple return values
+ return typecheck.Stmt(n)
case *syntax.IfStmt:
return g.ifStmt(stmt)
case *syntax.ForStmt:
return g.forStmt(stmt)
case *syntax.SelectStmt:
- return g.selectStmt(stmt)
+ n := g.selectStmt(stmt)
+ // Need to convert assignments to OSELRECV2 in tcSelect()
+ return typecheck.Stmt(n)
case *syntax.SwitchStmt:
return g.switchStmt(stmt)