@@ -217,16 +217,10 @@ impl UseDiagnostic<'_> {
217217
218218/// Suggest giving an appropriate return type to a closure expression.
219219fn closure_return_type_suggestion (
220- span : Span ,
221220 err : & mut DiagnosticBuilder < ' _ > ,
222221 output : & FnRetTy < ' _ > ,
223222 body : & Body < ' _ > ,
224- descr : & str ,
225- name : & str ,
226223 ret : & str ,
227- use_diag : Option < & UseDiagnostic < ' _ > > ,
228- parent_name : Option < String > ,
229- parent_descr : Option < & str > ,
230224) {
231225 let ( arrow, post) = match output {
232226 FnRetTy :: DefaultReturn ( _) => ( "-> " , " " ) ,
@@ -244,18 +238,6 @@ fn closure_return_type_suggestion(
244238 suggestion,
245239 Applicability :: HasPlaceholders ,
246240 ) ;
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- ) ;
259241}
260242
261243/// 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 {
300282pub struct InferenceDiagnosticsData {
301283 pub name : String ,
302284 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+ }
306331}
307332
308333impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
@@ -322,32 +347,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
322347 if let TypeVariableOriginKind :: TypeParameterDefinition ( name, def_id) =
323348 var_origin. kind
324349 {
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| {
328353 let parent_name = self
329354 . tcx
330355 . def_key ( parent_def_id)
331356 . disambiguated_data
332357 . 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+ } ) ;
343366
344367 if name != kw:: SelfUpper {
345368 return InferenceDiagnosticsData {
346369 name : name. to_string ( ) ,
347370 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,
351375 } ;
352376 }
353377 }
@@ -362,9 +386,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
362386 InferenceDiagnosticsData {
363387 name : s,
364388 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 ,
368391 }
369392 }
370393 GenericArgKind :: Const ( ct) => {
@@ -374,31 +397,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
374397 if let ConstVariableOriginKind :: ConstParameterDefinition ( name, def_id) =
375398 origin. kind
376399 {
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+ } ) ;
395414
396415 return InferenceDiagnosticsData {
397416 name : name. to_string ( ) ,
398417 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,
402420 } ;
403421 }
404422
@@ -413,9 +431,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
413431 InferenceDiagnosticsData {
414432 name : s,
415433 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 ,
419436 }
420437 } else {
421438 bug ! ( "unexpect const: {:?}" , ct) ;
@@ -554,19 +571,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
554571
555572 if let Some ( ( decl, body_id) ) = closure_decl_and_body_id {
556573 closure_return_type_suggestion (
557- span,
558574 & mut err,
559575 & decl. output ,
560576 self . tcx . hir ( ) . body ( body_id) ,
561- & arg_data. description ,
562- & arg_data. name ,
563577 & ret,
564- use_diag,
565- arg_data. parent_name ,
566- arg_data. parent_description ,
567578 ) ;
568579 // We don't want to give the other suggestions when the problem is the
569580 // closure return type.
581+ err. span_label (
582+ span,
583+ arg_data. cannot_infer_msg ( use_diag. filter ( |d| d. applies_to ( span) ) ) ,
584+ ) ;
570585 return err;
571586 }
572587
@@ -703,47 +718,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
703718 // |
704719 // = note: type must be known at this point
705720 let span = arg_data. span . unwrap_or ( err_span) ;
721+
722+ // Avoid multiple labels pointing at `span`.
706723 if !err
707724 . span
708725 . span_labels ( )
709726 . iter ( )
710727 . any ( |span_label| span_label. label . is_some ( ) && span_label. span == span)
711728 && local_visitor. found_arg_pattern . is_none ( )
712729 {
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-
719730 // FIXME(const_generics): we would like to handle const arguments
720731 // as part of the normal diagnostics flow below, but there appear to
721732 // be subtleties in doing so, so for now we special-case const args
722733 // 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 )
726736 {
727737 err. span_suggestion_verbose (
728738 span,
729739 "consider specifying the const argument" ,
730- suggestion ,
740+ format ! ( "{}::<{}>" , parent_data . name , arg_data . name ) ,
731741 Applicability :: MaybeIncorrect ,
732742 ) ;
733743 }
734744
735- // Avoid multiple labels pointing at `span`.
736745 err. span_label (
737746 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) ) ) ,
747748 ) ;
748749 }
749750
@@ -826,61 +827,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
826827 "type inside {} must be known in this context" ,
827828 kind,
828829 ) ;
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 ) ) ;
841831 err
842832 }
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- }
886833}
0 commit comments