1
2
3
4
5
6
7 package types2
8
9 import (
10 "cmd/compile/internal/syntax"
11 )
12
13
14
15
16 func (check *Checker) isTerminating(s syntax.Stmt, label string) bool {
17 switch s := s.(type) {
18 default:
19 unreachable()
20
21 case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.SendStmt,
22 *syntax.AssignStmt, *syntax.CallStmt:
23
24
25 case *syntax.LabeledStmt:
26 return check.isTerminating(s.Stmt, s.Label.Value)
27
28 case *syntax.ExprStmt:
29
30 if call, ok := syntax.Unparen(s.X).(*syntax.CallExpr); ok && check.isPanic[call] {
31 return true
32 }
33
34 case *syntax.ReturnStmt:
35 return true
36
37 case *syntax.BranchStmt:
38 if s.Tok == syntax.Goto || s.Tok == syntax.Fallthrough {
39 return true
40 }
41
42 case *syntax.BlockStmt:
43 return check.isTerminatingList(s.List, "")
44
45 case *syntax.IfStmt:
46 if s.Else != nil &&
47 check.isTerminating(s.Then, "") &&
48 check.isTerminating(s.Else, "") {
49 return true
50 }
51
52 case *syntax.SwitchStmt:
53 return check.isTerminatingSwitch(s.Body, label)
54
55 case *syntax.SelectStmt:
56 for _, cc := range s.Body {
57 if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
58 return false
59 }
60
61 }
62 return true
63
64 case *syntax.ForStmt:
65 if _, ok := s.Init.(*syntax.RangeClause); ok {
66
67
68 break
69 }
70 if s.Cond == nil && !hasBreak(s.Body, label, true) {
71 return true
72 }
73 }
74
75 return false
76 }
77
78 func (check *Checker) isTerminatingList(list []syntax.Stmt, label string) bool {
79
80 for i := len(list) - 1; i >= 0; i-- {
81 if _, ok := list[i].(*syntax.EmptyStmt); !ok {
82 return check.isTerminating(list[i], label)
83 }
84 }
85 return false
86 }
87
88 func (check *Checker) isTerminatingSwitch(body []*syntax.CaseClause, label string) bool {
89 hasDefault := false
90 for _, cc := range body {
91 if cc.Cases == nil {
92 hasDefault = true
93 }
94 if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
95 return false
96 }
97 }
98 return hasDefault
99 }
100
101
102
103
104
105
106
107
108 func hasBreak(s syntax.Stmt, label string, implicit bool) bool {
109 switch s := s.(type) {
110 default:
111 unreachable()
112
113 case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.ExprStmt,
114 *syntax.SendStmt, *syntax.AssignStmt, *syntax.CallStmt,
115 *syntax.ReturnStmt:
116
117
118 case *syntax.LabeledStmt:
119 return hasBreak(s.Stmt, label, implicit)
120
121 case *syntax.BranchStmt:
122 if s.Tok == syntax.Break {
123 if s.Label == nil {
124 return implicit
125 }
126 if s.Label.Value == label {
127 return true
128 }
129 }
130
131 case *syntax.BlockStmt:
132 return hasBreakList(s.List, label, implicit)
133
134 case *syntax.IfStmt:
135 if hasBreak(s.Then, label, implicit) ||
136 s.Else != nil && hasBreak(s.Else, label, implicit) {
137 return true
138 }
139
140 case *syntax.SwitchStmt:
141 if label != "" && hasBreakCaseList(s.Body, label, false) {
142 return true
143 }
144
145 case *syntax.SelectStmt:
146 if label != "" && hasBreakCommList(s.Body, label, false) {
147 return true
148 }
149
150 case *syntax.ForStmt:
151 if label != "" && hasBreak(s.Body, label, false) {
152 return true
153 }
154 }
155
156 return false
157 }
158
159 func hasBreakList(list []syntax.Stmt, label string, implicit bool) bool {
160 for _, s := range list {
161 if hasBreak(s, label, implicit) {
162 return true
163 }
164 }
165 return false
166 }
167
168 func hasBreakCaseList(list []*syntax.CaseClause, label string, implicit bool) bool {
169 for _, s := range list {
170 if hasBreakList(s.Body, label, implicit) {
171 return true
172 }
173 }
174 return false
175 }
176
177 func hasBreakCommList(list []*syntax.CommClause, label string, implicit bool) bool {
178 for _, s := range list {
179 if hasBreakList(s.Body, label, implicit) {
180 return true
181 }
182 }
183 return false
184 }
185
View as plain text