Auto merge of #118434 - matthiaskrgr:rollup-k1upt8b, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #118342 (Dont suggest `!` for path in function call if it has generic args)
 - #118383 (Address unused tuple struct fields in the standard library)
 - #118401 (`rustc_ast_lowering` cleanups)
 - #118409 (format_foreign.rs: unwrap return Option value for `fn position`, as it always returns Some)
 - #118413 (Fix the issue of suggesting unwrap/expect for shorthand field)
 - #118425 (Update cargo)
 - #118429 (Fix a typo in a `format_args!` note)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-11-29 06:23:14 +00:00
commit e9b7bf0114
25 changed files with 490 additions and 133 deletions

View file

@ -530,7 +530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
this.mark_span_with_reason( this.mark_span_with_reason(
DesugaringKind::TryBlock, DesugaringKind::TryBlock,
expr.span, expr.span,
this.allow_try_trait.clone(), Some(this.allow_try_trait.clone()),
), ),
expr, expr,
) )
@ -538,7 +538,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let try_span = this.mark_span_with_reason( let try_span = this.mark_span_with_reason(
DesugaringKind::TryBlock, DesugaringKind::TryBlock,
this.tcx.sess.source_map().end_point(body.span), this.tcx.sess.source_map().end_point(body.span),
this.allow_try_trait.clone(), Some(this.allow_try_trait.clone()),
); );
(try_span, this.expr_unit(try_span)) (try_span, this.expr_unit(try_span))
@ -618,8 +618,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
// Resume argument type: `ResumeTy` // Resume argument type: `ResumeTy`
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,
Some(self.allow_gen_future.clone()),
);
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span); let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
let input_ty = hir::Ty { let input_ty = hir::Ty {
hir_id: self.next_id(), hir_id: self.next_id(),
@ -741,7 +744,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let unstable_span = self.mark_span_with_reason( let unstable_span = self.mark_span_with_reason(
DesugaringKind::Async, DesugaringKind::Async,
span, span,
self.allow_gen_future.clone(), Some(self.allow_gen_future.clone()),
); );
self.lower_attrs( self.lower_attrs(
inner_hir_id, inner_hir_id,
@ -788,7 +791,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let gen_future_span = self.mark_span_with_reason( let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await, DesugaringKind::Await,
full_span, full_span,
self.allow_gen_future.clone(), Some(self.allow_gen_future.clone()),
); );
let expr = self.lower_expr_mut(expr); let expr = self.lower_expr_mut(expr);
let expr_hir_id = expr.hir_id; let expr_hir_id = expr.hir_id;
@ -1646,13 +1649,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let unstable_span = self.mark_span_with_reason( let unstable_span = self.mark_span_with_reason(
DesugaringKind::QuestionMark, DesugaringKind::QuestionMark,
span, span,
self.allow_try_trait.clone(), Some(self.allow_try_trait.clone()),
); );
let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.tcx.sess.source_map().end_point(span);
let try_span = self.mark_span_with_reason( let try_span = self.mark_span_with_reason(
DesugaringKind::QuestionMark, DesugaringKind::QuestionMark,
try_span, try_span,
self.allow_try_trait.clone(), Some(self.allow_try_trait.clone()),
); );
// `Try::branch(<expr>)` // `Try::branch(<expr>)`
@ -1745,7 +1748,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let unstable_span = self.mark_span_with_reason( let unstable_span = self.mark_span_with_reason(
DesugaringKind::YeetExpr, DesugaringKind::YeetExpr,
span, span,
self.allow_try_trait.clone(), Some(self.allow_try_trait.clone()),
); );
let from_yeet_expr = self.wrap_in_try_constructor( let from_yeet_expr = self.wrap_in_try_constructor(

View file

@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
/// A visitor that walks over the HIR and collects `Node`s into a HIR map. /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
pub(super) struct NodeCollector<'a, 'hir> { struct NodeCollector<'a, 'hir> {
tcx: TyCtxt<'hir>, tcx: TyCtxt<'hir>,
bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>, bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,

View file

@ -7,7 +7,6 @@ use hir::definitions::DefPathData;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt; use rustc_ast::visit::AssocCtxt;
use rustc_ast::*; use rustc_ast::*;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -55,42 +54,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
owner: NodeId, owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
) { ) {
let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller { let mut lctx = LoweringContext::new(self.tcx, self.resolver);
[sym::gen_future, sym::closure_track_caller][..].into()
} else {
[sym::gen_future][..].into()
});
let mut lctx = LoweringContext {
// Pseudo-globals.
tcx: self.tcx,
resolver: self.resolver,
arena: self.tcx.hir_arena,
// HirId handling.
bodies: Vec::new(),
attrs: SortedMap::default(),
children: Vec::default(),
current_hir_id_owner: hir::CRATE_OWNER_ID,
item_local_id_counter: hir::ItemLocalId::new(0),
node_id_to_local_id: Default::default(),
trait_map: Default::default(),
// Lowering state.
catch_scope: None,
loop_scope: None,
is_in_loop_condition: false,
is_in_trait_impl: false,
is_in_dyn_type: false,
coroutine_kind: None,
task_context: None,
current_item: None,
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future,
generics_def_id_map: Default::default(),
host_param_id: None,
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx)); lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children { for (def_id, info) in lctx.children {
@ -136,39 +100,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
let def_id = self.resolver.node_id_to_def_id[&item.id]; let def_id = self.resolver.node_id_to_def_id[&item.id];
let parent_id = self.tcx.local_parent(def_id); let parent_id = self.tcx.local_parent(def_id);
let parent_hir = self.lower_node(parent_id).unwrap(); let parent_hir = self.lower_node(parent_id).unwrap();
self.with_lctx(item.id, |lctx| { self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt, parent_hir))
// Evaluate with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(impl_) => {
lctx.is_in_trait_impl = impl_.of_trait.is_some();
}
hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
lctx.host_param_id = generics
.params
.iter()
.find(|param| {
parent_hir
.attrs
.get(param.hir_id.local_id)
.iter()
.any(|attr| attr.has_name(sym::rustc_host))
})
.map(|param| param.def_id);
}
_ => {}
}
match ctxt {
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
}
})
} }
fn lower_foreign_item(&mut self, item: &ForeignItem) { fn lower_foreign_item(&mut self, item: &ForeignItem) {
@ -611,6 +545,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
} }
} }
fn lower_assoc_item(
&mut self,
item: &AssocItem,
ctxt: AssocCtxt,
parent_hir: &'hir hir::OwnerInfo<'hir>,
) -> hir::OwnerNode<'hir> {
// Evaluate with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
}
hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => {
self.host_param_id = generics
.params
.iter()
.find(|param| {
parent_hir
.attrs
.get(param.hir_id.local_id)
.iter()
.any(|attr| attr.has_name(sym::rustc_host))
})
.map(|param| param.def_id);
}
_ => {}
}
match ctxt {
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)),
}
}
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
let hir_id = self.lower_node_id(i.id); let hir_id = self.lower_node_id(i.id);
let owner_id = hir_id.expect_owner(); let owner_id = hir_id.expect_owner();

