Auto merge of #116688 - compiler-errors:rustfmt-up, r=WaffleLapkin,Nilstrieb

Format all the let-chains in compiler crates

Since rust-lang/rustfmt#5910 has landed, soon we will have support for formatting let-chains (as soon as rustfmt syncs and beta gets bumped).

This PR applies the changes [from master rustfmt to rust-lang/rust eagerly](https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/out.20formatting.20of.20prs/near/374997516), so that the next beta bump does not have to deal with a 200+ file diff and can remain concerned with other things like `cfg(bootstrap)` -- #113637 was a pain to land, for example, because of let-else.

I will also add this commit to the ignore list after it has landed.

The commands that were run -- I'm not great at bash-foo, but this applies rustfmt to every compiler crate, and then reverts the two crates that should probably be formatted out-of-tree.
```
~/rustfmt $ ls -1d ~/rust/compiler/* | xargs -I@ cargo run --bin rustfmt -- `@/src/lib.rs` --config-path ~/rust --edition=2021 # format all of the compiler crates
~/rust $ git checkout HEAD -- compiler/rustc_codegen_{gcc,cranelift} # revert changes to cg-gcc and cg-clif
```

cc `@rust-lang/rustfmt`
r? `@WaffleLapkin` or `@Nilstrieb` who said they may be able to review this purely mechanical PR :>

cc `@Mark-Simulacrum` and `@petrochenkov,` who had some thoughts on the order of operations with big formatting changes in https://github.com/rust-lang/rust/pull/95262#issue-1178993801. I think the situation has changed since then, given that let-chains support exists on master rustfmt now, and I'm fairly confident that this formatting PR should land even if *bootstrap* rustfmt doesn't yet format let-chains in order to lessen the burden of the next beta bump.
This commit is contained in:
bors 2023-10-15 13:23:55 +00:00
commit a48396984a
207 changed files with 3121 additions and 2229 deletions

View File

@ -520,9 +520,7 @@ impl NestedMetaItem {
I: Iterator<Item = &'a TokenTree>, I: Iterator<Item = &'a TokenTree>,
{ {
match tokens.peek() { match tokens.peek() {
Some(TokenTree::Token(token, _)) Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
if let Some(lit) = MetaItemLit::from_token(token) =>
{
tokens.next(); tokens.next();
return Some(NestedMetaItem::Lit(lit)); return Some(NestedMetaItem::Lit(lit));
} }

View File

@ -21,7 +21,9 @@ pub fn entry_point_type(
} else if attr::contains_name(attrs, sym::rustc_main) { } else if attr::contains_name(attrs, sym::rustc_main) {
EntryPointType::RustcMainAttr EntryPointType::RustcMainAttr
} else { } else {
if let Some(name) = name && name == sym::main { if let Some(name) = name
&& name == sym::main
{
if at_root { if at_root {
// This is a top-level function so it can be `main`. // This is a top-level function so it can be `main`.
EntryPointType::MainNamed EntryPointType::MainNamed

View File

@ -107,13 +107,11 @@ impl Lit {
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation. /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
pub fn from_token(token: &Token) -> Option<Lit> { pub fn from_token(token: &Token) -> Option<Lit> {
match token.uninterpolate().kind { match token.uninterpolate().kind {
Ident(name, false) if name.is_bool_lit() => { Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
Some(Lit::new(Bool, name, None))
}
Literal(token_lit) => Some(token_lit), Literal(token_lit) => Some(token_lit),
Interpolated(ref nt) Interpolated(ref nt)
if let NtExpr(expr) | NtLiteral(expr) = &**nt if let NtExpr(expr) | NtLiteral(expr) = &**nt
&& let ast::ExprKind::Lit(token_lit) = expr.kind => && let ast::ExprKind::Lit(token_lit) = expr.kind =>
{ {
Some(token_lit) Some(token_lit)
} }
@ -655,7 +653,9 @@ impl Token {
/// Returns `true` if the token is an interpolated path. /// Returns `true` if the token is an interpolated path.
fn is_path(&self) -> bool { fn is_path(&self) -> bool {
if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt { if let Interpolated(nt) = &self.kind
&& let NtPath(..) = **nt
{
return true; return true;
} }
@ -677,7 +677,9 @@ impl Token {
/// Is the token an interpolated block (`$b:block`)? /// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool { pub fn is_whole_block(&self) -> bool {
if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt { if let Interpolated(nt) = &self.kind
&& let NtBlock(..) = **nt
{
return true; return true;
} }

View File

@ -550,7 +550,9 @@ impl TokenStream {
let stream_iter = stream.0.iter().cloned(); let stream_iter = stream.0.iter().cloned();
if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) { if let Some(first) = stream.0.first()
&& Self::try_glue_to_last(vec_mut, first)
{
// Now skip the first token tree from `stream`. // Now skip the first token tree from `stream`.
vec_mut.extend(stream_iter.skip(1)); vec_mut.extend(stream_iter.skip(1));
} else { } else {

View File

@ -673,12 +673,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{ {
let unstable_span = let unstable_span = self.mark_span_with_reason(
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); DesugaringKind::Async,
span,
self.allow_gen_future.clone(),
);
self.lower_attrs( self.lower_attrs(
inner_hir_id, inner_hir_id,
&[Attribute { &[Attribute {
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))), kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
sym::track_caller,
span,
)))),
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
style: AttrStyle::Outer, style: AttrStyle::Outer,
span: unstable_span, span: unstable_span,
@ -1102,7 +1108,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let ExprKind::Path(qself, path) = &expr.kind { if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a tuple struct/variant pattern? // Does the path resolve to something disallowed in a tuple struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() { if let Some(res) = partial_res.full_res()
&& !res.expected_in_tuple_struct_pat()
{
return None; return None;
} }
} }
@ -1122,7 +1130,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let ExprKind::Path(qself, path) = &expr.kind { if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a unit struct/variant pattern? // Does the path resolve to something disallowed in a unit struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() { if let Some(res) = partial_res.full_res()
&& !res.expected_in_unit_struct_pat()
{
return None; return None;
} }
} }

View File

@ -61,9 +61,12 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
let remaining_args = args.split_off(arg_index + 1); let remaining_args = args.split_off(arg_index + 1);
let old_arg_offset = args.len(); let old_arg_offset = args.len();
let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs. let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs.
let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs. let fmt2 = loop {
// Unwrap the Expr to get to the FormatArgs.
match &mut fmt2.kind { match &mut fmt2.kind {
ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner, ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => {
fmt2 = inner
}
ExprKind::FormatArgs(fmt2) => break fmt2, ExprKind::FormatArgs(fmt2) => break fmt2,
_ => unreachable!(), _ => unreachable!(),
} }

View File

@ -1387,10 +1387,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Desugar `~const` bound in generics into an additional `const host: bool` param // Desugar `~const` bound in generics into an additional `const host: bool` param
// if the effects feature is enabled. This needs to be done before we lower where // if the effects feature is enabled. This needs to be done before we lower where
// clauses since where clauses need to bind to the DefId of the host param // clauses since where clauses need to bind to the DefId of the host param
let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects { let host_param_parts = if let Const::Yes(span) = constness
if let Some(param) = generics.params.iter().find(|x| { && self.tcx.features().effects
x.attrs.iter().any(|x| x.has_name(sym::rustc_host)) {
}) { if let Some(param) =
generics.params.iter().find(|x| x.attrs.iter().any(|x| x.has_name(sym::rustc_host)))
{
// user has manually specified a `rustc_host` param, in this case, we set // user has manually specified a `rustc_host` param, in this case, we set
// the param id so that lowering logic can use that. But we don't create // the param id so that lowering logic can use that. But we don't create
// another host param, so this gives `None`. // another host param, so this gives `None`.
@ -1399,7 +1401,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else { } else {
let param_node_id = self.next_node_id(); let param_node_id = self.next_node_id();
let hir_id = self.next_id(); let hir_id = self.next_id();
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span); let def_id = self.create_def(
self.local_def_id(parent_node_id),
param_node_id,
DefPathData::TypeNs(sym::host),
span,
);
self.host_param_id = Some(def_id); self.host_param_id = Some(def_id);
Some((span, hir_id, def_id)) Some((span, hir_id, def_id))
} }

View File

@ -1256,7 +1256,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&PolyTraitRef { &PolyTraitRef {
bound_generic_params: ThinVec::new(), bound_generic_params: ThinVec::new(),
trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
span: t.span span: t.span,
}, },
itctx, itctx,
ast::Const::No, ast::Const::No,

View File

@ -82,7 +82,8 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
// We can sometimes encounter bare trait objects // We can sometimes encounter bare trait objects
// which are represented in AST as paths. // which are represented in AST as paths.
if let Some(partial_res) = self.resolver.get_partial_res(t.id) if let Some(partial_res) = self.resolver.get_partial_res(t.id)
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) =
partial_res.full_res()
{ {
self.current_binders.push(t.id); self.current_binders.push(t.id);
visit::walk_ty(self, t); visit::walk_ty(self, t);

View File

@ -215,14 +215,15 @@ impl<'a> AstValidator<'a> {
} }
fn visit_struct_field_def(&mut self, field: &'a FieldDef) { fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
if let Some(ident) = field.ident && if let Some(ident) = field.ident
ident.name == kw::Underscore { && ident.name == kw::Underscore
self.check_unnamed_field_ty(&field.ty, ident.span); {
self.visit_vis(&field.vis); self.check_unnamed_field_ty(&field.ty, ident.span);
self.visit_ident(ident); self.visit_vis(&field.vis);
self.visit_ty_common(&field.ty); self.visit_ident(ident);
self.walk_ty(&field.ty); self.visit_ty_common(&field.ty);
walk_list!(self, visit_attribute, &field.attrs); self.walk_ty(&field.ty);
walk_list!(self, visit_attribute, &field.attrs);
} else { } else {
self.visit_field_def(field); self.visit_field_def(field);
} }
@ -291,13 +292,11 @@ impl<'a> AstValidator<'a> {
} }
fn deny_unnamed_field(&self, field: &FieldDef) { fn deny_unnamed_field(&self, field: &FieldDef) {
if let Some(ident) = field.ident && if let Some(ident) = field.ident
ident.name == kw::Underscore { && ident.name == kw::Underscore
self.err_handler() {
.emit_err(errors::InvalidUnnamedField { self.err_handler()
span: field.span, .emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span });
ident_span: ident.span
});
} }
} }
@ -1180,28 +1179,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
self.err_handler().emit_err(errors::OptionalTraitSupertrait { self.err_handler().emit_err(errors::OptionalTraitSupertrait {
span: poly.span, span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path) path_str: pprust::path_to_string(&poly.trait_ref.path),
}); });
} }
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => { (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span}); self.err_handler().emit_err(errors::OptionalTraitObject { span: poly.span });
} }
(_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { (_, TraitBoundModifier::MaybeConst)
if let Some(reason) = &self.disallow_tilde_const =>
{
let reason = match reason { let reason = match reason {
DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject, DisallowTildeConstContext::TraitObject => {
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure, errors::TildeConstReason::TraitObject
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span }, }
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
errors::TildeConstReason::Closure
}
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
errors::TildeConstReason::Function { ident: ident.span }
}
}; };
self.err_handler().emit_err(errors::TildeConstDisallowed { self.err_handler()
span: bound.span(), .emit_err(errors::TildeConstDisallowed { span: bound.span(), reason });
reason
});
} }
(_, TraitBoundModifier::MaybeConstMaybe) => { (_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" }); self.err_handler().emit_err(errors::OptionalConstExclusive {
span: bound.span(),
modifier: "?",
});
} }
(_, TraitBoundModifier::MaybeConstNegative) => { (_, TraitBoundModifier::MaybeConstNegative) => {
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" }); self.err_handler().emit_err(errors::OptionalConstExclusive {
span: bound.span(),
modifier: "!",
});
} }
_ => {} _ => {}
} }
@ -1214,7 +1225,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
{ {
for arg in &args.args { for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg { if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); self.err_handler()
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
} }
} }
} }

View File

@ -405,7 +405,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
} }
} }
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { if let Some(s) = since
&& s.as_str() == VERSION_PLACEHOLDER
{
since = Some(rust_version_symbol()); since = Some(rust_version_symbol());
} }
@ -694,13 +696,16 @@ pub fn eval_condition(
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
} }
sym::target => { sym::target => {
if let Some(features) = features && !features.cfg_target_compact { if let Some(features) = features
&& !features.cfg_target_compact
{
feature_err( feature_err(
sess, sess,
sym::cfg_target_compact, sym::cfg_target_compact,
cfg.span, cfg.span,
"compact `cfg(target(..))` is experimental and subject to change" "compact `cfg(target(..))` is experimental and subject to change",
).emit(); )
.emit();
} }
mis.iter().fold(true, |res, mi| { mis.iter().fold(true, |res, mi| {

View File

@ -351,7 +351,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
// Check if we are in a situation of `ident @ ident` where we want to suggest // Check if we are in a situation of `ident @ ident` where we want to suggest
// `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`. // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
if let Some(subpat) = sub && self.pat.is_none() { if let Some(subpat) = sub
&& self.pat.is_none()
{
self.visit_pat(subpat); self.visit_pat(subpat);
if self.pat.is_some() { if self.pat.is_some() {
self.parent_pat = Some(p); self.parent_pat = Some(p);
@ -370,7 +372,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut finder = let mut finder =
ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None }; ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
finder.visit_expr(expr); finder.visit_expr(expr);
if let Some(span) = span && let Some(expr) = finder.expr { if let Some(span) = span
&& let Some(expr) = finder.expr
{
for (_, expr) in hir.parent_iter(expr.hir_id) { for (_, expr) in hir.parent_iter(expr.hir_id) {
if let hir::Node::Expr(expr) = expr { if let hir::Node::Expr(expr) = expr {
if expr.span.contains(span) { if expr.span.contains(span) {
@ -425,10 +429,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(hir::intravisit::FnKind::Method(..)) => "method", Some(hir::intravisit::FnKind::Method(..)) => "method",
Some(hir::intravisit::FnKind::Closure) => "closure", Some(hir::intravisit::FnKind::Closure) => "closure",
}; };
span.push_span_label( span.push_span_label(ident.span, format!("in this {descr}"));
ident.span,
format!("in this {descr}"),
);
err.span_note( err.span_note(
span, span,
format!( format!(
@ -441,15 +442,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = place.ty(self.body, self.infcx.tcx).ty; let ty = place.ty(self.body, self.infcx.tcx).ty;
if let hir::Node::Expr(parent_expr) = parent if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
&& let hir::ExprKind::Path( && let hir::ExprKind::Path(hir::QPath::LangItem(
hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _) LangItem::IntoIterIntoIter,
) = call_expr.kind _,
_,
)) = call_expr.kind
{ {
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
} else if let UseSpans::FnSelfUse { } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } =
kind: CallKind::Normal { .. }, move_spans
.. {
} = move_spans {
// We already suggest cloning for these cases in `explain_captures`. // We already suggest cloning for these cases in `explain_captures`.
} else { } else {
self.suggest_cloning(err, ty, expr, move_span); self.suggest_cloning(err, ty, expr, move_span);
@ -602,10 +604,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.sugg_span.is_some() { if self.sugg_span.is_some() {
return; return;
} }
if let hir::StmtKind::Local(hir::Local { if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind
span, ty, init: None, .. && span.contains(self.decl_span)
}) = &ex.kind && span.contains(self.decl_span) { {
self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
} }
hir::intravisit::walk_stmt(self, ex); hir::intravisit::walk_stmt(self, ex);
} }
@ -743,19 +745,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
".clone()".to_owned() ".clone()".to_owned()
}; };
if let Some(clone_trait_def) = tcx.lang_items().clone_trait() if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
&& self.infcx && self
.type_implements_trait( .infcx
clone_trait_def, .type_implements_trait(clone_trait_def, [ty], self.param_env)
[ty],
self.param_env,
)
.must_apply_modulo_regions() .must_apply_modulo_regions()
{ {
let msg = if let ty::Adt(def, _) = ty.kind() let msg = if let ty::Adt(def, _) = ty.kind()
&& [ && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
tcx.get_diagnostic_item(sym::Arc), .contains(&Some(def.did()))
tcx.get_diagnostic_item(sym::Rc),
].contains(&Some(def.did()))
{ {
"clone the value to increment its reference count" "clone the value to increment its reference count"
} else { } else {
@ -1350,9 +1347,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// }; // };
// corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`. // corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
if let hir::ExprKind::Call(path, [arg]) = ex.kind if let hir::ExprKind::Call(path, [arg]) = ex.kind
&& let hir::ExprKind::Path( && let hir::ExprKind::Path(hir::QPath::LangItem(
hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _), LangItem::IntoIterIntoIter,
) = path.kind _,
_,
)) = path.kind
&& arg.span.contains(self.issue_span) && arg.span.contains(self.issue_span)
{ {
// Find `IntoIterator::into_iter(<head>)` // Find `IntoIterator::into_iter(<head>)`
@ -1370,18 +1369,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.. ..
}) = stmt.kind }) = stmt.kind
&& let hir::ExprKind::Call(path, _args) = call.kind && let hir::ExprKind::Call(path, _args) = call.kind
&& let hir::ExprKind::Path( && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) =
hir::QPath::LangItem(LangItem::IteratorNext, _, _), path.kind
) = path.kind
&& let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
&& let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
&& call.span.contains(self.issue_span) && call.span.contains(self.issue_span)
{ {
// Find `<pat>` and the span for the whole `for` loop. // Find `<pat>` and the span for the whole `for` loop.
if let PatField { pat: hir::Pat { if let PatField {
kind: hir::PatKind::Binding(_, _, ident, ..), pat: hir::Pat { kind: hir::PatKind::Binding(_, _, ident, ..), .. },
.. ..
}, ..} = field { } = field
{
self.loop_bind = Some(ident); self.loop_bind = Some(ident);
} }
self.head_span = Some(*head_span); self.head_span = Some(*head_span);
@ -1441,18 +1440,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// A bare path doesn't need a `let` assignment, it's already a simple // A bare path doesn't need a `let` assignment, it's already a simple
// binding access. // binding access.
// As a new binding wasn't added, we don't need to modify the advancing call. // As a new binding wasn't added, we don't need to modify the advancing call.
sugg.push(( sugg.push((loop_span.with_hi(pat_span.lo()), format!("while let Some(")));
loop_span.with_hi(pat_span.lo()),
format!("while let Some("),
));
sugg.push(( sugg.push((
pat_span.shrink_to_hi().with_hi(head.span.lo()), pat_span.shrink_to_hi().with_hi(head.span.lo()),
") = ".to_string(), ") = ".to_string(),
)); ));
sugg.push(( sugg.push((head.span.shrink_to_hi(), ".next()".to_string()));
head.span.shrink_to_hi(),
".next()".to_string(),
));
} else { } else {
// Needs a new a `let` binding. // Needs a new a `let` binding.
let indent = if let Some(indent) = sm.indentation_before(loop_span) { let indent = if let Some(indent) = sm.indentation_before(loop_span) {
@ -1483,11 +1476,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
sugg.push((recv.span, "iter".to_string())); sugg.push((recv.span, "iter".to_string()));
} }
} }
err.multipart_suggestion( err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
msg,
sugg,
Applicability::MaybeIncorrect,
);
} else { } else {
err.help(msg); err.help(msg);
} }
@ -1666,69 +1655,80 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span.contains(self.capture_span) { if e.span.contains(self.capture_span) {
if let hir::ExprKind::Closure(&hir::Closure { if let hir::ExprKind::Closure(&hir::Closure {
movability: None, movability: None,
body, body,
fn_arg_span, fn_arg_span,
fn_decl: hir::FnDecl{ inputs, .. }, fn_decl: hir::FnDecl { inputs, .. },
.. ..
}) = e.kind && }) = e.kind
let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) { && let Some(hir::Node::Expr(body)) = self.hir.find(body.hir_id)
self.suggest_arg = "this: &Self".to_string(); {
if inputs.len() > 0 { self.suggest_arg = "this: &Self".to_string();
self.suggest_arg.push_str(", "); if inputs.len() > 0 {
} self.suggest_arg.push_str(", ");
self.in_closure = true; }
self.closure_arg_span = fn_arg_span; self.in_closure = true;
self.visit_expr(body); self.closure_arg_span = fn_arg_span;
self.in_closure = false; self.visit_expr(body);
self.in_closure = false;
} }
} }
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
seg.ident.name == kw::SelfLower && self.in_closure { && seg.ident.name == kw::SelfLower
self.closure_change_spans.push(e.span); && self.in_closure
{
self.closure_change_spans.push(e.span);
} }
} }
hir::intravisit::walk_expr(self, e); hir::intravisit::walk_expr(self, e);
} }
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) { fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } =
let Some(init) = local.init local.pat
&& let Some(init) = local.init
{ {
if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { if let hir::Expr {
movability: None, kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
.. ..
}), .. } = init && } = init
init.span.contains(self.capture_span) { && init.span.contains(self.capture_span)
self.closure_local_id = Some(*hir_id); {
self.closure_local_id = Some(*hir_id);
} }
} }
hir::intravisit::walk_local(self, local); hir::intravisit::walk_local(self, local);
} }
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
if let hir::StmtKind::Semi(e) = s.kind && if let hir::StmtKind::Semi(e) = s.kind
let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind && && let hir::ExprKind::Call(
let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && hir::Expr { kind: hir::ExprKind::Path(path), .. },
let Res::Local(hir_id) = seg.res && args,
Some(hir_id) == self.closure_local_id { ) = e.kind
let (span, arg_str) = if args.len() > 0 { && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
(args[0].span.shrink_to_lo(), "self, ".to_string()) && let Res::Local(hir_id) = seg.res
} else { && Some(hir_id) == self.closure_local_id
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); {
(span, "(self)".to_string()) let (span, arg_str) = if args.len() > 0 {
}; (args[0].span.shrink_to_lo(), "self, ".to_string())
self.closure_call_changes.push((span, arg_str)); } else {
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
(span, "(self)".to_string())
};
self.closure_call_changes.push((span, arg_str));
} }
hir::intravisit::walk_stmt(self, s); hir::intravisit::walk_stmt(self, s);
} }
} }
if let Some(hir::Node::ImplItem( if let Some(hir::Node::ImplItem(hir::ImplItem {
hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. } kind: hir::ImplItemKind::Fn(_fn_sig, body_id),
)) = hir.find(self.mir_hir_id()) && ..
let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) { })) = hir.find(self.mir_hir_id())
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
{
let mut finder = ExpressionFinder { let mut finder = ExpressionFinder {
capture_span: *capture_kind_span, capture_span: *capture_kind_span,
closure_change_spans: vec![], closure_change_spans: vec![],
@ -2299,15 +2299,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
visitor.visit_stmt(stmt); visitor.visit_stmt(stmt);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); let expr_ty: Option<Ty<'_>> =
visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
let is_format_arguments_item = let is_format_arguments_item = if let Some(expr_ty) = expr_ty
if let Some(expr_ty) = expr_ty && let ty::Adt(adt, _) = expr_ty.kind()
&& let ty::Adt(adt, _) = expr_ty.kind() { {
self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) self.infcx.tcx.lang_items().get(LangItem::FormatArguments)
} else { == Some(adt.did())
false } else {
}; false
};
if visitor.found == 0 if visitor.found == 0
&& stmt.span.contains(proper_span) && stmt.span.contains(proper_span)

View File

@ -76,10 +76,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
expr_finder.visit_expr(body.value); expr_finder.visit_expr(body.value);
if let Some(mut expr) = expr_finder.result { if let Some(mut expr) = expr_finder.result {
while let hir::ExprKind::AddrOf(_, _, inner) while let hir::ExprKind::AddrOf(_, _, inner)
| hir::ExprKind::Unary(hir::UnOp::Deref, inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
| hir::ExprKind::Field(inner, _) | hir::ExprKind::Field(inner, _)
| hir::ExprKind::MethodCall(_, inner, _, _) | hir::ExprKind::MethodCall(_, inner, _, _)
| hir::ExprKind::Index(inner, _, _) = &expr.kind | hir::ExprKind::Index(inner, _, _) = &expr.kind
{ {
expr = inner; expr = inner;
} }
@ -88,10 +88,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
&& let hir::def::Res::Local(hir_id) = p.res && let hir::def::Res::Local(hir_id) = p.res
&& let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id) && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
{ {
err.span_label( err.span_label(pat.span, format!("binding `{ident}` declared here"));
pat.span,
format!("binding `{ident}` declared here"),
);
} }
} }
} }
@ -419,7 +416,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.local_names[local].is_some() if self.local_names[local].is_some()
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
&& let Some(borrowed_local) = place.as_local() && let Some(borrowed_local) = place.as_local()
&& self.local_names[borrowed_local].is_some() && local != borrowed_local && self.local_names[borrowed_local].is_some()
&& local != borrowed_local
{ {
should_note_order = true; should_note_order = true;
} }

