]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/walk/stmt.go
cmd/compile: improve interface type switches
[gostls13.git] / src / cmd / compile / internal / walk / stmt.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package walk
6
7 import (
8         "cmd/compile/internal/base"
9         "cmd/compile/internal/ir"
10 )
11
12 // The result of walkStmt MUST be assigned back to n, e.g.
13 //
14 //      n.Left = walkStmt(n.Left)
15 func walkStmt(n ir.Node) ir.Node {
16         if n == nil {
17                 return n
18         }
19
20         ir.SetPos(n)
21
22         walkStmtList(n.Init())
23
24         switch n.Op() {
25         default:
26                 if n.Op() == ir.ONAME {
27                         n := n.(*ir.Name)
28                         base.Errorf("%v is not a top level statement", n.Sym())
29                 } else {
30                         base.Errorf("%v is not a top level statement", n.Op())
31                 }
32                 ir.Dump("nottop", n)
33                 return n
34
35         case ir.OAS,
36                 ir.OASOP,
37                 ir.OAS2,
38                 ir.OAS2DOTTYPE,
39                 ir.OAS2RECV,
40                 ir.OAS2FUNC,
41                 ir.OAS2MAPR,
42                 ir.OCLEAR,
43                 ir.OCLOSE,
44                 ir.OCOPY,
45                 ir.OCALLINTER,
46                 ir.OCALL,
47                 ir.OCALLFUNC,
48                 ir.ODELETE,
49                 ir.OSEND,
50                 ir.OPRINT,
51                 ir.OPRINTLN,
52                 ir.OPANIC,
53                 ir.ORECOVERFP,
54                 ir.OGETG:
55                 if n.Typecheck() == 0 {
56                         base.Fatalf("missing typecheck: %+v", n)
57                 }
58
59                 init := ir.TakeInit(n)
60                 n = walkExpr(n, &init)
61                 if n.Op() == ir.ONAME {
62                         // copy rewrote to a statement list and a temp for the length.
63                         // Throw away the temp to avoid plain values as statements.
64                         n = ir.NewBlockStmt(n.Pos(), init)
65                         init = nil
66                 }
67                 if len(init) > 0 {
68                         switch n.Op() {
69                         case ir.OAS, ir.OAS2, ir.OBLOCK:
70                                 n.(ir.InitNode).PtrInit().Prepend(init...)
71
72                         default:
73                                 init.Append(n)
74                                 n = ir.NewBlockStmt(n.Pos(), init)
75                         }
76                 }
77                 return n
78
79         // special case for a receive where we throw away
80         // the value received.
81         case ir.ORECV:
82                 n := n.(*ir.UnaryExpr)
83                 return walkRecv(n)
84
85         case ir.OBREAK,
86                 ir.OCONTINUE,
87                 ir.OFALL,
88                 ir.OGOTO,
89                 ir.OLABEL,
90                 ir.OJUMPTABLE,
91                 ir.OINTERFACESWITCH,
92                 ir.ODCL,
93                 ir.OCHECKNIL:
94                 return n
95
96         case ir.OBLOCK:
97                 n := n.(*ir.BlockStmt)
98                 walkStmtList(n.List)
99                 return n
100
101         case ir.OCASE:
102                 base.Errorf("case statement out of place")
103                 panic("unreachable")
104
105         case ir.ODEFER:
106                 n := n.(*ir.GoDeferStmt)
107                 ir.CurFunc.SetHasDefer(true)
108                 ir.CurFunc.NumDefers++
109                 if ir.CurFunc.NumDefers > maxOpenDefers || n.DeferAt != nil {
110                         // Don't allow open-coded defers if there are more than
111                         // 8 defers in the function, since we use a single
112                         // byte to record active defers.
113                         // Also don't allow if we need to use deferprocat.
114                         ir.CurFunc.SetOpenCodedDeferDisallowed(true)
115                 }
116                 if n.Esc() != ir.EscNever {
117                         // If n.Esc is not EscNever, then this defer occurs in a loop,
118                         // so open-coded defers cannot be used in this function.
119                         ir.CurFunc.SetOpenCodedDeferDisallowed(true)
120                 }
121                 fallthrough
122         case ir.OGO:
123                 n := n.(*ir.GoDeferStmt)
124                 return walkGoDefer(n)
125
126         case ir.OFOR:
127                 n := n.(*ir.ForStmt)
128                 return walkFor(n)
129
130         case ir.OIF:
131                 n := n.(*ir.IfStmt)
132                 return walkIf(n)
133
134         case ir.ORETURN:
135                 n := n.(*ir.ReturnStmt)
136                 return walkReturn(n)
137
138         case ir.OTAILCALL:
139                 n := n.(*ir.TailCallStmt)
140
141                 var init ir.Nodes
142                 n.Call.Fun = walkExpr(n.Call.Fun, &init)
143
144                 if len(init) > 0 {
145                         init.Append(n)
146                         return ir.NewBlockStmt(n.Pos(), init)
147                 }
148                 return n
149
150         case ir.OINLMARK:
151                 n := n.(*ir.InlineMarkStmt)
152                 return n
153
154         case ir.OSELECT:
155                 n := n.(*ir.SelectStmt)
156                 walkSelect(n)
157                 return n
158
159         case ir.OSWITCH:
160                 n := n.(*ir.SwitchStmt)
161                 walkSwitch(n)
162                 return n
163
164         case ir.ORANGE:
165                 n := n.(*ir.RangeStmt)
166                 return walkRange(n)
167         }
168
169         // No return! Each case must return (or panic),
170         // to avoid confusion about what gets returned
171         // in the presence of type assertions.
172 }
173
174 func walkStmtList(s []ir.Node) {
175         for i := range s {
176                 s[i] = walkStmt(s[i])
177         }
178 }
179
180 // walkFor walks an OFOR node.
181 func walkFor(n *ir.ForStmt) ir.Node {
182         if n.Cond != nil {
183                 init := ir.TakeInit(n.Cond)
184                 walkStmtList(init)
185                 n.Cond = walkExpr(n.Cond, &init)
186                 n.Cond = ir.InitExpr(init, n.Cond)
187         }
188
189         n.Post = walkStmt(n.Post)
190         walkStmtList(n.Body)
191         return n
192 }
193
194 // validGoDeferCall reports whether call is a valid call to appear in
195 // a go or defer statement; that is, whether it's a regular function
196 // call without arguments or results.
197 func validGoDeferCall(call ir.Node) bool {
198         if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 {
199                 sig := call.Fun.Type()
200                 return sig.NumParams()+sig.NumResults() == 0
201         }
202         return false
203 }
204
205 // walkGoDefer walks an OGO or ODEFER node.
206 func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
207         if !validGoDeferCall(n.Call) {
208                 base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call)
209         }
210
211         var init ir.Nodes
212
213         call := n.Call.(*ir.CallExpr)
214         call.Fun = walkExpr(call.Fun, &init)
215
216         if len(init) > 0 {
217                 init.Append(n)
218                 return ir.NewBlockStmt(n.Pos(), init)
219         }
220         return n
221 }
222
223 // walkIf walks an OIF node.
224 func walkIf(n *ir.IfStmt) ir.Node {
225         n.Cond = walkExpr(n.Cond, n.PtrInit())
226         walkStmtList(n.Body)
227         walkStmtList(n.Else)
228         return n
229 }