@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
2020use rustc_middle:: ty:: { self , DefIdTree , InferConst } ;
2121use rustc_middle:: ty:: { GenericArg , GenericArgKind , SubstsRef } ;
2222use rustc_middle:: ty:: { IsSuggestable , Ty , TyCtxt , TypeckResults } ;
23- use rustc_span:: symbol:: { kw, Ident } ;
23+ use rustc_span:: symbol:: { kw, sym , Ident } ;
2424use rustc_span:: { BytePos , Span } ;
2525use std:: borrow:: Cow ;
2626use std:: iter;
@@ -79,7 +79,7 @@ impl InferenceDiagnosticsData {
7979
8080 fn where_x_is_kind ( & self , in_type : Ty < ' _ > ) -> & ' static str {
8181 if in_type. is_ty_infer ( ) {
82- "empty "
82+ ""
8383 } else if self . name == "_" {
8484 // FIXME: Consider specializing this message if there is a single `_`
8585 // in the type.
@@ -183,13 +183,24 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
183183 printer
184184}
185185
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 {
187191 let printer = fmt_printer ( infcx, Namespace :: TypeNS ) ;
188192 let ty = infcx. resolve_vars_if_possible ( ty) ;
189- match ty. kind ( ) {
193+ match ( ty. kind ( ) , called_method_def_id ) {
190194 // We don't want the regular output for `fn`s because it includes its path in
191195 // 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 ( ) ,
193204 // FIXME: The same thing for closures, but this only works when the closure
194205 // does not capture anything.
195206 //
@@ -213,15 +224,15 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
213224 . map ( |args| {
214225 args. tuple_fields ( )
215226 . iter ( )
216- . map ( |arg| ty_to_string ( infcx, arg) )
227+ . map ( |arg| ty_to_string ( infcx, arg, None ) )
217228 . collect :: < Vec < _ > > ( )
218229 . join ( ", " )
219230 } )
220231 . unwrap_or_default ( ) ;
221232 let ret = if fn_sig. output ( ) . skip_binder ( ) . is_unit ( ) {
222233 String :: new ( )
223234 } else {
224- format ! ( " -> {}" , ty_to_string( infcx, fn_sig. output( ) . skip_binder( ) ) )
235+ format ! ( " -> {}" , ty_to_string( infcx, fn_sig. output( ) . skip_binder( ) , None ) )
225236 } ;
226237 format ! ( "fn({}){}" , args, ret)
227238}
@@ -368,6 +379,7 @@ impl<'tcx> InferCtxt<'tcx> {
368379}
369380
370381impl < ' tcx > TypeErrCtxt < ' _ , ' tcx > {
382+ #[ instrument( level = "debug" , skip( self , error_code) ) ]
371383 pub fn emit_inference_failure_err (
372384 & self ,
373385 body_id : Option < hir:: BodyId > ,
@@ -406,7 +418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
406418 let mut infer_subdiags = Vec :: new ( ) ;
407419 let mut multi_suggestions = Vec :: new ( ) ;
408420 match kind {
409- InferSourceKind :: LetBinding { insert_span, pattern_name, ty } => {
421+ InferSourceKind :: LetBinding { insert_span, pattern_name, ty, def_id } => {
410422 infer_subdiags. push ( SourceKindSubdiag :: LetLike {
411423 span : insert_span,
412424 name : pattern_name. map ( |name| name. to_string ( ) ) . unwrap_or_else ( String :: new) ,
@@ -415,7 +427,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
415427 prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
416428 arg_name : arg_data. name ,
417429 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 ) ,
419431 } ) ;
420432 }
421433 InferSourceKind :: ClosureArg { insert_span, ty } => {
@@ -427,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
427439 prefix : arg_data. kind . try_get_prefix ( ) . unwrap_or_default ( ) ,
428440 arg_name : arg_data. name ,
429441 kind : "closure" ,
430- type_name : ty_to_string ( self , ty) ,
442+ type_name : ty_to_string ( self , ty, None ) ,
431443 } ) ;
432444 }
433445 InferSourceKind :: GenericArg {
@@ -456,33 +468,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
456468 parent_name,
457469 } ) ;
458470
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+ }
464481
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 {
477486 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+ } ;
486504
487505 if !have_turbofish {
488506 infer_subdiags. push ( SourceKindSubdiag :: GenericSuggestion {
@@ -520,7 +538,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
520538 ) ) ;
521539 }
522540 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 ) ;
524542 multi_suggestions. push ( SourceKindMultiSuggestion :: new_closure_return (
525543 ty_info,
526544 data,
@@ -608,6 +626,7 @@ enum InferSourceKind<'tcx> {
608626 insert_span : Span ,
609627 pattern_name : Option < Ident > ,
610628 ty : Ty < ' tcx > ,
629+ def_id : Option < DefId > ,
611630 } ,
612631 ClosureArg {
613632 insert_span : Span ,
@@ -662,7 +681,7 @@ impl<'tcx> InferSourceKind<'tcx> {
662681 if ty. is_closure ( ) {
663682 ( "closure" , closure_as_fn_str ( infcx, ty) )
664683 } else if !ty. is_ty_infer ( ) {
665- ( "normal" , ty_to_string ( infcx, ty) )
684+ ( "normal" , ty_to_string ( infcx, ty, None ) )
666685 } else {
667686 ( "other" , String :: new ( ) )
668687 }
@@ -788,10 +807,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
788807 /// Uses `fn source_cost` to determine whether this inference source is preferable to
789808 /// previous sources. We generally prefer earlier sources.
790809 #[ 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 > ) {
792811 let cost = self . source_cost ( & new_source) + self . attempt ;
793812 debug ! ( ?cost) ;
794813 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+ }
795822 if cost < self . infer_source_cost {
796823 self . infer_source_cost = cost;
797824 self . infer_source = Some ( new_source) ;
@@ -1092,6 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
10921119 insert_span : local. pat . span . shrink_to_hi ( ) ,
10931120 pattern_name : local. pat . simple_ident ( ) ,
10941121 ty,
1122+ def_id : None ,
10951123 } ,
10961124 } )
10971125 }
0 commit comments