View File

@ -780,19 +780,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) =
**kind
{ {
debug!("move_spans: def_id={:?} places={:?}", def_id, places); debug!("move_spans: def_id={:?} places={:?}", def_id, places);
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
if let Some((args_span, generator_kind, capture_kind_span, path_span)) = if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
self.closure_span(def_id, moved_place, places) self.closure_span(def_id, moved_place, places)
{ {
return ClosureUse { return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
generator_kind,
args_span,
capture_kind_span,
path_span,
};
} }
} }
@ -1123,7 +1119,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self.infcx.tcx.sess.parse_sess.span_diagnostic, &self.infcx.tcx.sess.parse_sess.span_diagnostic,
CaptureReasonSuggest::FreshReborrow { CaptureReasonSuggest::FreshReborrow {
span: move_span.shrink_to_hi(), span: move_span.shrink_to_hi(),
}); },
);
} }
if let Some(clone_trait) = tcx.lang_items().clone_trait() if let Some(clone_trait) = tcx.lang_items().clone_trait()
&& let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]) && let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])

View File

@ -396,17 +396,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_hir_id = captured_place.get_root_variable(); let upvar_hir_id = captured_place.get_root_variable();
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding( && let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) =
hir::BindingAnnotation::NONE, pat.kind
_,
upvar_ident,
_,
) = pat.kind
{ {
if upvar_ident.name == kw::SelfLower { if upvar_ident.name == kw::SelfLower {
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) { for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
if let Some(fn_decl) = node.fn_decl() { if let Some(fn_decl) = node.fn_decl() {
if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) { if !matches!(
fn_decl.implicit_self,
hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
) {
err.span_suggestion( err.span_suggestion(
upvar_ident.span, upvar_ident.span,
"consider changing this to be mutable", "consider changing this to be mutable",
@ -573,7 +572,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.ty, self.ty,
), ),
vec![ vec![
vec![ // val.insert(index, rv); vec![
// val.insert(index, rv);
( (
val.span.shrink_to_hi().with_hi(index.span.lo()), val.span.shrink_to_hi().with_hi(index.span.lo()),
".insert(".to_string(), ".insert(".to_string(),
@ -584,7 +584,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
), ),
(rv.span.shrink_to_hi(), ")".to_string()), (rv.span.shrink_to_hi(), ")".to_string()),
], ],
vec![ // val.get_mut(index).map(|v| { *v = rv; }); vec![
// val.get_mut(index).map(|v| { *v = rv; });
( (
val.span.shrink_to_hi().with_hi(index.span.lo()), val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string(), ".get_mut(".to_string(),
@ -593,12 +594,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
index.span.shrink_to_hi().with_hi(place.span.hi()), index.span.shrink_to_hi().with_hi(place.span.hi()),
").map(|val| { *val".to_string(), ").map(|val| { *val".to_string(),
), ),
( (rv.span.shrink_to_hi(), "; })".to_string()),
rv.span.shrink_to_hi(),
"; })".to_string(),
),
], ],
vec![ // let x = val.entry(index).or_insert(rv); vec![
// let x = val.entry(index).or_insert(rv);
(val.span.shrink_to_lo(), "let val = ".to_string()), (val.span.shrink_to_lo(), "let val = ".to_string()),
( (
val.span.shrink_to_hi().with_hi(index.span.lo()), val.span.shrink_to_hi().with_hi(index.span.lo()),
@ -747,10 +746,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
{ {
let body = hir_map.body(body_id); let body = hir_map.body(body_id);
let mut v = BindingFinder { let mut v = BindingFinder { span: pat_span, hir_id: None };
span: pat_span,
hir_id: None,
};
v.visit_body(body); v.visit_body(body);
v.hir_id v.hir_id
} else { } else {
@ -766,7 +762,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
.. ..
})) = hir_map.find(hir_id) })) = hir_map.find(hir_id)
&& let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) && let Ok(name) =
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
{ {
err.span_suggestion( err.span_suggestion(
pat_span, pat_span,
@ -879,12 +876,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// `span` corresponds to the expression being iterated, find the `for`-loop desugared // `span` corresponds to the expression being iterated, find the `for`-loop desugared
// expression with that span in order to identify potential fixes when encountering a // expression with that span in order to identify potential fixes when encountering a
// read-only iterator that should be mutable. // read-only iterator that should be mutable.
let mut v = Finder { let mut v = Finder { span, expr: None };
span,
expr: None,
};
v.visit_block(block); v.visit_block(block);
if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind { if let Some(expr) = v.expr
&& let Call(_, [expr]) = expr.kind
{
match expr.kind { match expr.kind {
MethodCall(path_segment, _, _, span) => { MethodCall(path_segment, _, _, span) => {
// We have `for _ in iter.read_only_iter()`, try to // We have `for _ in iter.read_only_iter()`, try to
@ -1032,38 +1028,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let source = self.body.source; let source = self.body.source;
let hir = self.infcx.tcx.hir(); let hir = self.infcx.tcx.hir();
if let InstanceDef::Item(def_id) = source.instance if let InstanceDef::Item(def_id) = source.instance
&& let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
&& let ExprKind::Closure(closure) = kind && closure.movability == None && let ExprKind::Closure(closure) = kind
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { && closure.movability == None
let mut cur_expr = expr; && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { {
if path_segment.ident.name == sym::iter { let mut cur_expr = expr;
// check `_ty` has `iter_mut` method while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
let res = self if path_segment.ident.name == sym::iter {
.infcx // check `_ty` has `iter_mut` method
.tcx let res = self
.typeck(path_segment.hir_id.owner.def_id) .infcx
.type_dependent_def_id(cur_expr.hir_id) .tcx
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) .typeck(path_segment.hir_id.owner.def_id)
.map(|def_id| self.infcx.tcx.associated_items(def_id)) .type_dependent_def_id(cur_expr.hir_id)
.map(|assoc_items| { .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() .map(|def_id| self.infcx.tcx.associated_items(def_id))
}); .map(|assoc_items| {
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
});
if let Some(mut res) = res && res.peek().is_some() { if let Some(mut res) = res
err.span_suggestion_verbose( && res.peek().is_some()
path_segment.ident.span, {
"you may want to use `iter_mut` here", err.span_suggestion_verbose(
"iter_mut", path_segment.ident.span,
Applicability::MaybeIncorrect, "you may want to use `iter_mut` here",
); "iter_mut",
} Applicability::MaybeIncorrect,
break; );
} else {
cur_expr = recv;
} }
break;
} else {
cur_expr = recv;
} }
} }
}
} }
fn suggest_make_local_mut( fn suggest_make_local_mut(
@ -1200,14 +1200,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
let hir_map = self.infcx.tcx.hir(); let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id(); let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local() && let hir_id = if let Some(local_def_id) = def_id.as_local()
let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
{ {
let body = hir_map.body(body_id); let body = hir_map.body(body_id);
let mut v = BindingFinder { let mut v = BindingFinder { span: err_label_span, hir_id: None };
span: err_label_span,
hir_id: None,
};
v.visit_body(body); v.visit_body(body);
v.hir_id v.hir_id
} else { } else {
@ -1215,15 +1212,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}; };
if let Some(hir_id) = hir_id if let Some(hir_id) = hir_id
&& let Some(hir::Node::Local(local)) = hir_map.find(hir_id) && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
{ {
let (changing, span, sugg) = match local.ty { let (changing, span, sugg) = match local.ty {
Some(ty) => ("changing", ty.span, message), Some(ty) => ("changing", ty.span, message),
None => ( None => {
"specifying", ("specifying", local.pat.span.shrink_to_hi(), format!(": {message}"))
local.pat.span.shrink_to_hi(), }
format!(": {message}"),
),
}; };
err.span_suggestion_verbose( err.span_suggestion_verbose(
span, span,
@ -1234,9 +1229,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else { } else {
err.span_label( err.span_label(
err_label_span, err_label_span,
format!( format!("consider changing this binding's type to be: `{message}`"),
"consider changing this binding's type to be: `{message}`"
),
); );
} }
} }
@ -1380,11 +1373,7 @@ fn suggest_ampmut<'tcx>(
let ty_mut = decl_ty.builtin_deref(true).unwrap(); let ty_mut = decl_ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::Mutability::Not); assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
( (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty))
false,
span,
format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty)
)
} }
} }

View File

@ -942,9 +942,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {} ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
_ => return false, _ => return false,
} }
tcx.any_free_region_meets(pred, |r| { tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region))
*r == ty::ReEarlyBound(region)
})
}) })
} else { } else {
false false

View File

@ -173,7 +173,9 @@ fn do_mir_borrowck<'tcx>(
for var_debug_info in &input_body.var_debug_info { for var_debug_info in &input_body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value { if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() { if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local] && var_debug_info.name != prev_name { if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!( span_bug!(
var_debug_info.source_info.span, var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)", "local {:?} has many names (`{}` vs `{}`)",

View File

@ -49,7 +49,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// If the query has created new universes and errors are going to be emitted, register the // If the query has created new universes and errors are going to be emitted, register the
// cause of these new universes for improved diagnostics. // cause of these new universes for improved diagnostics.
let universe = self.infcx.universe(); let universe = self.infcx.universe();
if old_universe != universe && let Some(error_info) = error_info { if old_universe != universe
&& let Some(error_info) = error_info
{
let universe_info = error_info.to_universe_info(old_universe); let universe_info = error_info.to_universe_info(old_universe);
for u in (old_universe + 1)..=universe { for u in (old_universe + 1)..=universe {
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());

View File

@ -21,20 +21,22 @@ pub fn expand(
// Allow using `#[alloc_error_handler]` on an item statement // Allow using `#[alloc_error_handler]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here // FIXME - if we get deref patterns, use them to reduce duplication here
let (item, is_stmt, sig_span) = let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item
if let Annotatable::Item(item) = &item && let ItemKind::Fn(fn_kind) = &item.kind
&& let ItemKind::Fn(fn_kind) = &item.kind {
{ (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
(item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else if let Annotatable::Stmt(stmt) = &item
} else if let Annotatable::Stmt(stmt) = &item && let StmtKind::Item(item) = &stmt.kind
&& let StmtKind::Item(item) = &stmt.kind && let ItemKind::Fn(fn_kind) = &item.kind
&& let ItemKind::Fn(fn_kind) = &item.kind {
{ (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else {
} else { ecx.sess
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() }); .parse_sess
return vec![orig_item]; .span_diagnostic
}; .emit_err(errors::AllocErrorMustBeFn { span: item.span() });
return vec![orig_item];
};
// Generate a bunch of new items using the AllocFnFactory // Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span); let span = ecx.with_def_site_ctxt(item.span);

View File

@ -193,10 +193,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) { fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
match &mut expr.kind { match &mut expr.kind {
ExprKind::AddrOf(_, mutability, local_expr) => { ExprKind::AddrOf(_, mutability, local_expr) => {
self.with_is_consumed_management( self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| {
matches!(mutability, Mutability::Mut), this.manage_cond_expr(local_expr)
|this| this.manage_cond_expr(local_expr) });
);
} }
ExprKind::Array(local_exprs) => { ExprKind::Array(local_exprs) => {
for local_expr in local_exprs { for local_expr in local_exprs {
@ -223,7 +222,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|this| { |this| {
this.manage_cond_expr(lhs); this.manage_cond_expr(lhs);
this.manage_cond_expr(rhs); this.manage_cond_expr(rhs);
} },
); );
} }
ExprKind::Call(_, local_exprs) => { ExprKind::Call(_, local_exprs) => {
@ -285,10 +284,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
} }
} }
ExprKind::Unary(un_op, local_expr) => { ExprKind::Unary(un_op, local_expr) => {
self.with_is_consumed_management( self.with_is_consumed_management(matches!(un_op, UnOp::Neg | UnOp::Not), |this| {
matches!(un_op, UnOp::Neg | UnOp::Not), this.manage_cond_expr(local_expr)
|this| this.manage_cond_expr(local_expr) });
);
} }
// Expressions that are not worth or can not be captured. // Expressions that are not worth or can not be captured.
// //

View File

@ -33,7 +33,7 @@ pub fn expand_concat(
accumulator.push_str(&b.to_string()); accumulator.push_str(&b.to_string());
} }
Ok(ast::LitKind::CStr(..)) => { Ok(ast::LitKind::CStr(..)) => {
cx.emit_err(errors::ConcatCStrLit{ span: e.span}); cx.emit_err(errors::ConcatCStrLit { span: e.span });
has_errors = true; has_errors = true;
} }
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
@ -49,7 +49,9 @@ pub fn expand_concat(
} }
}, },
// We also want to allow negative numeric literals. // We also want to allow negative numeric literals.
ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => { ast::ExprKind::Unary(ast::UnOp::Neg, ref expr)
if let ast::ExprKind::Lit(token_lit) = expr.kind =>
{
match ast::LitKind::from_token_lit(token_lit) { match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),

View File

@ -140,8 +140,8 @@ pub fn expand_concat_bytes(
} }
ast::ExprKind::Repeat(expr, count) => { ast::ExprKind::Repeat(expr, count) => {
if let ast::ExprKind::Lit(token_lit) = count.value.kind if let ast::ExprKind::Lit(token_lit) = count.value.kind
&& let Ok(ast::LitKind::Int(count_val, _)) = && let Ok(ast::LitKind::Int(count_val, _)) =
ast::LitKind::from_token_lit(token_lit) ast::LitKind::from_token_lit(token_lit)
{ {
if let Some(elem) = if let Some(elem) =
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
@ -151,7 +151,7 @@ pub fn expand_concat_bytes(
} }
} }
} else { } else {
cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span }); cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
} }
} }
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {

View File

@ -106,7 +106,9 @@ fn cs_clone_simple(
// This basic redundancy checking only prevents duplication of // This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsClone<Foo>` where the type is a // assertions like `AssertParamIsClone<Foo>` where the type is a
// simple name. That's enough to get a lot of cases, though. // simple name. That's enough to get a lot of cases, though.
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { if let Some(name) = field.ty.kind.is_simple_path()
&& !seen_type_names.insert(name)
{
// Already produced an assertion for this type. // Already produced an assertion for this type.
} else { } else {
// let _: AssertParamIsClone<FieldTy>; // let _: AssertParamIsClone<FieldTy>;

View File

@ -73,7 +73,9 @@ fn cs_total_eq_assert(
// This basic redundancy checking only prevents duplication of // This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsEq<Foo>` where the type is a // assertions like `AssertParamIsEq<Foo>` where the type is a
// simple name. That's enough to get a lot of cases, though. // simple name. That's enough to get a lot of cases, though.
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { if let Some(name) = field.ty.kind.is_simple_path()
&& !seen_type_names.insert(name)
{
// Already produced an assertion for this type. // Already produced an assertion for this type.
} else { } else {
// let _: AssertParamIsEq<FieldTy>; // let _: AssertParamIsEq<FieldTy>;

View File

@ -21,25 +21,26 @@ pub fn expand_deriving_partial_ord(
// Order in which to perform matching // Order in which to perform matching
let tag_then_data = if let Annotatable::Item(item) = item let tag_then_data = if let Annotatable::Item(item) = item
&& let ItemKind::Enum(def, _) = &item.kind { && let ItemKind::Enum(def, _) = &item.kind
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); {
match dataful.iter().filter(|&&b| b).count() { let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
// No data, placing the tag check first makes codegen simpler match dataful.iter().filter(|&&b| b).count() {
0 => true, // No data, placing the tag check first makes codegen simpler
1..=2 => false, 0 => true,
_ => { 1..=2 => false,
(0..dataful.len()-1).any(|i| { _ => (0..dataful.len() - 1).any(|i| {
if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) { if dataful[i]
idx >= 2 && let Some(idx) = dataful[i + 1..].iter().position(|v| *v)
} else { {
false idx >= 2
} } else {
}) false
} }
} }),
} else { }
true } else {
}; true
};
let partial_cmp_def = MethodDef { let partial_cmp_def = MethodDef {
name: sym::partial_cmp, name: sym::partial_cmp,
generics: Bounds::empty(), generics: Bounds::empty(),
@ -133,12 +134,16 @@ fn cs_partial_cmp(
if !tag_then_data if !tag_then_data
&& let ExprKind::Match(_, arms) = &mut expr1.kind && let ExprKind::Match(_, arms) = &mut expr1.kind
&& let Some(last) = arms.last_mut() && let Some(last) = arms.last_mut()
&& let PatKind::Wild = last.pat.kind { && let PatKind::Wild = last.pat.kind
last.body = expr2; {
expr1 last.body = expr2;
expr1
} else { } else {
let eq_arm = let eq_arm = cx.arm(
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); span,
cx.pat_some(span, cx.pat_path(span, equal_path.clone())),
expr1,
);
let neq_arm = let neq_arm =
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm])

View File

@ -73,7 +73,9 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
let first_token = &p.token; let first_token = &p.token;
let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) { let fmtstr = if let token::Literal(lit) = first_token.kind
&& matches!(lit.kind, token::Str | token::StrRaw(_))
{
// This allows us to properly handle cases when the first comma // This allows us to properly handle cases when the first comma
// after the format string is mistakenly replaced with any operator, // after the format string is mistakenly replaced with any operator,
// which cause the expression parser to eat too much tokens. // which cause the expression parser to eat too much tokens.
@ -176,7 +178,7 @@ fn make_format_args(
&& block.stmts.len() == 1 && block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind && let StmtKind::Expr(expr) = &block.stmts[0].kind
&& let ExprKind::Path(None, path) = &expr.kind && let ExprKind::Path(None, path) = &expr.kind
&& path.is_potential_trivial_const_arg() && path.is_potential_trivial_const_arg()
{ {
err.multipart_suggestion( err.multipart_suggestion(
"quote your inlined format argument to use as string literal", "quote your inlined format argument to use as string literal",
@ -184,7 +186,7 @@ fn make_format_args(
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
], ],
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
let sugg_fmt = match args.explicit_args().len() { let sugg_fmt = match args.explicit_args().len() {
@ -257,8 +259,13 @@ fn make_format_args(
if let Some(note) = err.note { if let Some(note) = err.note {
e.note_ = Some(errors::InvalidFormatStringNote { note }); e.note_ = Some(errors::InvalidFormatStringNote { note });
} }
if let Some((label, span)) = err.secondary_label && is_source_literal { if let Some((label, span)) = err.secondary_label
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } ); && is_source_literal
{
e.label_ = Some(errors::InvalidFormatStringLabel {
span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)),
label,
});
} }
match err.suggestion { match err.suggestion {
parse::Suggestion::None => {} parse::Suggestion::None => {}

View File

@ -24,20 +24,22 @@ pub fn expand(
// Allow using `#[global_allocator]` on an item statement // Allow using `#[global_allocator]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here // FIXME - if we get deref patterns, use them to reduce duplication here
let (item, is_stmt, ty_span) = let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item
if let Annotatable::Item(item) = &item && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind {
{ (item, false, ecx.with_def_site_ctxt(ty.span))
(item, false, ecx.with_def_site_ctxt(ty.span)) } else if let Annotatable::Stmt(stmt) = &item
} else if let Annotatable::Stmt(stmt) = &item && let StmtKind::Item(item) = &stmt.kind
&& let StmtKind::Item(item) = &stmt.kind && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind {
{ (item, true, ecx.with_def_site_ctxt(ty.span))
(item, true, ecx.with_def_site_ctxt(ty.span)) } else {
} else { ecx.sess
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()}); .parse_sess
return vec![orig_item]; .span_diagnostic
}; .emit_err(errors::AllocMustStatics { span: item.span() });
return vec![orig_item];
};
// Generate a bunch of new items using the AllocFnFactory // Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span); let span = ecx.with_def_site_ctxt(item.span);

View File

@ -35,11 +35,13 @@ pub fn expand_test_case(
let sp = ecx.with_def_site_ctxt(attr_sp); let sp = ecx.with_def_site_ctxt(attr_sp);
let (mut item, is_stmt) = match anno_item { let (mut item, is_stmt) = match anno_item {
Annotatable::Item(item) => (item, false), Annotatable::Item(item) => (item, false),
Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind { Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => {
(i, true) if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
} else { (i, true)
unreachable!() } else {
}, unreachable!()
}
}
_ => { _ => {
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() }); ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
return vec![]; return vec![];

View File

@ -1521,8 +1521,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
llfn: &'ll Value, llfn: &'ll Value,
) { ) {
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
if self.tcx.sess.is_sanitizer_cfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call { if self.tcx.sess.is_sanitizer_cfi_enabled()
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) { && let Some(fn_abi) = fn_abi
&& is_indirect_call
{
if let Some(fn_attrs) = fn_attrs
&& fn_attrs.no_sanitize.contains(SanitizerSet::CFI)
{
return; return;
} }
@ -1559,25 +1564,29 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
llfn: &'ll Value, llfn: &'ll Value,
) -> Option<llvm::OperandBundleDef<'ll>> { ) -> Option<llvm::OperandBundleDef<'ll>> {
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
let kcfi_bundle = let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled()
if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call { && let Some(fn_abi) = fn_abi
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) { && is_indirect_call
return None; {
} if let Some(fn_attrs) = fn_attrs
&& fn_attrs.no_sanitize.contains(SanitizerSet::KCFI)
{
return None;
}
let mut options = TypeIdOptions::empty(); let mut options = TypeIdOptions::empty();
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
options.insert(TypeIdOptions::GENERALIZE_POINTERS); options.insert(TypeIdOptions::GENERALIZE_POINTERS);
} }
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
options.insert(TypeIdOptions::NORMALIZE_INTEGERS); options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
} }
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
} else { } else {
None None
}; };
kcfi_bundle kcfi_bundle
} }
} }

View File

@ -46,8 +46,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
llfn llfn
} else { } else {
let instance_def_id = instance.def_id(); let instance_def_id = instance.def_id();
let llfn = if tcx.sess.target.arch == "x86" && let llfn = if tcx.sess.target.arch == "x86"
let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym) && let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
{ {
// Fix for https://github.com/rust-lang/rust/issues/104453 // Fix for https://github.com/rust-lang/rust/issues/104453
// On x86 Windows, LLVM uses 'L' as the prefix for any private // On x86 Windows, LLVM uses 'L' as the prefix for any private
@ -60,8 +60,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the // LLVM will prefix the name with `__imp_`. Ideally, we'd like the
// existing logic below to set the Storage Class, but it has an // existing logic below to set the Storage Class, but it has an
// exemption for MinGW for backwards compatability. // exemption for MinGW for backwards compatability.
let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance)); let llfn = cx.declare_fn(
unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } &common::i686_decorated_name(
&dllimport,
common::is_mingw_gnu_toolchain(&tcx.sess.target),
true,
),
fn_abi,
Some(instance),
);
unsafe {
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
}
llfn llfn
} else { } else {
cx.declare_fn(sym, fn_abi, Some(instance)) cx.declare_fn(sym, fn_abi, Some(instance))

View File

@ -182,10 +182,17 @@ fn check_and_apply_linkage<'ll, 'tcx>(
llvm::LLVMSetInitializer(g2, g1); llvm::LLVMSetInitializer(g2, g1);
g2 g2
} }
} else if cx.tcx.sess.target.arch == "x86" && } else if cx.tcx.sess.target.arch == "x86"
let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym) && let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
{ {
cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty) cx.declare_global(
&common::i686_decorated_name(
&dllimport,
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
true,
),
llty,
)
} else { } else {
// Generate an external declaration. // Generate an external declaration.
// FIXME(nagisa): investigate whether it can be changed into define_global // FIXME(nagisa): investigate whether it can be changed into define_global

View File

@ -75,7 +75,10 @@ fn make_mir_scope<'ll, 'tcx>(
return; return;
}; };
if let Some(vars) = variables && !vars.contains(scope) && scope_data.inlined.is_none() { if let Some(vars) = variables
&& !vars.contains(scope)
&& scope_data.inlined.is_none()
{
// Do not create a DIScope if there are no variables defined in this // Do not create a DIScope if there are no variables defined in this
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
debug_context.scopes[scope] = parent_scope; debug_context.scopes[scope] = parent_scope;

View File

@ -537,7 +537,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// Only "class" methods are generally understood by LLVM, // Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g., `<*mut T>::null`). // so avoid methods on other types (e.g., `<*mut T>::null`).
if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() { if let ty::Adt(def, ..) = impl_self_ty.kind()
&& !def.is_box()
{
// Again, only create type information if full debuginfo is enabled // Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
{ {

View File

@ -368,17 +368,25 @@ fn link_rlib<'a>(
let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else { let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else {
continue; continue;
}; };
if flavor == RlibFlavor::Normal && let Some(filename) = lib.filename { if flavor == RlibFlavor::Normal
&& let Some(filename) = lib.filename
{
let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess); let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
let src = read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError {message: e }))?; let src =
read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError { message: e }))?;
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src); let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
packed_bundled_libs.push(wrapper_file); packed_bundled_libs.push(wrapper_file);
} else { } else {
let path = let path = find_native_static_library(
find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess); lib.name.as_str(),
lib.verbatim,
&lib_search_paths,
sess,
);
ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| { ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })}); sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })
});
} }
} }

