From 40ba1c902f0fa4f288242f573408f122c71945ce Mon Sep 17 00:00:00 2001 From: Robin Schroer Date: Thu, 8 Dec 2022 21:42:15 +0100 Subject: [PATCH 01/14] Illegal sized bounds: only suggest mutability change if needed In a scenario like ``` struct Type; pub trait Trait { fn function(&mut self) where Self: Sized; } impl Trait for Type { fn function(&mut self) {} } fn main() { (&mut Type as &mut dyn Trait).function(); } ``` the problem is Sized, not the mutability of self. Thus don't emit the "you need &T instead of &mut T" note, or the other way around, as all it does is just invert the mutability of whatever was supplied. Fixes #103622. --- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- .../mutability-mismatch.rs | 34 +++++++++++++++++++ .../mutability-mismatch.stderr | 24 +++++++++++++ src/test/ui/illegal-sized-bound/regular.rs | 32 +++++++++++++++++ .../ui/illegal-sized-bound/regular.stderr | 20 +++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/illegal-sized-bound/mutability-mismatch.rs create mode 100644 src/test/ui/illegal-sized-bound/mutability-mismatch.stderr create mode 100644 src/test/ui/illegal-sized-bound/regular.rs create mode 100644 src/test/ui/illegal-sized-bound/regular.stderr diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index a2ca5c3b7b7..5d76e17b9f4 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -210,7 +210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::TraitsInScope, ) { Ok(ref new_pick) if pick.differs_from(new_pick) => { - needs_mut = true; + needs_mut = new_pick.self_ty.ref_mutability() != self_ty.ref_mutability(); } _ => {} } diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch.rs b/src/test/ui/illegal-sized-bound/mutability-mismatch.rs new file mode 100644 index 00000000000..deb84f6fe97 --- /dev/null +++ b/src/test/ui/illegal-sized-bound/mutability-mismatch.rs @@ -0,0 +1,34 @@ +struct MutType; + +pub trait MutTrait { + fn function(&mut self) + where + Self: Sized; + //~^ this has a `Sized` requirement +} + +impl MutTrait for MutType { + fn function(&mut self) {} +} + +struct Type; + +pub trait Trait { + fn function(&self) + where + Self: Sized; + //~^ this has a `Sized` requirement +} + +impl Trait for Type { + fn function(&self) {} +} + +fn main() { + (&MutType as &dyn MutTrait).function(); + //~^ ERROR the `function` method cannot be invoked on a trait object + //~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait` + (&mut Type as &mut dyn Trait).function(); + //~^ ERROR the `function` method cannot be invoked on a trait object + //~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait` +} diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch.stderr b/src/test/ui/illegal-sized-bound/mutability-mismatch.stderr new file mode 100644 index 00000000000..dbbf79a4f1a --- /dev/null +++ b/src/test/ui/illegal-sized-bound/mutability-mismatch.stderr @@ -0,0 +1,24 @@ +error: the `function` method cannot be invoked on a trait object + --> $DIR/mutability-mismatch.rs:28:33 + | +LL | Self: Sized; + | ----- this has a `Sized` requirement +... +LL | (&MutType as &dyn MutTrait).function(); + | ^^^^^^^^ + | + = note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait` + +error: the `function` method cannot be invoked on a trait object + --> $DIR/mutability-mismatch.rs:31:35 + | +LL | Self: Sized; + | ----- this has a `Sized` requirement +... +LL | (&mut Type as &mut dyn Trait).function(); + | ^^^^^^^^ + | + = note: you need `&dyn Trait` instead of `&mut dyn Trait` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/illegal-sized-bound/regular.rs b/src/test/ui/illegal-sized-bound/regular.rs new file mode 100644 index 00000000000..7abd27ef983 --- /dev/null +++ b/src/test/ui/illegal-sized-bound/regular.rs @@ -0,0 +1,32 @@ +struct MutType; + +pub trait MutTrait { + fn function(&mut self) + where + Self: Sized; + //~^ this has a `Sized` requirement +} + +impl MutTrait for MutType { + fn function(&mut self) {} +} + +struct Type; + +pub trait Trait { + fn function(&self) + where + Self: Sized; + //~^ this has a `Sized` requirement +} + +impl Trait for Type { + fn function(&self) {} +} + +fn main() { + (&mut MutType as &mut dyn MutTrait).function(); + //~^ ERROR the `function` method cannot be invoked on a trait object + (&Type as &dyn Trait).function(); + //~^ ERROR the `function` method cannot be invoked on a trait object +} diff --git a/src/test/ui/illegal-sized-bound/regular.stderr b/src/test/ui/illegal-sized-bound/regular.stderr new file mode 100644 index 00000000000..7f3744145d9 --- /dev/null +++ b/src/test/ui/illegal-sized-bound/regular.stderr @@ -0,0 +1,20 @@ +error: the `function` method cannot be invoked on a trait object + --> $DIR/regular.rs:28:41 + | +LL | Self: Sized; + | ----- this has a `Sized` requirement +... +LL | (&mut MutType as &mut dyn MutTrait).function(); + | ^^^^^^^^ + +error: the `function` method cannot be invoked on a trait object + --> $DIR/regular.rs:30:27 + | +LL | Self: Sized; + | ----- this has a `Sized` requirement +... +LL | (&Type as &dyn Trait).function(); + | ^^^^^^^^ + +error: aborting due to 2 previous errors + From b70a869d8f49e87d8432de6af6d209243a7053a4 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 10 Dec 2022 01:31:34 +0800 Subject: [PATCH 02/14] fix #105366, suggest impl in the scenario of typo with fn --- .../locales/en-US/parse.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 8 ++++++++ compiler/rustc_parse/src/parser/item.rs | 20 +++++++++++++++++-- src/test/ui/parser/issue-105366.fixed | 12 +++++++++++ src/test/ui/parser/issue-105366.rs | 12 +++++++++++ src/test/ui/parser/issue-105366.stderr | 13 ++++++++++++ 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/parser/issue-105366.fixed create mode 100644 src/test/ui/parser/issue-105366.rs create mode 100644 src/test/ui/parser/issue-105366.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 114b7ec1628..b53550e5fd5 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -362,3 +362,6 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet parse_invalid_identifier_with_leading_number = expected identifier, found number literal .label = identifiers cannot start with a number + +parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` + .suggestion = replace `fn` with `impl` here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9875cde4a05..18a0bee9c2e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1221,3 +1221,11 @@ pub(crate) struct UnexpectedIfWithIf( #[suggestion(applicability = "machine-applicable", code = " ", style = "verbose")] pub Span, ); + +#[derive(Diagnostic)] +#[diag(parse_maybe_fn_typo_with_impl)] +pub(crate) struct FnTypoWithImpl { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")] + pub fn_span: Span, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 03f25392a7c..ce4bc929c5c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3,6 +3,7 @@ use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi}; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use crate::errors::FnTypoWithImpl; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; @@ -2126,11 +2127,26 @@ impl<'a> Parser<'a> { vis: &Visibility, case: Case, ) -> PResult<'a, (Ident, FnSig, Generics, Option>)> { + let fn_span = self.token.span; let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = - self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)` + let decl = match self.parse_fn_decl( + fn_parse_mode.req_name, + AllowPlus::Yes, + RecoverReturnSign::Yes, + ) { + Ok(decl) => decl, + Err(old_err) => { + // If we see `for Ty ...` then user probably meant `impl` item. + if self.token.is_keyword(kw::For) { + old_err.cancel(); + return Err(self.sess.create_err(FnTypoWithImpl { fn_span })); + } else { + return Err(old_err); + } + } + }; generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let mut sig_hi = self.prev_token.span; diff --git a/src/test/ui/parser/issue-105366.fixed b/src/test/ui/parser/issue-105366.fixed new file mode 100644 index 00000000000..ad26643c327 --- /dev/null +++ b/src/test/ui/parser/issue-105366.fixed @@ -0,0 +1,12 @@ +// run-rustfix + +struct Foo; + +impl From for Foo { + //~^ ERROR you might have meant to write `impl` instead of `fn` + fn from(_a: i32) -> Self { + Foo + } +} + +fn main() {} diff --git a/src/test/ui/parser/issue-105366.rs b/src/test/ui/parser/issue-105366.rs new file mode 100644 index 00000000000..311b6a60f1a --- /dev/null +++ b/src/test/ui/parser/issue-105366.rs @@ -0,0 +1,12 @@ +// run-rustfix + +struct Foo; + +fn From for Foo { + //~^ ERROR you might have meant to write `impl` instead of `fn` + fn from(_a: i32) -> Self { + Foo + } +} + +fn main() {} diff --git a/src/test/ui/parser/issue-105366.stderr b/src/test/ui/parser/issue-105366.stderr new file mode 100644 index 00000000000..0a7408e2c17 --- /dev/null +++ b/src/test/ui/parser/issue-105366.stderr @@ -0,0 +1,13 @@ +error: you might have meant to write `impl` instead of `fn` + --> $DIR/issue-105366.rs:5:1 + | +LL | fn From for Foo { + | ^^ + | +help: replace `fn` with `impl` here + | +LL | impl From for Foo { + | ~~~~ + +error: aborting due to previous error + From dd19656df3d76d3733243ea83b692cacdd7512a5 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 12 Dec 2022 14:28:08 +0000 Subject: [PATCH 03/14] fold instead of obliterating args --- compiler/rustc_infer/src/infer/mod.rs | 53 +++++++++++++------ .../generic_const_exprs/issue-105608.rs | 15 ++++++ .../generic_const_exprs/issue-105608.stderr | 14 +++++ 3 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-105608.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-105608.stderr diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2ce7cd8beba..996148a7090 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -2014,31 +2014,54 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| { - match arg.unpack() { - GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => { - tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + struct ReplaceParamAndInferWithPlaceholder<'tcx> { + tcx: TyCtxt<'tcx>, + idx: usize, + } + + impl<'tcx> TypeFolder<'tcx> for ReplaceParamAndInferWithPlaceholder<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Infer(_) = t.kind() { + self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_usize(idx), + name: ty::BoundVar::from_usize({ + let idx = self.idx; + self.idx += 1; + idx + }), })) - .into() + } else { + t.super_fold_with(self) } - GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => { - let ty = ct.ty(); - // If the type references param or infer, replace that too... + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Infer(_) = c.kind() { + let ty = c.ty(); + // If the type references param or infer then ICE ICE ICE if ty.has_non_region_param() || ty.has_non_region_infer() { - bug!("const `{ct}`'s type should not reference params or types"); + bug!("const `{c}`'s type should not reference params or types"); } - tcx.mk_const( + self.tcx.mk_const( ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_usize(idx), + name: ty::BoundVar::from_usize({ + let idx = self.idx; + self.idx += 1; + idx + }), }, ty, ) - .into() + } else { + c.super_fold_with(self) } - _ => arg, } - })) + } + + substs.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) } diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs b/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs new file mode 100644 index 00000000000..4c85abd5c1e --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs @@ -0,0 +1,15 @@ +#![allow(incomplete_features, unstable_features)] +#![feature(generic_const_exprs)] + +struct Combination; + +impl Combination { + fn and(self) -> Combination<{ STRATEGIES + 1 }> { + Combination + } +} + +pub fn main() { + Combination::<0>.and::<_>().and::<_>(); + //~^ ERROR: type annotations needed +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-105608.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-105608.stderr new file mode 100644 index 00000000000..0be4c43daac --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-105608.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/issue-105608.rs:13:22 + | +LL | Combination::<0>.and::<_>().and::<_>(); + | ^^^ cannot infer type of the type parameter `M` declared on the associated function `and` + | +help: consider specifying the generic argument + | +LL | Combination::<0>.and::<_>().and::<_>(); + | ~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From 5573485354aa618e22564f0fc332378c4ef9373a Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 12 Dec 2022 14:41:34 +0000 Subject: [PATCH 04/14] what is `unstable_features` lol --- src/test/ui/const-generics/generic_const_exprs/issue-105608.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs b/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs index 4c85abd5c1e..e28ba3b1ada 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs @@ -1,5 +1,5 @@ -#![allow(incomplete_features, unstable_features)] #![feature(generic_const_exprs)] +#![allow(incomplete_features)] struct Combination; From 52a9280fb249f2dfbc879ae32b1823203822fbec Mon Sep 17 00:00:00 2001 From: Cassaundra Smith Date: Thu, 1 Dec 2022 19:17:03 -0800 Subject: [PATCH 05/14] Refine when invalid prefix case error arises Fix cases where the "invalid base prefix for number literal" error arises with suffixes that look erroneously capitalized but which are in fact invalid. --- compiler/rustc_session/src/errors.rs | 33 ++++++++---- .../uppercase-base-prefix-invalid-no-fix.rs | 34 +++++++++++++ ...ppercase-base-prefix-invalid-no-fix.stderr | 50 +++++++++++++++++++ 3 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs create mode 100644 src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.stderr diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 2f7055e3cc5..268849ecd59 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -291,20 +291,33 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) } - // Try to lowercase the prefix if it's a valid base prefix. - fn fix_base_capitalisation(s: &str) -> Option { - if let Some(stripped) = s.strip_prefix('B') { - Some(format!("0b{stripped}")) - } else if let Some(stripped) = s.strip_prefix('O') { - Some(format!("0o{stripped}")) - } else if let Some(stripped) = s.strip_prefix('X') { - Some(format!("0x{stripped}")) + // Try to lowercase the prefix if the prefix and suffix are valid. + fn fix_base_capitalisation(prefix: &str, suffix: &str) -> Option { + let mut chars = suffix.chars(); + + let base_char = chars.next().unwrap(); + let base = match base_char { + 'B' => 2, + 'O' => 8, + 'X' => 16, + _ => return None, + }; + + // check that the suffix contains only base-appropriate characters + let valid = prefix == "0" + && chars + .filter(|c| *c != '_') + .take_while(|c| *c != 'i' && *c != 'u') + .all(|c| c.to_digit(base).is_some()); + + if valid { + Some(format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } else { None } } - let token::Lit { kind, suffix, .. } = lit; + let token::Lit { kind, symbol, suffix, .. } = lit; match err { // `LexerError` is an error, but it was already reported // by lexer, so here we don't report it the second time. @@ -324,7 +337,7 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: if looks_like_width_suffix(&['i', 'u'], &suf) { // If it looks like a width, try to be helpful. sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); - } else if let Some(fixed) = fix_base_capitalisation(suf) { + } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) { sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); } else { sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); diff --git a/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs b/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs new file mode 100644 index 00000000000..f00cde4a74c --- /dev/null +++ b/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs @@ -0,0 +1,34 @@ +// Checks that integers with seeming uppercase base prefixes do not get bogus capitalization +// suggestions. + +fn main() { + _ = 123X1a3; + //~^ ERROR invalid suffix `X1a3` for number literal + //~| NOTE invalid suffix `X1a3` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + + _ = 456O123; + //~^ ERROR invalid suffix `O123` for number literal + //~| NOTE invalid suffix `O123` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + + _ = 789B101; + //~^ ERROR invalid suffix `B101` for number literal + //~| NOTE invalid suffix `B101` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + + _ = 0XYZ; + //~^ ERROR invalid suffix `XYZ` for number literal + //~| NOTE invalid suffix `XYZ` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + + _ = 0OPQ; + //~^ ERROR invalid suffix `OPQ` for number literal + //~| NOTE invalid suffix `OPQ` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + + _ = 0BCD; + //~^ ERROR invalid suffix `BCD` for number literal + //~| NOTE invalid suffix `BCD` + //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) +} diff --git a/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.stderr b/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.stderr new file mode 100644 index 00000000000..380c16ca789 --- /dev/null +++ b/src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.stderr @@ -0,0 +1,50 @@ +error: invalid suffix `X1a3` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:5:9 + | +LL | _ = 123X1a3; + | ^^^^^^^ invalid suffix `X1a3` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: invalid suffix `O123` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:10:9 + | +LL | _ = 456O123; + | ^^^^^^^ invalid suffix `O123` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: invalid suffix `B101` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:15:9 + | +LL | _ = 789B101; + | ^^^^^^^ invalid suffix `B101` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: invalid suffix `XYZ` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:20:9 + | +LL | _ = 0XYZ; + | ^^^^ invalid suffix `XYZ` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: invalid suffix `OPQ` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:25:9 + | +LL | _ = 0OPQ; + | ^^^^ invalid suffix `OPQ` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: invalid suffix `BCD` for number literal + --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:30:9 + | +LL | _ = 0BCD; + | ^^^^ invalid suffix `BCD` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: aborting due to 6 previous errors + 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 06/14] 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::print::{FmtPrinter, PrettyPrinter, Print, Printer}; 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 @@ impl InferenceDiagnosticsData { } 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 @@ impl<'tcx> InferCtxt<'tcx> { } 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { /// 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 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, '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 @@ symbols! { 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 @@ pub trait Iterator { #[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 }; | +++ From b3fba5e18afe1548f6c6926ee377833d4c53d904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 10 Dec 2022 12:19:29 -0800 Subject: [PATCH 07/14] Remove unnecessary code and account for turbofish suggestion Remove previously existing fallback that tried to give a good turbofish suggestion, `need_type_info` is already good enough. Special case `::` suggestion for `Iterator::collect`. --- .../infer/error_reporting/need_type_info.rs | 56 ++++++++++-------- .../src/traits/error_reporting/mod.rs | 58 ++----------------- src/test/ui/error-codes/E0401.stderr | 2 +- .../erase-type-params-in-label.stderr | 12 ++-- .../ui/type/type-annotation-needed.stderr | 2 +- 5 files changed, 43 insertions(+), 87 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 b55cb091b1f..41e7a0608af 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 @@ -461,33 +461,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { parent_name, }); - let args = fmt_printer(self, Namespace::TypeNS) - .comma_sep(generic_args.iter().copied().map(|arg| { - if arg.is_suggestable(self.tcx, true) { - return arg; - } + let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) + == Some(generics_def_id) + { + "Vec<_>".to_string() + } else { + fmt_printer(self, Namespace::TypeNS) + .comma_sep(generic_args.iter().copied().map(|arg| { + if arg.is_suggestable(self.tcx, true) { + return arg; + } - match arg.unpack() { - GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { + match arg.unpack() { + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { span: rustc_span::DUMMY_SP, - kind: ConstVariableOriginKind::MiscVariable, - }, - ) - .into(), - } - })) - .unwrap() - .into_buffer(); + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + })) + .unwrap() + .into_buffer() + }; if !have_turbofish { infer_subdiags.push(SourceKindSubdiag::GenericSuggestion { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 30ff07ee6c3..28351d5ff88 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -42,7 +42,7 @@ use rustc_middle::ty::{ }; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; @@ -2198,60 +2198,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span) - && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..) - = *obligation.cause.code() + if let ObligationCauseCode::ItemObligation(def_id) + | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() { - let generics = self.tcx.generics_of(def_id); - if generics.params.iter().any(|p| p.name != kw::SelfUpper) - && !snippet.ends_with('>') - && !generics.has_impl_trait() - && !self.tcx.is_fn_trait(def_id) - { - // FIXME: To avoid spurious suggestions in functions where type arguments - // where already supplied, we check the snippet to make sure it doesn't - // end with a turbofish. Ideally we would have access to a `PathSegment` - // instead. Otherwise we would produce the following output: - // - // error[E0283]: type annotations needed - // --> $DIR/issue-54954.rs:3:24 - // | - // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // | | - // | cannot infer type - // | help: consider specifying the type argument - // | in the function call: - // | `Tt::const_val::<[i8; 123]>::` - // ... - // LL | const fn const_val() -> usize { - // | - required by this bound in `Tt::const_val` - // | - // = note: cannot satisfy `_: Tt` - - // Clear any more general suggestions in favor of our specific one - err.clear_suggestions(); - - err.span_suggestion_verbose( - span.shrink_to_hi(), - &format!( - "consider specifying the type argument{} in the function call", - pluralize!(generics.params.len()), - ), - format!( - "::<{}>", - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } + self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 9687eca61fa..fa4b91cacef 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -59,7 +59,7 @@ note: required by a bound in `bfnr` | LL | fn bfnr, W: Fn()>(y: T) { | ^^^^ required by this bound in `bfnr` -help: consider specifying the type arguments in the function call +help: consider specifying the generic arguments | LL | bfnr::(x); | +++++++++++ diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr index 5c52e7bcfab..9be18286480 100644 --- a/src/test/ui/inference/erase-type-params-in-label.stderr +++ b/src/test/ui/inference/erase-type-params-in-label.stderr @@ -10,10 +10,10 @@ note: required by a bound in `foo` | LL | fn foo(t: T, k: K) -> Foo { | ^^^^^^^ required by this bound in `foo` -help: consider specifying the type arguments in the function call +help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified | -LL | let foo = foo::(1, ""); - | ++++++++++++++ +LL | let foo: Foo = foo(1, ""); + | ++++++++++++++++++++++ error[E0283]: type annotations needed for `Bar` --> $DIR/erase-type-params-in-label.rs:5:9 @@ -27,10 +27,10 @@ note: required by a bound in `bar` | LL | fn bar(t: T, k: K) -> Bar { | ^^^^^^^ required by this bound in `bar` -help: consider specifying the type arguments in the function call +help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified | -LL | let bar = bar::(1, ""); - | +++++++++++ +LL | let bar: Bar = bar(1, ""); + | +++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 4af4c22f751..87bba3166be 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -10,7 +10,7 @@ note: required by a bound in `foo` | LL | fn foo>(x: i32) {} | ^^^^^^^^^^^^ required by this bound in `foo` -help: consider specifying the type argument in the function call +help: consider specifying the generic argument | LL | foo::(42); | +++++ From 3e25bcb02093bad56beb1dff6be7dd0d80115fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 10 Dec 2022 17:39:00 -0800 Subject: [PATCH 08/14] Mention implementations that satisfy the trait --- .../src/traits/error_reporting/mod.rs | 21 +++++++++++++++++-- .../generic_arg_infer/issue-91614.stderr | 6 ++++++ .../issue-72787.min.stderr | 2 ++ src/test/ui/lifetimes/issue-34979.stderr | 1 + src/test/ui/traits/issue-77982.stderr | 10 ++++++++- src/test/ui/traits/issue-85735.stderr | 3 +++ 6 files changed, 40 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 28351d5ff88..64821b5686a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -980,6 +980,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, obligation.cause.body_id, &mut err, + true, ) { // This is *almost* equivalent to // `obligation.cause.code().peel_derives()`, but it gives us the @@ -1015,6 +1016,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, obligation.cause.body_id, &mut err, + true, ); } } @@ -1432,6 +1434,7 @@ trait InferCtxtPrivExt<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, + other: bool, ) -> bool; /// Gets the parent trait chain start @@ -1887,7 +1890,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, + other: bool, ) -> bool { + let other = if other { "other " } else { "" }; let report = |mut candidates: Vec>, err: &mut Diagnostic| { candidates.sort(); candidates.dedup(); @@ -1938,7 +1943,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { candidates.dedup(); let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(&format!( - "the following other types implement trait `{}`:{}{}", + "the following {other}types implement trait `{}`:{}{}", trait_ref.print_only_trait_path(), candidates[..end].join(""), if len > 9 { format!("\nand {} others", len - 8) } else { String::new() } @@ -2179,7 +2184,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer()); // It doesn't make sense to talk about applicable impls if there are more // than a handful of them. - if impls.len() > 1 && impls.len() < 5 && has_non_region_infer { + if impls.len() > 1 && impls.len() < 10 && has_non_region_infer { self.annotate_source_of_ambiguity(&mut err, &impls, predicate); } else { if self.tainted_by_errors().is_some() { @@ -2187,6 +2192,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } err.note(&format!("cannot satisfy `{}`", predicate)); + let impl_candidates = self.find_similar_impl_candidates( + predicate.to_opt_poly_trait_pred().unwrap(), + ); + if impl_candidates.len() < 10 { + self.report_similar_impl_candidates( + impl_candidates, + trait_ref, + body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id), + &mut err, + false, + ); + } } } _ => { diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr index 688db695fa8..2cfc6f61f1a 100644 --- a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -5,6 +5,12 @@ LL | let y = Mask::<_, _>::splat(false); | ^ ------------------- type must be known at this point | = note: cannot satisfy `_: MaskElement` + = help: the following types implement trait `MaskElement`: + i16 + i32 + i64 + i8 + isize note: required by a bound in `Mask::::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL | diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 4d0d0253f1b..e0444042614 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -41,6 +41,7 @@ LL | IsLessOrEqual: True, | ^^^^ | = note: cannot satisfy `IsLessOrEqual: True` + = help: the trait `True` is implemented for `IsLessOrEqual` error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` --> $DIR/issue-72787.rs:21:26 @@ -49,6 +50,7 @@ LL | IsLessOrEqual: True, | ^^^^ | = note: cannot satisfy `IsLessOrEqual: True` + = help: the trait `True` is implemented for `IsLessOrEqual` error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/issue-34979.stderr b/src/test/ui/lifetimes/issue-34979.stderr index 5832c4d173c..a332c6547b8 100644 --- a/src/test/ui/lifetimes/issue-34979.stderr +++ b/src/test/ui/lifetimes/issue-34979.stderr @@ -5,6 +5,7 @@ LL | &'a (): Foo, | ^^^ | = note: cannot satisfy `&'a (): Foo` + = help: the trait `Foo` is implemented for `&'a T` error: aborting due to previous error diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr index b6a04585583..be7397fdb12 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -46,7 +46,15 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( | | | required by a bound introduced by this call | - = note: cannot satisfy `u32: From<_>` + = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`: + - impl From for u32; + - impl From for u32; + - impl From for u32; + - impl From for u32; + - impl From for u32; + - impl From for u32; + - impl From for T; + - impl From for T; help: try using a fully qualified path to specify the expected types | LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(>::into(0u32))).collect(); diff --git a/src/test/ui/traits/issue-85735.stderr b/src/test/ui/traits/issue-85735.stderr index fa280135beb..930708f9ad8 100644 --- a/src/test/ui/traits/issue-85735.stderr +++ b/src/test/ui/traits/issue-85735.stderr @@ -5,6 +5,9 @@ LL | T: FnMut(&'a ()), | ^^^^^^^^^^^^^ | = note: cannot satisfy `T: FnMut<(&'a (),)>` + = help: the following types implement trait `FnMut`: + &F + &mut F error: aborting due to previous error From 7d1e47aeb0bb1ad2ccf27cb62c25f4ba09d679e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 10 Dec 2022 18:40:04 -0800 Subject: [PATCH 09/14] Suggest `: Type` instead of `: _` --- .../locales/en-US/infer.ftl | 1 + .../infer/error_reporting/need_type_info.rs | 15 +++++++----- .../ui/array-slice-vec/infer_array_len.stderr | 6 ++--- ...er-vars-supply-ty-with-bound-region.stderr | 6 ++--- src/test/ui/closures/issue-52437.stderr | 6 ++--- .../const-generics/issues/issue-83249.stderr | 6 ++--- .../ui/impl-trait/issues/issue-86719.stderr | 6 ++--- src/test/ui/inference/issue-72690.stderr | 6 ++--- src/test/ui/issues/issue-18159.stderr | 6 ++--- src/test/ui/issues/issue-2151.stderr | 6 ++--- src/test/ui/issues/issue-24036.stderr | 6 ++--- .../branches3.stderr | 24 +++++++++---------- .../ui/match/match-unresolved-one-arm.stderr | 6 ++--- src/test/ui/pattern/pat-tuple-bad-type.stderr | 6 ++--- .../rest-pat-semantic-disallowed.stderr | 6 ++--- src/test/ui/resolve/issue-85348.stderr | 6 ++--- .../method-and-field-eager-resolution.stderr | 12 +++++----- .../closures_in_branches.stderr | 12 +++++----- .../unknown_type_for_closure.stderr | 6 ++--- .../ui/type/type-path-err-node-types.stderr | 6 ++--- 20 files changed, 79 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index c9d83746d54..fbef2da7cb9 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -34,6 +34,7 @@ infer_source_kind_subdiag_let = {$kind -> [const] the value of the constant } `{$arg_name}` is specified [underscore] , where the placeholders `_` are specified + [anon] , where the placeholder `Type` is specified *[empty] {""} } 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 41e7a0608af..38655492244 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 @@ -77,13 +77,15 @@ impl InferenceDiagnosticsData { !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. })) } - fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { - if self.name == "_" { + fn where_x_is_kind(&self, in_type: Ty<'_>, is_collect: bool) -> &'static str { + if is_collect { + "empty" + } else if in_type.is_ty_infer() { + "anon" + } else 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" } @@ -190,6 +192,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), + _ if ty.is_ty_infer() => "Type".to_string(), // FIXME: The same thing for closures, but this only works when the closure // does not capture anything. // @@ -411,7 +414,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), - x_kind: if is_collect { "empty" } else { arg_data.where_x_is_kind(ty) }, + x_kind: arg_data.where_x_is_kind(ty, is_collect), prefix_kind: arg_data.kind.clone(), prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, @@ -427,7 +430,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: String::new(), - x_kind: arg_data.where_x_is_kind(ty), + x_kind: arg_data.where_x_is_kind(ty, false), prefix_kind: arg_data.kind.clone(), prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, 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 bd757be126c..11a07164e8c 100644 --- a/src/test/ui/array-slice-vec/infer_array_len.stderr +++ b/src/test/ui/array-slice-vec/infer_array_len.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let [_, _] = a.into(); | ^^^^^^ | -help: consider giving this pattern a type, where the placeholders `_` are specified +help: consider giving this pattern a type, where the placeholder `Type` is specified | -LL | let [_, _]: _ = a.into(); - | +++ +LL | let [_, _]: Type = a.into(); + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr index d5432755cfe..9e5705ba00b 100644 --- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr +++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | with_closure(|x: u32, y| {}); | ^ | -help: consider giving this closure parameter an explicit type +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | with_closure(|x: u32, y: _| {}); - | +++ +LL | with_closure(|x: u32, y: Type| {}); + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index f7d34890a79..c635e743293 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -10,10 +10,10 @@ error[E0282]: type annotations needed LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize] - | +++ +LL | [(); &(&'static: loop { |x: Type| {}; }) as *const _ as usize] + | ++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr index 362b8554b2f..f148cb7699e 100644 --- a/src/test/ui/const-generics/issues/issue-83249.stderr +++ b/src/test/ui/const-generics/issues/issue-83249.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let _ = foo([0; 1]); | ^ | -help: consider giving this pattern a type +help: consider giving this pattern a type, where the placeholder `Type` is specified | -LL | let _: _ = foo([0; 1]); - | +++ +LL | let _: Type = foo([0; 1]); + | ++++++ 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 da184c26bfe..30bad841d15 100644 --- a/src/test/ui/impl-trait/issues/issue-86719.stderr +++ b/src/test/ui/impl-trait/issues/issue-86719.stderr @@ -18,10 +18,10 @@ error[E0282]: type annotations needed LL | |_| true | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |_: _| true - | +++ +LL | |_: Type| true + | ++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/inference/issue-72690.stderr b/src/test/ui/inference/issue-72690.stderr index e59bcea9512..37daeb6441f 100644 --- a/src/test/ui/inference/issue-72690.stderr +++ b/src/test/ui/inference/issue-72690.stderr @@ -30,10 +30,10 @@ error[E0282]: type annotations needed LL | |x| String::from("x".as_ref()); | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |x: _| String::from("x".as_ref()); - | +++ +LL | |x: Type| String::from("x".as_ref()); + | ++++++ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:12:26 diff --git a/src/test/ui/issues/issue-18159.stderr b/src/test/ui/issues/issue-18159.stderr index bedfeda2ea0..1cfb0e41504 100644 --- a/src/test/ui/issues/issue-18159.stderr +++ b/src/test/ui/issues/issue-18159.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let x; | ^ | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let x: _; - | +++ +LL | let x: Type; + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr index 411fdc48344..f689afd4ea7 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -6,10 +6,10 @@ LL | let x = panic!(); LL | x.clone(); | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let x: _ = panic!(); - | +++ +LL | let x: Type = panic!(); + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index fcfce56bcb1..2413db2cada 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -17,10 +17,10 @@ error[E0282]: type annotations needed LL | 1 => |c| c + 1, | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | 1 => |c: _| c + 1, - | +++ +LL | 1 => |c: Type| c + 1, + | ++++++ error: aborting due to 2 previous errors 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 9d56d96c8c1..d14cad4d71c 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -4,10 +4,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |s: _| s.len() - | +++ +LL | |s: Type| s.len() + | ++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:15:10 @@ -15,10 +15,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |s: _| s.len() - | +++ +LL | |s: Type| s.len() + | ++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:23:10 @@ -26,10 +26,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |s: _| s.len() - | +++ +LL | |s: Type| s.len() + | ++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:30:10 @@ -37,10 +37,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |s: _| s.len() - | +++ +LL | |s: Type| s.len() + | ++++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr index db5db38391e..0ebd56cb064 100644 --- a/src/test/ui/match/match-unresolved-one-arm.stderr +++ b/src/test/ui/match/match-unresolved-one-arm.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let x = match () { | ^ | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let x: _ = match () { - | +++ +LL | let x: Type = match () { + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 86fd1e0c196..ff45e9fb7a3 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -7,10 +7,10 @@ LL | let x; LL | (..) => {} | ---- type must be known at this point | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let x: _; - | +++ +LL | let x: Type; + | ++++++ error[E0308]: mismatched types --> $DIR/pat-tuple-bad-type.rs:10:9 diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr index 5bf168a5711..df0aa942fed 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -191,10 +191,10 @@ error[E0282]: type annotations needed LL | let x @ ..; | ^^^^^^ | -help: consider giving this pattern a type, where the placeholders `_` are specified +help: consider giving this pattern a type, where the placeholder `Type` is specified | -LL | let x @ ..: _; - | +++ +LL | let x @ ..: Type; + | ++++++ error: aborting due to 23 previous errors diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr index cc9cd3fe68b..2cbc109055f 100644 --- a/src/test/ui/resolve/issue-85348.stderr +++ b/src/test/ui/resolve/issue-85348.stderr @@ -19,10 +19,10 @@ error[E0282]: type annotations needed LL | let mut N; | ^^^^^ | -help: consider giving `N` an explicit type, where the placeholders `_` are specified +help: consider giving `N` an explicit type, where the placeholder `Type` is specified | -LL | let mut N: _; - | +++ +LL | let mut N: Type; + | ++++++ error: aborting due to 3 previous errors 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 85205464626..554a2580c94 100644 --- a/src/test/ui/span/method-and-field-eager-resolution.stderr +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -7,10 +7,10 @@ LL | LL | x.0; | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let mut x: _ = Default::default(); - | +++ +LL | let mut x: Type = Default::default(); + | ++++++ error[E0282]: type annotations needed --> $DIR/method-and-field-eager-resolution.rs:11:9 @@ -21,10 +21,10 @@ LL | LL | x[0]; | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholders `_` are specified +help: consider giving `x` an explicit type, where the placeholder `Type` is specified | -LL | let mut x: _ = Default::default(); - | +++ +LL | let mut x: Type = Default::default(); + | ++++++ error: aborting due to 2 previous errors 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 6f8b5cc4cc5..0d7341bfb91 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,10 +4,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |x: _| x.len() - | +++ +LL | |x: Type| x.len() + | ++++++ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:21:10 @@ -15,10 +15,10 @@ 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, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | |x: _| x.len() - | +++ +LL | |x: Type| x.len() + | ++++++ error: aborting due to 2 previous errors 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 2ba5f07a8f4..01e053ccd51 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,10 +10,10 @@ error[E0282]: type annotations needed LL | let x = |_| {}; | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | let x = |_: _| {}; - | +++ +LL | let x = |_: Type| {}; + | ++++++ error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:10:14 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 24cc4a2a761..51077dedbbe 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -28,10 +28,10 @@ error[E0282]: type annotations needed LL | let _ = |a, b: _| -> _ { 0 }; | ^ | -help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified +help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified | -LL | let _ = |a: _, b: _| -> _ { 0 }; - | +++ +LL | let _ = |a: Type, b: _| -> _ { 0 }; + | ++++++ error: aborting due to 5 previous errors From 19fa5b381c98016f643a9e59c7159c67bae1dd8c Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 14 Dec 2022 03:18:02 +0900 Subject: [PATCH 10/14] suggest dereferencing receiver arguments properly fix a stderr --- .../src/traits/error_reporting/suggestions.rs | 34 +++++++++++++++---- ...gest-dereferencing-receiver-argument.fixed | 14 ++++++++ ...suggest-dereferencing-receiver-argument.rs | 14 ++++++++ ...est-dereferencing-receiver-argument.stderr | 15 ++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed create mode 100644 src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs create mode 100644 src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 40c81025471..66c72d2f3c5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -694,7 +694,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It only make sense when suggesting dereferences for arguments - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = obligation.cause.code() else { return false; }; let Some(typeck_results) = &self.typeck_results else { return false; }; @@ -773,12 +773,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { real_trait_pred_and_base_ty, ); if self.predicate_may_hold(&obligation) { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider dereferencing here", - "*", - Applicability::MachineApplicable, + let call_node = self.tcx.hir().get(*call_hir_id); + let msg = "consider dereferencing here"; + let is_receiver = matches!( + call_node, + Node::Expr(hir::Expr { + kind: hir::ExprKind::MethodCall(_, receiver_expr, ..), + .. + }) + if receiver_expr.hir_id == *arg_hir_id ); + if is_receiver { + err.multipart_suggestion_verbose( + msg, + vec![ + (span.shrink_to_lo(), "(*".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ) + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + msg, + '*', + Applicability::MachineApplicable, + ) + }; return true; } } @@ -2857,6 +2878,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { arg_hir_id, call_hir_id, ref parent_code, + .. } => { self.function_argument_obligation( arg_hir_id, diff --git a/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed new file mode 100644 index 00000000000..ea3d1bf853a --- /dev/null +++ b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +struct TargetStruct; + +impl From for TargetStruct { + fn from(_unchecked: usize) -> Self { + TargetStruct + } +} + +fn main() { + let a = &3; + let _b: TargetStruct = (*a).into(); //~ ERROR the trait bound `TargetStruct: From<&{integer}>` is not satisfied +} diff --git a/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs new file mode 100644 index 00000000000..9eda68027b2 --- /dev/null +++ b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs @@ -0,0 +1,14 @@ +// run-rustfix + +struct TargetStruct; + +impl From for TargetStruct { + fn from(_unchecked: usize) -> Self { + TargetStruct + } +} + +fn main() { + let a = &3; + let _b: TargetStruct = a.into(); //~ ERROR the trait bound `TargetStruct: From<&{integer}>` is not satisfied +} diff --git a/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr new file mode 100644 index 00000000000..ede31a2c7bc --- /dev/null +++ b/src/test/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied + --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30 + | +LL | let _b: TargetStruct = a.into(); + | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct` + | + = note: required for `&{integer}` to implement `Into` +help: consider dereferencing here + | +LL | let _b: TargetStruct = (*a).into(); + | ++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 165efabbee6e2ea997bdbd7aee67f92554a83f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Dec 2022 11:36:43 -0800 Subject: [PATCH 11/14] review comments --- .../locales/en-US/infer.ftl | 1 - .../infer/error_reporting/need_type_info.rs | 55 +++++++++---------- .../ui/array-slice-vec/infer_array_len.stderr | 6 +- ...er-vars-supply-ty-with-bound-region.stderr | 6 +- src/test/ui/closures/issue-52437.stderr | 6 +- .../const-generics/issues/issue-83249.stderr | 6 +- .../ui/impl-trait/issues/issue-86719.stderr | 6 +- src/test/ui/inference/issue-72690.stderr | 6 +- src/test/ui/issues/issue-18159.stderr | 6 +- src/test/ui/issues/issue-2151.stderr | 6 +- src/test/ui/issues/issue-24036.stderr | 6 +- .../branches3.stderr | 24 ++++---- .../ui/match/match-unresolved-one-arm.stderr | 6 +- src/test/ui/pattern/pat-tuple-bad-type.stderr | 6 +- .../rest-pat-semantic-disallowed.stderr | 6 +- src/test/ui/resolve/issue-85348.stderr | 6 +- .../method-and-field-eager-resolution.stderr | 12 ++-- .../closures_in_branches.stderr | 12 ++-- .../unknown_type_for_closure.stderr | 6 +- .../ui/type/type-path-err-node-types.stderr | 6 +- 20 files changed, 96 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index fbef2da7cb9..c9d83746d54 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -34,7 +34,6 @@ infer_source_kind_subdiag_let = {$kind -> [const] the value of the constant } `{$arg_name}` is specified [underscore] , where the placeholders `_` are specified - [anon] , where the placeholder `Type` is specified *[empty] {""} } 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 38655492244..858ca6deedc 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 @@ -77,11 +77,9 @@ impl InferenceDiagnosticsData { !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. })) } - fn where_x_is_kind(&self, in_type: Ty<'_>, is_collect: bool) -> &'static str { - if is_collect { - "empty" - } else if in_type.is_ty_infer() { - "anon" + fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { + if in_type.is_ty_infer() { + "" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. @@ -185,14 +183,20 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte printer } -fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { +fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, def_id: Option) -> String { let printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - match ty.kind() { + match (ty.kind(), def_id) { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. - ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), - _ if ty.is_ty_infer() => "Type".to_string(), + (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), + (_, Some(def_id)) + if ty.is_ty_infer() + && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) => + { + "Vec<_>".to_string() + } + _ if ty.is_ty_infer() => "/* Type */".to_string(), // FIXME: The same thing for closures, but this only works when the closure // does not capture anything. // @@ -216,7 +220,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { .map(|args| { args.tuple_fields() .iter() - .map(|arg| ty_to_string(infcx, arg)) + .map(|arg| ty_to_string(infcx, arg, None)) .collect::>() .join(", ") }) @@ -224,7 +228,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { let ret = if fn_sig.output().skip_binder().is_unit() { String::new() } else { - format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder())) + format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None)) }; format!("fn({}){}", args, ret) } @@ -410,32 +414,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut infer_subdiags = Vec::new(); let mut multi_suggestions = Vec::new(); match kind { - InferSourceKind::LetBinding { insert_span, pattern_name, ty, is_collect } => { + InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => { 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, is_collect), + x_kind: 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: if is_collect { - "Vec<_>".to_string() - } else { - ty_to_string(self, ty) - }, + type_name: ty_to_string(self, ty, def_id), }); } InferSourceKind::ClosureArg { insert_span, ty } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: String::new(), - x_kind: arg_data.where_x_is_kind(ty, false), + x_kind: 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: "closure", - type_name: ty_to_string(self, ty), + type_name: ty_to_string(self, ty, None), }); } InferSourceKind::GenericArg { @@ -534,7 +534,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )); } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let ty_info = ty_to_string(self, ty); + let ty_info = ty_to_string(self, ty, None); multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( ty_info, data, @@ -622,7 +622,7 @@ enum InferSourceKind<'tcx> { insert_span: Span, pattern_name: Option, ty: Ty<'tcx>, - is_collect: bool, + def_id: Option, }, ClosureArg { insert_span: Span, @@ -677,7 +677,7 @@ impl<'tcx> InferSourceKind<'tcx> { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty)) } else if !ty.is_ty_infer() { - ("normal", ty_to_string(infcx, ty)) + ("normal", ty_to_string(infcx, ty, None)) } else { ("other", String::new()) } @@ -807,14 +807,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, '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 + if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source + && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = 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; + *def_id = Some(did); } if cost < self.infer_source_cost { self.infer_source_cost = cost; @@ -1113,7 +1112,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { insert_span: local.pat.span.shrink_to_hi(), pattern_name: local.pat.simple_ident(), ty, - is_collect: false, + def_id: None, }, }) } 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 11a07164e8c..c2a509a1963 100644 --- a/src/test/ui/array-slice-vec/infer_array_len.stderr +++ b/src/test/ui/array-slice-vec/infer_array_len.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let [_, _] = a.into(); | ^^^^^^ | -help: consider giving this pattern a type, where the placeholder `Type` is specified +help: consider giving this pattern a type | -LL | let [_, _]: Type = a.into(); - | ++++++ +LL | let [_, _]: /* Type */ = a.into(); + | ++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr index 9e5705ba00b..7a04ed7381e 100644 --- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr +++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | with_closure(|x: u32, y| {}); | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | with_closure(|x: u32, y: Type| {}); - | ++++++ +LL | with_closure(|x: u32, y: /* Type */| {}); + | ++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index c635e743293..9ba24c7a886 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -10,10 +10,10 @@ error[E0282]: type annotations needed LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | [(); &(&'static: loop { |x: Type| {}; }) as *const _ as usize] - | ++++++ +LL | [(); &(&'static: loop { |x: /* Type */| {}; }) as *const _ as usize] + | ++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr index f148cb7699e..7491fdc8a69 100644 --- a/src/test/ui/const-generics/issues/issue-83249.stderr +++ b/src/test/ui/const-generics/issues/issue-83249.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let _ = foo([0; 1]); | ^ | -help: consider giving this pattern a type, where the placeholder `Type` is specified +help: consider giving this pattern a type | -LL | let _: Type = foo([0; 1]); - | ++++++ +LL | let _: /* Type */ = foo([0; 1]); + | ++++++++++++ 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 30bad841d15..7592418fdfd 100644 --- a/src/test/ui/impl-trait/issues/issue-86719.stderr +++ b/src/test/ui/impl-trait/issues/issue-86719.stderr @@ -18,10 +18,10 @@ error[E0282]: type annotations needed LL | |_| true | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |_: Type| true - | ++++++ +LL | |_: /* Type */| true + | ++++++++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/inference/issue-72690.stderr b/src/test/ui/inference/issue-72690.stderr index 37daeb6441f..8eda71ec09b 100644 --- a/src/test/ui/inference/issue-72690.stderr +++ b/src/test/ui/inference/issue-72690.stderr @@ -30,10 +30,10 @@ error[E0282]: type annotations needed LL | |x| String::from("x".as_ref()); | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |x: Type| String::from("x".as_ref()); - | ++++++ +LL | |x: /* Type */| String::from("x".as_ref()); + | ++++++++++++ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:12:26 diff --git a/src/test/ui/issues/issue-18159.stderr b/src/test/ui/issues/issue-18159.stderr index 1cfb0e41504..5e0589eed43 100644 --- a/src/test/ui/issues/issue-18159.stderr +++ b/src/test/ui/issues/issue-18159.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let x; | ^ | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let x: Type; - | ++++++ +LL | let x: /* Type */; + | ++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr index f689afd4ea7..c75038b6169 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -6,10 +6,10 @@ LL | let x = panic!(); LL | x.clone(); | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let x: Type = panic!(); - | ++++++ +LL | let x: /* Type */ = panic!(); + | ++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 2413db2cada..0e73a51faed 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -17,10 +17,10 @@ error[E0282]: type annotations needed LL | 1 => |c| c + 1, | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | 1 => |c: Type| c + 1, - | ++++++ +LL | 1 => |c: /* Type */| c + 1, + | ++++++++++++ error: aborting due to 2 previous errors 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 d14cad4d71c..fe2631f9474 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -4,10 +4,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |s: Type| s.len() - | ++++++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:15:10 @@ -15,10 +15,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |s: Type| s.len() - | ++++++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:23:10 @@ -26,10 +26,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |s: Type| s.len() - | ++++++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:30:10 @@ -37,10 +37,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |s: Type| s.len() - | ++++++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr index 0ebd56cb064..e3b501b2fd5 100644 --- a/src/test/ui/match/match-unresolved-one-arm.stderr +++ b/src/test/ui/match/match-unresolved-one-arm.stderr @@ -4,10 +4,10 @@ error[E0282]: type annotations needed LL | let x = match () { | ^ | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let x: Type = match () { - | ++++++ +LL | let x: /* Type */ = match () { + | ++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index ff45e9fb7a3..da369d33397 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -7,10 +7,10 @@ LL | let x; LL | (..) => {} | ---- type must be known at this point | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let x: Type; - | ++++++ +LL | let x: /* Type */; + | ++++++++++++ error[E0308]: mismatched types --> $DIR/pat-tuple-bad-type.rs:10:9 diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr index df0aa942fed..beba7def96f 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -191,10 +191,10 @@ error[E0282]: type annotations needed LL | let x @ ..; | ^^^^^^ | -help: consider giving this pattern a type, where the placeholder `Type` is specified +help: consider giving this pattern a type | -LL | let x @ ..: Type; - | ++++++ +LL | let x @ ..: /* Type */; + | ++++++++++++ error: aborting due to 23 previous errors diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr index 2cbc109055f..42b43f825d1 100644 --- a/src/test/ui/resolve/issue-85348.stderr +++ b/src/test/ui/resolve/issue-85348.stderr @@ -19,10 +19,10 @@ error[E0282]: type annotations needed LL | let mut N; | ^^^^^ | -help: consider giving `N` an explicit type, where the placeholder `Type` is specified +help: consider giving `N` an explicit type | -LL | let mut N: Type; - | ++++++ +LL | let mut N: /* Type */; + | ++++++++++++ error: aborting due to 3 previous errors 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 554a2580c94..f6efbe40bc2 100644 --- a/src/test/ui/span/method-and-field-eager-resolution.stderr +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -7,10 +7,10 @@ LL | LL | x.0; | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let mut x: Type = Default::default(); - | ++++++ +LL | let mut x: /* Type */ = Default::default(); + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/method-and-field-eager-resolution.rs:11:9 @@ -21,10 +21,10 @@ LL | LL | x[0]; | - type must be known at this point | -help: consider giving `x` an explicit type, where the placeholder `Type` is specified +help: consider giving `x` an explicit type | -LL | let mut x: Type = Default::default(); - | ++++++ +LL | let mut x: /* Type */ = Default::default(); + | ++++++++++++ error: aborting due to 2 previous errors 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 0d7341bfb91..9cc15f14a99 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,10 +4,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |x: Type| x.len() - | ++++++ +LL | |x: /* Type */| x.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:21:10 @@ -15,10 +15,10 @@ 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, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | |x: Type| x.len() - | ++++++ +LL | |x: /* Type */| x.len() + | ++++++++++++ error: aborting due to 2 previous errors 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 01e053ccd51..e5e29aabf37 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,10 +10,10 @@ error[E0282]: type annotations needed LL | let x = |_| {}; | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | let x = |_: Type| {}; - | ++++++ +LL | let x = |_: /* Type */| {}; + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:10:14 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 51077dedbbe..1aed1dbe4ba 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -28,10 +28,10 @@ error[E0282]: type annotations needed LL | let _ = |a, b: _| -> _ { 0 }; | ^ | -help: consider giving this closure parameter an explicit type, where the placeholder `Type` is specified +help: consider giving this closure parameter an explicit type | -LL | let _ = |a: Type, b: _| -> _ { 0 }; - | ++++++ +LL | let _ = |a: /* Type */, b: _| -> _ { 0 }; + | ++++++++++++ error: aborting due to 5 previous errors From b486fd5d8300b8648eccfdde749725b3799dfa4d Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Thu, 27 Oct 2022 12:52:29 -0400 Subject: [PATCH 12/14] Add docs for question mark operator for Option --- library/core/src/option.rs | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 505d964e518..699e04eff2b 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -72,6 +72,51 @@ //! } //! ``` //! +//! # The question mark operator, `?` +//! +//! Similar to the [`Result`] type, when writing code that calls many functions that return the +//! [`Option`] type, handling `Some`/`None` can be tedious. The question mark +//! operator, [`?`], hides some of the boilerplate of propagating values +//! up the call stack. +//! +//! It replaces this: +//! +//! ``` +//! # #![allow(dead_code)] +//! fn add_last_numbers(stack: &mut Vec) -> Option { +//! let a = stack.pop(); +//! let b = stack.pop(); +//! +//! match (a, b) { +//! (Some(x), Some(y)) => Some(x + y), +//! _ => None, +//! } +//! } +//! +//! ``` +//! +//! With this: +//! +//! ``` +//! # #![allow(dead_code)] +//! fn add_last_numbers(stack: &mut Vec) -> Option { +//! Some(stack.pop()? + stack.pop()?) +//! } +//! ``` +//! +//! *It's much nicer!* +//! +//! Ending the expression with [`?`] will result in the unwrapped +//! success ([`Some`]) value, unless the result is [`None`], in which case +//! [`None`] is returned early from the enclosing function. +//! +//! [`?`] can only be used in functions that return [`Option`] because of the +//! early return of [`None`] that it provides. +//! +//! [`?`]: crate::ops::Try +//! [`Some`]: Some +//! [`None`]: None +//! //! # Representation //! //! Rust guarantees to optimize the following types `T` such that From e0fd37dcf79c8624092ccd0e1463cd239074ec83 Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Tue, 13 Dec 2022 14:49:10 -0500 Subject: [PATCH 13/14] Improve wording for Option and Result --- library/core/src/option.rs | 7 +++---- library/core/src/result.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 699e04eff2b..39462dca4ff 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -106,11 +106,10 @@ //! //! *It's much nicer!* //! -//! Ending the expression with [`?`] will result in the unwrapped -//! success ([`Some`]) value, unless the result is [`None`], in which case -//! [`None`] is returned early from the enclosing function. +//! Ending the expression with [`?`] will result in the [`Some`]'s unwrapped value, unless the +//! result is [`None`], in which case [`None`] is returned early from the enclosing function. //! -//! [`?`] can only be used in functions that return [`Option`] because of the +//! [`?`] can be used in functions that return [`Option`] because of the //! early return of [`None`] that it provides. //! //! [`?`]: crate::ops::Try diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 3f33c5fd6ca..f00c40f35d5 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -209,11 +209,10 @@ //! //! *It's much nicer!* //! -//! Ending the expression with [`?`] will result in the unwrapped -//! success ([`Ok`]) value, unless the result is [`Err`], in which case -//! [`Err`] is returned early from the enclosing function. +//! Ending the expression with [`?`] will result in the [`Ok`]'s unwrapped value, unless the result +//! is [`Err`], in which case [`Err`] is returned early from the enclosing function. //! -//! [`?`] can only be used in functions that return [`Result`] because of the +//! [`?`] can be used in functions that return [`Result`] because of the //! early return of [`Err`] that it provides. //! //! [`expect`]: Result::expect From 40a62758a7db892a47cb59de85612e8a5b9ab267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Dec 2022 13:23:19 -0800 Subject: [PATCH 14/14] rename argument --- .../src/infer/error_reporting/need_type_info.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 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 858ca6deedc..7d39aa010da 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 @@ -183,10 +183,14 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte printer } -fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, def_id: Option) -> String { +fn ty_to_string<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, + called_method_def_id: Option, +) -> String { let printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - match (ty.kind(), def_id) { + match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),