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_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index b15c086ffad..a7eae392de1 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -209,7 +209,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/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 4f9e069c176..a4c36b4c9cd 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; @@ -79,7 +79,7 @@ impl InferenceDiagnosticsData { fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { if in_type.is_ty_infer() { - "empty" + "" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. @@ -183,13 +183,24 @@ 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>, + called_method_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(), 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(), + (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. // @@ -213,7 +224,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(", ") }) @@ -221,7 +232,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) } @@ -368,6 +379,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,7 +418,7 @@ 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, def_id } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), @@ -415,7 +427,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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: ty_to_string(self, ty, def_id), }); } InferSourceKind::ClosureArg { insert_span, ty } => { @@ -427,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 { @@ -456,33 +468,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 { @@ -520,7 +538,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, @@ -608,6 +626,7 @@ enum InferSourceKind<'tcx> { insert_span: Span, pattern_name: Option, ty: Ty<'tcx>, + def_id: Option, }, ClosureArg { insert_span: Span, @@ -662,7 +681,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()) } @@ -788,10 +807,18 @@ 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: 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. + *def_id = Some(did); + } if cost < self.infer_source_cost { self.infer_source_cost = cost; self.infer_source = Some(new_source); @@ -1092,6 +1119,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, + def_id: None, }, }) } 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/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 beb9d55d454..7c2d01509de 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}; @@ -2131,11 +2132,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/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index ee492f802a7..4266430c4c6 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. @@ -320,7 +333,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/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/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 19a1f248177..c68da3e24a1 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; @@ -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, ); } } @@ -1434,6 +1436,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 @@ -1888,7 +1891,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(); @@ -1939,7 +1944,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() } @@ -2180,7 +2185,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() { @@ -2188,6 +2193,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, + ); + } } } _ => { @@ -2199,60 +2216,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/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e17c3777485..55a05df763f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -696,7 +696,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; }; @@ -775,12 +775,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; } } @@ -2854,6 +2875,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/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/library/core/src/option.rs b/library/core/src/option.rs index 505d964e518..39462dca4ff 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -72,6 +72,50 @@ //! } //! ``` //! +//! # 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 [`Some`]'s unwrapped value, unless the +//! result is [`None`], in which case [`None`] is returned early from the enclosing function. +//! +//! [`?`] can 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 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 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..c2a509a1963 100644 --- a/src/test/ui/array-slice-vec/infer_array_len.stderr +++ b/src/test/ui/array-slice-vec/infer_array_len.stderr @@ -6,8 +6,8 @@ LL | let [_, _] = a.into(); | help: consider giving this pattern a type | -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..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 @@ -6,8 +6,8 @@ LL | with_closure(|x: u32, y| {}); | help: consider giving this closure parameter an explicit type | -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 4c24a54bbbe..9ba24c7a886 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -12,8 +12,8 @@ LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | help: consider giving this closure parameter an explicit type | -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/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr index 293ca6232b1..13ea4a295af 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 help: consider giving `y` an explicit type, where the type for type parameter `T` is specified 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..e28ba3b1ada --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-105608.rs @@ -0,0 +1,15 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +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`. 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/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr index 362b8554b2f..7491fdc8a69 100644 --- a/src/test/ui/const-generics/issues/issue-83249.stderr +++ b/src/test/ui/const-generics/issues/issue-83249.stderr @@ -6,8 +6,8 @@ LL | let _ = foo([0; 1]); | help: consider giving this pattern a type | -LL | let _: _ = foo([0; 1]); - | +++ +LL | let _: /* Type */ = foo([0; 1]); + | ++++++++++++ error: aborting due to previous error 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/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/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 + diff --git a/src/test/ui/impl-trait/issues/issue-86719.stderr b/src/test/ui/impl-trait/issues/issue-86719.stderr index 09047cdcbe1..7592418fdfd 100644 --- a/src/test/ui/impl-trait/issues/issue-86719.stderr +++ b/src/test/ui/impl-trait/issues/issue-86719.stderr @@ -20,8 +20,8 @@ LL | |_| true | help: consider giving this closure parameter an explicit type | -LL | |_: _| true - | +++ +LL | |_: /* Type */| true + | ++++++++++++ error: aborting due to 3 previous errors 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/inference/issue-72690.stderr b/src/test/ui/inference/issue-72690.stderr index d4eeda07366..8eda71ec09b 100644 --- a/src/test/ui/inference/issue-72690.stderr +++ b/src/test/ui/inference/issue-72690.stderr @@ -32,8 +32,8 @@ LL | |x| String::from("x".as_ref()); | help: consider giving this closure parameter an explicit type | -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 605ff3829d1..5e0589eed43 100644 --- a/src/test/ui/issues/issue-18159.stderr +++ b/src/test/ui/issues/issue-18159.stderr @@ -6,8 +6,8 @@ LL | let x; | help: consider giving `x` an explicit type | -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 31a8ca5fbfa..c75038b6169 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -8,8 +8,8 @@ LL | x.clone(); | help: consider giving `x` an explicit type | -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 a42e35c4cad..0e73a51faed 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -19,8 +19,8 @@ LL | 1 => |c| c + 1, | help: consider giving this closure parameter an explicit type | -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 420104e526d..fe2631f9474 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -6,8 +6,8 @@ LL | |s| s.len() | help: consider giving this closure parameter an explicit type | -LL | |s: _| s.len() - | +++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:15:10 @@ -17,8 +17,8 @@ LL | |s| s.len() | help: consider giving this closure parameter an explicit type | -LL | |s: _| s.len() - | +++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:23:10 @@ -28,8 +28,8 @@ LL | |s| s.len() | help: consider giving this closure parameter an explicit type | -LL | |s: _| s.len() - | +++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/branches3.rs:30:10 @@ -39,8 +39,8 @@ LL | |s| s.len() | help: consider giving this closure parameter an explicit type | -LL | |s: _| s.len() - | +++ +LL | |s: /* Type */| s.len() + | ++++++++++++ error: aborting due to 4 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/match/match-unresolved-one-arm.stderr b/src/test/ui/match/match-unresolved-one-arm.stderr index 9eadb88a8ba..e3b501b2fd5 100644 --- a/src/test/ui/match/match-unresolved-one-arm.stderr +++ b/src/test/ui/match/match-unresolved-one-arm.stderr @@ -6,8 +6,8 @@ LL | let x = match () { | help: consider giving `x` an explicit type | -LL | let x: _ = match () { - | +++ +LL | let x: /* Type */ = match () { + | ++++++++++++ error: aborting due to previous error 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 + 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 + diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 3342b8e4002..da369d33397 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -9,8 +9,8 @@ LL | (..) => {} | help: consider giving `x` an explicit type | -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 e6a4e5f19b7..beba7def96f 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -193,8 +193,8 @@ LL | let x @ ..; | help: consider giving this pattern a type | -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 f839dd927db..42b43f825d1 100644 --- a/src/test/ui/resolve/issue-85348.stderr +++ b/src/test/ui/resolve/issue-85348.stderr @@ -21,8 +21,8 @@ LL | let mut N; | help: consider giving `N` an explicit type | -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 7d240589a3f..f6efbe40bc2 100644 --- a/src/test/ui/span/method-and-field-eager-resolution.stderr +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -9,8 +9,8 @@ LL | x.0; | help: consider giving `x` an explicit type | -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 @@ -23,8 +23,8 @@ LL | x[0]; | help: consider giving `x` an explicit type | -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/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr index 8ab6414d4d8..0b57a8212bd 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -43,7 +43,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 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`. 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..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 @@ -6,8 +6,8 @@ LL | |x| x.len() | help: consider giving this closure parameter an explicit type | -LL | |x: _| x.len() - | +++ +LL | |x: /* Type */| x.len() + | ++++++++++++ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:21:10 @@ -17,8 +17,8 @@ LL | |x| x.len() | help: consider giving this closure parameter an explicit type | -LL | |x: _| x.len() - | +++ +LL | |x: /* Type */| x.len() + | ++++++++++++ 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); | +++++ 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..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 @@ -12,8 +12,8 @@ LL | let x = |_| {}; | help: consider giving this closure parameter an explicit type | -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 c1ae10efac4..1aed1dbe4ba 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -30,8 +30,8 @@ LL | let _ = |a, b: _| -> _ { 0 }; | help: consider giving this closure parameter an explicit type | -LL | let _ = |a: _, b: _| -> _ { 0 }; - | +++ +LL | let _ = |a: /* Type */, b: _| -> _ { 0 }; + | ++++++++++++ error: aborting due to 5 previous errors