View file

@ -35,7 +35,6 @@
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(never_type)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
@ -132,8 +131,8 @@ struct LoweringContext<'a, 'hir> {
/// NodeIds that are lowered inside the current HIR owner. /// NodeIds that are lowered inside the current HIR owner.
node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>, node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
allow_try_trait: Option<Lrc<[Symbol]>>, allow_try_trait: Lrc<[Symbol]>,
allow_gen_future: Option<Lrc<[Symbol]>>, allow_gen_future: Lrc<[Symbol]>,
/// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
@ -144,6 +143,46 @@ struct LoweringContext<'a, 'hir> {
host_param_id: Option<LocalDefId>, host_param_id: Option<LocalDefId>,
} }
impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
Self {
// Pseudo-globals.
tcx,
resolver: resolver,
arena: tcx.hir_arena,
// HirId handling.
bodies: Vec::new(),
attrs: SortedMap::default(),
children: Vec::default(),
current_hir_id_owner: hir::CRATE_OWNER_ID,
item_local_id_counter: hir::ItemLocalId::new(0),
node_id_to_local_id: Default::default(),
trait_map: Default::default(),
// Lowering state.
catch_scope: None,
loop_scope: None,
is_in_loop_condition: false,
is_in_trait_impl: false,
is_in_dyn_type: false,
coroutine_kind: None,
task_context: None,
current_item: None,
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
allow_gen_future: if tcx.features().async_fn_track_caller {
[sym::gen_future, sym::closure_track_caller].into()
} else {
[sym::gen_future].into()
},
generics_def_id_map: Default::default(),
host_param_id: None,
}
}
}
trait ResolverAstLoweringExt { trait ResolverAstLoweringExt {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>; fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>; fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;

View file

@ -108,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
} }
} }
pub fn lifetimes_in_bounds( pub(crate) fn lifetimes_in_bounds(
resolver: &ResolverAstLowering, resolver: &ResolverAstLowering,
bounds: &GenericBounds, bounds: &GenericBounds,
) -> Vec<Lifetime> { ) -> Vec<Lifetime> {

View file

@ -18,7 +18,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.arena.alloc(self.lower_pat_mut(pattern)) self.arena.alloc(self.lower_pat_mut(pattern))
} }
pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
// loop here to avoid recursion // loop here to avoid recursion
let node = loop { let node = loop {

View file

@ -2352,7 +2352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used");
err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>"); err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
} }
suggested = true; suggested = true;