View File

@ -238,8 +238,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
&& let Some(fn_sig) = fn_sig() && let Some(fn_sig) = fn_sig()
&& fn_sig.skip_binder().abi() != abi::Abi::Rust && fn_sig.skip_binder().abi() != abi::Abi::Rust
{ {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") struct_span_err!(
.emit(); tcx.sess,
attr.span,
E0737,
"`#[track_caller]` requires Rust ABI"
)
.emit();
} }
if is_closure if is_closure
&& !tcx.features().closure_track_caller && !tcx.features().closure_track_caller
@ -435,17 +440,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
&& let [item] = items.as_slice() && let [item] = items.as_slice()
&& let Some((sym::align, literal)) = item.name_value_literal() && let Some((sym::align, literal)) = item.name_value_literal()
{ {
rustc_attr::parse_alignment(&literal.kind).map_err(|msg| { rustc_attr::parse_alignment(&literal.kind)
struct_span_err!( .map_err(|msg| {
tcx.sess.diagnostic(), struct_span_err!(
attr.span, tcx.sess.diagnostic(),
E0589, attr.span,
"invalid `repr(align)` attribute: {}", E0589,
msg "invalid `repr(align)` attribute: {}",
) msg
.emit(); )
}) .emit();
.ok() })
.ok()
} else { } else {
None None
}; };
@ -626,10 +632,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
&& let ty::AssocItemContainer::ImplContainer = impl_item.container && let ty::AssocItemContainer::ImplContainer = impl_item.container
&& let Some(trait_item) = impl_item.trait_item_def_id && let Some(trait_item) = impl_item.trait_item_def_id
{ {
return tcx return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER);
.codegen_fn_attrs(trait_item)
.flags
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
} }
false false

View File

@ -1555,7 +1555,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason { if let Some((cached_bb, cached_reason)) = self.terminate_block
&& reason == cached_reason
{
return cached_bb; return cached_bb;
} }

View File

@ -117,9 +117,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::vtable_size => { sym::vtable_size => {
let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
bx.range_metadata(value, WrappingRange { start: 0, end: size_bound }); bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
}, }
// Alignment is always nonzero. // Alignment is always nonzero.
sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }), sym::vtable_align => {
bx.range_metadata(value, WrappingRange { start: 1, end: !0 })
}
_ => {} _ => {}
} }
value value
@ -220,9 +222,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else { } else {
bx.exactudiv(args[0].immediate(), args[1].immediate()) bx.exactudiv(args[0].immediate(), args[1].immediate())
} }
}, }
None => { None => {
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
return; return;
} }
} }
@ -238,7 +244,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(), _ => bug!(),
}, },
None => { None => {
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] }); bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType {
span,
name,
ty: arg_tys[0],
});
return; return;
} }
} }
@ -246,11 +256,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::float_to_int_unchecked => { sym::float_to_int_unchecked => {
if float_type_width(arg_tys[0]).is_none() { if float_type_width(arg_tys[0]).is_none() {
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] }); bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
span,
ty: arg_tys[0],
});
return; return;
} }
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else { let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty }); bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
span,
ty: ret_ty,
});
return; return;
}; };
if signed { if signed {
@ -299,7 +315,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}; };
let invalid_monomorphization = |ty| { let invalid_monomorphization = |ty| {
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
}; };
match instruction { match instruction {
@ -319,7 +339,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
cmp = bx.ptrtoint(cmp, bx.type_isize()); cmp = bx.ptrtoint(cmp, bx.type_isize());
src = bx.ptrtoint(src, bx.type_isize()); src = bx.ptrtoint(src, bx.type_isize());
} }
let pair = bx.atomic_cmpxchg(dst, cmp, src, parse_ordering(bx, success), parse_ordering(bx, failure), weak); let pair = bx.atomic_cmpxchg(
dst,
cmp,
src,
parse_ordering(bx, success),
parse_ordering(bx, failure),
weak,
);
let val = bx.extract_value(pair, 0); let val = bx.extract_value(pair, 0);
let success = bx.extract_value(pair, 1); let success = bx.extract_value(pair, 1);
let val = bx.from_immediate(val); let val = bx.from_immediate(val);
@ -345,11 +372,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Some platforms do not support atomic operations on pointers, // Some platforms do not support atomic operations on pointers,
// so we cast to integer first... // so we cast to integer first...
let llty = bx.type_isize(); let llty = bx.type_isize();
let result = bx.atomic_load(llty, source, parse_ordering(bx, ordering), size); let result = bx.atomic_load(
llty,
source,
parse_ordering(bx, ordering),
size,
);
// ... and then cast the result back to a pointer // ... and then cast the result back to a pointer
bx.inttoptr(result, bx.backend_type(layout)) bx.inttoptr(result, bx.backend_type(layout))
} else { } else {
bx.atomic_load(bx.backend_type(layout), source, parse_ordering(bx, ordering), size) bx.atomic_load(
bx.backend_type(layout),
source,
parse_ordering(bx, ordering),
size,
)
} }
} else { } else {
return invalid_monomorphization(ty); return invalid_monomorphization(ty);
@ -375,12 +412,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
"fence" => { "fence" => {
bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::CrossThread); bx.atomic_fence(
parse_ordering(bx, ordering),
SynchronizationScope::CrossThread,
);
return; return;
} }
"singlethreadfence" => { "singlethreadfence" => {
bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::SingleThread); bx.atomic_fence(
parse_ordering(bx, ordering),
SynchronizationScope::SingleThread,
);
return; return;
} }

View File

@ -239,17 +239,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}; };
if let OperandValueKind::Immediate(out_scalar) = cast_kind if let OperandValueKind::Immediate(out_scalar) = cast_kind
&& in_scalar.size(self.cx) == out_scalar.size(self.cx) && in_scalar.size(self.cx) == out_scalar.size(self.cx)
{ {
let operand_bty = bx.backend_type(operand.layout); let operand_bty = bx.backend_type(operand.layout);
let cast_bty = bx.backend_type(cast); let cast_bty = bx.backend_type(cast);
Some(OperandValue::Immediate(self.transmute_immediate( Some(OperandValue::Immediate(self.transmute_immediate(
bx, bx,
imm, imm,
in_scalar, in_scalar,
operand_bty, operand_bty,
out_scalar, out_scalar,
cast_bty, cast_bty,
))) )))
} else { } else {
None None
} }

View File

@ -39,8 +39,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
hir::Node::Ctor(_) hir::Node::Ctor(_)
| hir::Node::AnonConst(_) | hir::Node::AnonConst(_)
| hir::Node::ConstBlock(_) | hir::Node::ConstBlock(_)
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const, | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const), hir::Constness::Const
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx
.generics_of(def_id)
.host_effect_index
.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time. // foreign items cannot be evaluated at compile-time.

View File

@ -268,7 +268,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
NullaryOp(ref null_op, ty) => { NullaryOp(ref null_op, ty) => {
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?; let layout = self.layout_of(ty)?;
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() { if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
&& layout.is_unsized()
{
span_bug!( span_bug!(
self.frame().current_span(), self.frame().current_span(),
"{null_op:?} MIR operator called for unsized type {ty}", "{null_op:?} MIR operator called for unsized type {ty}",

View File

@ -464,7 +464,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Aggregate(kind, ..) => { Rvalue::Aggregate(kind, ..) => {
if let AggregateKind::Generator(def_id, ..) = kind.as_ref() if let AggregateKind::Generator(def_id, ..) = kind.as_ref()
&& let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id) && let Some(generator_kind @ hir::GeneratorKind::Async(..)) =
self.tcx.generator_kind(def_id)
{ {
self.check_op(ops::Generator(generator_kind)); self.check_op(ops::Generator(generator_kind));
} }
@ -579,8 +580,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
} }
} }
Rvalue::BinaryOp(op, box (lhs, rhs)) Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
| Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
let lhs_ty = lhs.ty(self.body, self.tcx); let lhs_ty = lhs.ty(self.body, self.tcx);
let rhs_ty = rhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx);
@ -588,18 +588,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Int, bool, and char operations are fine. // Int, bool, and char operations are fine.
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
assert_eq!(lhs_ty, rhs_ty); assert_eq!(lhs_ty, rhs_ty);
assert!( assert!(matches!(
matches!( op,
op, BinOp::Eq
BinOp::Eq
| BinOp::Ne | BinOp::Ne
| BinOp::Le | BinOp::Le
| BinOp::Lt | BinOp::Lt
| BinOp::Ge | BinOp::Ge
| BinOp::Gt | BinOp::Gt
| BinOp::Offset | BinOp::Offset
) ));
);
self.check_op(ops::RawPtrComparison); self.check_op(ops::RawPtrComparison);
} else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
@ -947,7 +945,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if self.span.allows_unstable(gate) { if self.span.allows_unstable(gate) {
return; return;
} }
if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) { if let Some(implied_by_gate) = implied_by
&& self.span.allows_unstable(implied_by_gate)
{
return; return;
} }

View File

@ -311,10 +311,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx.const_kind(), ccx.const_kind(),
)); ));
if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() { if let Some(feature) = feature
err.help(format!( && ccx.tcx.sess.is_nightly_build()
"add `#![feature({feature})]` to the crate attributes to enable", {
)); err.help(format!("add `#![feature({feature})]` to the crate attributes to enable",));
} }
if let ConstContext::Static(_) = ccx.const_kind() { if let ConstContext::Static(_) = ccx.const_kind() {

View File

@ -1290,7 +1290,9 @@ fn ice_path() -> &'static Option<PathBuf> {
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
return None; return None;
} }
if let Some(s) = std::env::var_os("RUST_BACKTRACE") && s == "0" { if let Some(s) = std::env::var_os("RUST_BACKTRACE")
&& s == "0"
{
return None; return None;
} }
let mut path = match std::env::var_os("RUSTC_ICE") { let mut path = match std::env::var_os("RUSTC_ICE") {
@ -1357,8 +1359,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
eprintln!(); eprintln!();
if let Some(ice_path) = ice_path() if let Some(ice_path) = ice_path()
&& let Ok(mut out) = && let Ok(mut out) = File::options().create(true).append(true).open(&ice_path)
File::options().create(true).append(true).open(&ice_path)
{ {
// The current implementation always returns `Some`. // The current implementation always returns `Some`.
let location = info.location().unwrap(); let location = info.location().unwrap();

View File

@ -337,9 +337,7 @@ pub trait Emitter: Translate {
&& last_name != name && last_name != name
{ {
let descr = macro_kind.descr(); let descr = macro_kind.descr();
format!( format!(" which comes from the expansion of the {descr} `{last_name}`",)
" which comes from the expansion of the {descr} `{last_name}`",
)
} else { } else {
"".to_string() "".to_string()
}; };
@ -1935,7 +1933,9 @@ impl EmitterWriter {
is_multiline, is_multiline,
) )
} }
if let DisplaySuggestion::Add = show_code_change && is_item_attribute { if let DisplaySuggestion::Add = show_code_change
&& is_item_attribute
{
// The suggestion adds an entire line of code, ending on a newline, so we'll also // The suggestion adds an entire line of code, ending on a newline, so we'll also
// print the *following* line, to provide context of what we're advising people to // print the *following* line, to provide context of what we're advising people to
// do. Otherwise you would only see contextless code that can be confused for // do. Otherwise you would only see contextless code that can be confused for

View File

@ -1673,7 +1673,11 @@ impl HandlerInner {
let _ = write!( let _ = write!(
&mut out, &mut out,
"delayed span bug: {}\n{}\n", "delayed span bug: {}\n{}\n",
bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(), bug.inner
.styled_message()
.iter()
.filter_map(|(msg, _)| msg.as_str())
.collect::<String>(),
&bug.note &bug.note
); );
} }

View File

@ -151,12 +151,14 @@ fn misformed_fluent() {
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
} = &err } = &err
&& let [FluentError::ResolverError(ResolverError::Reference( && let [
ReferenceKind::Message { id, .. } FluentError::ResolverError(ResolverError::Reference(
| ReferenceKind::Variable { id, .. }, ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. },
))] = &**errs )),
] = &**errs
&& id == "name" && id == "name"
{} else { {
} else {
panic!("{err:#?}") panic!("{err:#?}")
}; };
assert_eq!( assert_eq!(
@ -176,12 +178,14 @@ fn misformed_fluent() {
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
} = &err } = &err
&& let [FluentError::ResolverError(ResolverError::Reference( && let [
ReferenceKind::Message { id, .. } FluentError::ResolverError(ResolverError::Reference(
| ReferenceKind::Variable { id, .. }, ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. },
))] = &**errs )),
] = &**errs
&& id == "oops" && id == "oops"
{} else { {
} else {
panic!("{err:#?}") panic!("{err:#?}")
}; };
assert_eq!( assert_eq!(

View File

@ -47,7 +47,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
} }
fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> { fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() { if attr.has_name(sym::feature)
&& let Some(list) = attr.meta_item_list()
{
list list
} else { } else {
ThinVec::new() ThinVec::new()
@ -69,7 +71,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
if mi.is_word() { if mi.is_word() {
let name = mi.name_or_empty(); let name = mi.name_or_empty();
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
if let Some(edition) = edition && edition > features_edition { if let Some(edition) = edition
&& edition > features_edition
{
features_edition = edition; features_edition = edition;
} }
} }
@ -248,7 +252,8 @@ impl<'a> StripUnconfigured<'a> {
let trees: Vec<_> = stream let trees: Vec<_> = stream
.0 .0
.iter() .iter()
.flat_map(|tree| match tree.clone() { .flat_map(|tree| {
match tree.clone() {
AttrTokenTree::Attributes(mut data) => { AttrTokenTree::Attributes(mut data) => {
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
@ -263,18 +268,17 @@ impl<'a> StripUnconfigured<'a> {
} }
AttrTokenTree::Delimited(sp, delim, mut inner) => { AttrTokenTree::Delimited(sp, delim, mut inner) => {
inner = self.configure_tokens(&inner); inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, delim, inner)) Some(AttrTokenTree::Delimited(sp, delim, inner)).into_iter()
.into_iter()
} }
AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => { AttrTokenTree::Token(ref token, _)
panic!( if let TokenKind::Interpolated(nt) = &token.kind =>
"Nonterminal should have been flattened at {:?}: {:?}", {
token.span, nt panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
);
} }
AttrTokenTree::Token(token, spacing) => { AttrTokenTree::Token(token, spacing) => {
Some(AttrTokenTree::Token(token, spacing)).into_iter() Some(AttrTokenTree::Token(token, spacing)).into_iter()
} }
}
}) })
.collect(); .collect();
AttrTokenStream::new(trees) AttrTokenStream::new(trees)

View File

@ -716,18 +716,18 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
match rhs { match rhs {
mbe::TokenTree::Delimited(_sp, d) => { mbe::TokenTree::Delimited(_sp, d) => {
let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| { let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
if let mbe::TokenTree::Token(ident) = ident && if let mbe::TokenTree::Token(ident) = ident
let TokenKind::Ident(ident, _) = ident.kind && && let TokenKind::Ident(ident, _) = ident.kind
ident == sym::compile_error && && ident == sym::compile_error
let mbe::TokenTree::Token(bang) = bang && && let mbe::TokenTree::Token(bang) = bang
let TokenKind::Not = bang.kind && && let TokenKind::Not = bang.kind
let mbe::TokenTree::Delimited(_, del) = args && && let mbe::TokenTree::Delimited(_, del) = args
del.delim != Delimiter::Invisible && del.delim != Delimiter::Invisible
{ {
true true
} else { } else {
false false
} }
}); });
if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) } if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
} }

View File

@ -124,8 +124,7 @@ fn parse_depth<'sess>(
&& let Ok(n_usize) = usize::try_from(n_u128) && let Ok(n_usize) = usize::try_from(n_u128)
{ {
Ok(n_usize) Ok(n_usize)
} } else {
else {
let msg = "only unsuffixes integer literals are supported in meta-variable expressions"; let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
Err(sess.span_diagnostic.struct_span_err(span, msg)) Err(sess.span_diagnostic.struct_span_err(span, msg))
} }
@ -137,15 +136,16 @@ fn parse_ident<'sess>(
sess: &'sess ParseSess, sess: &'sess ParseSess,
span: Span, span: Span,
) -> PResult<'sess, Ident> { ) -> PResult<'sess, Ident> {
if let Some(tt) = iter.next() && let TokenTree::Token(token, _) = tt { if let Some(tt) = iter.next()
&& let TokenTree::Token(token, _) = tt
{
if let Some((elem, false)) = token.ident() { if let Some((elem, false)) = token.ident() {
return Ok(elem); return Ok(elem);
} }
let token_str = pprust::token_to_string(token); let token_str = pprust::token_to_string(token);
let mut err = sess.span_diagnostic.struct_span_err( let mut err = sess
span, .span_diagnostic
format!("expected identifier, found `{}`", &token_str) .struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
);
err.span_suggestion( err.span_suggestion(
token.span, token.span,
format!("try removing `{}`", &token_str), format!("try removing `{}`", &token_str),

View File

@ -91,7 +91,9 @@ pub(crate) fn mod_dir_path(
inline: Inline, inline: Inline,
) -> (PathBuf, DirOwnership) { ) -> (PathBuf, DirOwnership) {
match inline { match inline {
Inline::Yes if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) => { Inline::Yes
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) =>
{
// For inline modules file path from `#[path]` is actually the directory path // For inline modules file path from `#[path]` is actually the directory path
// for historical reasons, so we don't pop the last segment here. // for historical reasons, so we don't pop the last segment here.
(file_path, DirOwnership::Owned { relative: None }) (file_path, DirOwnership::Owned { relative: None })

View File

@ -226,9 +226,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
})); }));
} }
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees
trees.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })) .push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })),
}
Interpolated(nt) => { Interpolated(nt) => {
let stream = TokenStream::from_nonterminal_ast(&nt); let stream = TokenStream::from_nonterminal_ast(&nt);

View File

@ -517,8 +517,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
); );
if let DefKind::AssocConst = def_kind if let DefKind::AssocConst = def_kind
&& let Some(t) = term.ty() && (t.is_enum() || t.references_error()) && let Some(t) = term.ty()
&& tcx.features().associated_const_equality { && (t.is_enum() || t.references_error())
&& tcx.features().associated_const_equality
{
err.span_suggestion( err.span_suggestion(
binding.span, binding.span,
"if equating a const, try wrapping with braces", "if equating a const, try wrapping with braces",

View File

@ -432,9 +432,11 @@ pub(crate) fn check_generic_arg_count(
let infer_lifetimes = let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { if gen_pos != GenericArgPosition::Type
prohibit_assoc_ty_binding(tcx, b.span, None); && let Some(b) = gen_args.bindings.first()
} {
prohibit_assoc_ty_binding(tcx, b.span, None);
}
let explicit_late_bound = let explicit_late_bound =
prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos); prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);

View File

@ -18,18 +18,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let hir::Node::Item(hir::Item { if let hir::Node::Item(hir::Item {
kind: kind:
hir::ItemKind::Impl(hir::Impl { hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. self_ty: impl_self_ty,
of_trait: Some(of_trait_ref),
generics,
..
}), }),
.. ..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id }) = tcx.hir().get_by_def_id(parent_id)
&& self_ty.hir_id == impl_self_ty.hir_id
{ {
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return; return;
} }
let of_trait_span = of_trait_ref.path.span; let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation // make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; return;
};
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
return;
};
// check if the trait has generics, to make a correct suggestion // check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None); let param_name = generics.params.next_type_param_name(None);
@ -39,13 +47,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(generics.span, format!("<{param_name}: {impl_trait_name}>")) (generics.span, format!("<{param_name}: {impl_trait_name}>"))
}; };
diag.multipart_suggestion( diag.multipart_suggestion(
format!("alternatively use a blanket \ format!(
"alternatively use a blanket \
implementation to implement `{of_trait_name}` for \ implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"), all types that also implement `{impl_trait_name}`"
vec![ ),
(self_ty.span, param_name), vec![(self_ty.span, param_name), add_generic_sugg],
add_generic_sugg,
],
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }

