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:
commit
e9b7bf0114
25 changed files with 490 additions and 133 deletions
|
@ -530,7 +530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
expr.span,
|
||||
this.allow_try_trait.clone(),
|
||||
Some(this.allow_try_trait.clone()),
|
||||
),
|
||||
expr,
|
||||
)
|
||||
|
@ -538,7 +538,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let try_span = this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
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))
|
||||
|
@ -618,8 +618,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span =
|
||||
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
span,
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
|
@ -741,7 +744,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
span,
|
||||
self.allow_gen_future.clone(),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
self.lower_attrs(
|
||||
inner_hir_id,
|
||||
|
@ -788,7 +791,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let gen_future_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Await,
|
||||
full_span,
|
||||
self.allow_gen_future.clone(),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let expr = self.lower_expr_mut(expr);
|
||||
let expr_hir_id = expr.hir_id;
|
||||
|
@ -1646,13 +1649,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::QuestionMark,
|
||||
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.mark_span_with_reason(
|
||||
DesugaringKind::QuestionMark,
|
||||
try_span,
|
||||
self.allow_try_trait.clone(),
|
||||
Some(self.allow_try_trait.clone()),
|
||||
);
|
||||
|
||||
// `Try::branch(<expr>)`
|
||||
|
@ -1745,7 +1748,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::YeetExpr,
|
||||
span,
|
||||
self.allow_try_trait.clone(),
|
||||
Some(self.allow_try_trait.clone()),
|
||||
);
|
||||
|
||||
let from_yeet_expr = self.wrap_in_try_constructor(
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
/// 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>,
|
||||
|
||||
bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
|
||||
|
|
|
@ -7,7 +7,6 @@ use hir::definitions::DefPathData;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -55,42 +54,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller {
|
||||
[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,
|
||||
};
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
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) {
|
||||
let def_id = self.resolver.node_id_to_def_id[&item.id];
|
||||
|
||||
let parent_id = self.tcx.local_parent(def_id);
|
||||
let parent_hir = self.lower_node(parent_id).unwrap();
|
||||
self.with_lctx(item.id, |lctx| {
|
||||
// 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)),
|
||||
}
|
||||
})
|
||||
self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt, parent_hir))
|
||||
}
|
||||
|
||||
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> {
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
let owner_id = hir_id.expect_owner();
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#![doc(rust_logo)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
@ -132,8 +131,8 @@ struct LoweringContext<'a, 'hir> {
|
|||
/// NodeIds that are lowered inside the current HIR owner.
|
||||
node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
|
||||
|
||||
allow_try_trait: Option<Lrc<[Symbol]>>,
|
||||
allow_gen_future: Option<Lrc<[Symbol]>>,
|
||||
allow_try_trait: Lrc<[Symbol]>,
|
||||
allow_gen_future: Lrc<[Symbol]>,
|
||||
|
||||
/// 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
|
||||
|
@ -144,6 +143,46 @@ struct LoweringContext<'a, 'hir> {
|
|||
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 {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
|
||||
|
|
|
@ -108,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lifetimes_in_bounds(
|
||||
pub(crate) fn lifetimes_in_bounds(
|
||||
resolver: &ResolverAstLowering,
|
||||
bounds: &GenericBounds,
|
||||
) -> Vec<Lifetime> {
|
||||
|
|
|
@ -18,7 +18,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
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(|| {
|
||||
// loop here to avoid recursion
|
||||
let node = loop {
|
||||
|
|
|
@ -2352,7 +2352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} 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>");
|
||||
}
|
||||
suggested = true;
|
||||
|
|
|
@ -672,30 +672,22 @@ fn report_missing_placeholders(
|
|||
if explained.contains(&sub) {
|
||||
continue;
|
||||
}
|
||||
explained.insert(sub.clone());
|
||||
explained.insert(sub);
|
||||
|
||||
if !found_foreign {
|
||||
found_foreign = true;
|
||||
show_doc_note = true;
|
||||
}
|
||||
|
||||
if let Some(inner_sp) = pos {
|
||||
let sp = fmt_span.from_inner(inner_sp);
|
||||
let sp = fmt_span.from_inner(pos);
|
||||
|
||||
if success {
|
||||
suggestions.push((sp, trn));
|
||||
} else {
|
||||
diag.span_note(
|
||||
sp,
|
||||
format!("format specifiers use curly braces, and {}", trn),
|
||||
);
|
||||
}
|
||||
if success {
|
||||
suggestions.push((sp, trn));
|
||||
} else {
|
||||
if success {
|
||||
diag.help(format!("`{}` should be written as `{}`", sub, trn));
|
||||
} else {
|
||||
diag.note(format!("`{}` should use curly braces, and {}", sub, trn));
|
||||
}
|
||||
diag.span_note(
|
||||
sp,
|
||||
format!("format specifiers use curly braces, and {}", trn),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ pub(crate) mod printf {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Option<InnerSpan> {
|
||||
pub fn position(&self) -> InnerSpan {
|
||||
match self {
|
||||
Substitution::Format(fmt) => Some(fmt.position),
|
||||
&Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)),
|
||||
Substitution::Format(fmt) => fmt.position,
|
||||
&Substitution::Escape((start, end)) => InnerSpan::new(start, end),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,10 +302,9 @@ pub(crate) mod printf {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (mut sub, tail) = parse_next_substitution(self.s)?;
|
||||
self.s = tail;
|
||||
if let Some(InnerSpan { start, end }) = sub.position() {
|
||||
sub.set_position(start + self.pos, end + self.pos);
|
||||
self.pos += end;
|
||||
}
|
||||
let InnerSpan { start, end } = sub.position();
|
||||
sub.set_position(start + self.pos, end + self.pos);
|
||||
self.pos += end;
|
||||
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;
|
||||
Some(InnerSpan::new(pos.0, pos.1))
|
||||
InnerSpan::new(pos.0, pos.1)
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, start: usize, end: usize) {
|
||||
|
@ -664,10 +663,9 @@ pub mod shell {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (mut sub, tail) = parse_next_substitution(self.s)?;
|
||||
self.s = tail;
|
||||
if let Some(InnerSpan { start, end }) = sub.position() {
|
||||
sub.set_position(start + self.pos, end + self.pos);
|
||||
self.pos += end;
|
||||
}
|
||||
let InnerSpan { start, end } = sub.position();
|
||||
sub.set_position(start + self.pos, end + self.pos);
|
||||
self.pos += end;
|
||||
Some(sub)
|
||||
}
|
||||
|
||||
|
|
|
@ -492,7 +492,7 @@ where
|
|||
let returned_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);
|
||||
(successor_node, self.inspect_node(successor_node))
|
||||
});
|
||||
|
|
|
@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> {
|
|||
pub span: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
pub borrow_removal_span: Option<Span>,
|
||||
pub sugg: &'static str,
|
||||
pub sugg: String,
|
||||
pub expected: Ty<'tcx>,
|
||||
pub found: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
@ -442,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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`,
|
||||
// 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 {
|
||||
let sugg = prefix_wrap(".as_ref()");
|
||||
err.subdiagnostic(errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg: ".as_ref()",
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
|
@ -458,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&& self.can_eq(self.param_env, deref_ty, peeled)
|
||||
&& error_tys_equate_as_ref
|
||||
{
|
||||
let sugg = prefix_wrap(".as_deref()");
|
||||
err.subdiagnostic(errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg: ".as_deref()",
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
|
@ -474,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.can_eq(self.param_env, found, expected)
|
||||
})
|
||||
{
|
||||
let sugg = prefix_wrap(".map(|x| x.as_str())");
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
fluent::hir_typeck_convert_to_str,
|
||||
".map(|x| x.as_str())",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
|
@ -628,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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(
|
||||
"you need to pin and box this expression",
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "Box::pin(".to_string()),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
@ -1214,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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())]
|
||||
} else {
|
||||
vec![
|
||||
|
@ -1222,6 +1242,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(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(
|
||||
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
|
||||
sugg,
|
||||
|
@ -1811,6 +1834,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
".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(
|
||||
expr.span.shrink_to_hi(),
|
||||
msg,
|
||||
|
|
|
@ -744,6 +744,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
err,
|
||||
span,
|
||||
source,
|
||||
path,
|
||||
res,
|
||||
&path_str,
|
||||
&base_error.fallback_label,
|
||||
|
@ -1328,6 +1329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
path: &[Segment],
|
||||
res: Res,
|
||||
path_str: &str,
|
||||
fallback_label: &str,
|
||||
|
@ -1523,12 +1525,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
| PathSource::Struct,
|
||||
) => {
|
||||
err.span_label(span, fallback_label.to_string());
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"use `!` to invoke the macro",
|
||||
"!",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
// Don't suggest `!` for a macro invocation if there are generic args
|
||||
if path
|
||||
.last()
|
||||
.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() {
|
||||
err.note("if you want the `try` keyword, you need Rust 2018 or later");
|
||||
}
|
||||
|
|
|
@ -222,7 +222,6 @@ rustc_index::newtype_index! {
|
|||
}
|
||||
}
|
||||
|
||||
// njn: I don't understand these
|
||||
impl<E: Encoder> Encodable<E> for DefIndex {
|
||||
default fn encode(&self, _: &mut E) {
|
||||
panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());
|
||||
|
|
|
@ -171,6 +171,7 @@ struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
|
|||
/// An opaque representation of `WithHeader<H>` to avoid the
|
||||
/// projection invariance of `<T as Pointee>::Metadata`.
|
||||
#[repr(transparent)]
|
||||
#[allow(unused_tuple_struct_fields)] // Field only used through `WithHeader` type above.
|
||||
struct WithOpaqueHeader(NonNull<u8>);
|
||||
|
||||
impl WithOpaqueHeader {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 9b13310ca596020a737aaa47daa4ed9ff8898a2f
|
||||
Subproject commit 26333c732095d207aa05932ce863d850fb309386
|
|
@ -9,7 +9,7 @@ LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
|
|||
LL | bar(x);
|
||||
| - 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: 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);
|
||||
| --- 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: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
|
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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`.
|
4
tests/ui/resolve/resolve-dont-hint-macro.rs
Normal file
4
tests/ui/resolve/resolve-dont-hint-macro.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
let zero = assert_eq::<()>();
|
||||
//~^ ERROR expected function, found macro `assert_eq`
|
||||
}
|
9
tests/ui/resolve/resolve-dont-hint-macro.stderr
Normal file
9
tests/ui/resolve/resolve-dont-hint-macro.stderr
Normal 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`.
|
Loading…
Add table
Reference in a new issue