1
1
use Context :: * ;
2
2
3
- use rustc_errors:: { struct_span_err, Applicability } ;
4
3
use rustc_hir as hir;
5
4
use rustc_hir:: def_id:: LocalDefId ;
6
5
use rustc_hir:: intravisit:: { self , Visitor } ;
@@ -13,6 +12,11 @@ use rustc_session::Session;
13
12
use rustc_span:: hygiene:: DesugaringKind ;
14
13
use rustc_span:: Span ;
15
14
15
+ use crate :: errors:: {
16
+ BreakInsideAsyncBlock , BreakInsideClosure , BreakNonLoop , ContinueLabeledBlock , OutsideLoop ,
17
+ UnlabeledCfInWhileCondition , UnlabeledInLabeledBlock ,
18
+ } ;
19
+
16
20
#[ derive( Clone , Copy , Debug , PartialEq ) ]
17
21
enum Context {
18
22
Normal ,
@@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
90
94
Ok ( loop_id) => Some ( loop_id) ,
91
95
Err ( hir:: LoopIdError :: OutsideLoopScope ) => None ,
92
96
Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
93
- self . emit_unlabled_cf_in_while_condition ( e. span , "break" ) ;
97
+ self . sess . emit_err ( UnlabeledCfInWhileCondition {
98
+ span : e. span ,
99
+ cf_type : "break" ,
100
+ } ) ;
94
101
None
95
102
}
96
103
Err ( hir:: LoopIdError :: UnresolvedLabel ) => None ,
@@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
116
123
match loop_kind {
117
124
None | Some ( hir:: LoopSource :: Loop ) => ( ) ,
118
125
Some ( kind) => {
119
- let mut err = struct_span_err ! (
120
- self . sess,
121
- e. span,
122
- E0571 ,
123
- "`break` with value from a `{}` loop" ,
124
- kind. name( )
125
- ) ;
126
- err. span_label (
127
- e. span ,
128
- "can only break with a value inside `loop` or breakable block" ,
126
+ let suggestion = format ! (
127
+ "break{}" ,
128
+ break_label
129
+ . label
130
+ . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
129
131
) ;
130
- if let Some ( head) = head {
131
- err. span_label (
132
- head,
133
- & format ! (
134
- "you can't `break` with a value in a `{}` loop" ,
135
- kind. name( )
136
- ) ,
137
- ) ;
138
- }
139
- err. span_suggestion (
140
- e. span ,
141
- & format ! (
142
- "use `break` on its own without a value inside this `{}` loop" ,
143
- kind. name( ) ,
144
- ) ,
145
- format ! (
146
- "break{}" ,
147
- break_label
148
- . label
149
- . map_or_else( String :: new, |l| format!( " {}" , l. ident) )
150
- ) ,
151
- Applicability :: MaybeIncorrect ,
152
- ) ;
153
- if let ( Some ( label) , None ) = ( loop_label, break_label. label ) {
154
- match break_expr. kind {
155
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
156
- None ,
157
- hir:: Path {
158
- segments : [ segment] ,
159
- res : hir:: def:: Res :: Err ,
160
- ..
161
- } ,
162
- ) ) if label. ident . to_string ( )
163
- == format ! ( "'{}" , segment. ident) =>
164
- {
165
- // This error is redundant, we will have already emitted a
166
- // suggestion to use the label when `segment` wasn't found
167
- // (hence the `Res::Err` check).
168
- err. delay_as_bug ( ) ;
169
- }
170
- _ => {
171
- err. span_suggestion (
172
- break_expr. span ,
173
- "alternatively, you might have meant to use the \
174
- available loop label",
175
- label. ident ,
176
- Applicability :: MaybeIncorrect ,
177
- ) ;
178
- }
179
- }
180
- }
181
- err. emit ( ) ;
132
+ self . sess . emit_err ( BreakNonLoop {
133
+ span : e. span ,
134
+ head,
135
+ kind : kind. name ( ) ,
136
+ suggestion,
137
+ loop_label,
138
+ break_label : break_label. label ,
139
+ break_expr_kind : & break_expr. kind ,
140
+ break_expr_span : break_expr. span ,
141
+ } ) ;
182
142
}
183
143
}
184
144
}
@@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
191
151
match destination. target_id {
192
152
Ok ( loop_id) => {
193
153
if let Node :: Block ( block) = self . hir_map . find ( loop_id) . unwrap ( ) {
194
- struct_span_err ! (
195
- self . sess,
196
- e. span,
197
- E0696 ,
198
- "`continue` pointing to a labeled block"
199
- )
200
- . span_label ( e. span , "labeled blocks cannot be `continue`'d" )
201
- . span_label ( block. span , "labeled block the `continue` points to" )
202
- . emit ( ) ;
154
+ self . sess . emit_err ( ContinueLabeledBlock {
155
+ span : e. span ,
156
+ block_span : block. span ,
157
+ } ) ;
203
158
}
204
159
}
205
160
Err ( hir:: LoopIdError :: UnlabeledCfInWhileCondition ) => {
206
- self . emit_unlabled_cf_in_while_condition ( e. span , "continue" ) ;
161
+ self . sess . emit_err ( UnlabeledCfInWhileCondition {
162
+ span : e. span ,
163
+ cf_type : "continue" ,
164
+ } ) ;
207
165
}
208
166
Err ( _) => { }
209
167
}
@@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
226
184
}
227
185
228
186
fn require_break_cx ( & self , name : & str , span : Span ) {
229
- let err_inside_of = |article, ty, closure_span| {
230
- struct_span_err ! ( self . sess, span, E0267 , "`{}` inside of {} {}" , name, article, ty)
231
- . span_label ( span, format ! ( "cannot `{}` inside of {} {}" , name, article, ty) )
232
- . span_label ( closure_span, & format ! ( "enclosing {}" , ty) )
233
- . emit ( ) ;
234
- } ;
235
-
236
187
match self . cx {
237
188
LabeledBlock | Loop ( _) => { }
238
- Closure ( closure_span) => err_inside_of ( "a" , "closure" , closure_span) ,
239
- AsyncClosure ( closure_span) => err_inside_of ( "an" , "`async` block" , closure_span) ,
189
+ Closure ( closure_span) => {
190
+ self . sess . emit_err ( BreakInsideClosure { span, closure_span, name } ) ;
191
+ }
192
+ AsyncClosure ( closure_span) => {
193
+ self . sess . emit_err ( BreakInsideAsyncBlock { span, closure_span, name } ) ;
194
+ }
240
195
Normal | AnonConst => {
241
- struct_span_err ! ( self . sess, span, E0268 , "`{}` outside of a loop" , name)
242
- . span_label ( span, format ! ( "cannot `{}` outside of a loop" , name) )
243
- . emit ( ) ;
196
+ self . sess . emit_err ( OutsideLoop { span, name } ) ;
244
197
}
245
198
}
246
199
}
@@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
251
204
label : & Destination ,
252
205
cf_type : & str ,
253
206
) -> bool {
254
- if !span. is_desugaring ( DesugaringKind :: QuestionMark ) && self . cx == LabeledBlock {
255
- if label. label . is_none ( ) {
256
- struct_span_err ! (
257
- self . sess,
258
- span,
259
- E0695 ,
260
- "unlabeled `{}` inside of a labeled block" ,
261
- cf_type
262
- )
263
- . span_label (
264
- span,
265
- format ! (
266
- "`{}` statements that would diverge to or through \
267
- a labeled block need to bear a label",
268
- cf_type
269
- ) ,
270
- )
271
- . emit ( ) ;
272
- return true ;
273
- }
207
+ if !span. is_desugaring ( DesugaringKind :: QuestionMark )
208
+ && self . cx == LabeledBlock
209
+ && label. label . is_none ( )
210
+ {
211
+ self . sess . emit_err ( UnlabeledInLabeledBlock { span, cf_type } ) ;
212
+ return true ;
274
213
}
275
214
false
276
215
}
277
- fn emit_unlabled_cf_in_while_condition ( & mut self , span : Span , cf_type : & str ) {
278
- struct_span_err ! (
279
- self . sess,
280
- span,
281
- E0590 ,
282
- "`break` or `continue` with no label in the condition of a `while` loop"
283
- )
284
- . span_label ( span, format ! ( "unlabeled `{}` in the condition of a `while` loop" , cf_type) )
285
- . emit ( ) ;
286
- }
287
216
}
0 commit comments