View File

@ -567,9 +567,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
); );
if let ty::BoundConstness::ConstIfConst = constness if let ty::BoundConstness::ConstIfConst = constness
&& generics.has_self && !tcx.has_attr(def_id, sym::const_trait) && generics.has_self
&& !tcx.has_attr(def_id, sym::const_trait)
{ {
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } ); tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
} }
(args, arg_count) (args, arg_count)
@ -1919,9 +1920,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} else { } else {
Some(( Some((
match segment.res { match segment.res {
Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()), Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name())
}
Res::Def(_, def_id) Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) => { if let Some(name) = self.tcx().opt_item_name(def_id) =>
{
format!("{} `{name}`", segment.res.descr()) format!("{} `{name}`", segment.res.descr())
} }
Res::Err => "this type".to_string(), Res::Err => "this type".to_string(),
@ -2251,7 +2255,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note(msg); err.note(msg);
} }
for segment in path.segments { for segment in path.segments {
if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper { if let Some(args) = segment.args
&& segment.ident.name == kw::SelfUpper
{
if generics == 0 { if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being // FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*. // work for the `enum`, instead of just looking if it takes *any*.
@ -2633,7 +2639,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, a)| { .map(|(i, a)| {
if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() { if let hir::TyKind::Infer = a.kind
&& !self.allow_ty_infer()
{
if let Some(suggested_ty) = if let Some(suggested_ty) =
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{ {
@ -2662,7 +2670,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty(output) self.ast_ty_to_ty(output)
} }
} }
hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,), hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx),
}; };
debug!(?output_ty); debug!(?output_ty);

View File

@ -481,8 +481,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi); fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
} }
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
let trait_args = let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id);
GenericArgs::identity_for_item(tcx, id.owner_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx, tcx,
assoc_item, assoc_item,
@ -502,7 +501,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
} }
DefKind::OpaqueTy => { DefKind::OpaqueTy => {
let origin = tcx.opaque_type_origin(id.owner_id.def_id); let origin = tcx.opaque_type_origin(id.owner_id.def_id);
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
{ {
@ -589,7 +589,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
} }
DefKind::GlobalAsm => { DefKind::GlobalAsm => {
let it = tcx.hir().item(id); let it = tcx.hir().item(id);
let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; let hir::ItemKind::GlobalAsm(asm) = it.kind else {
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
};
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
} }
_ => {} _ => {}
@ -873,10 +875,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
ty::Array(t, _clen) ty::Array(t, _clen)
if matches!( if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) =>
t.kind(),
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
) =>
{ /* struct([f32; 4]) is ok */ } { /* struct([f32; 4]) is ok */ }
_ => { _ => {
struct_span_err!( struct_span_err!(
@ -899,17 +898,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
for attr in tcx.get_attrs(def.did(), sym::repr) { for attr in tcx.get_attrs(def.did(), sym::repr) {
for r in attr::parse_repr_attr(&tcx.sess, attr) { for r in attr::parse_repr_attr(&tcx.sess, attr) {
if let attr::ReprPacked(pack) = r if let attr::ReprPacked(pack) = r
&& let Some(repr_pack) = repr.pack && let Some(repr_pack) = repr.pack
&& pack as u64 != repr_pack.bytes() && pack as u64 != repr_pack.bytes()
{ {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
sp, sp,
E0634, E0634,
"type has conflicting packed representation hints" "type has conflicting packed representation hints"
) )
.emit(); .emit();
} }
} }
} }
if repr.align.is_some() { if repr.align.is_some() {
@ -1174,7 +1173,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
let (span, display_discr) = match var.discr { let (span, display_discr) = match var.discr {
ty::VariantDiscr::Explicit(discr_def_id) => { ty::VariantDiscr::Explicit(discr_def_id) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know // In the case the discriminant is both a duplicate and overflowed, let the user know
if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local()) if let hir::Node::AnonConst(expr) =
tcx.hir().get_by_def_id(discr_def_id.expect_local())
&& let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val && *lit_value != dis.val
@ -1303,15 +1303,9 @@ pub(super) fn check_type_params_are_used<'tcx>(
&& let ty::GenericParamDefKind::Type { .. } = param.kind && let ty::GenericParamDefKind::Type { .. } = param.kind
{ {
let span = tcx.def_span(param.def_id); let span = tcx.def_span(param.def_id);
struct_span_err!( struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,)
tcx.sess, .span_label(span, "unused type parameter")
span, .emit();
E0091,
"type parameter `{}` is unused",
param.name,
)
.span_label(span, "unused type parameter")
.emit();
} }
} }
} }
@ -1430,7 +1424,10 @@ fn opaque_type_cycle_error(
let mut label_match = |ty: Ty<'_>, span| { let mut label_match = |ty: Ty<'_>, span| {
for arg in ty.walk() { for arg in ty.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack() if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind() && let ty::Alias(
ty::Opaque,
ty::AliasTy { def_id: captured_def_id, .. },
) = *ty.kind()
&& captured_def_id == opaque_def_id.to_def_id() && captured_def_id == opaque_def_id.to_def_id()
{ {
err.span_label( err.span_label(

View File

@ -1009,7 +1009,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
}); });
self.types.insert(proj.def_id, (infer_ty, proj.args)); self.types.insert(proj.def_id, (infer_ty, proj.args));
// Recurse into bounds // Recurse into bounds
for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) { for (pred, pred_span) in self
.interner()
.explicit_item_bounds(proj.def_id)
.iter_instantiated_copied(self.interner(), proj.args)
{
let pred = pred.fold_with(self); let pred = pred.fold_with(self);
let pred = self.ocx.normalize( let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id), &ObligationCause::misc(self.span, self.body_id),
@ -1180,7 +1184,8 @@ fn report_trait_method_mismatch<'tcx>(
if trait_sig.inputs().len() == *i { if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions // Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output. // to avoid complex logic or incorrect output.
if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind if let ImplItemKind::Fn(sig, _) =
&tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
&& !sig.header.asyncness.is_async() && !sig.header.asyncness.is_async()
{ {
let msg = "change the output type to match the trait"; let msg = "change the output type to match the trait";

View File

@ -550,9 +550,11 @@ fn infringing_fields_error(
.entry((ty.clone(), predicate.clone())) .entry((ty.clone(), predicate.clone()))
.or_default() .or_default()
.push(origin.span()); .push(origin.span());
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { if let ty::RegionKind::ReEarlyBound(ebr) = *b
bounds.push((b.to_string(), a.to_string(), None)); && ebr.has_name()
} {
bounds.push((b.to_string(), a.to_string(), None));
}
} }
RegionResolutionError::GenericBoundFailure(origin, a, b) => { RegionResolutionError::GenericBoundFailure(origin, a, b) => {
let predicate = format!("{a}: {b}"); let predicate = format!("{a}: {b}");

View File

@ -212,7 +212,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
let mut is_fn = false; let mut is_fn = false;
let mut is_const_or_static = false; let mut is_const_or_static = false;
if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind { if let Some(hir_ty) = hir_ty
&& let hir::TyKind::BareFn(_) = hir_ty.kind
{
is_fn = true; is_fn = true;
// Check if parent is const or static // Check if parent is const or static
@ -224,10 +226,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
Node::Item(&hir::Item { Node::Item(&hir::Item {
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
.. ..
}) | Node::TraitItem(&hir::TraitItem { }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
kind: hir::TraitItemKind::Const(..), | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
..
}) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
); );
} }
@ -1004,10 +1004,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
&& let Some(lit) = meta.name_value_literal() && let Some(lit) = meta.name_value_literal()
{ {
if seen_attr { if seen_attr {
tcx.sess.span_err( tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item");
meta.span,
"duplicated `implement_via_object` meta item",
);
} }
seen_attr = true; seen_attr = true;
@ -1021,7 +1018,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
_ => { _ => {
tcx.sess.span_err( tcx.sess.span_err(
meta.span, meta.span,
format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), format!(
"unknown literal passed to `implement_via_object` attribute: {}",
lit.symbol
),
); );
} }
} }
@ -1115,8 +1115,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait // Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id)
tcx.hir().get_parent(hir_id)
&& i.of_trait.is_some() && i.of_trait.is_some()
{ {
icx.astconv().ty_of_fn( icx.astconv().ty_of_fn(
@ -1343,7 +1342,13 @@ fn suggest_impl_trait<'tcx>(
if ocx.select_where_possible().is_empty() if ocx.select_where_possible().is_empty()
&& let item_ty = infcx.resolve_vars_if_possible(item_ty) && let item_ty = infcx.resolve_vars_if_possible(item_ty)
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false) && let Some(item_ty) = item_ty.make_suggestable(tcx, false)
&& let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(args), trait_def_id, assoc_item_def_id, item_ty) && let Some(sugg) = formatter(
tcx,
infcx.resolve_vars_if_possible(args),
trait_def_id,
assoc_item_def_id,
item_ty,
)
{ {
return Some(sugg); return Some(sugg);
} }

View File

@ -169,8 +169,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Projection, projection_ty) = ty.kind() if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
= self.tcx.opt_rpitit_info(projection_ty.def_id) self.tcx.opt_rpitit_info(projection_ty.def_id)
&& fn_def_id == self.fn_def_id && fn_def_id == self.fn_def_id
{ {
self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args) self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)

View File

@ -389,7 +389,9 @@ fn const_evaluatable_predicates_of(
let node = tcx.hir().get(hir_id); let node = tcx.hir().get(hir_id);
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind { if let hir::Node::Item(item) = node
&& let hir::ItemKind::Impl(impl_) = item.kind
{
if let Some(of_trait) = &impl_.of_trait { if let Some(of_trait) = &impl_.of_trait {
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
collector.visit_trait_ref(of_trait); collector.visit_trait_ref(of_trait);

View File

@ -1190,7 +1190,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Root { opt_parent_item } => { Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item) && let parent_generics = self.tcx.generics_of(parent_item)
&& parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some() && parent_generics
.param_def_id_to_index(self.tcx, region_def_id.to_def_id())
.is_some()
{ {
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
} }
@ -1209,13 +1211,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// regular fns. // regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
&& let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) && let Some(generics) =
self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
&& param.is_elided_lifetime() && param.is_elided_lifetime()
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait && !self.tcx.features().anonymous_lifetime_in_impl_trait
{ {
let mut diag = rustc_session::parse::feature_err( let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait, sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.ident.span, lifetime_ref.ident.span,
@ -1225,25 +1228,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if let Some(generics) = if let Some(generics) =
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
{ {
let new_param_sugg = if let Some(span) = let new_param_sugg =
generics.span_for_lifetime_suggestion() if let Some(span) = generics.span_for_lifetime_suggestion() {
{ (span, "'a, ".to_owned())
(span, "'a, ".to_owned()) } else {
} else { (generics.span, "<'a>".to_owned())
(generics.span, "<'a>".to_owned()) };
};
let lifetime_sugg = match lifetime_ref.suggestion_position() { let lifetime_sugg = match lifetime_ref.suggestion_position() {
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()), (hir::LifetimeSuggestionPosition::Normal, span) => {
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()), (span, "'a".to_owned())
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()), }
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()), (hir::LifetimeSuggestionPosition::Ampersand, span) => {
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()), (span, "'a ".to_owned())
}
(hir::LifetimeSuggestionPosition::ElidedPath, span) => {
(span, "<'a>".to_owned())
}
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => {
(span, "'a, ".to_owned())
}
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => {
(span, "+ 'a".to_owned())
}
}; };
let suggestions = vec![ let suggestions = vec![lifetime_sugg, new_param_sugg];
lifetime_sugg,
new_param_sugg,
];
diag.span_label( diag.span_label(
lifetime_ref.ident.span, lifetime_ref.ident.span,
@ -1378,7 +1387,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Root { opt_parent_item } => { Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item) && let parent_generics = self.tcx.generics_of(parent_item)
&& parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some() && parent_generics
.param_def_id_to_index(self.tcx, param_def_id.to_def_id())
.is_some()
{ {
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
} }
@ -1689,14 +1700,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
let bound_vars = if let Some(type_def_id) = type_def_id let bound_vars = if let Some(type_def_id) = type_def_id
&& self.tcx.def_kind(type_def_id) == DefKind::Trait && self.tcx.def_kind(type_def_id) == DefKind::Trait
&& let Some((mut bound_vars, assoc_fn)) = && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
BoundVarContext::supertrait_hrtb_vars( self.tcx,
self.tcx, type_def_id,
type_def_id, binding.ident,
binding.ident, ty::AssocKind::Fn,
ty::AssocKind::Fn, ) {
)
{
bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map( bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
|param| match param.kind { |param| match param.kind {
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
@ -1708,14 +1717,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
}, },
)); ));
bound_vars bound_vars.extend(
.extend(self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars()); self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
);
bound_vars bound_vars
} else { } else {
self.tcx.sess.delay_span_bug( self.tcx
binding.ident.span, .sess
"bad return type notation here", .delay_span_bug(binding.ident.span, "bad return type notation here");
);
vec![] vec![]
}; };
self.with(scope, |this| { self.with(scope, |this| {

View File

@ -30,10 +30,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id() == hir_id => if constant.hir_id() == hir_id =>
{ {
return tcx.types.usize return tcx.types.usize;
} }
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
return tcx.typeck(def_id).node_type(e.hir_id) return tcx.typeck(def_id).node_type(e.hir_id);
} }
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
@ -43,36 +43,38 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => false, _ => false,
}) => }) =>
{ {
return tcx.typeck(def_id).node_type(hir_id) return tcx.typeck(def_id).node_type(hir_id);
} }
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
return tcx return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx);
.adt_def(tcx.hir().get_parent_item(hir_id))
.repr()
.discr_type()
.to_ty(tcx)
} }
Node::GenericParam(&GenericParam { Node::GenericParam(&GenericParam {
def_id: param_def_id, def_id: param_def_id,
kind: GenericParamKind::Const { default: Some(ct), .. }, kind: GenericParamKind::Const { default: Some(ct), .. },
.. ..
}) if ct.hir_id == hir_id => { }) if ct.hir_id == hir_id => {
return tcx.type_of(param_def_id) return tcx
.type_of(param_def_id)
.no_bound_vars() .no_bound_vars()
.expect("const parameter types cannot be generic") .expect("const parameter types cannot be generic");
} }
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
if let Node::TraitRef(trait_ref) = tcx.hir().get( if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) =>
tcx.hir().parent_id(binding_id)
) =>
{ {
let Some(trait_def_id) = trait_ref.trait_def_id() else { let Some(trait_def_id) = trait_ref.trait_def_id() else {
return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait"); return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id),
"Could not find trait",
);
}; };
let assoc_items = tcx.associated_items(trait_def_id); let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind( let assoc_item = assoc_items.find_by_name_and_kind(
tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), tcx,
binding.ident,
ty::AssocKind::Const,
def_id.to_def_id(),
); );
return if let Some(assoc_item) = assoc_item { return if let Some(assoc_item) = assoc_item {
tcx.type_of(assoc_item.def_id) tcx.type_of(assoc_item.def_id)
@ -80,8 +82,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.expect("const parameter types cannot be generic") .expect("const parameter types cannot be generic")
} else { } else {
// FIXME(associated_const_equality): add a useful error message here. // FIXME(associated_const_equality): add a useful error message here.
Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait") Ty::new_error_with_message(
} tcx,
tcx.def_span(def_id),
"Could not find associated const on trait",
)
};
} }
// This match arm is for when the def_id appears in a GAT whose // This match arm is for when the def_id appears in a GAT whose
@ -138,7 +144,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
(generics, arg_index) (generics, arg_index)
} else { } else {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
"unexpected non-GAT usage of an anon const", "unexpected non-GAT usage of an anon const",
); );
@ -155,7 +162,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// As there is no relevant param for `def_id`, we simply return // As there is no relevant param for `def_id`, we simply return
// `None` here. // `None` here.
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
format!("unable to find type-dependent def for {parent_node_id:?}"), format!("unable to find type-dependent def for {parent_node_id:?}"),
); );
@ -196,14 +204,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
path path
} else { } else {
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
format!("unable to find const parent for {hir_id} in pat {pat:?}"), format!("unable to find const parent for {hir_id} in pat {pat:?}"),
); );
} }
} }
_ => { _ => {
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
format!("unexpected const parent path {parent_node:?}"), format!("unexpected const parent path {parent_node:?}"),
); );
@ -216,16 +226,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
let args = seg.args?; let args = seg.args?;
args.args args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
.position(|arg| arg.hir_id() == hir_id)
.map(|index| (index, seg)).or_else(|| args.bindings
.iter() .iter()
.filter_map(TypeBinding::opt_const) .filter(|arg| arg.is_ty_or_const())
.position(|ct| ct.hir_id == hir_id) .position(|arg| arg.hir_id() == hir_id)
.map(|idx| (idx, seg))) .map(|index| (index, seg))
.or_else(|| {
args.bindings
.iter()
.filter_map(TypeBinding::opt_const)
.position(|ct| ct.hir_id == hir_id)
.map(|idx| (idx, seg))
})
}) else { }) else {
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
"no arg matching AnonConst in path", "no arg matching AnonConst in path",
); );
@ -234,7 +248,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let generics = match tcx.res_generics_def_id(segment.res) { let generics = match tcx.res_generics_def_id(segment.res) {
Some(def_id) => tcx.generics_of(def_id), Some(def_id) => tcx.generics_of(def_id),
None => { None => {
return Ty::new_error_with_message(tcx, return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id), tcx.def_span(def_id),
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
); );
@ -244,10 +259,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
(generics, arg_index) (generics, arg_index)
} }
_ => return Ty::new_error_with_message(tcx, _ => {
tcx.def_span(def_id), return Ty::new_error_with_message(
format!("unexpected const parent in type_of(): {parent_node:?}"), tcx,
), tcx.def_span(def_id),
format!("unexpected const parent in type_of(): {parent_node:?}"),
);
}
}; };
debug!(?parent_node); debug!(?parent_node);

View File

@ -226,7 +226,9 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
let mut suggested = false; let mut suggested = false;
// Don't suggest setting the type params if there are some already: the order is // Don't suggest setting the type params if there are some already: the order is
// tricky to get right and the user will already know what the syntax is. // tricky to get right and the user will already know what the syntax is.
if let Some(snippet) = self.span_snippet && self.empty_generic_args { if let Some(snippet) = self.span_snippet
&& self.empty_generic_args
{
if snippet.ends_with('>') { if snippet.ends_with('>') {
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
// we would have to preserve the right order. For now, as clearly the user is // we would have to preserve the right order. For now, as clearly the user is

View File

@ -131,7 +131,9 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
} }
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { if let Node::Impl(impl2_id) = impl2_node
&& tcx.associated_item_def_ids(impl1_def_id).is_empty()
{
let base_impl_span = tcx.def_span(impl2_id); let base_impl_span = tcx.def_span(impl2_id);
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span }); tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
} }

View File

