mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Auto merge of #105686 - matthiaskrgr:rollup-bedfk3j, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #103644 (Add docs for question mark operator for Option) - #105161 (Refine when invalid prefix case error arises) - #105491 (Illegal sized bounds: only suggest mutability change if needed) - #105502 (Suggest impl in the scenario of typo with fn) - #105523 (Suggest `collect`ing into `Vec<_>`) - #105595 (Suggest dereferencing receiver arguments properly) - #105611 (fold instead of obliterating args) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7bdda8f801
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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<DefId>,
|
||||
) -> 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::<Vec<_>>()
|
||||
.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<hir::BodyId>,
|
||||
@ -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<Ident>,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: Option<DefId>,
|
||||
},
|
||||
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,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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<P<Block>>)> {
|
||||
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;
|
||||
|
@ -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<String> {
|
||||
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<String> {
|
||||
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() });
|
||||
|
@ -827,6 +827,7 @@ symbols! {
|
||||
item_like_imports,
|
||||
iter,
|
||||
iter_repeat,
|
||||
iterator_collect_fn,
|
||||
kcfi,
|
||||
keyword,
|
||||
kind,
|
||||
|
@ -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<TraitRef<'tcx>>, 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]>::<T>`
|
||||
// ...
|
||||
// LL | const fn const_val<T: Sized>() -> 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::<Vec<String>>()
|
||||
.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(_))) =
|
||||
|
@ -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,
|
||||
|
@ -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<B: FromIterator<Self::Item>>(self) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -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<i32>) -> Option<i32> {
|
||||
//! 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<i32>) -> Option<i32> {
|
||||
//! 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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::<T, LANES>::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
|
||||
|
@ -0,0 +1,15 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Combination<const STRATEGIES: usize>;
|
||||
|
||||
impl<const STRATEGIES: usize> Combination<STRATEGIES> {
|
||||
fn and<M>(self) -> Combination<{ STRATEGIES + 1 }> {
|
||||
Combination
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
Combination::<0>.and::<_>().and::<_>();
|
||||
//~^ ERROR: type annotations needed
|
||||
}
|
@ -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`.
|
@ -41,6 +41,7 @@ LL | IsLessOrEqual<I, 8>: True,
|
||||
| ^^^^
|
||||
|
|
||||
= note: cannot satisfy `IsLessOrEqual<I, 8>: True`
|
||||
= help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
|
||||
|
||||
error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
|
||||
--> $DIR/issue-72787.rs:21:26
|
||||
@ -49,6 +50,7 @@ LL | IsLessOrEqual<I, 8>: True,
|
||||
| ^^^^
|
||||
|
|
||||
= note: cannot satisfy `IsLessOrEqual<I, 8>: True`
|
||||
= help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -59,7 +59,7 @@ note: required by a bound in `bfnr`
|
||||
|
|
||||
LL | fn bfnr<U, V: Baz<U>, 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::<U, V, W>(x);
|
||||
| +++++++++++
|
||||
|
34
src/test/ui/illegal-sized-bound/mutability-mismatch.rs
Normal file
34
src/test/ui/illegal-sized-bound/mutability-mismatch.rs
Normal file
@ -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`
|
||||
}
|
24
src/test/ui/illegal-sized-bound/mutability-mismatch.stderr
Normal file
24
src/test/ui/illegal-sized-bound/mutability-mismatch.stderr
Normal file
@ -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
|
||||
|
32
src/test/ui/illegal-sized-bound/regular.rs
Normal file
32
src/test/ui/illegal-sized-bound/regular.rs
Normal file
@ -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
|
||||
}
|
20
src/test/ui/illegal-sized-bound/regular.stderr
Normal file
20
src/test/ui/illegal-sized-bound/regular.stderr
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -10,10 +10,10 @@ note: required by a bound in `foo`
|
||||
|
|
||||
LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
|
||||
| ^^^^^^^ 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::<T, K, W, Z>(1, "");
|
||||
| ++++++++++++++
|
||||
LL | let foo: Foo<i32, &str, W, Z> = foo(1, "");
|
||||
| ++++++++++++++++++++++
|
||||
|
||||
error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
|
||||
--> $DIR/erase-type-params-in-label.rs:5:9
|
||||
@ -27,10 +27,10 @@ note: required by a bound in `bar`
|
||||
|
|
||||
LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
|
||||
| ^^^^^^^ 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::<T, K, Z>(1, "");
|
||||
| +++++++++++
|
||||
LL | let bar: Bar<i32, &str, Z> = bar(1, "");
|
||||
| +++++++++++++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
34
src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs
Normal file
34
src/test/ui/numeric/uppercase-base-prefix-invalid-no-fix.rs
Normal file
@ -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.)
|
||||
}
|
@ -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
|
||||
|
12
src/test/ui/parser/issue-105366.fixed
Normal file
12
src/test/ui/parser/issue-105366.fixed
Normal file
@ -0,0 +1,12 @@
|
||||
// run-rustfix
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl From<i32> for Foo {
|
||||
//~^ ERROR you might have meant to write `impl` instead of `fn`
|
||||
fn from(_a: i32) -> Self {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
12
src/test/ui/parser/issue-105366.rs
Normal file
12
src/test/ui/parser/issue-105366.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// run-rustfix
|
||||
|
||||
struct Foo;
|
||||
|
||||
fn From<i32> for Foo {
|
||||
//~^ ERROR you might have meant to write `impl` instead of `fn`
|
||||
fn from(_a: i32) -> Self {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/ui/parser/issue-105366.stderr
Normal file
13
src/test/ui/parser/issue-105366.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error: you might have meant to write `impl` instead of `fn`
|
||||
--> $DIR/issue-105366.rs:5:1
|
||||
|
|
||||
LL | fn From<i32> for Foo {
|
||||
| ^^
|
||||
|
|
||||
help: replace `fn` with `impl` here
|
||||
|
|
||||
LL | impl From<i32> for Foo {
|
||||
| ~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<Ipv4Addr> for u32;
|
||||
- impl From<NonZeroU32> for u32;
|
||||
- impl From<bool> for u32;
|
||||
- impl From<char> for u32;
|
||||
- impl From<u16> for u32;
|
||||
- impl From<u8> for u32;
|
||||
- impl<T> From<!> for T;
|
||||
- impl<T> From<T> for T;
|
||||
help: try using a fully qualified path to specify the expected types
|
||||
|
|
||||
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
|
||||
|
@ -5,6 +5,9 @@ LL | T: FnMut(&'a ()),
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: cannot satisfy `T: FnMut<(&'a (),)>`
|
||||
= help: the following types implement trait `FnMut<Args>`:
|
||||
&F
|
||||
&mut F
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
// run-rustfix
|
||||
|
||||
struct TargetStruct;
|
||||
|
||||
impl From<usize> 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
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// run-rustfix
|
||||
|
||||
struct TargetStruct;
|
||||
|
||||
impl From<usize> 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
|
||||
}
|
@ -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<TargetStruct>`
|
||||
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`.
|
@ -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
|
||||
|
||||
|
@ -10,7 +10,7 @@ note: required by a bound in `foo`
|
||||
|
|
||||
LL | fn foo<T: Into<String>>(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::<T>(42);
|
||||
| +++++
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user