@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
20
20
use rustc_middle:: ty:: { self , DefIdTree , InferConst } ;
21
21
use rustc_middle:: ty:: { GenericArg , GenericArgKind , SubstsRef } ;
22
22
use rustc_middle:: ty:: { IsSuggestable , Ty , TyCtxt , TypeckResults } ;
23
- use rustc_span:: symbol:: { kw, Ident } ;
23
+ use rustc_span:: symbol:: { kw, sym , Ident } ;
24
24
use rustc_span:: { BytePos , Span } ;
25
25
use std:: borrow:: Cow ;
26
26
use std:: iter;
@@ -79,7 +79,7 @@ impl InferenceDiagnosticsData {
79
79
80
80
fn where_x_is_kind ( & self , in_type : Ty < ' _ > ) -> & ' static str {
81
81
if in_type. is_ty_infer ( ) {
82
- "empty "
82
+ ""
83
83
} else if self . name == "_" {
84
84
// FIXME: Consider specializing this message if there is a single `_`
85
85
// in the type.
@@ -183,13 +183,24 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
183
183
printer
184
184
}
185
185
186
- fn ty_to_string < ' tcx > ( infcx : & InferCtxt < ' tcx > , ty : Ty < ' tcx > ) -> String {
186
+ fn ty_to_string < ' tcx > (
187
+ infcx : & InferCtxt < ' tcx > ,
188
+ ty : Ty < ' tcx > ,
189
+ called_method_def_id : Option < DefId > ,
190
+ ) -> String {
187
191
let printer = fmt_printer ( infcx, Namespace :: TypeNS ) ;
188
192
let ty = infcx. resolve_vars_if_possible ( ty) ;
189
- match ty. kind ( ) {
193
+ match ( ty. kind ( ) , called_method_def_id ) {
190
194
// We don't want the regular output for `fn`s because it includes its path in
191
195
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
192
- ty:: FnDef ( ..) => ty. fn_sig ( infcx. tcx ) . print ( printer) . unwrap ( ) . into_buffer ( ) ,
196
+ ( ty:: FnDef ( ..) , _) => ty. fn_sig ( infcx. tcx ) . print ( printer) . unwrap ( ) . into_buffer ( ) ,
197
+ ( _, Some ( def_id) )
198
+ if ty. is_ty_infer ( )
199
+ && infcx. tcx . get_diagnostic_item ( sym:: iterator_collect_fn) == Some ( def_id) =>
200
+ {
201
+ "Vec<_>" . to_string ( )
202
+ }
203
+ _ if ty. is_ty_infer ( ) => "/* Type */" . to_string ( ) ,
193
204
// FIXME: The same thing for closures, but this only works when the closure
194
205
// does not capture anything.
195
206
//
@@ -213,15 +224,15 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
213
224
. map ( |args| {
214
225
args. tuple_fields ( )
215
226
. iter ( )
216
- . map ( |arg| ty_to_string ( infcx, arg) )
227
+ . map ( |arg| ty_to_string ( infcx, arg, None ) )
217
228
. collect :: < Vec < _ > > ( )
218
229
. join ( ", " )
219
230
} )
220
231
. unwrap_or_default ( ) ;
221
232
let ret = if fn_sig. output ( ) . skip_binder ( ) . is_unit ( ) {
222
233
String :: new ( )
223
234
} else {
224
- format ! ( " -> {}" , ty_to_string( infcx, fn_sig. output( ) . skip_binder( ) ) )
235
+ format ! ( " -> {}" , ty_to_string( infcx, fn_sig. output( ) . skip_binder( ) , None ) )
225
236
} ;
226
237
format ! ( "fn({}){}" , args, ret)
227
238
}
@@ -368,6 +379,7 @@ impl<'tcx> InferCtxt<'tcx> {
368
379
}
369
380
370
381
impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
382
+ #[ instrument( level = "debug" , skip( self , error_code) ) ]
371
383
pub fn emit_inference_failure_err (
372
384
& self ,
373
385
body_id : Option < hir:: BodyId > ,
@@ -406,7 +418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
406
418
let mut infer_subdiags = Vec :: new ( ) ;
407
419
let mut multi_suggestions = Vec :: new ( ) ;
408
420
match kind {
409
- InferSourceKind :: LetBinding { insert_span, pattern_name, ty } => {
421
+ InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id } => {
410
422
infer_subdiags. push ( SourceKindSubdiag :: LetLike {
411
423
span : insert_span,
412
424
name : pattern_name. map ( |name| name. to_string ( ) ) . unwrap_or_else ( String :: new) ,
@@ -415,7 +427,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
415
427
prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
416
428
arg_name : arg_data. name ,
417
429
kind : if pattern_name. is_some ( ) { "with_pattern" } else { "other" } ,
418
- type_name : ty_to_string ( self , ty) ,
430
+ type_name : ty_to_string ( self , ty, def_id ) ,
419
431
} ) ;
420
432
}
421
433
InferSourceKind :: ClosureArg { insert_span, ty } => {
@@ -427,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
427
439
prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
428
440
arg_name : arg_data. name ,
429
441
kind : "closure" ,
430
- type_name : ty_to_string ( self , ty) ,
442
+ type_name : ty_to_string ( self , ty, None ) ,
431
443
} ) ;
432
444
}
433
445
InferSourceKind :: GenericArg {
@@ -456,33 +468,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
456
468
parent_name,
457
469
} ) ;
458
470
459
- let args = fmt_printer ( self , Namespace :: TypeNS )
460
- . comma_sep ( generic_args. iter ( ) . copied ( ) . map ( |arg| {
461
- if arg. is_suggestable ( self . tcx , true ) {
462
- return arg;
463
- }
471
+ let args = if self . infcx . tcx . get_diagnostic_item ( sym:: iterator_collect_fn)
472
+ == Some ( generics_def_id)
473
+ {
474
+ "Vec<_>" . to_string ( )
475
+ } else {
476
+ fmt_printer ( self , Namespace :: TypeNS )
477
+ . comma_sep ( generic_args. iter ( ) . copied ( ) . map ( |arg| {
478
+ if arg. is_suggestable ( self . tcx , true ) {
479
+ return arg;
480
+ }
464
481
465
- match arg. unpack ( ) {
466
- GenericArgKind :: Lifetime ( _) => bug ! ( "unexpected lifetime" ) ,
467
- GenericArgKind :: Type ( _) => self
468
- . next_ty_var ( TypeVariableOrigin {
469
- span : rustc_span:: DUMMY_SP ,
470
- kind : TypeVariableOriginKind :: MiscVariable ,
471
- } )
472
- . into ( ) ,
473
- GenericArgKind :: Const ( arg) => self
474
- . next_const_var (
475
- arg. ty ( ) ,
476
- ConstVariableOrigin {
482
+ match arg. unpack ( ) {
483
+ GenericArgKind :: Lifetime ( _) => bug ! ( "unexpected lifetime" ) ,
484
+ GenericArgKind :: Type ( _) => self
485
+ . next_ty_var ( TypeVariableOrigin {
477
486
span : rustc_span:: DUMMY_SP ,
478
- kind : ConstVariableOriginKind :: MiscVariable ,
479
- } ,
480
- )
481
- . into ( ) ,
482
- }
483
- } ) )
484
- . unwrap ( )
485
- . into_buffer ( ) ;
487
+ kind : TypeVariableOriginKind :: MiscVariable ,
488
+ } )
489
+ . into ( ) ,
490
+ GenericArgKind :: Const ( arg) => self
491
+ . next_const_var (
492
+ arg. ty ( ) ,
493
+ ConstVariableOrigin {
494
+ span : rustc_span:: DUMMY_SP ,
495
+ kind : ConstVariableOriginKind :: MiscVariable ,
496
+ } ,
497
+ )
498
+ . into ( ) ,
499
+ }
500
+ } ) )
501
+ . unwrap ( )
502
+ . into_buffer ( )
503
+ } ;
486
504
487
505
if !have_turbofish {
488
506
infer_subdiags. push ( SourceKindSubdiag :: GenericSuggestion {
@@ -520,7 +538,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
520
538
) ) ;
521
539
}
522
540
InferSourceKind :: ClosureReturn { ty, data, should_wrap_expr } => {
523
- let ty_info = ty_to_string ( self , ty) ;
541
+ let ty_info = ty_to_string ( self , ty, None ) ;
524
542
multi_suggestions. push ( SourceKindMultiSuggestion :: new_closure_return (
525
543
ty_info,
526
544
data,
@@ -608,6 +626,7 @@ enum InferSourceKind<'tcx> {
608
626
insert_span : Span ,
609
627
pattern_name : Option < Ident > ,
610
628
ty : Ty < ' tcx > ,
629
+ def_id : Option < DefId > ,
611
630
} ,
612
631
ClosureArg {
613
632
insert_span : Span ,
@@ -662,7 +681,7 @@ impl<'tcx> InferSourceKind<'tcx> {
662
681
if ty. is_closure ( ) {
663
682
( "closure" , closure_as_fn_str ( infcx, ty) )
664
683
} else if !ty. is_ty_infer ( ) {
665
- ( "normal" , ty_to_string ( infcx, ty) )
684
+ ( "normal" , ty_to_string ( infcx, ty, None ) )
666
685
} else {
667
686
( "other" , String :: new ( ) )
668
687
}
@@ -788,10 +807,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
788
807
/// Uses `fn source_cost` to determine whether this inference source is preferable to
789
808
/// previous sources. We generally prefer earlier sources.
790
809
#[ instrument( level = "debug" , skip( self ) ) ]
791
- fn update_infer_source ( & mut self , new_source : InferSource < ' tcx > ) {
810
+ fn update_infer_source ( & mut self , mut new_source : InferSource < ' tcx > ) {
792
811
let cost = self . source_cost ( & new_source) + self . attempt ;
793
812
debug ! ( ?cost) ;
794
813
self . attempt += 1 ;
814
+ if let Some ( InferSource { kind : InferSourceKind :: GenericArg { def_id : did, ..} , .. } ) = self . infer_source
815
+ && let InferSourceKind :: LetBinding { ref ty, ref mut def_id, ..} = new_source. kind
816
+ && ty. is_ty_infer ( )
817
+ {
818
+ // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
819
+ // `let x: _ = iter.collect();`, as this is a very common case.
820
+ * def_id = Some ( did) ;
821
+ }
795
822
if cost < self . infer_source_cost {
796
823
self . infer_source_cost = cost;
797
824
self . infer_source = Some ( new_source) ;
@@ -1092,6 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
1092
1119
insert_span : local. pat . span . shrink_to_hi ( ) ,
1093
1120
pattern_name : local. pat . simple_ident ( ) ,
1094
1121
ty,
1122
+ def_id : None ,
1095
1123
} ,
1096
1124
} )
1097
1125
}
0 commit comments