@ -316,12 +316,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
} }
// Suggest `'_` when in function parameter or elided function return. // Suggest `'_` when in function parameter or elided function return.
if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id { if let Some(fn_decl) = node.fn_decl()
&& let Some(ty_id) = ty_id
{
let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id); let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); let in_ret =
matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) { if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", "); return std::iter::repeat("'_".to_owned())
.take(num_params_to_take)
.collect::<Vec<_>>()
.join(", ");
} }
} }
@ -730,28 +736,27 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
); );
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
&& let Some(parent_node) = self.tcx.hir().find(parent_node) && let Some(parent_node) = self.tcx.hir().find(parent_node)
&& let hir::Node::Expr(expr) = parent_node { && let hir::Node::Expr(expr) = parent_node
{
match &expr.kind { match &expr.kind {
hir::ExprKind::Path(qpath) => { hir::ExprKind::Path(qpath) => self
self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
err, err,
qpath, qpath,
msg, msg,
num_assoc_fn_excess_args, num_assoc_fn_excess_args,
num_trait_generics_except_self num_trait_generics_except_self,
) ),
}, hir::ExprKind::MethodCall(..) => self
hir::ExprKind::MethodCall(..) => { .suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
err, err,
trait_, trait_,
expr, expr,
msg, msg,
num_assoc_fn_excess_args, num_assoc_fn_excess_args,
num_trait_generics_except_self num_trait_generics_except_self,
) ),
},
_ => return, _ => return,
} }
} }
@ -766,23 +771,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
num_trait_generics_except_self: usize, num_trait_generics_except_self: usize,
) { ) {
if let hir::QPath::Resolved(_, path) = qpath if let hir::QPath::Resolved(_, path) = qpath
&& let Some(trait_path_segment) = path.segments.get(0) { && let Some(trait_path_segment) = path.segments.get(0)
{
let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params(); let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args
== num_trait_generics_except_self
{ {
if let Some(span) = self.gen_args.span_ext() if let Some(span) = self.gen_args.span_ext()
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
let sugg = vec![ let sugg = vec![
(self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)), (
(span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()) self.path_segment.ident.span,
format!("{}::{}", snippet, self.path_segment.ident),
),
(span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()),
]; ];
err.multipart_suggestion( err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
msg,
sugg,
Applicability::MaybeIncorrect
);
} }
} }
} }

View File

@ -373,7 +373,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 6 | | }; // 6 | | };
// | |_____^ expected integer, found `()` // | |_____^ expected integer, found `()`
// ``` // ```
if block.expr.is_none() && block.stmts.is_empty() if block.expr.is_none()
&& block.stmts.is_empty()
&& let Some(outer_span) = &mut outer_span && let Some(outer_span) = &mut outer_span
&& let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span) && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
{ {

View File

@ -421,13 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
{ {
// Try suggesting `foo(a)` -> `a.foo()` if possible. // Try suggesting `foo(a)` -> `a.foo()` if possible.
self.suggest_call_as_method( self.suggest_call_as_method(&mut diag, segment, arg_exprs, call_expr, expected);
&mut diag,
segment,
arg_exprs,
call_expr,
expected
);
diag.emit(); diag.emit();
} }

View File

@ -373,50 +373,49 @@ impl<'a, 'tcx> CastCheck<'tcx> {
let mut sugg_mutref = false; let mut sugg_mutref = false;
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
&& fcx && fcx.can_coerce(
.can_coerce( Ty::new_ref(
Ty::new_ref(fcx.tcx, fcx.tcx,
fcx.tcx.lifetimes.re_erased, fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: expr_ty, mutbl }, TypeAndMut { ty: expr_ty, mutbl },
), ),
self.cast_ty, self.cast_ty,
) )
{ {
sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
} else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
&& expr_mutbl == Mutability::Not && expr_mutbl == Mutability::Not
&& mutbl == Mutability::Mut && mutbl == Mutability::Mut
&& fcx && fcx.can_coerce(
.can_coerce( Ty::new_ref(
Ty::new_ref(fcx.tcx, fcx.tcx,
expr_reg, expr_reg,
TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
), ),
self.cast_ty, self.cast_ty,
) )
{ {
sugg_mutref = true; sugg_mutref = true;
} }
if !sugg_mutref if !sugg_mutref
&& sugg == None && sugg == None
&& fcx && fcx.can_coerce(
.can_coerce( Ty::new_ref(fcx.tcx, reg, TypeAndMut { ty: self.expr_ty, mutbl }),
Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }), self.cast_ty,
self.cast_ty, )
)
{ {
sugg = Some((format!("&{}", mutbl.prefix_str()), false)); sugg = Some((format!("&{}", mutbl.prefix_str()), false));
} }
} else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
&& fcx && fcx.can_coerce(
.can_coerce( Ty::new_ref(
Ty::new_ref(fcx.tcx, fcx.tcx,
fcx.tcx.lifetimes.re_erased, fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: self.expr_ty, mutbl }, TypeAndMut { ty: self.expr_ty, mutbl },
), ),
self.cast_ty, self.cast_ty,
) )
{ {
sugg = Some((format!("&{}", mutbl.prefix_str()), false)); sugg = Some((format!("&{}", mutbl.prefix_str()), false));
} }
@ -942,10 +941,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::CENUM_IMPL_DROP_CAST, lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id, self.expr.hir_id,
self.span, self.span,
errors::CastEnumDrop { errors::CastEnumDrop { expr_ty, cast_ty },
expr_ty,
cast_ty,
}
); );
} }
} }

View File

@ -55,18 +55,22 @@ pub(super) fn check_fn<'a, 'tcx>(
fn_maybe_err(tcx, span, fn_sig.abi); fn_maybe_err(tcx, span, fn_sig.abi);
if let Some(kind) = body.generator_kind && can_be_generator.is_some() { if let Some(kind) = body.generator_kind
&& can_be_generator.is_some()
{
let yield_ty = if kind == hir::GeneratorKind::Gen { let yield_ty = if kind == hir::GeneratorKind::Gen {
let yield_ty = fcx let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); kind: TypeVariableOriginKind::TypeInference,
span,
});
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
yield_ty yield_ty
} else { } else {
Ty::new_unit(tcx,) Ty::new_unit(tcx)
}; };
// Resume type defaults to `()` if the generator has no argument. // Resume type defaults to `()` if the generator has no argument.
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,)); let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx));
fcx.resume_yield_tys = Some((resume_ty, yield_ty)); fcx.resume_yield_tys = Some((resume_ty, yield_ty));
} }
@ -173,7 +177,9 @@ pub(super) fn check_fn<'a, 'tcx>(
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig); check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
} }
if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { if let Some(lang_start_defid) = tcx.lang_items().start_fn()
&& lang_start_defid == fn_def_id.to_def_id()
{
check_lang_start_fn(tcx, fn_sig, fn_def_id); check_lang_start_fn(tcx, fn_sig, fn_def_id);
} }

View File

