From 9d5e7d3c042f73153cf8f009400569ff9e8e12a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 9 Dec 2022 22:31:16 -0800 Subject: [PATCH] Suggest `collect`ing into `Vec<_>` --- .../infer/error_reporting/need_type_info.rs | 32 ++++++++++++++----- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/iter/traits/iterator.rs | 1 + .../ui/array-slice-vec/infer_array_len.stderr | 2 +- src/test/ui/closures/issue-52437.stderr | 2 +- src/test/ui/error-codes/E0282.stderr | 4 +-- .../ui/impl-trait/issues/issue-86719.stderr | 2 +- src/test/ui/inference/issue-72690.stderr | 2 +- src/test/ui/issues/issue-18159.stderr | 2 +- src/test/ui/issues/issue-2151.stderr | 2 +- src/test/ui/issues/issue-24036.stderr | 2 +- .../branches3.stderr | 8 ++--- .../ui/match/match-unresolved-one-arm.stderr | 2 +- src/test/ui/pattern/pat-tuple-bad-type.stderr | 2 +- .../rest-pat-semantic-disallowed.stderr | 2 +- src/test/ui/resolve/issue-85348.stderr | 2 +- .../method-and-field-eager-resolution.stderr | 4 +-- .../closures_in_branches.stderr | 4 +-- .../unknown_type_for_closure.stderr | 2 +- .../ui/type/type-path-err-node-types.stderr | 2 +- 20 files changed, 49 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 8ff1639a3a2..b55cb091b1f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; use std::iter; @@ -78,12 +78,12 @@ fn can_add_more_info(&self) -> bool { } fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { - if in_type.is_ty_infer() { - "empty" - } else if self.name == "_" { + if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. "underscore" + } else if in_type.is_ty_infer() { + "empty" } else { "has_name" } @@ -368,6 +368,7 @@ fn bad_inference_failure_err( } impl<'tcx> TypeErrCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, body_id: Option, @@ -406,16 +407,20 @@ pub fn emit_inference_failure_err( let mut infer_subdiags = Vec::new(); let mut multi_suggestions = Vec::new(); match kind { - InferSourceKind::LetBinding { insert_span, pattern_name, ty } => { + InferSourceKind::LetBinding { insert_span, pattern_name, ty, is_collect } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), - x_kind: arg_data.where_x_is_kind(ty), + x_kind: if is_collect { "empty" } else { arg_data.where_x_is_kind(ty) }, prefix_kind: arg_data.kind.clone(), prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, - type_name: ty_to_string(self, ty), + type_name: if is_collect { + "Vec<_>".to_string() + } else { + ty_to_string(self, ty) + }, }); } InferSourceKind::ClosureArg { insert_span, ty } => { @@ -608,6 +613,7 @@ enum InferSourceKind<'tcx> { insert_span: Span, pattern_name: Option, ty: Ty<'tcx>, + is_collect: bool, }, ClosureArg { insert_span: Span, @@ -788,10 +794,19 @@ fn ty_cost(self, ty: Ty<'tcx>) -> usize { /// Uses `fn source_cost` to determine whether this inference source is preferable to /// previous sources. We generally prefer earlier sources. #[instrument(level = "debug", skip(self))] - fn update_infer_source(&mut self, new_source: InferSource<'tcx>) { + fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) { let cost = self.source_cost(&new_source) + self.attempt; debug!(?cost); self.attempt += 1; + if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id, ..}, .. }) = self.infer_source + && self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) + && let InferSourceKind::LetBinding { ref ty, ref mut is_collect, ..} = new_source.kind + && ty.is_ty_infer() + { + // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of + // `let x: _ = iter.collect();`, as this is a very common case. + *is_collect = true; + } if cost < self.infer_source_cost { self.infer_source_cost = cost; self.infer_source = Some(new_source); @@ -1089,6 +1104,7 @@ fn visit_local(&mut self, local: &'tcx Local<'tcx>) { insert_span: local.pat.span.shrink_to_hi(), pattern_name: local.pat.simple_ident(), ty, + is_collect: false, }, }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 85d416c43f9..ace095736c9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -827,6 +827,7 @@ item_like_imports, iter, iter_repeat, + iterator_collect_fn, kcfi, keyword, kind, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 83c7e8977e9..1cdee992137 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1829,6 +1829,7 @@ fn by_ref(&mut self) -> &mut Self #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] + #[cfg_attr(not(test), rustc_diagnostic_item = "iterator_collect_fn")] fn collect>(self) -> B where Self: Sized, diff --git a/src/test/ui/array-slice-vec/infer_array_len.stderr b/src/test/ui/array-slice-vec/infer_array_len.stderr index 919550cac30..bd757be126c 100644 --- a/src/test/ui/array-slice-vec/infer_array_len.stderr +++ b/src/test/ui/array-slice-vec/infer_array_len.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let [_, _] = a.into(); | ^^^^^^ | -help: consider giving this pattern a type +help: consider giving this pattern a type, where the placeholders `_` are specified | LL | let [_, _]: _ = a.into(); | +++ diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index 4c24a54bbbe..f7d34890a79 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -10,7 +10,7 @@ error[E0282]: type annotations needed LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize] | +++ diff --git a/src/test/ui/error-codes/E0282.stderr b/src/test/ui/error-codes/E0282.stderr index d01aa3617c7..892d3a81f27 100644 --- a/src/test/ui/error-codes/E0282.stderr +++ b/src/test/ui/error-codes/E0282.stderr @@ -6,8 +6,8 @@ LL | let x = "hello".chars().rev().collect(); | help: consider giving `x` an explicit type | -LL | let x: _ = "hello".chars().rev().collect(); - | +++ +LL | let x: Vec<_> = "hello".chars().rev().collect(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issues/issue-86719.stderr b/src/test/ui/impl-trait/issues/issue-86719.stderr index 09047cdcbe1..da184c26bfe 100644 --- a/src/test/ui/impl-trait/issues/issue-86719.stderr +++ b/src/test/ui/impl-trait/issues/issue-86719.stderr @@ -18,7 +18,7 @@ error[E0282]: type annotations needed LL | |_| true | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |_: _| true | +++ diff --git a/src/test/ui/inference/issue-72690.stderr b/src/test/ui/inference/issue-72690.stderr index d4eeda07366..e59bcea9512 100644 --- a/src/test/ui/inference/issue-72690.stderr +++ b/src/test/ui/inference/issue-72690.stderr @@ -30,7 +30,7 @@ error[E0282]: type annotations needed LL | |x| String::from("x".as_ref()); | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |x: _| String::from("x".as_ref()); | +++ diff --git a/src/test/ui/issues/issue-18159.stderr b/src/test/ui/issues/issue-18159.stderr index 605ff3829d1..bedfeda2ea0 100644 --- a/src/test/ui/issues/issue-18159.stderr +++ b/src/test/ui/issues/issue-18159.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x; | ^ | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let x: _; | +++ diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr index 31a8ca5fbfa..411fdc48344 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -6,7 +6,7 @@ LL | let x = panic!(); LL | x.clone(); | - type must be known at this point | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let x: _ = panic!(); | +++ diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index a42e35c4cad..fcfce56bcb1 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -17,7 +17,7 @@ error[E0282]: type annotations needed LL | 1 => |c| c + 1, | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | 1 => |c: _| c + 1, | +++ diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr index 420104e526d..9d56d96c8c1 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | |s| s.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |s: _| s.len() | +++ @@ -15,7 +15,7 @@ error[E0282]: type annotations needed LL | |s| s.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |s: _| s.len() | +++ @@ -26,7 +26,7 @@ error[E0282]: type annotations needed LL | |s| s.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |s: _| s.len() | +++ @@ -37,7 +37,7 @@ error[E0282]: type annotations needed LL | |s| s.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |s: _| s.len() | +++ diff --git a/src/test/ui/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr index 9eadb88a8ba..db5db38391e 100644 --- a/src/test/ui/match/match-unresolved-one-arm.stderr +++ b/src/test/ui/match/match-unresolved-one-arm.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x = match () { | ^ | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let x: _ = match () { | +++ diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 3342b8e4002..86fd1e0c196 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -7,7 +7,7 @@ LL | let x; LL | (..) => {} | ---- type must be known at this point | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let x: _; | +++ diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr index e6a4e5f19b7..5bf168a5711 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -191,7 +191,7 @@ error[E0282]: type annotations needed LL | let x @ ..; | ^^^^^^ | -help: consider giving this pattern a type +help: consider giving this pattern a type, where the placeholders `_` are specified | LL | let x @ ..: _; | +++ diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr index f839dd927db..cc9cd3fe68b 100644 --- a/src/test/ui/resolve/issue-85348.stderr +++ b/src/test/ui/resolve/issue-85348.stderr @@ -19,7 +19,7 @@ error[E0282]: type annotations needed LL | let mut N; | ^^^^^ | -help: consider giving `N` an explicit type +help: consider giving `N` an explicit type, where the placeholders `_` are specified | LL | let mut N: _; | +++ diff --git a/src/test/ui/span/method-and-field-eager-resolution.stderr b/src/test/ui/span/method-and-field-eager-resolution.stderr index 7d240589a3f..85205464626 100644 --- a/src/test/ui/span/method-and-field-eager-resolution.stderr +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -7,7 +7,7 @@ LL | LL | x.0; | - type must be known at this point | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let mut x: _ = Default::default(); | +++ @@ -21,7 +21,7 @@ LL | LL | x[0]; | - type must be known at this point | -help: consider giving `x` an explicit type +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let mut x: _ = Default::default(); | +++ diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr index 48b7946ea82..6f8b5cc4cc5 100644 --- a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr +++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | |x| x.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |x: _| x.len() | +++ @@ -15,7 +15,7 @@ error[E0282]: type annotations needed LL | |x| x.len() | ^ - type must be known at this point | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | |x: _| x.len() | +++ diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.stderr b/src/test/ui/type/type-check/unknown_type_for_closure.stderr index 9ae97f390d3..2ba5f07a8f4 100644 --- a/src/test/ui/type/type-check/unknown_type_for_closure.stderr +++ b/src/test/ui/type/type-check/unknown_type_for_closure.stderr @@ -10,7 +10,7 @@ error[E0282]: type annotations needed LL | let x = |_| {}; | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | let x = |_: _| {}; | +++ diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index c1ae10efac4..24cc4a2a761 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -28,7 +28,7 @@ error[E0282]: type annotations needed LL | let _ = |a, b: _| -> _ { 0 }; | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified | LL | let _ = |a: _, b: _| -> _ { 0 }; | +++