@@ -199,7 +199,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
199
199
return ;
200
200
}
201
201
202
- let mut compatible_variants = expected_adt
202
+ // If the expression is of type () and it's the return expression of a block,
203
+ // we suggest adding a separate return expression instead.
204
+ // (To avoid things like suggesting `Ok(while .. { .. })`.)
205
+ if expr_ty. is_unit ( ) {
206
+ if let Some ( hir:: Node :: Block ( & hir:: Block {
207
+ span : block_span, expr : Some ( e) , ..
208
+ } ) ) = self . tcx . hir ( ) . find ( self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) )
209
+ {
210
+ if e. hir_id == expr. hir_id {
211
+ if let Some ( span) = expr. span . find_ancestor_inside ( block_span) {
212
+ let return_suggestions =
213
+ if self . tcx . is_diagnostic_item ( sym:: Result , expected_adt. did ) {
214
+ vec ! [ "Ok(())" . to_string( ) ]
215
+ } else if self . tcx . is_diagnostic_item ( sym:: Option , expected_adt. did )
216
+ {
217
+ vec ! [ "None" . to_string( ) , "Some(())" . to_string( ) ]
218
+ } else {
219
+ return ;
220
+ } ;
221
+ if let Some ( indent) =
222
+ self . tcx . sess . source_map ( ) . indentation_before ( span. shrink_to_lo ( ) )
223
+ {
224
+ // Add a semicolon, except after `}`.
225
+ let semicolon =
226
+ match self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
227
+ Ok ( s) if s. ends_with ( '}' ) => "" ,
228
+ _ => ";" ,
229
+ } ;
230
+ err. span_suggestions (
231
+ span. shrink_to_hi ( ) ,
232
+ "try adding an expression at the end of the block" ,
233
+ return_suggestions
234
+ . into_iter ( )
235
+ . map ( |r| format ! ( "{}\n {}{}" , semicolon, indent, r) ) ,
236
+ Applicability :: MaybeIncorrect ,
237
+ ) ;
238
+ }
239
+ return ;
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ let compatible_variants: Vec < String > = expected_adt
203
246
. variants
204
247
. iter ( )
205
248
. filter ( |variant| variant. fields . len ( ) == 1 )
@@ -220,19 +263,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
220
263
None
221
264
}
222
265
} )
223
- . peekable ( ) ;
266
+ . collect ( ) ;
224
267
225
- if compatible_variants. peek ( ) . is_some ( ) {
226
- if let Ok ( expr_text) = self . tcx . sess . source_map ( ) . span_to_snippet ( expr. span ) {
227
- let suggestions = compatible_variants. map ( |v| format ! ( "{}({})" , v, expr_text) ) ;
228
- let msg = "try using a variant of the expected enum" ;
229
- err. span_suggestions (
230
- expr. span ,
231
- msg,
232
- suggestions,
233
- Applicability :: MaybeIncorrect ,
234
- ) ;
235
- }
268
+ if let [ variant] = & compatible_variants[ ..] {
269
+ // Just a single matching variant.
270
+ err. multipart_suggestion (
271
+ & format ! ( "try wrapping the expression in `{}`" , variant) ,
272
+ vec ! [
273
+ ( expr. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
274
+ ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
275
+ ] ,
276
+ Applicability :: MaybeIncorrect ,
277
+ ) ;
278
+ } else if compatible_variants. len ( ) > 1 {
279
+ // More than one matching variant.
280
+ err. multipart_suggestions (
281
+ & format ! (
282
+ "try wrapping the expression in a variant of `{}`" ,
283
+ self . tcx. def_path_str( expected_adt. did)
284
+ ) ,
285
+ compatible_variants. into_iter ( ) . map ( |variant| {
286
+ vec ! [
287
+ ( expr. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
288
+ ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
289
+ ]
290
+ } ) ,
291
+ Applicability :: MaybeIncorrect ,
292
+ ) ;
236
293
}
237
294
}
238
295
}
0 commit comments