@ -228,7 +228,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Given a Projection predicate, we can potentially infer // Given a Projection predicate, we can potentially infer
// the complete signature. // the complete signature.
if expected_sig.is_none() if expected_sig.is_none()
&& let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) =
bound_predicate.skip_binder()
{ {
let inferred_sig = self.normalize( let inferred_sig = self.normalize(
span, span,

View File

@ -1619,8 +1619,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
unsized_return = self.is_return_ty_definitely_unsized(fcx); unsized_return = self.is_return_ty_definitely_unsized(fcx);
} }
if let Some(expression) = expression if let Some(expression) = expression
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind
intravisit::walk_block(& mut visitor, loop_blk); {
intravisit::walk_block(&mut visitor, loop_blk);
} }
} }
ObligationCauseCode::ReturnValue(id) => { ObligationCauseCode::ReturnValue(id) => {
@ -1661,7 +1662,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
); );
} }
if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { if visitor.ret_exprs.len() > 0
&& let Some(expr) = expression
{
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
} }
@ -1723,7 +1726,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let parent_id = fcx.tcx.hir().parent_id(id); let parent_id = fcx.tcx.hir().parent_id(id);
let parent = fcx.tcx.hir().get(parent_id); let parent = fcx.tcx.hir().get(parent_id);
if let Some(expr) = expression if let Some(expr) = expression
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent && let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
..
}) = parent
&& !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..)) && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
{ {
fcx.suggest_missing_semicolon(&mut err, expr, expected, true); fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
@ -1798,12 +1804,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
&& let Some(fn_sig) = fcx.body_fn_sig() && let Some(fn_sig) = fcx.body_fn_sig()
&& fn_sig.output().is_ty_var() && fn_sig.output().is_ty_var()
{ {
err.span_note( err.span_note(sp, format!("return type inferred to be `{expected}` here"));
sp,
format!(
"return type inferred to be `{expected}` here"
),
);
} }
err err

View File

@ -151,7 +151,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let [segment] = path.segments && let [segment] = path.segments
&& segment.ident.name.as_str() == name && segment.ident.name.as_str() == name
&& let Res::Local(hir_id) = path.res && let Res::Local(hir_id) = path.res
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2) && let Some((_, hir::Node::Expr(match_expr))) =
self.tcx.hir().parent_iter(hir_id).nth(2)
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind && let hir::ExprKind::Tup(exprs) = scrutinee.kind
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
@ -450,20 +451,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If our binding became incompatible while it was a receiver // If our binding became incompatible while it was a receiver
// to a method call, we may be able to make a better guess to // to a method call, we may be able to make a better guess to
// the source of a type mismatch. // the source of a type mismatch.
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else {
continue;
};
let rcvr_ty = rcvr_ty.fold_with(&mut fudger); let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let Ok(method) = let Ok(method) = self.lookup_method_for_diagnostic(
self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) rcvr_ty,
else { segment,
DUMMY_SP,
parent_expr,
rcvr,
) else {
continue; continue;
}; };
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let ideal_method = self let ideal_method = self
.lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) .lookup_method_for_diagnostic(
ideal_rcvr_ty,
segment,
DUMMY_SP,
parent_expr,
rcvr,
)
.ok() .ok()
.and_then(|method| { .and_then(|method| {
let _ = self.at(&ObligationCause::dummy(), self.param_env) let _ = self
.at(&ObligationCause::dummy(), self.param_env)
.eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty) .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
.ok()?; .ok()?;
Some(method) Some(method)
@ -474,15 +488,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (idx, (expected_arg_ty, arg_expr)) in for (idx, (expected_arg_ty, arg_expr)) in
std::iter::zip(&method.sig.inputs()[1..], args).enumerate() std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
{ {
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else {
continue;
};
let arg_ty = arg_ty.fold_with(&mut fudger); let arg_ty = arg_ty.fold_with(&mut fudger);
let _ = self.coerce( let _ =
arg_expr, self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
arg_ty,
*expected_arg_ty,
AllowTwoPhase::No,
None,
);
self.select_obligations_where_possible(|errs| { self.select_obligations_where_possible(|errs| {
// Yeet the errors, we're already reporting errors. // Yeet the errors, we're already reporting errors.
errs.clear(); errs.clear();
@ -648,10 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => self.tcx.types.unit, None => self.tcx.types.unit,
}; };
if self.can_eq(self.param_env, ty, expected) { if self.can_eq(self.param_env, ty, expected) {
err.span_label( err.span_label(ex.span, "expected because of this `break`");
ex.span,
"expected because of this `break`",
);
exit = true; exit = true;
} }
} }
@ -1410,10 +1418,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
let bind = self.tcx.hir().find(*bind_hir_id); let bind = self.tcx.hir().find(*bind_hir_id);
let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id)); let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind && if let Some(hir::Node::Pat(hir::Pat {
let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent { kind: hir::PatKind::Binding(_, _hir_id, _, _),
return true; ..
} })) = bind
&& let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent
{
return true;
}
} }
return false; return false;
} }
@ -1507,10 +1519,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ``` // ```
let ref_ty = match mutability { let ref_ty = match mutability {
hir::Mutability::Mut => { hir::Mutability::Mut => {
Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
} }
hir::Mutability::Not => { hir::Mutability::Not => {
Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
} }
}; };
if self.can_coerce(ref_ty, expected) { if self.can_coerce(ref_ty, expected) {
@ -1566,7 +1578,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)); ));
} }
let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
{
Some(ident) => format!("{ident}: "), Some(ident) => format!("{ident}: "),
None => String::new(), None => String::new(),
}; };
@ -1611,8 +1624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let make_sugg = |start: Span, end: BytePos| { let make_sugg = |start: Span, end: BytePos| {
// skip `(` for tuples such as `(c) = (&123)`. // skip `(` for tuples such as `(c) = (&123)`.
// make sure we won't suggest like `(c) = 123)` which is incorrect. // make sure we won't suggest like `(c) = 123)` which is incorrect.
let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace()) let sp = sm
.map_or(start, |s| s.shrink_to_hi()); .span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
.map_or(start, |s| s.shrink_to_hi());
Some(( Some((
vec![(sp.with_hi(end), String::new())], vec![(sp.with_hi(end), String::new())],
"consider removing the borrow".to_string(), "consider removing the borrow".to_string(),
@ -1635,12 +1649,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.find(|&s| sp.contains(s)) .find(|&s| sp.contains(s))
&& sm.is_span_accessible(call_span) && sm.is_span_accessible(call_span)
{ {
return make_sugg(sp, call_span.lo()) return make_sugg(sp, call_span.lo());
} }
return None; return None;
} }
if sp.contains(expr.span) && sm.is_span_accessible(expr.span) { if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
return make_sugg(sp, expr.span.lo()) return make_sugg(sp, expr.span.lo());
} }
} }
( (
@ -1760,10 +1774,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
}; };
let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { let prefix =
Some(ident) => format!("{ident}: "), match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
None => String::new(), Some(ident) => format!("{ident}: "),
}; None => String::new(),
};
let (span, suggestion) = if self.is_else_if_block(expr) { let (span, suggestion) = if self.is_else_if_block(expr) {
// Don't suggest nonsense like `else *if` // Don't suggest nonsense like `else *if`

View File

@ -717,7 +717,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ... except when we try to 'break rust;'. // ... except when we try to 'break rust;'.
// ICE this expression in particular (see #43162). // ICE this expression in particular (see #43162).
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind { if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
if let [segment] = path.segments && segment.ident.name == sym::rust { if let [segment] = path.segments
&& segment.ident.name == sym::rust
{
fatally_break_rust(self.tcx); fatally_break_rust(self.tcx);
} }
} }
@ -826,7 +828,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let ExprKind::Block(body, _) = return_expr.kind && let ExprKind::Block(body, _) = return_expr.kind
&& let Some(last_expr) = body.expr && let Some(last_expr) = body.expr
{ {
span = last_expr.span; span = last_expr.span;
} }
ret_coercion.borrow_mut().coerce( ret_coercion.borrow_mut().coerce(
self, self,
@ -841,7 +843,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Point any obligations that were registered due to opaque type // Point any obligations that were registered due to opaque type
// inference at the return expression. // inference at the return expression.
self.select_obligations_where_possible(|errors| { self.select_obligations_where_possible(|errors| {
self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty, return_expr.span); self.point_at_return_for_opaque_ty_error(
errors,
span,
return_expr_ty,
return_expr.span,
);
}); });
} }
} }
@ -1402,7 +1409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
&& let Some(span) = self.tcx.hir().opt_span(hir_id) && let Some(span) = self.tcx.hir().opt_span(hir_id)
{ {
match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { match self
.tcx
.sess
.diagnostic()
.steal_diagnostic(span, StashKey::UnderscoreForArrayLengths)
{
Some(mut err) => { Some(mut err) => {
err.span_suggestion( err.span_suggestion(
span, span,
@ -1412,7 +1424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
err.emit(); err.emit();
} }
None => () None => (),
} }
} }
} }
@ -1931,11 +1943,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut Diagnostic, err: &mut Diagnostic,
) { ) {
// I don't use 'is_range_literal' because only double-sided, half-open ranges count. // I don't use 'is_range_literal' because only double-sided, half-open ranges count.
if let ExprKind::Struct( if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) =
QPath::LangItem(LangItem::Range, ..), last_expr_field.expr.kind
[range_start, range_end],
_,
) = last_expr_field.expr.kind
&& let variant_field = && let variant_field =
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident) variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
&& let range_def_id = self.tcx.lang_items().range_struct() && let range_def_id = self.tcx.lang_items().range_struct()
@ -1970,13 +1979,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.sess .sess
.source_map() .source_map()
.span_extend_while(range_start.span, |c| c.is_whitespace()) .span_extend_while(range_start.span, |c| c.is_whitespace())
.unwrap_or(range_start.span).shrink_to_hi().to(range_end.span); .unwrap_or(range_start.span)
.shrink_to_hi()
.to(range_end.span);
err.subdiagnostic(TypeMismatchFruTypo { err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
expr_span: range_start.span,
fru_span,
expr,
});
} }
} }
@ -2293,7 +2300,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some('e') | Some('E') => { Some('e') | Some('E') => {
chars.next(); chars.next();
if let Some(c) = chars.peek() if let Some(c) = chars.peek()
&& !c.is_numeric() && *c != '-' && *c != '+' && !c.is_numeric()
&& *c != '-'
&& *c != '+'
{ {
return false; return false;
} }
@ -2421,7 +2430,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
self.suggest_fn_call(&mut err, base, base_ty, |output_ty| { self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() { if let ty::Adt(def, _) = output_ty.kind()
&& !def.is_enum()
{
def.non_enum_variant().fields.iter().any(|field| { def.non_enum_variant().fields.iter().any(|field| {
field.ident(self.tcx) == ident field.ident(self.tcx) == ident
&& field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) && field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
@ -2842,9 +2853,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// fixed expression: // fixed expression:
if let ExprKind::Lit(ref lit) = idx.kind if let ExprKind::Lit(ref lit) = idx.kind
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
&& i < types.len().try_into().expect("expected tuple index to be < usize length") && i < types
.len()
.try_into()
.expect("expected tuple index to be < usize length")
{ {
err.span_suggestion( err.span_suggestion(
brackets_span, brackets_span,
"to access tuple elements, use", "to access tuple elements, use",
@ -2853,7 +2866,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
needs_note = false; needs_note = false;
} else if let ExprKind::Path(..) = idx.peel_borrows().kind { } else if let ExprKind::Path(..) = idx.peel_borrows().kind {
err.span_label(idx.span, "cannot access tuple elements at a variable index"); err.span_label(
idx.span,
"cannot access tuple elements at a variable index",
);
} }
if needs_note { if needs_note {
err.help( err.help(

View File

@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// type, `?T` is not considered unsolved, but `?I` is. The // type, `?T` is not considered unsolved, but `?I` is. The
// same is true for float variables.) // same is true for float variables.)
let fallback = match ty.kind() { let fallback = match ty.kind() {
_ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match diverging_fallback.get(&ty) { _ => match diverging_fallback.get(&ty) {

View File

@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
match self.typeck_results.borrow().node_types().get(id) { match self.typeck_results.borrow().node_types().get(id) {
Some(&t) => t, Some(&t) => t,
None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
None => { None => {
bug!( bug!(
"no type for node {} in fcx {}", "no type for node {} in fcx {}",
@ -459,7 +459,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> { pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
match self.typeck_results.borrow().node_types().get(id) { match self.typeck_results.borrow().node_types().get(id) {
Some(&t) => Some(t), Some(&t) => Some(t),
None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)), None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx, e)),
None => None, None => None,
} }
} }
@ -713,7 +713,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::GenericArgKind::Type(ty) = ty.unpack() if let ty::GenericArgKind::Type(ty) = ty.unpack()
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
&& let Some(def_id) = def_id.as_local() && let Some(def_id) = def_id.as_local()
&& self.opaque_type_origin(def_id).is_some() { && self.opaque_type_origin(def_id).is_some()
{
return None; return None;
} }
} }
@ -833,7 +834,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
.and_then(|r| { .and_then(|r| {
// lint bare trait if the method is found in the trait // lint bare trait if the method is found in the trait
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if span.edition().at_least_rust_2021()
&& let Some(mut diag) = self
.tcx
.sess
.diagnostic()
.steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
{
diag.emit(); diag.emit();
} }
Ok(r) Ok(r)
@ -863,7 +870,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
// emit or cancel the diagnostic for bare traits // emit or cancel the diagnostic for bare traits
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if span.edition().at_least_rust_2021()
&& let Some(mut diag) = self
.tcx
.sess
.diagnostic()
.steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
{
if trait_missing_method { if trait_missing_method {
// cancel the diag for bare traits when meeting `MyTrait::missing_method` // cancel the diag for bare traits when meeting `MyTrait::missing_method`
diag.cancel(); diag.cancel();
@ -949,12 +962,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: hir::ItemKind::Fn(ref sig, ..), kind: hir::ItemKind::Fn(ref sig, ..),
owner_id, owner_id,
.. ..
})) = self.tcx.hir().find_parent(hir_id) => Some(( })) = self.tcx.hir().find_parent(hir_id) =>
hir::HirId::make_owner(owner_id.def_id), {
&sig.decl, Some((
ident, hir::HirId::make_owner(owner_id.def_id),
ident.name != sym::main, &sig.decl,
)), ident,
ident.name != sym::main,
))
}
_ => None, _ => None,
} }
} }
@ -1077,11 +1093,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut user_self_ty = None; let mut user_self_ty = None;
let mut is_alias_variant_ctor = false; let mut is_alias_variant_ctor = false;
match res { match res {
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => {
if let Some(self_ty) = self_ty =>
{
let adt_def = self_ty.normalized.ty_adt_def().unwrap(); let adt_def = self_ty.normalized.ty_adt_def().unwrap();
user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); user_self_ty =
Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
is_alias_variant_ctor = true; is_alias_variant_ctor = true;
} }
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
@ -1090,9 +1105,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let container_id = assoc_item.container_id(tcx); let container_id = assoc_item.container_id(tcx);
debug!(?def_id, ?container, ?container_id); debug!(?def_id, ?container, ?container_id);
match container { match container {
ty::TraitContainer => { ty::TraitContainer => callee::check_legal_trait_for_method_call(
callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id) tcx,
} span,
None,
span,
container_id,
),
ty::ImplContainer => { ty::ImplContainer => {
if segments.len() == 1 { if segments.len() == 1 {
// `<T>::assoc` will end up here, and so // `<T>::assoc` will end up here, and so
@ -1478,12 +1497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(normalized_ty) => normalized_ty, Ok(normalized_ty) => normalized_ty,
Err(errors) => { Err(errors) => {
let guar = self.err_ctxt().report_fulfillment_errors(errors); let guar = self.err_ctxt().report_fulfillment_errors(errors);
return Ty::new_error(self.tcx,guar); return Ty::new_error(self.tcx, guar);
} }
} }
} else { } else {
ty ty
} }
} }
/// Resolves `ty` by a single level if `ty` is a type variable. /// Resolves `ty` by a single level if `ty` is a type variable.

View File

@ -129,21 +129,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false; return false;
} }
for param in for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter() .into_iter()
.flatten() .flatten()
{ {
if self.blame_specific_arg_if_possible( if self.blame_specific_arg_if_possible(
error, error,
def_id, def_id,
param, param,
*call_hir_id, *call_hir_id,
callee.span, callee.span,
None, None,
args, args,
) ) {
{
return true; return true;
} }
} }
@ -346,8 +344,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
&& let generics = self.0.tcx.generics_of(self.1) && let generics = self.0.tcx.generics_of(self.1)
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
&& let Some(subst) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1) && let Some(subst) =
.get(index as usize) ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
{ {
ControlFlow::Break(*subst) ControlFlow::Break(*subst)
} else { } else {
@ -364,11 +362,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span, span: Span,
) -> bool { ) -> bool {
if let traits::FulfillmentErrorCode::CodeSelectionError( if let traits::FulfillmentErrorCode::CodeSelectionError(
traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{ traits::SelectionError::OutputTypeParameterMismatch(
expected_trait_ref, .. box traits::SelectionOutputTypeParameterMismatch { expected_trait_ref, .. },
}), ),
) = error.code ) = error.code
&& let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind() && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) =
expected_trait_ref.skip_binder().self_ty().kind()
&& span.overlaps(self.tcx.def_span(*def_id)) && span.overlaps(self.tcx.def_span(*def_id))
{ {
true true
@ -446,10 +445,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect(); .collect();
// If there's one field that references the given generic, great! // If there's one field that references the given generic, great!
if let [(idx, _)] = args_referencing_param.as_slice() if let [(idx, _)] = args_referencing_param.as_slice()
&& let Some(arg) = receiver && let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| {
.map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }
})
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); {
error.obligation.cause.span = arg
.span
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
.unwrap_or(arg.span);
if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) { if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
// This is more specific than pointing at the entire argument. // This is more specific than pointing at the entire argument.
@ -934,16 +937,16 @@ fn find_param_in_ty<'tcx>(
return true; return true;
} }
if let ty::GenericArgKind::Type(ty) = arg.unpack() if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind() && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
{ {
// This logic may seem a bit strange, but typically when // This logic may seem a bit strange, but typically when
// we have a projection type in a function signature, the // we have a projection type in a function signature, the
// argument that's being passed into that signature is // argument that's being passed into that signature is
// not actually constraining that projection's args in // not actually constraining that projection's args in
// a meaningful way. So we skip it, and see improvements // a meaningful way. So we skip it, and see improvements
// in some UI tests. // in some UI tests.
walk.skip_current_subtree(); walk.skip_current_subtree();
} }
} }
false false
} }

View File

@ -652,7 +652,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
{ {
// Wrap up the N provided arguments starting at this position in a tuple. // Wrap up the N provided arguments starting at this position in a tuple.
let provided_as_tuple = Ty::new_tup_from_iter(tcx, let provided_as_tuple = Ty::new_tup_from_iter(
tcx,
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
); );
@ -884,8 +885,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.tcx.def_kind(fn_def_id).is_fn_like() && self.tcx.def_kind(fn_def_id).is_fn_like()
&& let self_implicit = && let self_implicit =
matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
&& let Some(arg) = self.tcx.fn_arg_names(fn_def_id) && let Some(arg) =
.get(expected_idx.as_usize() + self_implicit) self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
&& arg.name != kw::SelfLower && arg.name != kw::SelfLower
{ {
format!("/* {} */", arg.name) format!("/* {} */", arg.name)
@ -946,9 +947,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& error_span.can_be_used_for_suggestions() && error_span.can_be_used_for_suggestions()
{ {
if arg_idx.index() > 0 if arg_idx.index() > 0
&& let Some((_, prev)) = provided_arg_tys && let Some((_, prev)) =
.get(ProvidedIdx::from_usize(arg_idx.index() - 1) provided_arg_tys.get(ProvidedIdx::from_usize(arg_idx.index() - 1))
) { {
// Include previous comma // Include previous comma
span = prev.shrink_to_hi().to(span); span = prev.shrink_to_hi().to(span);
} }
@ -1291,7 +1292,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>, err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>,
) { ) {
if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind() if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind()
&& let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = provided_ty.kind() && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) =
provided_ty.kind()
&& let hir::ExprKind::Call(callee, _) = arg.kind && let hir::ExprKind::Call(callee, _) = arg.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
&& let Res::Def(_, def_id) = path.res && let Res::Def(_, def_id) = path.res
@ -1299,9 +1301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
// The user provided `ptr::null()`, but the function expects // The user provided `ptr::null()`, but the function expects
// `ptr::null_mut()`. // `ptr::null_mut()`.
err.subdiagnostic(SuggestPtrNullMut { err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
span: arg.span
});
} }
} }
@ -1928,8 +1928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let callee_ty = callee_ty.peel_refs(); let callee_ty = callee_ty.peel_refs();
match *callee_ty.kind() { match *callee_ty.kind() {
ty::Param(param) => { ty::Param(param) => {
let param = let param = self.tcx.generics_of(self.body_id).type_param(&param, self.tcx);
self.tcx.generics_of(self.body_id).type_param(&param, self.tcx);
if param.kind.is_synthetic() { if param.kind.is_synthetic() {
// if it's `impl Fn() -> ..` then just fall down to the def-id based logic // if it's `impl Fn() -> ..` then just fall down to the def-id based logic
def_id = param.def_id; def_id = param.def_id;
@ -1943,8 +1942,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(compiler-errors): This could be problematic if something has two // FIXME(compiler-errors): This could be problematic if something has two
// fn-like predicates with different args, but callable types really never // fn-like predicates with different args, but callable types really never
// do that, so it's OK. // do that, so it's OK.
for (predicate, span) in instantiated for (predicate, span) in instantiated {
{
if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder() if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty && pred.self_ty().peel_refs() == callee_ty
&& self.tcx.is_fn_trait(pred.def_id()) && self.tcx.is_fn_trait(pred.def_id())
@ -1963,7 +1961,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => { _ => {
// Look for a user-provided impl of a `Fn` trait, and point to it. // Look for a user-provided impl of a `Fn` trait, and point to it.
let new_def_id = self.probe(|_| { let new_def_id = self.probe(|_| {
let trait_ref = ty::TraitRef::new(self.tcx, let trait_ref = ty::TraitRef::new(
self.tcx,
call_kind.to_def_id(self.tcx), call_kind.to_def_id(self.tcx),
[ [
callee_ty, callee_ty,
@ -1995,7 +1994,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { if let Some(def_span) = self.tcx.def_ident_span(def_id)
&& !def_span.is_dummy()
{
let mut spans: MultiSpan = def_span.into(); let mut spans: MultiSpan = def_span.into();
let params = self let params = self
@ -2025,7 +2026,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Try to find earlier invocations of this closure to find if the type mismatch // Try to find earlier invocations of this closure to find if the type mismatch
// is because of inference. If we find one, point at them. // is because of inference. If we find one, point at them.
let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] }; let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
let node = self.tcx let node = self
.tcx
.opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id)) .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id))
.and_then(|hir_id| self.tcx.hir().find(hir_id)); .and_then(|hir_id| self.tcx.hir().find(hir_id));
match node { match node {

View File

@ -254,22 +254,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'tcx>, expr: &hir::Expr<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
) -> bool { ) -> bool {
if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) = expr.kind && if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) && expr.kind
self.can_coerce(recv_ty, expected) { && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) { && self.can_coerce(recv_ty, expected)
expr.span.with_lo(recv_span.hi()) {
} else { let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1)) expr.span.with_lo(recv_span.hi())
}; } else {
err.span_suggestion_verbose( expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1))
span, };
"try removing the method call", err.span_suggestion_verbose(
"", span,
Applicability::MachineApplicable, "try removing the method call",
); "",
return true; Applicability::MachineApplicable,
} );
return true;
}
false false
} }
@ -347,10 +349,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let name = self.tcx.item_name(def_id); let name = self.tcx.item_name(def_id);
let kind = self.tcx.def_kind(def_id); let kind = self.tcx.def_kind(def_id);
if let DefKind::Ctor(of, CtorKind::Fn) = kind { if let DefKind::Ctor(of, CtorKind::Fn) = kind {
err.span_label(sp, format!("`{name}` defines {} constructor here, which should be called", match of { err.span_label(
CtorOf::Struct => "a struct", sp,
CtorOf::Variant => "an enum variant", format!(
})); "`{name}` defines {} constructor here, which should be called",
match of {
CtorOf::Struct => "a struct",
CtorOf::Variant => "an enum variant",
}
),
);
} else { } else {
let descr = self.tcx.def_kind_descr(kind, def_id); let descr = self.tcx.def_kind_descr(kind, def_id);
err.span_label(sp, format!("{descr} `{name}` defined here")); err.span_label(sp, format!("{descr} `{name}` defined here"));
@ -370,25 +378,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(method_ident) = receiver_method_ident if let Some(method_ident) = receiver_method_ident
&& method_ident.name == conversion_method.name && method_ident.name == conversion_method.name
{ {
return None // do not suggest code that is already there (#53348) return None; // do not suggest code that is already there (#53348)
} }
let method_call_list = [sym::to_vec, sym::to_string]; let method_call_list = [sym::to_vec, sym::to_string];
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
&& receiver_method.ident.name == sym::clone && receiver_method.ident.name == sym::clone
&& method_call_list.contains(&conversion_method.name) && method_call_list.contains(&conversion_method.name)
// If receiver is `.clone()` and found type has one of those methods, // If receiver is `.clone()` and found type has one of those methods,
// we guess that the user wants to convert from a slice type (`&[]` or `&str`) // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
// to an owned type (`Vec` or `String`). These conversions clone internally, // to an owned type (`Vec` or `String`). These conversions clone internally,
// so we remove the user's `clone` call. // so we remove the user's `clone` call.
{
vec![(
receiver_method.ident.span,
conversion_method.name.to_string()
)]
} else if expr.precedence().order()
< ExprPrecedence::MethodCall.order()
{ {
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
} else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
vec![ vec![
(expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
@ -431,7 +434,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
// `as_ref` and `as_deref` compatibility. // `as_ref` and `as_deref` compatibility.
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected) self.can_eq(
self.param_env,
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found),
expected,
)
}); });
// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
// but those checks need to be a bit more delicate and the benefit is diminishing. // but those checks need to be a bit more delicate and the benefit is diminishing.
@ -770,41 +777,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
if let Some(found) = found.make_suggestable(self.tcx, false) { if let Some(found) = found.make_suggestable(self.tcx, false) {
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
span,
found: found.to_string(),
});
return true; return true;
} else if let ty::Closure(_, args) = found.kind() } else if let ty::Closure(_, args) = found.kind()
// FIXME(compiler-errors): Get better at printing binders... // FIXME(compiler-errors): Get better at printing binders...
&& let closure = args.as_closure() && let closure = args.as_closure()
&& closure.sig().is_suggestable(self.tcx, false) && closure.sig().is_suggestable(self.tcx, false)
{ {
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
span,
found: closure.print_as_impl_trait().to_string(),
});
return true; return true;
} else { } else {
// FIXME: if `found` could be `impl Iterator` we should suggest that. // FIXME: if `found` could be `impl Iterator` we should suggest that.
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
return true return true;
} }
} }
hir::FnRetTy::Return(hir_ty) => { hir::FnRetTy::Return(hir_ty) => {
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
&& let hir::Node::Item(hir::Item { && let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(op_ty), kind: hir::ItemKind::OpaqueTy(op_ty), ..
..
}) = self.tcx.hir().get(item_id.hir_id()) }) = self.tcx.hir().get(item_id.hir_id())
&& let [hir::GenericBound::LangItemTrait( && let [
hir::LangItem::Future, _, _, generic_args)] = op_ty.bounds hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args),
] = op_ty.bounds
&& let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } =
ty_binding.kind
{ {
// Check if async function's return type was omitted. // Check if async function's return type was omitted.
// Don't emit suggestions if the found type is `impl Future<...>`. // Don't emit suggestions if the found type is `impl Future<...>`.
debug!(?found); debug!(?found);
if found.is_suggestable(self.tcx, false) { if found.is_suggestable(self.tcx, false) {
if term.span.is_empty() { if term.span.is_empty() {
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span: term.span, found: found.to_string() }); err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
span: term.span,
found: found.to_string(),
});
return true; return true;
} else { } else {
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: term.span, expected }); err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
span: term.span,
expected,
});
} }
} }
} else { } else {
@ -819,7 +839,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.normalize(hir_ty.span, ty); let ty = self.normalize(hir_ty.span, ty);
let ty = self.tcx.erase_late_bound_regions(ty); let ty = self.tcx.erase_late_bound_regions(ty);
if self.can_coerce(expected, ty) { if self.can_coerce(expected, ty) {
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected }); err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
span: hir_ty.span,
expected,
});
self.try_suggest_return_impl_trait(err, expected, ty, fn_id); self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
return true; return true;
} }
@ -1077,13 +1100,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.type_implements_trait( .type_implements_trait(
clone_trait_def, clone_trait_def,
[self.tcx.erase_regions(expected_ty)], [self.tcx.erase_regions(expected_ty)],
self.param_env self.param_env,
) )
.must_apply_modulo_regions() .must_apply_modulo_regions()
{ {
let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!(": {ident}.clone()"), Some(ident) => format!(": {ident}.clone()"),
None => ".clone()".to_string() None => ".clone()".to_string(),
}; };
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
@ -1093,7 +1116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
return true; return true;
} }
false false
} }
@ -1121,31 +1144,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr_inner_ty = args.type_at(0); let expr_inner_ty = args.type_at(0);
let expected_inner_ty = expected_args.type_at(0); let expected_inner_ty = expected_args.type_at(0);
if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind() if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, ty, expected_inner_ty) && self.can_eq(self.param_env, ty, expected_inner_ty)
{
let def_path = self.tcx.def_path_str(adt_def.did());
let span = expr.span.shrink_to_hi();
let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) {
errors::OptionResultRefMismatch::Copied { span, def_path }
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
ty,
clone_did,
)
{ {
let def_path = self.tcx.def_path_str(adt_def.did()); errors::OptionResultRefMismatch::Cloned { span, def_path }
let span = expr.span.shrink_to_hi(); } else {
let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { return false;
errors::OptionResultRefMismatch::Copied { };
span, def_path diag.subdiagnostic(subdiag);
} return true;
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait() }
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
ty,
clone_did,
)
{
errors::OptionResultRefMismatch::Cloned {
span, def_path
}
} else {
return false;
};
diag.subdiagnostic(subdiag);
return true;
}
} }
false false
@ -1181,14 +1200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx, self.tcx,
self.misc(expr.span), self.misc(expr.span),
self.param_env, self.param_env,
ty::TraitRef::new(self.tcx, ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
into_def_id,
[expr_ty, expected_ty]
),
)) ))
{ {
let mut span = expr.span; let mut span = expr.span;
while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() while expr.span.eq_ctxt(span)
&& let Some(parent_callsite) = span.parent_callsite()
{ {
span = parent_callsite; span = parent_callsite;
} }
@ -1196,7 +1213,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sugg = if expr.precedence().order() >= PREC_POSTFIX { let sugg = if expr.precedence().order() >= PREC_POSTFIX {
vec![(span.shrink_to_hi(), ".into()".to_owned())] vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else { } else {
vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())] vec![
(span.shrink_to_lo(), "(".to_owned()),
(span.shrink_to_hi(), ").into()".to_owned()),
]
}; };
diag.multipart_suggestion( diag.multipart_suggestion(
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
@ -1238,9 +1258,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// since the user probably just misunderstood how `let else` // since the user probably just misunderstood how `let else`
// and `&&` work together. // and `&&` work together.
if let Some((_, hir::Node::Local(local))) = cond_parent if let Some((_, hir::Node::Local(local))) = cond_parent
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
&local.pat.kind
&& let hir::QPath::Resolved(None, path) = qpath && let hir::QPath::Resolved(None, path) = qpath
&& let Some(did) = path.res.opt_def_id() && let Some(did) = path
.res
.opt_def_id()
.and_then(|did| self.tcx.opt_parent(did)) .and_then(|did| self.tcx.opt_parent(did))
.and_then(|did| self.tcx.opt_parent(did)) .and_then(|did| self.tcx.opt_parent(did))
&& self.tcx.is_diagnostic_item(sym::Option, did) && self.tcx.is_diagnostic_item(sym::Option, did)
@ -1607,7 +1630,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.. ..
}) => { }) => {
let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) = let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) =
self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else { self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id))
else {
return expr; return expr;
}; };
@ -1634,12 +1658,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to worry if it's a call to a typed function or closure as this would ne handled // to worry if it's a call to a typed function or closure as this would ne handled
// previously. // previously.
hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => { hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) =
&& let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path call_expr_kind
&& let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding) && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
call_expr_path
&& let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) =
self.tcx.hir().find(*binding)
&& let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) && let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id))
&& let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure && let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure
&& let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init && let Expr {
kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
..
} = init
{ {
let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id); let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
self.note_type_is_not_clone_inner_expr(body_expr) self.note_type_is_not_clone_inner_expr(body_expr)

View File

@ -129,25 +129,29 @@ impl<'tcx> Inherited<'tcx> {
let infer_var_info = &mut self.infer_var_info.borrow_mut(); let infer_var_info = &mut self.infer_var_info.borrow_mut();
// (*) binder skipped // (*) binder skipped
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder() if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) =
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) obligation.predicate.kind().skip_binder()
&& let Some(ty) =
self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
{ {
let new_self_ty = self.tcx.types.unit; let new_self_ty = self.tcx.types.unit;
// Then construct a new obligation with Self = () added // Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds. // to the ParamEnv, and see if it holds.
let o = obligation.with(self.tcx, let o = obligation.with(
obligation self.tcx,
.predicate obligation.predicate.kind().rebind(
.kind() // (*) binder moved here
.rebind( ty::PredicateKind::Clause(ty::ClauseKind::Trait(
// (*) binder moved here tpred.with_self_ty(self.tcx, new_self_ty),
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) )),
), ),
); );
// Don't report overflow errors. Otherwise equivalent to may_hold. // Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() { if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o))
&& result.may_apply()
{
infer_var_info.entry(ty).or_default().self_in_trait = true; infer_var_info.entry(ty).or_default().self_in_trait = true;
} }
} }

View File

@ -70,7 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Special-case transmuting from `typeof(function)` and // Special-case transmuting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error. // `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(tcx, from); let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to)
&& size_to == Pointer(dl.instruction_address_space).size(&tcx)
{
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
.note(format!("source type: {from}")) .note(format!("source type: {from}"))
.note(format!("target type: {to}")) .note(format!("target type: {to}"))

View File

@ -667,8 +667,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// will still match the original object type, but it won't pollute our // will still match the original object type, but it won't pollute our
// type variables in any form, so just do that! // type variables in any form, so just do that!
let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
self.fcx self.fcx.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty);
self.assemble_inherent_impl_candidates_for_type(p.def_id()); self.assemble_inherent_impl_candidates_for_type(p.def_id());
@ -1690,15 +1689,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
} }
debug!( debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty);
"comparing return_ty {:?} with xform ret ty {:?}",
return_ty, xform_ret_ty
);
if let ProbeResult::Match = result if let ProbeResult::Match = result
&& self && self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty) .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
.is_err() .is_err()
{ {
result = ProbeResult::BadReturnType; result = ProbeResult::BadReturnType;
} }
@ -1959,15 +1955,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some(nested) = v.meta_item_list() { if let Some(nested) = v.meta_item_list() {
// #[doc(alias("foo", "bar"))] // #[doc(alias("foo", "bar"))]
for n in nested { for n in nested {
if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() { if let Some(lit) = n.lit()
&& name.as_str() == lit.symbol.as_str()
{
return true; return true;
} }
} }
} else if let Some(meta) = v.meta_item() } else if let Some(meta) = v.meta_item()
&& let Some(lit) = meta.name_value_literal() && let Some(lit) = meta.name_value_literal()
&& name.as_str() == lit.symbol.as_str() { && name.as_str() == lit.symbol.as_str()
// #[doc(alias = "foo")] {
return true; // #[doc(alias = "foo")]
return true;
} }
} }
} }

View File