View file

@ -672,30 +672,22 @@ fn report_missing_placeholders(
if explained.contains(&sub) { if explained.contains(&sub) {
continue; continue;
} }
explained.insert(sub.clone()); explained.insert(sub);
if !found_foreign { if !found_foreign {
found_foreign = true; found_foreign = true;
show_doc_note = true; show_doc_note = true;
} }
if let Some(inner_sp) = pos { let sp = fmt_span.from_inner(pos);
let sp = fmt_span.from_inner(inner_sp);
if success { if success {
suggestions.push((sp, trn)); suggestions.push((sp, trn));
} else {
diag.span_note(
sp,
format!("format specifiers use curly braces, and {}", trn),
);
}
} else { } else {
if success { diag.span_note(
diag.help(format!("`{}` should be written as `{}`", sub, trn)); sp,
} else { format!("format specifiers use curly braces, and {}", trn),
diag.note(format!("`{}` should use curly braces, and {}", sub, trn)); );
}
} }
} }

View file

@ -19,10 +19,10 @@ pub(crate) mod printf {
} }
} }
pub fn position(&self) -> Option<InnerSpan> { pub fn position(&self) -> InnerSpan {
match self { match self {
Substitution::Format(fmt) => Some(fmt.position), Substitution::Format(fmt) => fmt.position,
&Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), &Substitution::Escape((start, end)) => InnerSpan::new(start, end),
} }
} }
@ -302,10 +302,9 @@ pub(crate) mod printf {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let (mut sub, tail) = parse_next_substitution(self.s)?; let (mut sub, tail) = parse_next_substitution(self.s)?;
self.s = tail; self.s = tail;
if let Some(InnerSpan { start, end }) = sub.position() { let InnerSpan { start, end } = sub.position();
sub.set_position(start + self.pos, end + self.pos); sub.set_position(start + self.pos, end + self.pos);
self.pos += end; self.pos += end;
}
Some(sub) Some(sub)
} }
@ -629,9 +628,9 @@ pub mod shell {
} }
} }
pub fn position(&self) -> Option<InnerSpan> { pub fn position(&self) -> InnerSpan {
let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
Some(InnerSpan::new(pos.0, pos.1)) InnerSpan::new(pos.0, pos.1)
} }
pub fn set_position(&mut self, start: usize, end: usize) { pub fn set_position(&mut self, start: usize, end: usize) {
@ -664,10 +663,9 @@ pub mod shell {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let (mut sub, tail) = parse_next_substitution(self.s)?; let (mut sub, tail) = parse_next_substitution(self.s)?;
self.s = tail; self.s = tail;
if let Some(InnerSpan { start, end }) = sub.position() { let InnerSpan { start, end } = sub.position();
sub.set_position(start + self.pos, end + self.pos); sub.set_position(start + self.pos, end + self.pos);
self.pos += end; self.pos += end;
}
Some(sub) Some(sub)
} }

View file

@ -492,7 +492,7 @@ where
let returned_walk = let returned_walk =
return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
let successor_walk = successors.by_ref().map(|successor_node| { let successor_walk = successors.map(|successor_node| {
debug!(?node, ?successor_node); debug!(?node, ?successor_node);
(successor_node, self.inspect_node(successor_node)) (successor_node, self.inspect_node(successor_node))
}); });

View file

@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> {
pub span: Span, pub span: Span,
#[suggestion_part(code = "")] #[suggestion_part(code = "")]
pub borrow_removal_span: Option<Span>, pub borrow_removal_span: Option<Span>,
pub sugg: &'static str, pub sugg: String,
pub expected: Ty<'tcx>, pub expected: Ty<'tcx>,
pub found: Ty<'tcx>, pub found: Ty<'tcx>,
} }

