@@ -199,7 +199,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
199199 return ;
200200 }
201201
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
203246 . variants
204247 . iter ( )
205248 . filter ( |variant| variant. fields . len ( ) == 1 )
@@ -220,19 +263,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
220263 None
221264 }
222265 } )
223- . peekable ( ) ;
266+ . collect ( ) ;
224267
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+ ) ;
236293 }
237294 }
238295 }
0 commit comments