@@ -217,16 +217,10 @@ impl UseDiagnostic<'_> {
217
217
218
218
/// Suggest giving an appropriate return type to a closure expression.
219
219
fn closure_return_type_suggestion (
220
- span : Span ,
221
220
err : & mut DiagnosticBuilder < ' _ > ,
222
221
output : & FnRetTy < ' _ > ,
223
222
body : & Body < ' _ > ,
224
- descr : & str ,
225
- name : & str ,
226
223
ret : & str ,
227
- use_diag : Option < & UseDiagnostic < ' _ > > ,
228
- parent_name : Option < String > ,
229
- parent_descr : Option < & str > ,
230
224
) {
231
225
let ( arrow, post) = match output {
232
226
FnRetTy :: DefaultReturn ( _) => ( "-> " , " " ) ,
@@ -244,18 +238,6 @@ fn closure_return_type_suggestion(
244
238
suggestion,
245
239
Applicability :: HasPlaceholders ,
246
240
) ;
247
- err. span_label (
248
- span,
249
- InferCtxt :: cannot_infer_msg (
250
- span,
251
- "type" ,
252
- & name,
253
- & descr,
254
- use_diag,
255
- parent_name,
256
- parent_descr,
257
- ) ,
258
- ) ;
259
241
}
260
242
261
243
/// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -300,9 +282,52 @@ impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
300
282
pub struct InferenceDiagnosticsData {
301
283
pub name : String ,
302
284
pub span : Option < Span > ,
303
- pub description : Cow < ' static , str > ,
304
- pub parent_name : Option < String > ,
305
- pub parent_description : Option < & ' static str > ,
285
+ pub kind : UnderspecifiedArgKind ,
286
+ pub parent : Option < InferenceDiagnosticsParentData > ,
287
+ }
288
+
289
+ pub struct InferenceDiagnosticsParentData {
290
+ pub prefix : & ' static str ,
291
+ pub name : String ,
292
+ }
293
+
294
+ pub enum UnderspecifiedArgKind {
295
+ Type { prefix : Cow < ' static , str > } ,
296
+ Const { is_parameter : bool } ,
297
+ }
298
+
299
+ impl InferenceDiagnosticsData {
300
+ /// Generate a label for a generic argument which can't be inferred. When not
301
+ /// much is known about the argument, `use_diag` may be used to describe the
302
+ /// labeled value.
303
+ fn cannot_infer_msg ( & self , use_diag : Option < & UseDiagnostic < ' _ > > ) -> String {
304
+ if self . name == "_" && matches ! ( self . kind, UnderspecifiedArgKind :: Type { .. } ) {
305
+ if let Some ( use_diag) = use_diag {
306
+ return format ! ( "cannot infer type of {}" , use_diag. descr( ) ) ;
307
+ }
308
+
309
+ return "cannot infer type" . to_string ( ) ;
310
+ }
311
+
312
+ let suffix = match ( & self . parent , use_diag) {
313
+ ( Some ( parent) , _) => format ! ( " declared on the {} `{}`" , parent. prefix, parent. name) ,
314
+ ( None , Some ( use_diag) ) => format ! ( " in {}" , use_diag. type_descr( ) ) ,
315
+ ( None , None ) => String :: new ( ) ,
316
+ } ;
317
+
318
+ // For example: "cannot infer type for type parameter `T`"
319
+ format ! ( "cannot infer {} `{}`{}" , self . kind. prefix_string( ) , self . name, suffix)
320
+ }
321
+ }
322
+
323
+ impl UnderspecifiedArgKind {
324
+ fn prefix_string ( & self ) -> Cow < ' static , str > {
325
+ match self {
326
+ Self :: Type { prefix } => format ! ( "type for {}" , prefix) . into ( ) ,
327
+ Self :: Const { is_parameter : true } => "the value of const parameter" . into ( ) ,
328
+ Self :: Const { is_parameter : false } => "the value of the constant" . into ( ) ,
329
+ }
330
+ }
306
331
}
307
332
308
333
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
@@ -322,32 +347,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
322
347
if let TypeVariableOriginKind :: TypeParameterDefinition ( name, def_id) =
323
348
var_origin. kind
324
349
{
325
- let parent_def_id = def_id. and_then ( |def_id| self . tcx . parent ( def_id ) ) ;
326
- let ( parent_name , parent_description ) =
327
- if let Some ( parent_def_id) = parent_def_id {
350
+ let parent_data = def_id
351
+ . and_then ( |def_id| self . tcx . parent ( def_id ) )
352
+ . and_then ( | parent_def_id| {
328
353
let parent_name = self
329
354
. tcx
330
355
. def_key ( parent_def_id)
331
356
. disambiguated_data
332
357
. data
333
- . get_opt_name ( )
334
- . map ( |parent_symbol| parent_symbol. to_string ( ) ) ;
335
-
336
- (
337
- parent_name,
338
- Some ( self . tcx . def_kind ( parent_def_id) . descr ( parent_def_id) ) ,
339
- )
340
- } else {
341
- ( None , None )
342
- } ;
358
+ . get_opt_name ( ) ?
359
+ . to_string ( ) ;
360
+
361
+ Some ( InferenceDiagnosticsParentData {
362
+ prefix : self . tcx . def_kind ( parent_def_id) . descr ( parent_def_id) ,
363
+ name : parent_name,
364
+ } )
365
+ } ) ;
343
366
344
367
if name != kw:: SelfUpper {
345
368
return InferenceDiagnosticsData {
346
369
name : name. to_string ( ) ,
347
370
span : Some ( var_origin. span ) ,
348
- description : "type parameter" . into ( ) ,
349
- parent_name,
350
- parent_description,
371
+ kind : UnderspecifiedArgKind :: Type {
372
+ prefix : "type parameter" . into ( ) ,
373
+ } ,
374
+ parent : parent_data,
351
375
} ;
352
376
}
353
377
}
@@ -362,9 +386,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
362
386
InferenceDiagnosticsData {
363
387
name : s,
364
388
span : None ,
365
- description : ty. prefix_string ( ) ,
366
- parent_name : None ,
367
- parent_description : None ,
389
+ kind : UnderspecifiedArgKind :: Type { prefix : ty. prefix_string ( ) } ,
390
+ parent : None ,
368
391
}
369
392
}
370
393
GenericArgKind :: Const ( ct) => {
@@ -374,31 +397,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
374
397
if let ConstVariableOriginKind :: ConstParameterDefinition ( name, def_id) =
375
398
origin. kind
376
399
{
377
- let parent_def_id = self . tcx . parent ( def_id) ;
378
- let ( parent_name, parent_description) =
379
- if let Some ( parent_def_id) = parent_def_id {
380
- let parent_name = self
381
- . tcx
382
- . def_key ( parent_def_id)
383
- . disambiguated_data
384
- . data
385
- . get_opt_name ( )
386
- . map ( |parent_symbol| parent_symbol. to_string ( ) ) ;
387
-
388
- (
389
- parent_name,
390
- Some ( self . tcx . def_kind ( parent_def_id) . descr ( parent_def_id) ) ,
391
- )
392
- } else {
393
- ( None , None )
394
- } ;
400
+ let parent_data = self . tcx . parent ( def_id) . and_then ( |parent_def_id| {
401
+ let parent_name = self
402
+ . tcx
403
+ . def_key ( parent_def_id)
404
+ . disambiguated_data
405
+ . data
406
+ . get_opt_name ( ) ?
407
+ . to_string ( ) ;
408
+
409
+ Some ( InferenceDiagnosticsParentData {
410
+ prefix : self . tcx . def_kind ( parent_def_id) . descr ( parent_def_id) ,
411
+ name : parent_name,
412
+ } )
413
+ } ) ;
395
414
396
415
return InferenceDiagnosticsData {
397
416
name : name. to_string ( ) ,
398
417
span : Some ( origin. span ) ,
399
- description : "const parameter" . into ( ) ,
400
- parent_name,
401
- parent_description,
418
+ kind : UnderspecifiedArgKind :: Const { is_parameter : true } ,
419
+ parent : parent_data,
402
420
} ;
403
421
}
404
422
@@ -413,9 +431,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
413
431
InferenceDiagnosticsData {
414
432
name : s,
415
433
span : Some ( origin. span ) ,
416
- description : "the constant" . into ( ) ,
417
- parent_name : None ,
418
- parent_description : None ,
434
+ kind : UnderspecifiedArgKind :: Const { is_parameter : false } ,
435
+ parent : None ,
419
436
}
420
437
} else {
421
438
bug ! ( "unexpect const: {:?}" , ct) ;
@@ -554,19 +571,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
554
571
555
572
if let Some ( ( decl, body_id) ) = closure_decl_and_body_id {
556
573
closure_return_type_suggestion (
557
- span,
558
574
& mut err,
559
575
& decl. output ,
560
576
self . tcx . hir ( ) . body ( body_id) ,
561
- & arg_data. description ,
562
- & arg_data. name ,
563
577
& ret,
564
- use_diag,
565
- arg_data. parent_name ,
566
- arg_data. parent_description ,
567
578
) ;
568
579
// We don't want to give the other suggestions when the problem is the
569
580
// closure return type.
581
+ err. span_label (
582
+ span,
583
+ arg_data. cannot_infer_msg ( use_diag. filter ( |d| d. applies_to ( span) ) ) ,
584
+ ) ;
570
585
return err;
571
586
}
572
587
@@ -703,47 +718,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
703
718
// |
704
719
// = note: type must be known at this point
705
720
let span = arg_data. span . unwrap_or ( err_span) ;
721
+
722
+ // Avoid multiple labels pointing at `span`.
706
723
if !err
707
724
. span
708
725
. span_labels ( )
709
726
. iter ( )
710
727
. any ( |span_label| span_label. label . is_some ( ) && span_label. span == span)
711
728
&& local_visitor. found_arg_pattern . is_none ( )
712
729
{
713
- let ( kind_str, const_value) = match arg. unpack ( ) {
714
- GenericArgKind :: Type ( _) => ( "type" , None ) ,
715
- GenericArgKind :: Const ( _) => ( "the value" , Some ( ( ) ) ) ,
716
- GenericArgKind :: Lifetime ( _) => bug ! ( "unexpected lifetime" ) ,
717
- } ;
718
-
719
730
// FIXME(const_generics): we would like to handle const arguments
720
731
// as part of the normal diagnostics flow below, but there appear to
721
732
// be subtleties in doing so, so for now we special-case const args
722
733
// here.
723
- if let Some ( suggestion) = const_value
724
- . and_then ( |_| arg_data. parent_name . as_ref ( ) )
725
- . map ( |parent| format ! ( "{}::<{}>" , parent, arg_data. name) )
734
+ if let ( UnderspecifiedArgKind :: Const { .. } , Some ( parent_data) ) =
735
+ ( & arg_data. kind , & arg_data. parent )
726
736
{
727
737
err. span_suggestion_verbose (
728
738
span,
729
739
"consider specifying the const argument" ,
730
- suggestion ,
740
+ format ! ( "{}::<{}>" , parent_data . name , arg_data . name ) ,
731
741
Applicability :: MaybeIncorrect ,
732
742
) ;
733
743
}
734
744
735
- // Avoid multiple labels pointing at `span`.
736
745
err. span_label (
737
746
span,
738
- InferCtxt :: cannot_infer_msg (
739
- span,
740
- kind_str,
741
- & arg_data. name ,
742
- & arg_data. description ,
743
- use_diag,
744
- arg_data. parent_name ,
745
- arg_data. parent_description ,
746
- ) ,
747
+ arg_data. cannot_infer_msg ( use_diag. filter ( |d| d. applies_to ( span) ) ) ,
747
748
) ;
748
749
}
749
750
@@ -826,61 +827,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
826
827
"type inside {} must be known in this context" ,
827
828
kind,
828
829
) ;
829
- err. span_label (
830
- span,
831
- InferCtxt :: cannot_infer_msg (
832
- span,
833
- "type" ,
834
- & data. name ,
835
- & data. description ,
836
- None ,
837
- data. parent_name ,
838
- data. parent_description ,
839
- ) ,
840
- ) ;
830
+ err. span_label ( span, data. cannot_infer_msg ( None ) ) ;
841
831
err
842
832
}
843
-
844
- fn cannot_infer_msg (
845
- span : Span ,
846
- kind_str : & str ,
847
- type_name : & str ,
848
- descr : & str ,
849
- use_diag : Option < & UseDiagnostic < ' _ > > ,
850
- parent_name : Option < String > ,
851
- parent_descr : Option < & str > ,
852
- ) -> String {
853
- let use_diag = use_diag. filter ( |d| d. applies_to ( span) ) ;
854
-
855
- if type_name == "_" {
856
- if let Some ( use_diag) = use_diag {
857
- format ! ( "cannot infer {} of {}" , kind_str, use_diag. descr( ) )
858
- } else {
859
- format ! ( "cannot infer {}" , kind_str)
860
- }
861
- } else {
862
- let extra_descr = if let Some ( parent_name) = parent_name {
863
- let parent_type_descr = if let Some ( parent_descr) = parent_descr {
864
- format ! ( " the {}" , parent_descr)
865
- } else {
866
- "" . into ( )
867
- } ;
868
-
869
- format ! ( " declared on{} `{}`" , parent_type_descr, parent_name)
870
- } else if let Some ( use_diag) = use_diag {
871
- format ! ( " in {}" , use_diag. type_descr( ) )
872
- } else {
873
- "" . into ( )
874
- } ;
875
-
876
- // FIXME: We really shouldn't be dealing with strings here
877
- // but instead use a sensible enum for cases like this.
878
- let preposition = if "the value" == kind_str { "of" } else { "for" } ;
879
- // For example: "cannot infer type for type parameter `T`"
880
- format ! (
881
- "cannot infer {} {} {} `{}`{}" ,
882
- kind_str, preposition, descr, type_name, extra_descr
883
- )
884
- }
885
- }
886
833
}
0 commit comments