return typecheck(n, ctxExpr|ctxCallee)
}
-var importlist []*ir.Func
-
var traceIndent []byte
func tracePrint(title string, n ir.Node) func(np *ir.Node) {
return true
}
-// markBreak marks control statements containing break statements with SetHasBreak(true).
-func markBreak(fn *ir.Func) {
- var labels map[*types.Sym]ir.Node
- var implicit ir.Node
-
- var mark func(ir.Node) bool
- mark = func(n ir.Node) bool {
- switch n.Op() {
- default:
- ir.DoChildren(n, mark)
-
- case ir.OBREAK:
- n := n.(*ir.BranchStmt)
- if n.Label == nil {
- setHasBreak(implicit)
- } else {
- setHasBreak(labels[n.Label])
- }
-
- case ir.OFOR, ir.OSWITCH, ir.OSELECT, ir.ORANGE:
- old := implicit
- implicit = n
- var sym *types.Sym
- switch n := n.(type) {
- case *ir.ForStmt:
- sym = n.Label
- case *ir.RangeStmt:
- sym = n.Label
- case *ir.SelectStmt:
- sym = n.Label
- case *ir.SwitchStmt:
- sym = n.Label
- }
- if sym != nil {
- if labels == nil {
- // Map creation delayed until we need it - most functions don't.
- labels = make(map[*types.Sym]ir.Node)
- }
- labels[sym] = n
- }
- ir.DoChildren(n, mark)
- if sym != nil {
- delete(labels, sym)
- }
- implicit = old
- }
- return false
- }
-
- mark(fn)
-}
-
-func setHasBreak(n ir.Node) {
- switch n := n.(type) {
- default:
- base.Fatalf("setHasBreak %+v", n.Op())
- case nil:
- // ignore
- case *ir.ForStmt:
- n.HasBreak = true
- case *ir.RangeStmt:
- n.HasBreak = true
- case *ir.SelectStmt:
- n.HasBreak = true
- case *ir.SwitchStmt:
- n.HasBreak = true
- }
-}
-
-// isTermNodes reports whether the Nodes list ends with a terminating statement.
-func isTermNodes(l ir.Nodes) bool {
- s := l
- c := len(s)
- if c == 0 {
- return false
- }
- return isTermNode(s[c-1])
-}
-
-// isTermNode reports whether the node n, the last one in a
-// statement list, is a terminating statement.
-func isTermNode(n ir.Node) bool {
- switch n.Op() {
- // NOTE: OLABEL is treated as a separate statement,
- // not a separate prefix, so skipping to the last statement
- // in the block handles the labeled statement case by
- // skipping over the label. No case OLABEL here.
-
- case ir.OBLOCK:
- n := n.(*ir.BlockStmt)
- return isTermNodes(n.List)
-
- case ir.OGOTO, ir.ORETURN, ir.OTAILCALL, ir.OPANIC, ir.OFALL:
- return true
-
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- if n.Cond != nil {
- return false
- }
- if n.HasBreak {
- return false
- }
- return true
-
- case ir.OIF:
- n := n.(*ir.IfStmt)
- return isTermNodes(n.Body) && isTermNodes(n.Else)
-
- case ir.OSWITCH:
- n := n.(*ir.SwitchStmt)
- if n.HasBreak {
- return false
- }
- def := false
- for _, cas := range n.Cases {
- if !isTermNodes(cas.Body) {
- return false
- }
- if len(cas.List) == 0 { // default
- def = true
- }
- }
- return def
-
- case ir.OSELECT:
- n := n.(*ir.SelectStmt)
- if n.HasBreak {
- return false
- }
- for _, cas := range n.Cases {
- if !isTermNodes(cas.Body) {
- return false
- }
- }
- return true
- }
-
- return false
-}
-
func Conv(n ir.Node, t *types.Type) ir.Node {
if types.IdenticalStrict(n.Type(), t) {
return n