View file

@ -442,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected, expected,
) )
}); });
let prefix_wrap = |sugg: &str| {
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
format!(": {}{}", name, sugg)
} else {
sugg.to_string()
}
};
// 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.
if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
let sugg = prefix_wrap(".as_ref()");
err.subdiagnostic(errors::SuggestConvertViaMethod { err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(), span: expr.span.shrink_to_hi(),
sugg: ".as_ref()", sugg,
expected, expected,
found, found,
borrow_removal_span, borrow_removal_span,
@ -458,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.can_eq(self.param_env, deref_ty, peeled) && self.can_eq(self.param_env, deref_ty, peeled)
&& error_tys_equate_as_ref && error_tys_equate_as_ref
{ {
let sugg = prefix_wrap(".as_deref()");
err.subdiagnostic(errors::SuggestConvertViaMethod { err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(), span: expr.span.shrink_to_hi(),
sugg: ".as_deref()", sugg,
expected, expected,
found, found,
borrow_removal_span, borrow_removal_span,
@ -474,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.can_eq(self.param_env, found, expected) self.can_eq(self.param_env, found, expected)
}) })
{ {
let sugg = prefix_wrap(".map(|x| x.as_str())");
err.span_suggestion_verbose( err.span_suggestion_verbose(
expr.span.shrink_to_hi(), expr.span.shrink_to_hi(),
fluent::hir_typeck_convert_to_str, fluent::hir_typeck_convert_to_str,
".map(|x| x.as_str())", sugg,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
return true; return true;
@ -628,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help("use `Box::pin`"); err.help("use `Box::pin`");
} }
_ => { _ => {
let prefix = if let Some(name) =
self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
{
format!("{}: ", name)
} else {
String::new()
};
let suggestion = vec![
(expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
(expr.span.shrink_to_hi(), ")".to_string()),
];
err.multipart_suggestion( err.multipart_suggestion(
"you need to pin and box this expression", "you need to pin and box this expression",
vec![ suggestion,
(expr.span.shrink_to_lo(), "Box::pin(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
@ -1214,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span = parent_callsite; span = parent_callsite;
} }
let sugg = if expr.precedence().order() >= PREC_POSTFIX { let mut 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![ vec![
@ -1222,6 +1242,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(span.shrink_to_hi(), ").into()".to_owned()), (span.shrink_to_hi(), ").into()".to_owned()),
] ]
}; };
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
}
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}`"),
sugg, sugg,
@ -1811,6 +1834,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".expect(\"REASON\")", ".expect(\"REASON\")",
) )
}; };
let sugg = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!(": {ident}{sugg}"),
None => sugg.to_string(),
};
err.span_suggestion_verbose( err.span_suggestion_verbose(
expr.span.shrink_to_hi(), expr.span.shrink_to_hi(),
msg, msg,

View file

@ -744,6 +744,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err, err,
span, span,
source, source,
path,
res, res,
&path_str, &path_str,
&base_error.fallback_label, &base_error.fallback_label,
@ -1328,6 +1329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic, err: &mut Diagnostic,
span: Span, span: Span,
source: PathSource<'_>, source: PathSource<'_>,
path: &[Segment],
res: Res, res: Res,
path_str: &str, path_str: &str,
fallback_label: &str, fallback_label: &str,
@ -1523,12 +1525,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
| PathSource::Struct, | PathSource::Struct,
) => { ) => {
err.span_label(span, fallback_label.to_string()); err.span_label(span, fallback_label.to_string());
err.span_suggestion_verbose(
span.shrink_to_hi(), // Don't suggest `!` for a macro invocation if there are generic args
"use `!` to invoke the macro", if path
"!", .last()
Applicability::MaybeIncorrect, .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
); {
err.span_suggestion_verbose(
span.shrink_to_hi(),
"use `!` to invoke the macro",
"!",
Applicability::MaybeIncorrect,
);
}
if path_str == "try" && span.is_rust_2015() { if path_str == "try" && span.is_rust_2015() {
err.note("if you want the `try` keyword, you need Rust 2018 or later"); err.note("if you want the `try` keyword, you need Rust 2018 or later");
} }

View file

@ -222,7 +222,6 @@ rustc_index::newtype_index! {
} }
} }
// njn: I don't understand these
impl<E: Encoder> Encodable<E> for DefIndex { impl<E: Encoder> Encodable<E> for DefIndex {
default fn encode(&self, _: &mut E) { default fn encode(&self, _: &mut E) {
panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>()); panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());

View file

@ -171,6 +171,7 @@ struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
/// An opaque representation of `WithHeader<H>` to avoid the /// An opaque representation of `WithHeader<H>` to avoid the
/// projection invariance of `<T as Pointee>::Metadata`. /// projection invariance of `<T as Pointee>::Metadata`.
#[repr(transparent)] #[repr(transparent)]
#[allow(unused_tuple_struct_fields)] // Field only used through `WithHeader` type above.
struct WithOpaqueHeader(NonNull<u8>); struct WithOpaqueHeader(NonNull<u8>);
impl WithOpaqueHeader { impl WithOpaqueHeader {

@ -1 +1 @@
Subproject commit 9b13310ca596020a737aaa47daa4ed9ff8898a2f Subproject commit 26333c732095d207aa05932ce863d850fb309386

View file

@ -9,7 +9,7 @@ LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
LL | bar(x); LL | bar(x);
| - borrow later used here | - borrow later used here
| |
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
@ -24,7 +24,7 @@ LL |
LL | bar(foo); LL | bar(foo);
| --- borrow later used here | --- borrow later used here
| |
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -0,0 +1,20 @@
// run-rustfix
#![allow(unused, dead_code)]
#[derive(Clone, Copy)]
struct Stuff {
count: i32,
}
struct Error;
fn demo() -> Result<Stuff, Error> {
let count = Ok(1);
Ok(Stuff { count: count? }) //~ ERROR mismatched types
}
fn demo_unwrap() -> Stuff {
let count = Some(1);
Stuff { count: count.expect("REASON") } //~ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,20 @@
// run-rustfix
#![allow(unused, dead_code)]
#[derive(Clone, Copy)]
struct Stuff {
count: i32,
}
struct Error;
fn demo() -> Result<Stuff, Error> {
let count = Ok(1);
Ok(Stuff { count }) //~ ERROR mismatched types
}
fn demo_unwrap() -> Stuff {
let count = Some(1);
Stuff { count } //~ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,29 @@
error[E0308]: mismatched types
--> $DIR/issue-118145-unwrap-for-shorthand.rs:12:16
|
LL | Ok(Stuff { count })
| ^^^^^ expected `i32`, found `Result<{integer}, _>`
|
= note: expected type `i32`
found enum `Result<{integer}, _>`
help: use the `?` operator to extract the `Result<{integer}, _>` value, propagating a `Result::Err` value to the caller
|
LL | Ok(Stuff { count: count? })
| ++++++++
error[E0308]: mismatched types
--> $DIR/issue-118145-unwrap-for-shorthand.rs:17:13
|
LL | Stuff { count }
| ^^^^^ expected `i32`, found `Option<{integer}>`
|
= note: expected type `i32`
found enum `Option<{integer}>`
help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
|
LL | Stuff { count: count.expect("REASON") }
| ++++++++++++++++++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,77 @@
// run-rustfix
// edition:2021
#![allow(dead_code)]
#![allow(unused_variables)]
use std::future::Future;
use std::pin::Pin;
fn test1() {
let string = String::from("Hello, world");
struct Demo<'a> {
option: Option<&'a str>,
}
let option: Option<String> = Some(string.clone());
let s = Demo { option: option.as_deref() }; //~ ERROR mismatched types
}
fn test2() {
let string = String::from("Hello, world");
struct Demo<'a> {
option_ref: Option<&'a str>,
}
let option_ref = Some(&string);
let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
}
fn test3() {
let string = String::from("Hello, world");
struct Demo<'a> {
option_ref_ref: Option<&'a str>,
}
let option_ref = Some(&string);
let option_ref_ref = option_ref.as_ref();
let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
}
fn test4() {
let a = 1;
struct Demo {
a: String,
}
let s = Demo { a: a.to_string() }; //~ ERROR mismatched types
}
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
fn test5() {
let a = async { 42 };
struct Demo {
a: BoxFuture<'static, i32>,
}
let s = Demo { a: Box::pin(a) }; //~ ERROR mismatched types
}
fn test6() {
struct A;
struct B;
impl From<B> for A {
fn from(_: B) -> Self {
A
}
}
struct Demo {
a: A,
}
let a = B;
let s = Demo { a: a.into() }; //~ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,77 @@
// run-rustfix
// edition:2021
#![allow(dead_code)]
#![allow(unused_variables)]
use std::future::Future;
use std::pin::Pin;
fn test1() {
let string = String::from("Hello, world");
struct Demo<'a> {
option: Option<&'a str>,
}
let option: Option<String> = Some(string.clone());
let s = Demo { option }; //~ ERROR mismatched types
}
fn test2() {
let string = String::from("Hello, world");
struct Demo<'a> {
option_ref: Option<&'a str>,
}
let option_ref = Some(&string);
let s = Demo { option_ref }; //~ ERROR mismatched types
}
fn test3() {
let string = String::from("Hello, world");
struct Demo<'a> {
option_ref_ref: Option<&'a str>,
}
let option_ref = Some(&string);
let option_ref_ref = option_ref.as_ref();
let s = Demo { option_ref_ref }; //~ ERROR mismatched types
}
fn test4() {
let a = 1;
struct Demo {
a: String,
}
let s = Demo { a }; //~ ERROR mismatched types
}
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
fn test5() {
let a = async { 42 };
struct Demo {
a: BoxFuture<'static, i32>,
}
let s = Demo { a }; //~ ERROR mismatched types
}
fn test6() {
struct A;
struct B;
impl From<B> for A {
fn from(_: B) -> Self {
A
}
}
struct Demo {
a: A,
}
let a = B;
let s = Demo { a }; //~ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,80 @@
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:16:20
|
LL | let s = Demo { option };
| ^^^^^^ expected `Option<&str>`, found `Option<String>`
|
= note: expected enum `Option<&str>`
found enum `Option<String>`
help: try using `: option.as_deref()` to convert `Option<String>` to `Option<&str>`
|
LL | let s = Demo { option: option.as_deref() };
| +++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:27:20
|
LL | let s = Demo { option_ref };
| ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
|
= note: expected enum `Option<&str>`
found enum `Option<&String>`
help: try converting the passed type into a `&str`
|
LL | let s = Demo { option_ref: option_ref.map(|x| x.as_str()) };
| ++++++++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:40:20
|
LL | let s = Demo { option_ref_ref };
| ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
|
= note: expected enum `Option<&str>`
found enum `Option<&&String>`
help: try converting the passed type into a `&str`
|
LL | let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) };
| ++++++++++++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:48:20
|
LL | let s = Demo { a };
| ^ expected `String`, found integer
|
help: try using a conversion method
|
LL | let s = Demo { a: a.to_string() };
| ++ ++++++++++++
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20
|
LL | let a = async { 42 };
| ------------ the found `async` block
...
LL | let s = Demo { a };
| ^ expected `Pin<Box<...>>`, found `async` block
|
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}`
help: you need to pin and box this expression
|
LL | let s = Demo { a: Box::pin(a) };
| ++++++++++++ +
error[E0308]: mismatched types
--> $DIR/mismatch-sugg-for-shorthand-field.rs:74:20
|
LL | let s = Demo { a };
| ^ expected `A`, found `B`
|
help: call `Into::into` on this expression to convert `B` into `A`
|
LL | let s = Demo { a: a.into() };
| ++ +++++++
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,4 @@
fn main() {
let zero = assert_eq::<()>();
//~^ ERROR expected function, found macro `assert_eq`
}

View file

@ -0,0 +1,9 @@
error[E0423]: expected function, found macro `assert_eq`
--> $DIR/resolve-dont-hint-macro.rs:2:16
|
LL | let zero = assert_eq::<()>();
| ^^^^^^^^^^^^^^^ not a function
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0423`.