@ -305,8 +305,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mode = no_match_data.mode; let mode = no_match_data.mode;
let tcx = self.tcx; let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method let ((mut ty_str, ty_file), short_ty_str) =
&& let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string())) ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
} else { } else {
(tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string())) (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
@ -377,9 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.is_diagnostic_item(sym::write_macro, def_id) tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_name.name == Symbol::intern("write_fmt"); }) && item_name.name == Symbol::intern("write_fmt");
let mut err = if is_write let mut err = if is_write && let Some(args) = args {
&& let Some(args) = args
{
self.suggest_missing_writer(rcvr_ty, args) self.suggest_missing_writer(rcvr_ty, args)
} else { } else {
tcx.sess.create_err(NoAssociatedItem { tcx.sess.create_err(NoAssociatedItem {
@ -421,9 +419,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source { if let Mode::MethodCall = mode
&& let SelfSource::MethodCall(cal) = source
{
self.suggest_await_before_method( self.suggest_await_before_method(
&mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self), &mut err,
item_name,
rcvr_ty,
cal,
span,
expected.only_has_type(self),
); );
} }
if let Some(span) = if let Some(span) =
@ -863,7 +868,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter_map(|(pred, parent_pred, _cause)| { .filter_map(|(pred, parent_pred, _cause)| {
let mut suggested = false; let mut suggested = false;
format_pred(*pred).map(|(p, self_ty)| { format_pred(*pred).map(|(p, self_ty)| {
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) { if let Some(parent) = parent_pred
&& suggested_bounds.contains(parent)
{
// We don't suggest `PartialEq` when we already suggest `Eq`. // We don't suggest `PartialEq` when we already suggest `Eq`.
} else if !suggested_bounds.contains(pred) { } else if !suggested_bounds.contains(pred) {
if collect_type_param_suggestions(self_ty, *pred, &p) { if collect_type_param_suggestions(self_ty, *pred, &p) {
@ -967,7 +974,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unsatisfied_bounds = true; unsatisfied_bounds = true;
} }
} else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args { } else if let ty::Adt(def, targs) = rcvr_ty.kind()
&& let Some(args) = args
{
// This is useful for methods on arbitrary self types that might have a simple // This is useful for methods on arbitrary self types that might have a simple
// mutability difference, like calling a method on `Pin<&mut Self>` that is on // mutability difference, like calling a method on `Pin<&mut Self>` that is on
// `Pin<&Self>`. // `Pin<&Self>`.
@ -975,16 +984,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut item_segment = hir::PathSegment::invalid(); let mut item_segment = hir::PathSegment::invalid();
item_segment.ident = item_name; item_segment.ident = item_name;
for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] { for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
let new_args = tcx.mk_args_from_iter( let new_args =
targs tcx.mk_args_from_iter(targs.iter().map(|arg| match arg.as_type() {
.iter() Some(ty) => ty::GenericArg::from(t(
.map(|arg| match arg.as_type() { tcx,
Some(ty) => ty::GenericArg::from( tcx.lifetimes.re_erased,
t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()), ty.peel_refs(),
), )),
_ => arg, _ => arg,
}) }));
);
let rcvr_ty = Ty::new_adt(tcx, *def, new_args); let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
if let Ok(method) = self.lookup_method_for_diagnostic( if let Ok(method) = self.lookup_method_for_diagnostic(
rcvr_ty, rcvr_ty,
@ -1088,7 +1096,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for inherent_method in for inherent_method in
self.tcx.associated_items(inherent_impl_did).in_definition_order() self.tcx.associated_items(inherent_impl_did).in_definition_order()
{ {
if let Some(attr) = self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables) if let Some(attr) = self
.tcx
.get_attr(inherent_method.def_id, sym::rustc_confusables)
&& let Some(candidates) = parse_confusables(attr) && let Some(candidates) = parse_confusables(attr)
&& candidates.contains(&item_name.name) && candidates.contains(&item_name.name)
{ {
@ -1307,7 +1317,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.note(note_str); err.note(note_str);
} }
if let Some(sugg_span) = sugg_span if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
{
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id); let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
let ty = match item.kind { let ty = match item.kind {
@ -1453,10 +1464,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& assoc.kind == ty::AssocKind::Fn && assoc.kind == ty::AssocKind::Fn
{ {
let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity(); let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() { sig.inputs().skip_binder().get(0).and_then(|first| {
None if first.peel_refs() == rcvr_ty.peel_refs() {
} else { None
Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) } else {
Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
}
}) })
} else { } else {
None None
@ -1729,8 +1742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = tcx.hir().span(hir_id); let span = tcx.hir().span(hir_id);
let filename = tcx.sess.source_map().span_to_filename(span); let filename = tcx.sess.source_map().span_to_filename(span);
let parent_node = let parent_node = self.tcx.hir().get_parent(hir_id);
self.tcx.hir().get_parent(hir_id);
let msg = format!( let msg = format!(
"you must specify a type for this binding, like `{concrete_type}`", "you must specify a type for this binding, like `{concrete_type}`",
); );
@ -1744,7 +1756,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.. ..
}), }),
) => { ) => {
let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi()); let type_span = ty
.map(|ty| ty.span.with_lo(span.hi()))
.unwrap_or(span.shrink_to_hi());
err.span_suggestion( err.span_suggestion(
// account for `let x: _ = 42;` // account for `let x: _ = 42;`
// ^^^ // ^^^
@ -1843,9 +1857,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_type: Option<Ty<'tcx>>, return_type: Option<Ty<'tcx>>,
) { ) {
if let SelfSource::MethodCall(expr) = source if let SelfSource::MethodCall(expr) = source
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
&& let Some((fields, args)) = && let Some((fields, args)) =
self.get_field_candidates_considering_privacy(span, actual, mod_id) self.get_field_candidates_considering_privacy(span, actual, mod_id)
{ {
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
@ -2324,7 +2338,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between // <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
// but for Adt type like Vec::function() // but for Adt type like Vec::function()
// we would suggest <[_]>::function(); // we would suggest <[_]>::function();
_ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"), _ if self
.tcx
.sess
.source_map()
.span_wrapped_by_angle_or_parentheses(ty.span) =>
{
format!("{deref_ty}")
}
_ => format!("<{deref_ty}>"), _ => format!("<{deref_ty}>"),
}; };
err.span_suggestion_verbose( err.span_suggestion_verbose(
@ -2576,8 +2597,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
// implement the `AsRef` trait. // implement the `AsRef` trait.
let skip = skippable.contains(&did) let skip = skippable.contains(&did)
|| (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin)) || (("Pin::new" == *pre)
|| inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len); && ((sym::as_ref == item_name.name) || !unpin))
|| inputs_len.is_some_and(|inputs_len| {
pick.item.kind == ty::AssocKind::Fn
&& self
.tcx
.fn_sig(pick.item.def_id)
.skip_binder()
.skip_binder()
.inputs()
.len()
!= inputs_len
});
// Make sure the method is defined for the *actual* receiver: we don't // Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of // want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self` // an autoderef to `&self`
@ -2628,7 +2660,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// receiver has the same number of arguments that appear in the user's code. // receiver has the same number of arguments that appear in the user's code.
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
{ {
let indent = self.tcx.sess let indent = self
.tcx
.sess
.source_map() .source_map()
.indentation_before(rcvr.span) .indentation_before(rcvr.span)
.unwrap_or_else(|| " ".to_string()); .unwrap_or_else(|| " ".to_string());
@ -2995,14 +3029,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
let parent = self.tcx.hir().parent_id(expr.hir_id); let parent = self.tcx.hir().parent_id(expr.hir_id);
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) && if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
let hir::ExprKind::MethodCall( && let hir::ExprKind::MethodCall(
hir::PathSegment { ident: method_name, .. }, hir::PathSegment { ident: method_name, .. },
self_expr, self_expr,
args, args,
.., ..,
) = call_expr.kind && ) = call_expr.kind
let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) { && let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr)
{
let new_name = Ident { let new_name = Ident {
name: Symbol::intern(&format!("{}_else", method_name.as_str())), name: Symbol::intern(&format!("{}_else", method_name.as_str())),
span: method_name.span, span: method_name.span,
@ -3016,10 +3051,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
// check the method arguments number // check the method arguments number
if let Ok(pick) = probe && if let Ok(pick) = probe
let fn_sig = self.tcx.fn_sig(pick.item.def_id) && && let fn_sig = self.tcx.fn_sig(pick.item.def_id)
let fn_args = fn_sig.skip_binder().skip_binder().inputs() && && let fn_args = fn_sig.skip_binder().skip_binder().inputs()
fn_args.len() == args.len() + 1 { && fn_args.len() == args.len() + 1
{
err.span_suggestion_verbose( err.span_suggestion_verbose(
method_name.span.shrink_to_hi(), method_name.span.shrink_to_hi(),
format!("try calling `{}` instead", new_name.name.as_str()), format!("try calling `{}` instead", new_name.name.as_str()),

View File

@ -430,33 +430,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(lhs_new_mutbl) = lhs_new_mutbl if let Some(lhs_new_mutbl) = lhs_new_mutbl
&& let Some(rhs_new_mutbl) = rhs_new_mutbl && let Some(rhs_new_mutbl) = rhs_new_mutbl
&& lhs_new_mutbl.is_not() && lhs_new_mutbl.is_not()
&& rhs_new_mutbl.is_not() { && rhs_new_mutbl.is_not()
{
err.multipart_suggestion_verbose( err.multipart_suggestion_verbose(
"consider reborrowing both sides", "consider reborrowing both sides",
vec![ vec![
(lhs_expr.span.shrink_to_lo(), "&*".to_string()), (lhs_expr.span.shrink_to_lo(), "&*".to_string()),
(rhs_expr.span.shrink_to_lo(), "&*".to_string()) (rhs_expr.span.shrink_to_lo(), "&*".to_string()),
], ],
rustc_errors::Applicability::MachineApplicable, rustc_errors::Applicability::MachineApplicable,
); );
} else { } else {
let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| { let mut suggest_new_borrow =
// Can reborrow (&mut -> &) |new_mutbl: ast::Mutability, sp: Span| {
if new_mutbl.is_not() { // Can reborrow (&mut -> &)
err.span_suggestion_verbose( if new_mutbl.is_not() {
sp.shrink_to_lo(), err.span_suggestion_verbose(
"consider reborrowing this side", sp.shrink_to_lo(),
"&*", "consider reborrowing this side",
rustc_errors::Applicability::MachineApplicable, "&*",
); rustc_errors::Applicability::MachineApplicable,
// Works on &mut but have & );
} else { // Works on &mut but have &
err.span_help( } else {
sp, err.span_help(
"consider making this expression a mutable borrow", sp,
); "consider making this expression a mutable borrow",
} );
}; }
};
if let Some(lhs_new_mutbl) = lhs_new_mutbl { if let Some(lhs_new_mutbl) = lhs_new_mutbl {
suggest_new_borrow(lhs_new_mutbl, lhs_expr.span); suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
@ -493,20 +495,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if is_assign == IsAssign::No } else if is_assign == IsAssign::No
&& let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind() && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
{ {
if self.type_is_copy_modulo_regions( if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) {
self.param_env,
*lhs_deref_ty,
) {
suggest_deref_binop(&mut err, *lhs_deref_ty); suggest_deref_binop(&mut err, *lhs_deref_ty);
} else { } else {
let lhs_inv_mutbl = mutbl.invert(); let lhs_inv_mutbl = mutbl.invert();
let lhs_inv_mutbl_ty = Ty::new_ref( let lhs_inv_mutbl_ty = Ty::new_ref(
self.tcx, self.tcx,
*region, *region,
ty::TypeAndMut { ty::TypeAndMut { ty: *lhs_deref_ty, mutbl: lhs_inv_mutbl },
ty: *lhs_deref_ty,
mutbl: lhs_inv_mutbl,
},
); );
suggest_different_borrow( suggest_different_borrow(
@ -522,10 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rhs_inv_mutbl_ty = Ty::new_ref( let rhs_inv_mutbl_ty = Ty::new_ref(
self.tcx, self.tcx,
*region, *region,
ty::TypeAndMut { ty::TypeAndMut { ty: *rhs_deref_ty, mutbl: rhs_inv_mutbl },
ty: *rhs_deref_ty,
mutbl: rhs_inv_mutbl,
},
); );
suggest_different_borrow( suggest_different_borrow(
@ -599,7 +592,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(output_def_id) = output_def_id if let Some(output_def_id) = output_def_id
&& let Some(trait_def_id) = trait_def_id && let Some(trait_def_id) = trait_def_id
&& self.tcx.parent(output_def_id) == trait_def_id && self.tcx.parent(output_def_id) == trait_def_id
&& let Some(output_ty) = output_ty.make_suggestable(self.tcx, false) && let Some(output_ty) =
output_ty.make_suggestable(self.tcx, false)
{ {
Some(("Output", output_ty)) Some(("Output", output_ty))
} else { } else {

View File

@ -406,16 +406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.borrow_mut() .borrow_mut()
.treat_byte_string_as_slice .treat_byte_string_as_slice
.insert(lt.hir_id.local_id); .insert(lt.hir_id.local_id);
pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8)); pat_ty =
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
} }
} }
if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { if self.tcx.features().string_deref_patterns
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind
{
let tcx = self.tcx; let tcx = self.tcx;
let expected = self.resolve_vars_if_possible(expected); let expected = self.resolve_vars_if_possible(expected);
pat_ty = match expected.kind() { pat_ty = match expected.kind() {
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
ty::Str => Ty::new_static_str(tcx,), ty::Str => Ty::new_static_str(tcx),
_ => pat_ty, _ => pat_ty,
}; };
} }
@ -707,7 +710,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
let tcx = self.tcx; let tcx = self.tcx;
if let PatKind::Ref(inner, mutbl) = pat.kind if let PatKind::Ref(inner, mutbl) = pat.kind
&& let PatKind::Binding(_, _, binding, ..) = inner.kind { && let PatKind::Binding(_, _, binding, ..) = inner.kind
{
let binding_parent_id = tcx.hir().parent_id(pat.hir_id); let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
let binding_parent = tcx.hir().get(binding_parent_id); let binding_parent = tcx.hir().get(binding_parent_id);
debug!(?inner, ?pat, ?binding_parent); debug!(?inner, ?pat, ?binding_parent);
@ -754,7 +758,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("to declare a mutable {ident_kind} use"), format!("to declare a mutable {ident_kind} use"),
format!("mut {binding}"), format!("mut {binding}"),
)) ))
}; };
match binding_parent { match binding_parent {
@ -777,7 +780,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => { hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
for i in pat_arr.iter() { for i in pat_arr.iter() {
if let PatKind::Ref(the_ref, _) = i.kind if let PatKind::Ref(the_ref, _) = i.kind
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind { && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
{
let hir::BindingAnnotation(_, mtblty) = mt; let hir::BindingAnnotation(_, mtblty) = mt;
err.span_suggestion_verbose( err.span_suggestion_verbose(
i.span, i.span,
@ -1480,7 +1484,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(Some(mut err), None) => { (Some(mut err), None) => {
err.emit(); err.emit();
} }
(None, None) if let Some(mut err) = (None, None)
if let Some(mut err) =
self.error_tuple_variant_index_shorthand(variant, pat, fields) => self.error_tuple_variant_index_shorthand(variant, pat, fields) =>
{ {
err.emit(); err.emit();
@ -2263,7 +2268,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let ty::Array(..) | ty::Slice(..) = ty.kind() && let ty::Array(..) | ty::Slice(..) = ty.kind()
{ {
err.help("the semantics of slice patterns changed recently; see issue #62254"); err.help("the semantics of slice patterns changed recently; see issue #62254");
} else if self.autoderef(span, expected_ty) } else if self
.autoderef(span, expected_ty)
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
&& let Some(span) = ti.span && let Some(span) = ti.span
&& let Some(_) = ti.origin_expr && let Some(_) = ti.origin_expr
@ -2284,7 +2290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
_ => () _ => (),
} }
if is_slice_or_array_or_vector.0 { if is_slice_or_array_or_vector.0 {
err.span_suggestion( err.span_suggestion(

View File

@ -174,7 +174,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
} }
} }
hir::ExprKind::AssignOp(..) hir::ExprKind::AssignOp(..)
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) => if let Some(a) =
self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
{ {
a.pop(); a.pop();
} }
@ -247,7 +248,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// Since this is "after" the other adjustment to be // Since this is "after" the other adjustment to be
// discarded, we do an extra `pop()` // discarded, we do an extra `pop()`
if let Some(Adjustment { if let Some(Adjustment {
kind: Adjust::Pointer(PointerCoercion::Unsize), .. kind: Adjust::Pointer(PointerCoercion::Unsize),
..
}) = a.pop() }) = a.pop()
{ {
// So the borrow discard actually happens here // So the borrow discard actually happens here
@ -568,10 +570,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// Here we only detect impl trait definition conflicts when they // Here we only detect impl trait definition conflicts when they
// are equal modulo regions. // are equal modulo regions.
if let Some(last_opaque_ty) = self if let Some(last_opaque_ty) =
.typeck_results self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type)
.concrete_opaque_types
.insert(opaque_type_key, hidden_type)
&& last_opaque_ty.ty != hidden_type.ty && last_opaque_ty.ty != hidden_type.ty
{ {
assert!(!self.fcx.next_trait_solver()); assert!(!self.fcx.next_trait_solver());

View File

@ -60,9 +60,7 @@ impl<'a> DescriptionCtx<'a> {
let span = Some(tcx.def_span(scope)); let span = Some(tcx.def_span(scope));
(span, "defined_here", String::new()) (span, "defined_here", String::new())
} }
_ => { _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
(Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
}
} }
} }
} }

View File

@ -227,8 +227,10 @@ fn msg_span_from_named_region<'tcx>(
let scope = region.free_region_binding_scope(tcx).expect_local(); let scope = region.free_region_binding_scope(tcx).expect_local();
match fr.bound_region { match fr.bound_region {
ty::BoundRegionKind::BrNamed(_, name) => { ty::BoundRegionKind::BrNamed(_, name) => {
let span = if let Some(param) = let span = if let Some(param) = tcx
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) .hir()
.get_generics(scope)
.and_then(|generics| generics.get_named(name))
{ {
param.span param.span
} else { } else {
@ -243,7 +245,7 @@ fn msg_span_from_named_region<'tcx>(
} }
ty::BrAnon => ( ty::BrAnon => (
"the anonymous lifetime as defined here".to_string(), "the anonymous lifetime as defined here".to_string(),
Some(tcx.def_span(scope)) Some(tcx.def_span(scope)),
), ),
_ => ( _ => (
format!("the lifetime `{region}` as defined here"), format!("the lifetime `{region}` as defined here"),
@ -715,13 +717,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let ty::Adt(def, args) = ty.kind() && let ty::Adt(def, args) = ty.kind()
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
{ {
err.span_label(span, format!("this is an iterator with items of type `{}`", args.type_at(0))); err.span_label(
span,
format!("this is an iterator with items of type `{}`", args.type_at(0)),
);
} else { } else {
err.span_label(span, format!("this expression has type `{ty}`")); err.span_label(span, format!("this expression has type `{ty}`"));
} }
} }
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
&& ty.is_box() && ty.boxed_ty() == found && ty.is_box()
&& ty.boxed_ty() == found
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{ {
err.span_suggestion( err.span_suggestion(
@ -743,9 +749,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
let arg_expr = args.first().expect("try desugaring call w/out arg"); let arg_expr = args.first().expect("try desugaring call w/out arg");
self.typeck_results.as_ref().and_then(|typeck_results| { self.typeck_results
typeck_results.expr_ty_opt(arg_expr) .as_ref()
}) .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
} else { } else {
bug!("try desugaring w/out call expr as scrutinee"); bug!("try desugaring w/out call expr as scrutinee");
}; };
@ -763,7 +769,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_ => {} _ => {}
} }
} }
}, }
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_block_id, arm_block_id,
arm_span, arm_span,
@ -782,9 +788,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
let arg_expr = args.first().expect("try desugaring call w/out arg"); let arg_expr = args.first().expect("try desugaring call w/out arg");
self.typeck_results.as_ref().and_then(|typeck_results| { self.typeck_results
typeck_results.expr_ty_opt(arg_expr) .as_ref()
}) .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
} else { } else {
bug!("try desugaring w/out call expr as scrutinee"); bug!("try desugaring w/out call expr as scrutinee");
}; };
@ -878,8 +884,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
// don't suggest wrapping either blocks in `if .. {} else {}` // don't suggest wrapping either blocks in `if .. {} else {}`
let is_empty_arm = |id| { let is_empty_arm = |id| {
let hir::Node::Block(blk) = self.tcx.hir().get(id) let hir::Node::Block(blk) = self.tcx.hir().get(id) else {
else {
return false; return false;
}; };
if blk.expr.is_some() || !blk.stmts.is_empty() { if blk.expr.is_some() || !blk.stmts.is_empty() {
@ -908,12 +913,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
_ => { _ => {
if let ObligationCauseCode::BindingObligation(_, span) if let ObligationCauseCode::BindingObligation(_, span)
| ObligationCauseCode::ExprBindingObligation(_, span, ..) | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
= cause.code().peel_derives() cause.code().peel_derives()
&& let TypeError::RegionsPlaceholderMismatch = terr && let TypeError::RegionsPlaceholderMismatch = terr
{ {
err.span_note( * span, err.span_note(*span, "the lifetime requirement is introduced here");
"the lifetime requirement is introduced here");
} }
} }
} }
@ -1742,19 +1746,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| { let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() { if let ty::Adt(expected, _) = expected.kind()
&& let Some(primitive) = found.primitive_symbol()
{
let path = self.tcx.def_path(expected.did()).data; let path = self.tcx.def_path(expected.did()).data;
let name = path.last().unwrap().data.get_opt_name(); let name = path.last().unwrap().data.get_opt_name();
if name == Some(primitive) { if name == Some(primitive) {
return Some(Similar::PrimitiveFound { expected: *expected, found }); return Some(Similar::PrimitiveFound { expected: *expected, found });
} }
} else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() { } else if let Some(primitive) = expected.primitive_symbol()
&& let ty::Adt(found, _) = found.kind()
{
let path = self.tcx.def_path(found.did()).data; let path = self.tcx.def_path(found.did()).data;
let name = path.last().unwrap().data.get_opt_name(); let name = path.last().unwrap().data.get_opt_name();
if name == Some(primitive) { if name == Some(primitive) {
return Some(Similar::PrimitiveExpected { expected, found: *found }); return Some(Similar::PrimitiveExpected { expected, found: *found });
} }
} else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() { } else if let ty::Adt(expected, _) = expected.kind()
&& let ty::Adt(found, _) = found.kind()
{
if !expected.did().is_local() && expected.did().krate == found.did().krate { if !expected.did().is_local() && expected.did().krate == found.did().krate {
// Most likely types from different versions of the same crate // Most likely types from different versions of the same crate
// are in play, in which case this message isn't so helpful. // are in play, in which case this message isn't so helpful.
@ -1764,8 +1774,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let f_path = self.tcx.def_path(found.did()).data; let f_path = self.tcx.def_path(found.did()).data;
let e_path = self.tcx.def_path(expected.did()).data; let e_path = self.tcx.def_path(expected.did()).data;
if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last { if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
return Some(Similar::Adts{expected: *expected, found: *found}); && e_last == f_last
{
return Some(Similar::Adts { expected: *expected, found: *found });
} }
} }
None None
@ -1796,7 +1808,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}; };
let diagnose_adts = let diagnose_adts =
|expected_adt : ty::AdtDef<'tcx>, |expected_adt: ty::AdtDef<'tcx>,
found_adt: ty::AdtDef<'tcx>, found_adt: ty::AdtDef<'tcx>,
diagnostic: &mut Diagnostic| { diagnostic: &mut Diagnostic| {
let found_name = values.found.sort_string(self.tcx); let found_name = values.found.sort_string(self.tcx);
@ -1816,8 +1828,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.tcx .tcx
.parent_module_from_def_id(defid.expect_local()) .parent_module_from_def_id(defid.expect_local())
.to_def_id(); .to_def_id();
let module_name = self.tcx.def_path(module).to_string_no_crate_verbose(); let module_name =
format!("{name} is defined in module `crate{module_name}` of the current crate") self.tcx.def_path(module).to_string_no_crate_verbose();
format!(
"{name} is defined in module `crate{module_name}` of the current crate"
)
} else if defid.is_local() { } else if defid.is_local() {
format!("{name} is defined in the current crate") format!("{name} is defined in the current crate")
} else { } else {
@ -1829,13 +1844,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}; };
match s { match s {
Similar::Adts{expected, found} => { Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
diagnose_adts(expected, found, diag) Similar::PrimitiveFound { expected, found: prim } => {
}
Similar::PrimitiveFound{expected, found: prim} => {
diagnose_primitive(prim, values.expected, expected.did(), diag) diagnose_primitive(prim, values.expected, expected.did(), diag)
} }
Similar::PrimitiveExpected{expected: prim, found} => { Similar::PrimitiveExpected { expected: prim, found } => {
diagnose_primitive(prim, values.found, found.did(), diag) diagnose_primitive(prim, values.found, found.did(), diag)
} }
} }
@ -1877,7 +1890,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
s s
}; };
if !(values.expected.is_simple_text(self.tcx) && values.found.is_simple_text(self.tcx)) if !(values.expected.is_simple_text(self.tcx)
&& values.found.is_simple_text(self.tcx))
|| (exp_found.is_some_and(|ef| { || (exp_found.is_some_and(|ef| {
// This happens when the type error is a subset of the expectation, // This happens when the type error is a subset of the expectation,
// like when you have two references but one is `usize` and the other // like when you have two references but one is `usize` and the other
@ -1967,13 +1981,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let exp_found = TypeError::Sorts(exp_found) && let exp_found = TypeError::Sorts(exp_found)
&& exp_found != terr && exp_found != terr
{ {
self.note_and_explain_type_err( self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
diag,
exp_found,
cause,
span,
cause.body_id.to_def_id(),
);
} }
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
@ -1983,7 +1991,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
{ {
let span = self.tcx.def_span(def_id); let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements"); diag.span_note(span, "this closure does not fulfill the lifetime requirements");
self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag); self.suggest_for_all_lifetime_closure(
span,
self.tcx.hir().get_by_def_id(def_id),
&exp_found,
diag,
);
} }
// It reads better to have the error origin as the final // It reads better to have the error origin as the final
@ -2009,7 +2022,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// parentheses around it, perhaps the user meant to write `(expr,)` to // parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100) // build a tuple (issue #86100)
(ty::Tuple(fields), _) => { (ty::Tuple(fields), _) => {
suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields)) suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields))
} }
// If a byte was expected and the found expression is a char literal // If a byte was expected and the found expression is a char literal
// containing a single ASCII character, perhaps the user meant to write `b'c'` to // containing a single ASCII character, perhaps the user meant to write `b'c'` to
@ -2059,8 +2072,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
// we try to suggest to add the missing `let` for `if let Some(..) = expr` // we try to suggest to add the missing `let` for `if let Some(..) = expr`
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 { (ty::Bool, ty::Tuple(list)) => {
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); if list.len() == 0 {
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
}
} }
(ty::Array(_, _), ty::Array(_, _)) => { (ty::Array(_, _), ty::Array(_, _)) => {
suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)) suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
@ -2070,8 +2085,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
let code = trace.cause.code(); let code = trace.cause.code();
if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. }) if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
| BlockTailExpression(.., source) | BlockTailExpression(.., source)) = code
) = code
&& let hir::MatchSource::TryDesugar(_) = source && let hir::MatchSource::TryDesugar(_) = source
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{ {
@ -2108,17 +2122,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Find a local statement where the initializer has // Find a local statement where the initializer has
// the same span as the error and the type is specified. // the same span as the error and the type is specified.
if let hir::Stmt { if let hir::Stmt {
kind: hir::StmtKind::Local(hir::Local { kind:
init: Some(hir::Expr { hir::StmtKind::Local(hir::Local {
span: init_span, init: Some(hir::Expr { span: init_span, .. }),
ty: Some(array_ty),
.. ..
}), }),
ty: Some(array_ty),
..
}),
.. ..
} = s } = s
&& init_span == &self.span { && init_span == &self.span
{
self.result = Some(*array_ty); self.result = Some(*array_ty);
} }
} }

View File

@ -163,13 +163,13 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
let ty_vars = infcx_inner.type_variables(); let ty_vars = infcx_inner.type_variables();
let var_origin = ty_vars.var_origin(ty_vid); let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
&& name != kw::SelfUpper && !var_origin.span.from_expansion() && name != kw::SelfUpper
&& !var_origin.span.from_expansion()
{ {
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
let generic_param_def = generics.param_at(idx as usize, infcx.tcx); let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind {
{
None None
} else { } else {
Some(name) Some(name)
@ -792,8 +792,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
let cost = self.source_cost(&new_source) + self.attempt; let cost = self.source_cost(&new_source) + self.attempt;
debug!(?cost); debug!(?cost);
self.attempt += 1; self.attempt += 1;
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, .. }, .. }) =
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind self.infer_source
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, .. } = new_source.kind
&& ty.is_ty_or_numeric_infer() && ty.is_ty_or_numeric_infer()
{ {
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
@ -1242,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
successor, successor,
args, args,
def_id, def_id,
} },
}) })
} }
} }

View File

@ -214,7 +214,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
_ => cause.code(), _ => cause.code(),
} }
&& let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code) && let (
&ObligationCauseCode::ItemObligation(item_def_id)
| &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
None,
) = (code, override_error_code)
{ {
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
// lifetime as above, but called using a fully-qualified path to the method: // lifetime as above, but called using a fully-qualified path to the method:
@ -322,13 +326,27 @@ pub fn suggest_new_region_bound(
let existing_lt_name = if let Some(id) = scope_def_id let existing_lt_name = if let Some(id) = scope_def_id
&& let Some(generics) = tcx.hir().get_generics(id) && let Some(generics) = tcx.hir().get_generics(id)
&& let named_lifetimes = generics && let named_lifetimes = generics
.params .params
.iter() .iter()
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit })) .filter(|p| {
.map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}}) matches!(
.filter(|n| ! matches!(n, None)) p.kind,
.collect::<Vec<_>>() GenericParamKind::Lifetime {
&& named_lifetimes.len() > 0 { kind: hir::LifetimeParamKind::Explicit
}
)
})
.map(|p| {
if let hir::ParamName::Plain(name) = p.name {
Some(name.to_string())
} else {
None
}
})
.filter(|n| !matches!(n, None))
.collect::<Vec<_>>()
&& named_lifetimes.len() > 0
{
named_lifetimes[0].clone() named_lifetimes[0].clone()
} else { } else {
None None
@ -342,30 +360,28 @@ pub fn suggest_new_region_bound(
.params .params
.iter() .iter()
.filter(|p| p.is_elided_lifetime()) .filter(|p| p.is_elided_lifetime())
.map(|p| .map(|p| {
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_) if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) {
(p.span.shrink_to_hi(),format!("{name} ")) // Ampersand (elided without '_)
} else { // Underscore (elided with '_) (p.span.shrink_to_hi(), format!("{name} "))
(p.span, name.to_string()) } else {
} // Underscore (elided with '_)
) (p.span, name.to_string())
}
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
&& spans_suggs.len() > 1 && spans_suggs.len() > 1
{ {
let use_lt = let use_lt = if existing_lt_name == None {
if existing_lt_name == None {
spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>"))); spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
format!("you can introduce a named lifetime parameter `{name}`") format!("you can introduce a named lifetime parameter `{name}`")
} else { } else {
// make use the existing named lifetime // make use the existing named lifetime
format!("you can use the named lifetime parameter `{name}`") format!("you can use the named lifetime parameter `{name}`")
}; };
spans_suggs spans_suggs.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
err.multipart_suggestion_verbose( err.multipart_suggestion_verbose(
format!( format!("{declare} `{ty}` {captures}, {use_lt}",),
"{declare} `{ty}` {captures}, {use_lt}",
),
spans_suggs, spans_suggs,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
@ -443,8 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let trait_did = trait_id.to_def_id(); let trait_did = trait_id.to_def_id();
tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| { tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
if let Node::Item(Item { if let Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }), kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
..
}) = tcx.hir().find_by_def_id(impl_did)? }) = tcx.hir().find_by_def_id(impl_did)?
&& trait_objects.iter().all(|did| { && trait_objects.iter().all(|did| {
// FIXME: we should check `self_ty` against the receiver // FIXME: we should check `self_ty` against the receiver

View File

@ -72,32 +72,30 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#traits-as-parameters", #traits-as-parameters",
); );
} }
(ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => { (
ty::Alias(ty::Projection | ty::Inherent, _),
ty::Alias(ty::Projection | ty::Inherent, _),
) => {
diag.note("an associated type was expected, but a different one was found"); diag.note("an associated type was expected, but a different one was found");
} }
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) (ty::Param(p), ty::Alias(ty::Projection, proj))
| (ty::Alias(ty::Projection, proj), ty::Param(p))
if !tcx.is_impl_trait_in_trait(proj.def_id) => if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{ {
let p_def_id = tcx let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id;
.generics_of(body_owner_def_id)
.type_param(p, tcx)
.def_id;
let p_span = tcx.def_span(p_def_id); let p_span = tcx.def_span(p_def_id);
if !sp.contains(p_span) { if !sp.contains(p_span) {
diag.span_label(p_span, "this type parameter"); diag.span_label(p_span, "this type parameter");
} }
let hir = tcx.hir(); let hir = tcx.hir();
let mut note = true; let mut note = true;
let parent = p_def_id let parent = p_def_id.as_local().and_then(|id| {
.as_local() let local_id = hir.local_def_id_to_hir_id(id);
.and_then(|id| { let generics = tcx.hir().find_parent(local_id)?.generics()?;
let local_id = hir.local_def_id_to_hir_id(id); Some((id, generics))
let generics = tcx.hir().find_parent(local_id)?.generics()?; });
Some((id, generics)) if let Some((local_id, generics)) = parent {
});
if let Some((local_id, generics)) = parent
{
// Synthesize the associated type restriction `Add<Output = Expected>`. // Synthesize the associated type restriction `Add<Output = Expected>`.
// FIXME: extract this logic for use in other diagnostics. // FIXME: extract this logic for use in other diagnostics.
let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx); let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
@ -112,15 +110,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut matching_span = None; let mut matching_span = None;
let mut matched_end_of_args = false; let mut matched_end_of_args = false;
for bound in generics.bounds_for_param(local_id) { for bound in generics.bounds_for_param(local_id) {
let potential_spans = bound let potential_spans = bound.bounds.iter().find_map(|bound| {
.bounds let bound_trait_path = bound.trait_ref()?.path;
.iter() let def_id = bound_trait_path.res.opt_def_id()?;
.find_map(|bound| { let generic_args = bound_trait_path
let bound_trait_path = bound.trait_ref()?.path; .segments
let def_id = bound_trait_path.res.opt_def_id()?; .iter()
let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args()); .last()
(def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args)) .map(|path| path.args());
}); (def_id == trait_ref.def_id)
.then_some((bound_trait_path.span, generic_args))
});
if let Some((end_of_trait, end_of_args)) = potential_spans { if let Some((end_of_trait, end_of_args)) = potential_spans {
let args_span = end_of_args.and_then(|args| args.span()); let args_span = end_of_args.and_then(|args| args.span());
@ -223,7 +223,9 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter"); diag.span_label(p_span, "this type parameter");
} }
} }
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
{
self.expected_projection( self.expected_projection(
diag, diag,
proj_ty, proj_ty,
@ -232,11 +234,15 @@ impl<T> Trait<T> for X {
cause.code(), cause.code(),
); );
} }
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
let msg = || format!( if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
"consider constraining the associated type `{}` to `{}`", {
values.found, values.expected, let msg = || {
); format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
)
};
if !(self.suggest_constraining_opaque_associated_type( if !(self.suggest_constraining_opaque_associated_type(
diag, diag,
msg, msg,
@ -256,19 +262,40 @@ impl<T> Trait<T> for X {
); );
} }
} }
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => { (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias))
if alias.def_id.is_local()
&& matches!(
tcx.def_kind(body_owner_def_id),
DefKind::Fn
| DefKind::Static(_)
| DefKind::Const
| DefKind::AssocFn
| DefKind::AssocConst
) =>
{
if tcx.is_type_alias_impl_trait(alias.def_id) { if tcx.is_type_alias_impl_trait(alias.def_id) {
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { if !tcx
let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id)); .opaque_types_defined_by(body_owner_def_id.expect_local())
diag.span_note(sp, "\ .contains(&alias.def_id.expect_local())
{
let sp = tcx
.def_ident_span(body_owner_def_id)
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
diag.span_note(
sp,
"\
this item must have the opaque type in its signature \ this item must have the opaque type in its signature \
in order to be able to register hidden types"); in order to be able to register hidden types",
);
} }
} }
} }
(ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => { (ty::FnPtr(sig), ty::FnDef(def_id, _))
| (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() { if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
diag.note("unsafe functions cannot be coerced into safe function pointers"); diag.note(
"unsafe functions cannot be coerced into safe function pointers",
);
} }
} }
_ => {} _ => {}
@ -616,7 +643,8 @@ fn foo(&self) -> Self::T { String::new() }
for item in &items[..] { for item in &items[..] {
if let hir::AssocItemKind::Type = item.kind { if let hir::AssocItemKind::Type = item.kind {
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id) if let hir::Defaultness::Default { has_value: true } =
tcx.defaultness(item.id.owner_id)
&& self.infcx.can_eq(param_env, assoc_ty, found) && self.infcx.can_eq(param_env, assoc_ty, found)
{ {
diag.span_label( diag.span_label(

View File

@ -491,12 +491,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
if let hir::StmtKind::Local(hir::Local { if let hir::StmtKind::Local(hir::Local {
span, pat: hir::Pat{..}, ty: None, init: Some(_), .. span,
}) = &ex.kind pat: hir::Pat { .. },
&& self.found_if ty: None,
&& span.eq(&self.err_span) { init: Some(_),
self.result = true; ..
} }) = &ex.kind
&& self.found_if
&& span.eq(&self.err_span)
{
self.result = true;
}
walk_stmt(self, ex); walk_stmt(self, ex);
} }
@ -546,45 +551,59 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let expected = expected.unpack(); let expected = expected.unpack();
let found = found.unpack(); let found = found.unpack();
// 3. Extract the tuple type from Fn trait and suggest the change. // 3. Extract the tuple type from Fn trait and suggest the change.
if let GenericArgKind::Type(expected) = expected && if let GenericArgKind::Type(expected) = expected
let GenericArgKind::Type(found) = found && && let GenericArgKind::Type(found) = found
let ty::Tuple(expected) = expected.kind() && && let ty::Tuple(expected) = expected.kind()
let ty::Tuple(found)= found.kind() && && let ty::Tuple(found) = found.kind()
expected.len() == found.len() { && expected.len() == found.len()
{
let mut suggestion = "|".to_string(); let mut suggestion = "|".to_string();
let mut is_first = true; let mut is_first = true;
let mut has_suggestion = false; let mut has_suggestion = false;
for (((expected, found), param_hir), arg_hir) in expected.iter() for (((expected, found), param_hir), arg_hir) in
.zip(found.iter()) expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter())
.zip(params.iter()) {
.zip(fn_decl.inputs.iter()) {
if is_first { if is_first {
is_first = false; is_first = false;
} else { } else {
suggestion += ", "; suggestion += ", ";
} }
if let ty::Ref(expected_region, _, _) = expected.kind() && if let ty::Ref(expected_region, _, _) = expected.kind()
let ty::Ref(found_region, _, _) = found.kind() && && let ty::Ref(found_region, _, _) = found.kind()
expected_region.is_late_bound() && && expected_region.is_late_bound()
!found_region.is_late_bound() && && !found_region.is_late_bound()
let hir::TyKind::Infer = arg_hir.kind { && let hir::TyKind::Infer = arg_hir.kind
{
// If the expected region is late bound, the found region is not, and users are asking compiler // If the expected region is late bound, the found region is not, and users are asking compiler
// to infer the type, we can suggest adding `: &_`. // to infer the type, we can suggest adding `: &_`.
if param_hir.pat.span == param_hir.ty_span { if param_hir.pat.span == param_hir.ty_span {
// for `|x|`, `|_|`, `|x: impl Foo|` // for `|x|`, `|_|`, `|x: impl Foo|`
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; let Ok(pat) =
self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
else {
return;
};
suggestion += &format!("{pat}: &_"); suggestion += &format!("{pat}: &_");
} else { } else {
// for `|x: ty|`, `|_: ty|` // for `|x: ty|`, `|_: ty|`
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; let Ok(pat) =
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; }; self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
else {
return;
};
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span)
else {
return;
};
suggestion += &format!("{pat}: &{ty}"); suggestion += &format!("{pat}: &{ty}");
} }
has_suggestion = true; has_suggestion = true;
} else { } else {
let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; }; let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else {
return;
};
// Otherwise, keep it as-is. // Otherwise, keep it as-is.
suggestion += &arg; suggestion += &arg;
} }

View File

@ -220,7 +220,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
} }
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReVar(vid) = *r && self.region_vars.0.contains(&vid) { if let ty::ReVar(vid) = *r
&& self.region_vars.0.contains(&vid)
{
let idx = vid.index() - self.region_vars.0.start.index(); let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx]; let origin = self.region_vars.1[idx];
return self.infcx.next_region_var(origin); return self.infcx.next_region_var(origin);

View File

@ -346,7 +346,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// tighter bound than `'static`. // tighter bound than `'static`.
// //
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) { if let ty::RePlaceholder(p) = *lub
&& b_universe.cannot_name(p.universe)
{
lub = self.tcx().lifetimes.re_static; lub = self.tcx().lifetimes.re_static;
} }

View File

@ -177,7 +177,9 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
value: ty::Region<'tcx>, value: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> { ) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("self.pattern_depth = {:?}", self.pattern_depth); debug!("self.pattern_depth = {:?}", self.pattern_depth);
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth { if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind()
&& depth == self.pattern_depth
{
self.bind(br, value) self.bind(br, value)
} else if pattern == value { } else if pattern == value {
Ok(pattern) Ok(pattern)

View File

@ -108,20 +108,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
let alias_ty_as_ty = alias_ty.to_ty(self.tcx); let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`. // Search the env for where clauses like `P: 'a`.
let env_bounds = self let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
.approx_declared_bounds_from_env(alias_ty) if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
.into_iter() && ty == alias_ty_as_ty
.map(|binder| { {
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty { // Micro-optimize if this is an exact match (this
// Micro-optimize if this is an exact match (this // occurs often when there are no region variables
// occurs often when there are no region variables // involved).
// involved). VerifyBound::OutlivedBy(r)
VerifyBound::OutlivedBy(r) } else {
} else { let verify_if_eq_b =
let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound }); binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
VerifyBound::IfEq(verify_if_eq_b) VerifyBound::IfEq(verify_if_eq_b)
} }
}); });
// Extend with bounds that we can find from the definition. // Extend with bounds that we can find from the definition.
let definition_bounds = let definition_bounds =

View File

@ -457,7 +457,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
debug!("RegionConstraintCollector: add_verify({:?})", verify); debug!("RegionConstraintCollector: add_verify({:?})", verify);
// skip no-op cases known to be satisfied // skip no-op cases known to be satisfied
if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() { if let VerifyBound::AllBounds(ref bs) = verify.bound
&& bs.is_empty()
{
return; return;
} }

View File

@ -62,7 +62,9 @@ pub fn report_object_safety_error<'tcx>(
let mut multi_span = vec![]; let mut multi_span = vec![];
let mut messages = vec![]; let mut messages = vec![];
for violation in violations { for violation in violations {
if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() { if let ObjectSafetyViolation::SizedSelf(sp) = &violation
&& !sp.is_empty()
{
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
// with a `Span`. // with a `Span`.
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));

View File

@ -117,9 +117,12 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
def.owner_id.def_id, def.owner_id.def_id,
" + Send", " + Send",
); );
cx.tcx.emit_spanned_lint(ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, AsyncFnInTraitDiag { cx.tcx.emit_spanned_lint(
sugg ASYNC_FN_IN_TRAIT,
}); item.hir_id(),
async_span,
AsyncFnInTraitDiag { sugg },
);
} }
} }
} }

View File

@ -121,16 +121,14 @@ impl EarlyLintPass for WhileTrue {
{ {
let condition_span = e.span.with_hi(cond.span.hi()); let condition_span = e.span.with_hi(cond.span.hi());
let replace = format!( let replace = format!(
"{}loop", "{}loop",
label.map_or_else(String::new, |label| format!( label.map_or_else(String::new, |label| format!("{}: ", label.ident,))
"{}: ", );
label.ident, cx.emit_spanned_lint(
)) WHILE_TRUE,
); condition_span,
cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue { BuiltinWhileTrue { suggestion: condition_span, replace },
suggestion: condition_span, );
replace,
});
} }
} }
} }
@ -164,7 +162,9 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers { impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
for leaf in ty.walk() { for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
&& leaf_ty.is_box()
{
cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
} }
} }
@ -681,7 +681,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
// We shouldn't recommend implementing `Copy` on stateful things, // We shouldn't recommend implementing `Copy` on stateful things,
// such as iterators. // such as iterators.
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& cx.tcx && cx
.tcx
.infer_ctxt() .infer_ctxt()
.build() .build()
.type_implements_trait(iter_trait, [ty], param_env) .type_implements_trait(iter_trait, [ty], param_env)
@ -1298,10 +1299,14 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
// Now, check if the function has the `#[track_caller]` attribute // Now, check if the function has the `#[track_caller]` attribute
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
{ {
cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { cx.emit_spanned_lint(
label: span, UNGATED_ASYNC_FN_TRACK_CALLER,
parse_sess: &cx.tcx.sess.parse_sess, attr.span,
}); BuiltinUngatedAsyncFnTrackCaller {
label: span,
parse_sess: &cx.tcx.sess.parse_sess,
},
);
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More