summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck')
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml1
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs74
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs121
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs52
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs167
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs293
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs40
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs171
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs159
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs129
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs156
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs320
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs21
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs93
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs108
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs44
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs45
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs89
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs305
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs167
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs264
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs124
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs206
39 files changed, 1902 insertions, 1460 deletions
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index 13e1ea31c..ce91d023a 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2021"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
+rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 3d012a15a..2281343e2 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -77,6 +77,10 @@ hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang
hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
+hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expected_ty}` to `{$expr_ty}`
+hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
+hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
+
hir_typeck_return_stmt_outside_of_fn_body =
{$statement_kind} statement outside of function body
.encl_body_label = the {$statement_kind} is part of this body...
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e8720a5da..7ad9f51ba 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// #55810: Type check patterns first so we get types for all bindings.
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
for arm in arms {
- self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
+ self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None);
}
// Now typecheck the blocks.
@@ -107,7 +107,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (span, code) = match prior_arm {
// The reason for the first arm to fail is not that the match arms diverge,
// but rather that there's a prior obligation that doesn't hold.
- None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
+ None => {
+ (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src))
+ }
Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
expr.span,
ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
@@ -120,7 +122,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
scrut_span: scrut.span,
source: match_src,
prior_arms: other_arms.clone(),
- scrut_hir_id: scrut.hir_id,
opt_suggest_box_span,
})),
),
@@ -136,15 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&cause,
Some(&arm.body),
arm_ty,
- Some(&mut |err| {
- self.suggest_removing_semicolon_for_coerce(
- err,
- expr,
- orig_expected,
- arm_ty,
- prior_arm,
- )
- }),
+ |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm),
false,
);
@@ -153,7 +146,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
other_arms.remove(0);
}
- prior_arm = Some((arm_block_id, arm_ty, arm_span));
+ if !arm_ty.is_never() {
+ // When a match arm has type `!`, then it doesn't influence the expected type for
+ // the following arm. If all of the prior arms are `!`, then the influence comes
+ // from elsewhere and we shouldn't point to any previous arm.
+ prior_arm = Some((arm_block_id, arm_ty, arm_span));
+ }
}
// If all of the arms in the `match` diverge,
@@ -181,18 +179,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
diag: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
- expectation: Expectation<'tcx>,
arm_ty: Ty<'tcx>,
prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
) {
let hir = self.tcx.hir();
// First, check that we're actually in the tail of a function.
- let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; };
+ let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else {
+ return;
+ };
let body = hir.body(body_id);
- let hir::ExprKind::Block(block, _) = body.value.kind else { return; };
- let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
- = block.innermost_block().stmts.last() else { return; };
+ let hir::ExprKind::Block(block, _) = body.value.kind else {
+ return;
+ };
+ let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), span: semi_span, .. }) =
+ block.innermost_block().stmts.last()
+ else {
+ return;
+ };
if last_expr.hir_id != expr.hir_id {
return;
}
@@ -201,8 +205,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(ret) = hir
.find_by_def_id(self.body_id)
.and_then(|owner| owner.fn_decl())
- .map(|decl| decl.output.span()) else { return; };
- let Expectation::IsLast(stmt) = expectation else {
+ .map(|decl| decl.output.span())
+ else {
return;
};
@@ -221,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+ let semi_span = expr.span.shrink_to_hi().with_hi(semi_span.hi());
let mut ret_span: MultiSpan = semi_span.into();
ret_span.push_span_label(
expr.span,
@@ -269,7 +273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coercion.coerce_forced_unit(
self,
&cause,
- &mut |err| {
+ |err| {
if let Some((span, msg)) = &ret_reason {
err.span_label(*span, msg.clone());
} else if let ExprKind::Block(block, _) = &then_expr.kind
@@ -508,9 +512,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id),
..
- } = self.type_var_origin(expected)? else { return None; };
+ } = self.type_var_origin(expected)?
+ else {
+ return None;
+ };
- let Some(rpit_local_def_id) = rpit_def_id.as_local() else { return None; };
+ let Some(rpit_local_def_id) = rpit_def_id.as_local() else {
+ return None;
+ };
if !matches!(
self.tcx.hir().expect_item(rpit_local_def_id).expect_opaque_ty().origin,
hir::OpaqueTyOrigin::FnReturn(..)
@@ -520,12 +529,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sig = self.body_fn_sig()?;
- let substs = sig.output().walk().find_map(|arg| {
+ let args = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *ty.kind()
&& def_id == rpit_def_id
{
- Some(substs)
+ Some(args)
} else {
None
}
@@ -539,23 +548,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (clause, _) in self
.tcx
.explicit_item_bounds(rpit_def_id)
- .subst_iter_copied(self.tcx, substs)
+ .iter_instantiated_copied(self.tcx, args)
{
let pred = clause.kind().rebind(match clause.kind().skip_binder() {
ty::ClauseKind::Trait(trait_pred) => {
- // FIXME(rpitit): This will need to be fixed when we move to associated types
assert!(matches!(
*trait_pred.trait_ref.self_ty().kind(),
- ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
- if def_id == rpit_def_id && substs == alias_substs
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
+ if def_id == rpit_def_id && args == alias_args
));
ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
}
ty::ClauseKind::Projection(mut proj_pred) => {
assert!(matches!(
*proj_pred.projection_ty.self_ty().kind(),
- ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
- if def_id == rpit_def_id && substs == alias_substs
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
+ if def_id == rpit_def_id && args == alias_args
));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::ClauseKind::Projection(proj_pred)
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index f306653c1..02371f85a 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -21,7 +21,7 @@ use rustc_infer::{
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
-use rustc_middle::ty::SubstsRef;
+use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident};
@@ -149,14 +149,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Some(CallStep::Builtin(adjusted_ty));
}
- ty::Closure(def_id, substs) => {
+ ty::Closure(def_id, args) => {
let def_id = def_id.expect_local();
// Check whether this is a call to a closure where we
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
- if self.closure_kind(substs).is_none() {
- let closure_sig = substs.as_closure().sig();
+ if self.closure_kind(args).is_none() {
+ let closure_sig = args.as_closure().sig();
let closure_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
infer::FnCall,
@@ -171,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
adjusted_ty,
adjustments,
fn_sig: closure_sig,
- closure_substs: substs,
+ closure_args: args,
},
);
return Some(CallStep::DeferredClosure(def_id, closure_sig));
@@ -380,16 +380,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let (fn_sig, def_id) = match *callee_ty.kind() {
- ty::FnDef(def_id, substs) => {
- self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs);
- let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
+ ty::FnDef(def_id, args) => {
+ self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, args);
+ let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);
// Unit testing: function items annotated with
// `#[rustc_evaluate_where_clauses]` trigger special output
// to let us test the trait evaluation system.
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
let predicates = self.tcx.predicates_of(def_id);
- let predicates = predicates.instantiate(self.tcx, substs);
+ let predicates = predicates.instantiate(self.tcx, args);
for (predicate, predicate_span) in predicates {
let obligation = Obligation::new(
self.tcx,
@@ -402,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.sess
.struct_span_err(
callee_expr.span,
- format!("evaluate({:?}) = {:?}", predicate, result),
+ format!("evaluate({predicate:?}) = {result:?}"),
)
.span_label(predicate_span, "predicate")
.emit();
@@ -499,15 +499,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
) {
if let [callee_expr, rest @ ..] = arg_exprs {
- let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else {
+ let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)
+ else {
return;
};
// First, do a probe with `IsSuggestion(true)` to avoid emitting
// any strange errors. If it's successful, then we'll do a true
// method lookup.
- let Ok(pick) = self
- .lookup_probe_for_diagnostic(
+ let Ok(pick) = self.lookup_probe_for_diagnostic(
segment.ident,
callee_ty,
call_expr,
@@ -531,8 +531,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
- let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+ let Some(callee_expr_span) = callee_expr.span.find_ancestor_inside(call_expr.span)
+ else {
+ return;
+ };
+ let up_to_rcvr_span = segment.ident.span.until(callee_expr_span);
+ let rest_span = callee_expr_span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
let rest_snippet = if let Some(first) = rest.first() {
self.tcx
.sess
@@ -581,12 +585,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
callee_ty: Ty<'tcx>,
arg_exprs: &'tcx [hir::Expr<'tcx>],
) -> ErrorGuaranteed {
+ // Callee probe fails when APIT references errors, so suppress those
+ // errors here.
+ if let Some((_, _, args)) = self.extract_callable_info(callee_ty)
+ && let Err(err) = args.error_reported()
+ {
+ return err;
+ }
+
let mut unit_variant = None;
if let hir::ExprKind::Path(qpath) = &callee_expr.kind
&& let Res::Def(def::DefKind::Ctor(kind, CtorKind::Const), _)
= self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
// Only suggest removing parens if there are no arguments
&& arg_exprs.is_empty()
+ && call_expr.span.contains(callee_expr.span)
{
let descr = match kind {
def::CtorOf::Struct => "struct",
@@ -633,18 +646,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
}
hir::ExprKind::Call(ref inner_callee, _) => {
- // If the call spans more than one line and the callee kind is
- // itself another `ExprCall`, that's a clue that we might just be
- // missing a semicolon (Issue #51055)
- let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
- if call_is_multiline {
- err.span_suggestion(
- callee_expr.span.shrink_to_hi(),
- "consider using a semicolon here",
- ";",
- Applicability::MaybeIncorrect,
- );
- }
if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
inner_callee_path = Some(inner_qpath);
self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
@@ -656,6 +657,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+ // If the call spans more than one line and the callee kind is
+ // itself another `ExprCall`, that's a clue that we might just be
+ // missing a semicolon (#51055, #106515).
+ let call_is_multiline = self
+ .tcx
+ .sess
+ .source_map()
+ .is_multiline(call_expr.span.with_lo(callee_expr.span.hi()))
+ && call_expr.span.ctxt() == callee_expr.span.ctxt();
+ if call_is_multiline {
+ err.span_suggestion(
+ callee_expr.span.shrink_to_hi(),
+ "consider using a semicolon here to finish the statement",
+ ";",
+ Applicability::MaybeIncorrect,
+ );
+ }
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty)
{
@@ -751,13 +769,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_hir: HirId,
span: Span,
callee_did: DefId,
- callee_substs: SubstsRef<'tcx>,
+ callee_args: GenericArgsRef<'tcx>,
) {
let tcx = self.tcx;
- if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
- return;
- }
+ // fast-reject if callee doesn't have the host effect param (non-const)
+ let generics = tcx.generics_of(callee_did);
+ let Some(host_effect_index) = generics.host_effect_index else { return };
+
+ // if the callee does have the param, we need to equate the param to some const
+ // value no matter whether the effects feature is enabled in the local crate,
+ // because inference will fail if we don't.
+ let mut host_always_on =
+ !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
// Compute the constness required by the context.
let context = tcx.hir().enclosing_body_owner(call_expr_hir);
@@ -768,33 +792,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
trace!("do not const check this context");
- return;
+ host_always_on = true;
}
let effect = match const_context {
+ _ if host_always_on => tcx.consts.true_,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
Some(hir::ConstContext::ConstFn) => {
- let substs = ty::InternalSubsts::identity_for_item(tcx, context);
- substs.host_effect_param().expect("ConstContext::Maybe must have host effect param")
+ let args = ty::GenericArgs::identity_for_item(tcx, context);
+ args.host_effect_param().expect("ConstContext::Maybe must have host effect param")
}
None => tcx.consts.true_,
};
- let generics = tcx.generics_of(callee_did);
+ trace!(?effect, ?generics, ?callee_args);
- trace!(?effect, ?generics, ?callee_substs);
-
- if let Some(idx) = generics.host_effect_index {
- let param = callee_substs.const_at(idx);
- let cause = self.misc(span);
- match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
- Ok(infer::InferOk { obligations, value: () }) => {
- self.register_predicates(obligations);
- }
- Err(e) => {
- // FIXME(effects): better diagnostic
- self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
- }
+ let param = callee_args.const_at(host_effect_index);
+ let cause = self.misc(span);
+ match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
+ Ok(infer::InferOk { obligations, value: () }) => {
+ self.register_predicates(obligations);
+ }
+ Err(e) => {
+ // FIXME(effects): better diagnostic
+ self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
}
}
}
@@ -827,7 +848,7 @@ pub struct DeferredCallResolution<'tcx> {
adjusted_ty: Ty<'tcx>,
adjustments: Vec<Adjustment<'tcx>>,
fn_sig: ty::FnSig<'tcx>,
- closure_substs: SubstsRef<'tcx>,
+ closure_args: GenericArgsRef<'tcx>,
}
impl<'a, 'tcx> DeferredCallResolution<'tcx> {
@@ -836,7 +857,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
// we should not be invoked until the closure kind has been
// determined by upvar inference
- assert!(fcx.closure_kind(self.closure_substs).is_some());
+ assert!(fcx.closure_kind(self.closure_args).is_some());
// We may now know enough to figure out fn vs fnmut etc.
match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) {
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 633933317..31a03fabe 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -103,10 +103,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(match *t.kind() {
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
- ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() {
+ ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
None => Some(PointerKind::Thin),
Some(f) => {
- let field_ty = self.field_ty(span, f, substs);
+ let field_ty = self.field_ty(span, f, args);
self.pointer_kind(field_ty, span)?
}
},
@@ -144,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let reported = self
.tcx
.sess
- .delay_span_bug(span, format!("`{:?}` should be sized but is not?", t));
+ .delay_span_bug(span, format!("`{t:?}` should be sized but is not?"));
return Err(reported);
}
})
@@ -389,34 +389,26 @@ impl<'a, 'tcx> CastCheck<'tcx> {
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
&& fcx
- .try_coerce(
- self.expr,
+ .can_coerce(
Ty::new_ref(fcx.tcx,
fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: expr_ty, mutbl },
),
self.cast_ty,
- AllowTwoPhase::No,
- None,
)
- .is_ok()
{
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()
&& expr_mutbl == Mutability::Not
&& mutbl == Mutability::Mut
&& fcx
- .try_coerce(
- self.expr,
+ .can_coerce(
Ty::new_ref(fcx.tcx,
expr_reg,
TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
),
self.cast_ty,
- AllowTwoPhase::No,
- None,
)
- .is_ok()
{
sugg_mutref = true;
}
@@ -424,30 +416,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
if !sugg_mutref
&& sugg == None
&& fcx
- .try_coerce(
- self.expr,
+ .can_coerce(
Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }),
self.cast_ty,
- AllowTwoPhase::No,
- None,
)
- .is_ok()
{
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
}
} else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
&& fcx
- .try_coerce(
- self.expr,
+ .can_coerce(
Ty::new_ref(fcx.tcx,
fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: self.expr_ty, mutbl },
),
self.cast_ty,
- AllowTwoPhase::No,
- None,
)
- .is_ok()
{
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
}
@@ -644,12 +628,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
err.span_suggestion(
self.cast_span,
"try casting to a reference instead",
- format!("&{}{}", mtstr, s),
+ format!("&{mtstr}{s}"),
Applicability::MachineApplicable,
);
}
Err(_) => {
- let msg = format!("did you mean `&{}{}`?", mtstr, tstr);
+ let msg = format!("did you mean `&{mtstr}{tstr}`?");
err.span_help(self.cast_span, msg);
}
}
@@ -705,10 +689,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
)
}),
|lint| {
- lint.help(format!(
+ lint.help(
"cast can be replaced by coercion; this might \
- require a temporary variable"
- ))
+ require a temporary variable",
+ )
},
);
}
@@ -760,7 +744,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
ty::FnDef(..) => {
// Attempt a coercion to a fn pointer type.
let f = fcx.normalize(self.expr_span, self.expr_ty.fn_sig(fcx.tcx));
- let res = fcx.try_coerce(
+ let res = fcx.coerce(
self.expr,
self.expr_ty,
Ty::new_fn_ptr(fcx.tcx, f),
@@ -860,7 +844,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(_, DynStar) => {
if fcx.tcx.features().dyn_star {
- bug!("should be handled by `try_coerce`")
+ bug!("should be handled by `coerce`")
} else {
Err(CastError::IllegalCast)
}
@@ -956,7 +940,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// Coerce to a raw pointer so that we generate AddressOf in MIR.
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr);
- fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
+ fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
.unwrap_or_else(|_| {
bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
@@ -992,7 +976,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'tcx>> {
- match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
+ match fcx.coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 8b57e311f..1fc1e5aca 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -80,7 +80,7 @@ pub(super) fn check_fn<'a, 'tcx>(
let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
- tcx.type_of(va_list_did).subst(tcx, &[region.into()])
+ tcx.type_of(va_list_did).instantiate(tcx, &[region.into()])
});
// Add formal parameters.
@@ -89,7 +89,7 @@ pub(super) fn check_fn<'a, 'tcx>(
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// Check the pattern.
let ty_span = try { inputs_hir?.get(idx)?.span };
- fcx.check_pat_top(&param.pat, param_ty, ty_span, None);
+ fcx.check_pat_top(&param.pat, param_ty, ty_span, None, None);
// Check that argument is Sized.
if !params_can_be_unsized {
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 78a9ac49d..b19fb6da6 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -10,8 +10,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime};
use rustc_infer::infer::{InferOk, InferResult};
use rustc_macros::{TypeFoldable, TypeVisitable};
-use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
+use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
@@ -81,7 +81,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!(?bound_sig, ?liberated_sig);
- let mut fcx = FnCtxt::new(self, self.param_env.without_const(), closure.def_id);
+ let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id);
let generator_types = check_fn(
&mut fcx,
liberated_sig,
@@ -93,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false,
);
- let parent_substs = InternalSubsts::identity_for_item(
+ let parent_args = GenericArgs::identity_for_item(
self.tcx,
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
@@ -105,10 +105,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
{
- let generator_substs = ty::GeneratorSubsts::new(
+ let generator_args = ty::GeneratorArgs::new(
self.tcx,
- ty::GeneratorSubstsParts {
- parent_substs,
+ ty::GeneratorArgsParts {
+ parent_args,
resume_ty,
yield_ty,
return_ty: liberated_sig.output(),
@@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Ty::new_generator(
self.tcx,
expr_def_id.to_def_id(),
- generator_substs.substs,
+ generator_args.args,
movability,
);
}
@@ -151,17 +151,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}),
};
- let closure_substs = ty::ClosureSubsts::new(
+ let closure_args = ty::ClosureArgs::new(
self.tcx,
- ty::ClosureSubstsParts {
- parent_substs,
+ ty::ClosureArgsParts {
+ parent_args,
closure_kind_ty,
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig),
tupled_upvars_ty,
},
);
- Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_substs.substs)
+ Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_args.args)
}
/// Given the expected type, figures out what it can about this closure we
@@ -172,12 +172,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
.deduce_closure_signature_from_predicates(
expected_ty,
self.tcx
.explicit_item_bounds(def_id)
- .subst_iter_copied(self.tcx, substs)
+ .iter_instantiated_copied(self.tcx, args)
.map(|(c, s)| (c.as_predicate(), s)),
),
ty::Dynamic(ref object_type, ..) => {
@@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let input_tys = if is_fn {
- let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
+ let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
debug!(?arg_param_ty);
@@ -711,38 +711,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
+ let span = self.tcx.def_span(expr_def_id);
+
let output_ty = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => {
self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
.tcx
.explicit_item_bounds(def_id)
- .subst_iter_copied(self.tcx, substs)
+ .iter_instantiated_copied(self.tcx, args)
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
ty::Error(_) => return None,
- ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
- .tcx
- .explicit_item_bounds(proj.def_id)
- .subst_iter_copied(self.tcx, proj.substs)
- .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
_ => span_bug!(
- self.tcx.def_span(expr_def_id),
+ span,
"async fn generator return type not an inference variable: {ret_ty}"
),
};
+ let output_ty = self.normalize(span, output_ty);
+
// async fn that have opaque types in their return type need to redo the conversion to inference variables
// as they fetch the still opaque version from the signature.
let InferOk { value: output_ty, obligations } = self
- .replace_opaque_types_with_inference_vars(
- output_ty,
- body_def_id,
- self.tcx.def_span(expr_def_id),
- self.param_env,
- );
+ .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env);
self.register_predicates(obligations);
Some(output_ty)
@@ -800,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Converts the types that the user supplied, in case that doing
/// so should yield an error, but returns back a signature where
- /// all parameters are of type `TyErr`.
+ /// all parameters are of type `ty::Error`.
fn error_sig_of_closure(
&self,
decl: &hir::FnDecl<'_>,
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index dc58d99ed..fca675ea9 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -46,13 +46,14 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro;
+use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
-use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::visit::TypeVisitableExt;
+use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
@@ -251,11 +252,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
- ty::Closure(closure_def_id_a, substs_a) => {
+ ty::Closure(closure_def_id_a, args_a) => {
// Non-capturing closures are coercible to
// function pointers or unsafe function pointers.
// It cannot convert closures that require unsafe.
- self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
+ self.coerce_closure_to_fn(a, closure_def_id_a, args_a, b)
}
_ => {
// Otherwise, just use unification rules.
@@ -509,9 +510,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
success(adjustments, ty, obligations)
}
- // &[T; n] or &mut [T; n] -> &[T]
- // or &mut [T; n] -> &mut [T]
- // or &Concrete -> &Trait, etc.
+ /// Performs [unsized coercion] by emulating a fulfillment loop on a
+ /// `CoerceUnsized` goal until all `CoerceUnsized` and `Unsize` goals
+ /// are successfully selected.
+ ///
+ /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
#[instrument(skip(self), level = "debug")]
fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
source = self.shallow_resolve(source);
@@ -636,21 +639,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
if traits.contains(&trait_pred.def_id()) =>
{
- if unsize_did == trait_pred.def_id() {
- let self_ty = trait_pred.self_ty();
- let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
- if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) =
- (self_ty.kind(), unsize_ty.kind())
- && data_a.principal_def_id() != data_b.principal_def_id()
- {
- debug!("coerce_unsized: found trait upcasting coercion");
- has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
- }
- if let ty::Tuple(..) = unsize_ty.kind() {
- debug!("coerce_unsized: found unsized tuple coercion");
- has_unsized_tuple_coercion = true;
- }
- }
trait_pred
}
_ => {
@@ -658,13 +646,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
continue;
}
};
+ let trait_pred = self.resolve_vars_if_possible(trait_pred);
match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) {
// Uncertain or unimplemented.
Ok(None) => {
if trait_pred.def_id() == unsize_did {
- let trait_pred = self.resolve_vars_if_possible(trait_pred);
let self_ty = trait_pred.self_ty();
- let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
+ let unsize_ty = trait_pred.trait_ref.args[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
match (self_ty.kind(), unsize_ty.kind()) {
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
@@ -701,20 +689,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// be silent, as it causes a type mismatch later.
}
- Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
+ Ok(Some(impl_source)) => {
+ // Some builtin coercions are still unstable so we detect
+ // these here and emit a feature error if coercion doesn't fail
+ // due to another reason.
+ match impl_source {
+ traits::ImplSource::Builtin(
+ BuiltinImplSource::TraitUpcasting { .. },
+ _,
+ ) => {
+ has_trait_upcasting_coercion =
+ Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
+ }
+ traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
+ has_unsized_tuple_coercion = true;
+ }
+ _ => {}
+ }
+ queue.extend(impl_source.nested_obligations())
+ }
}
}
- if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
- feature_err(
- &self.tcx.sess.parse_sess,
- sym::unsized_tuple_coercion,
- self.cause.span,
- "unsized tuple coercion is not stable enough for use and is subject to change",
- )
- .emit();
- }
-
if let Some((sub, sup)) = has_trait_upcasting_coercion
&& !self.tcx().features().trait_upcasting
{
@@ -730,6 +726,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
err.emit();
}
+ if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::unsized_tuple_coercion,
+ self.cause.span,
+ "unsized tuple coercion is not stable enough for use and is subject to change",
+ )
+ .emit();
+ }
+
Ok(coercion)
}
@@ -916,7 +922,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&self,
a: Ty<'tcx>,
closure_def_id_a: DefId,
- substs_a: SubstsRef<'tcx>,
+ args_a: GenericArgsRef<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a non-capturing closure
@@ -927,7 +933,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match b.kind() {
// At this point we haven't done capture analysis, which means
- // that the ClosureSubsts just contains an inference variable instead
+ // that the ClosureArgs just contains an inference variable instead
// of tuple of captured types.
//
// All we care here is if any variable is being captured and not the exact paths,
@@ -944,7 +950,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// `fn(arg0,arg1,...) -> _`
// or
// `unsafe fn(arg0,arg1,...) -> _`
- let closure_sig = substs_a.as_closure().sig();
+ let closure_sig = args_a.as_closure().sig();
let unsafety = fn_ty.unsafety();
let pointer_ty =
Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety));
@@ -999,15 +1005,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// adjusted type of the expression, if successful.
/// Adjustments are only recorded if the coercion succeeded.
/// The expressions *must not* have any preexisting adjustments.
- pub fn try_coerce(
+ pub fn coerce(
&self,
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
- target: Ty<'tcx>,
+ mut target: Ty<'tcx>,
allow_two_phase: AllowTwoPhase,
cause: Option<ObligationCause<'tcx>>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let source = self.try_structurally_resolve_type(expr.span, expr_ty);
+ if self.next_trait_solver() {
+ target = self.try_structurally_resolve_type(
+ cause.as_ref().map_or(expr.span, |cause| cause.span),
+ target,
+ );
+ }
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
let cause =
@@ -1024,11 +1036,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
}
- /// Same as `try_coerce()`, but without side-effects.
+ /// Same as `coerce()`, but without side-effects.
///
/// Returns false if the coercion creates any obligations that result in
/// errors.
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
+ // FIXME(-Ztrait-solver=next): We need to structurally resolve both types here.
let source = self.resolve_vars_with_obligations(expr_ty);
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
@@ -1093,8 +1106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
where
E: AsCoercionSite,
{
- let prev_ty = self.resolve_vars_with_obligations(prev_ty);
- let new_ty = self.resolve_vars_with_obligations(new_ty);
+ let prev_ty = self.try_structurally_resolve_type(cause.span, prev_ty);
+ let new_ty = self.try_structurally_resolve_type(new.span, new_ty);
debug!(
"coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
prev_ty,
@@ -1109,10 +1122,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Special-case that coercion alone cannot handle:
- // Function items or non-capturing closures of differing IDs or InternalSubsts.
+ // Function items or non-capturing closures of differing IDs or GenericArgs.
let (a_sig, b_sig) = {
let is_capturing_closure = |ty: Ty<'tcx>| {
- if let &ty::Closure(closure_def_id, _substs) = ty.kind() {
+ if let &ty::Closure(closure_def_id, _args) = ty.kind() {
self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
} else {
false
@@ -1139,30 +1152,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- (ty::Closure(_, substs), ty::FnDef(..)) => {
+ (ty::Closure(_, args), ty::FnDef(..)) => {
let b_sig = new_ty.fn_sig(self.tcx);
- let a_sig = self
- .tcx
- .signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
+ let a_sig =
+ self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.unsafety());
(Some(a_sig), Some(b_sig))
}
- (ty::FnDef(..), ty::Closure(_, substs)) => {
+ (ty::FnDef(..), ty::Closure(_, args)) => {
let a_sig = prev_ty.fn_sig(self.tcx);
- let b_sig = self
- .tcx
- .signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
+ let b_sig =
+ self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.unsafety());
(Some(a_sig), Some(b_sig))
}
- (ty::Closure(_, substs_a), ty::Closure(_, substs_b)) => (
- Some(self.tcx.signature_unclosure(
- substs_a.as_closure().sig(),
- hir::Unsafety::Normal,
- )),
- Some(self.tcx.signature_unclosure(
- substs_b.as_closure().sig(),
- hir::Unsafety::Normal,
- )),
- ),
+ (ty::Closure(_, args_a), ty::Closure(_, args_b)) => {
+ (
+ Some(self.tcx.signature_unclosure(
+ args_a.as_closure().sig(),
+ hir::Unsafety::Normal,
+ )),
+ Some(self.tcx.signature_unclosure(
+ args_b.as_closure().sig(),
+ hir::Unsafety::Normal,
+ )),
+ )
+ }
_ => (None, None),
}
}
@@ -1414,7 +1427,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expression: &'tcx hir::Expr<'tcx>,
expression_ty: Ty<'tcx>,
) {
- self.coerce_inner(fcx, cause, Some(expression), expression_ty, None, false)
+ self.coerce_inner(fcx, cause, Some(expression), expression_ty, |_| {}, false)
}
/// Indicates that one of the inputs is a "forced unit". This
@@ -1433,7 +1446,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
&mut self,
fcx: &FnCtxt<'a, 'tcx>,
cause: &ObligationCause<'tcx>,
- augment_error: &mut dyn FnMut(&mut Diagnostic),
+ augment_error: impl FnOnce(&mut Diagnostic),
label_unit_as_expected: bool,
) {
self.coerce_inner(
@@ -1441,7 +1454,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
cause,
None,
Ty::new_unit(fcx.tcx),
- Some(augment_error),
+ augment_error,
label_unit_as_expected,
)
}
@@ -1456,7 +1469,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
cause: &ObligationCause<'tcx>,
expression: Option<&'tcx hir::Expr<'tcx>>,
mut expression_ty: Ty<'tcx>,
- augment_error: Option<&mut dyn FnMut(&mut Diagnostic)>,
+ augment_error: impl FnOnce(&mut Diagnostic),
label_expression_as_expected: bool,
) {
// Incorporate whatever type inference information we have
@@ -1481,7 +1494,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// Special-case the first expression we are coercing.
// To be honest, I'm not entirely sure why we do this.
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
- fcx.try_coerce(
+ fcx.coerce(
expression,
expression_ty,
self.expected_ty,
@@ -1590,7 +1603,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
);
err.span_label(cause.span, "return type is not `()`");
}
- ObligationCauseCode::BlockTailExpression(blk_id) => {
+ ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
let parent_id = fcx.tcx.hir().parent_id(blk_id);
err = self.report_return_mismatched_types(
cause,
@@ -1635,14 +1648,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
- if let Some(augment_error) = augment_error {
- augment_error(&mut err);
- }
-
- let is_insufficiently_polymorphic =
- matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..));
+ augment_error(&mut err);
- if !is_insufficiently_polymorphic && let Some(expr) = expression {
+ if let Some(expr) = expression {
fcx.emit_coerce_suggestions(
&mut err,
expr,
@@ -1670,7 +1678,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expr: &hir::Expr<'tcx>,
ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
) {
- let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
+ let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else {
+ return;
+ };
let mut span: MultiSpan = vec![loop_span].into();
span.push_span_label(loop_span, "this might have zero elements to iterate on");
const MAXITER: usize = 3;
@@ -1738,7 +1748,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
&& !matches!(
cond_expr.kind,
- hir::ExprKind::Match(.., hir::MatchSource::TryDesugar)
+ hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
)
{
err.span_label(cond_expr.span, "expected this to be `()`");
@@ -1791,8 +1801,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
err.span_note(
sp,
format!(
- "return type inferred to be `{}` here",
- expected
+ "return type inferred to be `{expected}` here"
),
);
}
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index cc8198aab..2c16f21b4 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;
@@ -53,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_no_capture_closure(err, expected, expr_ty)
|| self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
- || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected)
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected)
@@ -84,6 +84,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.annotate_expected_due_to_let_ty(err, expr, error);
+ // FIXME(#73154): For now, we do leak check when coercing function
+ // pointers in typeck, instead of only during borrowck. This can lead
+ // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
+ if matches!(error, Some(TypeError::RegionsInsufficientlyPolymorphic(..))) {
+ return;
+ }
+
if self.is_destruct_assignment_desugaring(expr) {
return;
}
@@ -102,7 +109,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found_expr: &mut &'tcx hir::Expr<'tcx>,
expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
) {
- let Some(expected_expr) = expected_expr else { return; };
+ let Some(expected_expr) = expected_expr else {
+ return;
+ };
if !found_expr.span.eq_ctxt(expected_expr.span) {
return;
@@ -121,11 +130,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::ExprKind::Unary(
hir::UnOp::Deref,
hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
- ) = found_expr.kind else { return; };
+ ) = found_expr.kind
+ else {
+ return;
+ };
let hir::ExprKind::Unary(
hir::UnOp::Deref,
hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
- ) = expected_expr.kind else { return; };
+ ) = expected_expr.kind
+ else {
+ return;
+ };
for (path, name, idx, var) in [
(expected_path, "left_val", 0, expected_expr),
@@ -239,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
let expected = self.resolve_vars_with_obligations(expected);
- let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
+ let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {
Ok(ty) => return (ty, None),
Err(e) => e,
};
@@ -252,25 +267,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
- let expr_ty = self.resolve_vars_with_obligations(checked_ty);
+ let expr_ty = self.resolve_vars_if_possible(checked_ty);
let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
- let is_insufficiently_polymorphic =
- matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
-
- // FIXME(#73154): For now, we do leak check when coercing function
- // pointers in typeck, instead of only during borrowck. This can lead
- // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
- if !is_insufficiently_polymorphic {
- self.emit_coerce_suggestions(
- &mut err,
- expr,
- expr_ty,
- expected,
- expected_ty_expr,
- Some(e),
- );
- }
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
(expected, Some(err))
}
@@ -285,16 +285,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool {
let hir = self.tcx.hir();
- let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; };
- let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; };
- let hir::def::Res::Local(local_hir_id) = p.res else { return false; };
- let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; };
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else {
+ return false;
+ };
+ let [hir::PathSegment { ident, args: None, .. }] = p.segments else {
+ return false;
+ };
+ let hir::def::Res::Local(local_hir_id) = p.res else {
+ return false;
+ };
+ let hir::Node::Pat(pat) = hir.get(local_hir_id) else {
+ return false;
+ };
let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) {
hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
_ => return false,
};
- let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; };
+ let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
+ return false;
+ };
// Locate all the usages of the relevant binding.
struct FindExprs<'tcx> {
@@ -413,14 +423,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Bindings always update their recorded type after the fact, so we
// need to look at the *following* usage's type to see when the
// binding became incompatible.
- let [binding, next_usage] = *window else { continue; };
+ let [binding, next_usage] = *window else {
+ continue;
+ };
// Don't go past the binding (always gonna be a nonsense label if so)
if binding.hir_id == expr.hir_id {
break;
}
- let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; };
+ let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else {
+ continue;
+ };
// If the type is not constrained in a way making it not possible to
// equate with `expected_ty` by this point, skip.
@@ -461,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
let arg_ty = arg_ty.fold_with(&mut fudger);
- let _ = self.try_coerce(
+ let _ = self.coerce(
arg_expr,
arg_ty,
*expected_arg_ty,
@@ -599,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// is in a different line, so we point at both.
err.span_label(secondary_span, "expected due to the type of this binding");
err.span_label(primary_span, format!("expected due to this{post_message}"));
- } else if post_message == "" {
+ } else if post_message.is_empty() {
// We are pointing at either the assignment lhs or the binding def pattern.
err.span_label(primary_span, "expected due to the type of this binding");
} else {
@@ -634,27 +648,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: Option<TypeError<'tcx>>,
) {
let parent = self.tcx.hir().parent_id(expr.hir_id);
- let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
- let Some(hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Assign(lhs, rhs, _), ..
- })) = self.tcx.hir().find(parent) else {return; };
+ let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
+ return;
+ };
+ let Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. })) =
+ self.tcx.hir().find(parent)
+ else {
+ return;
+ };
if rhs.hir_id != expr.hir_id || expected.is_closure() {
return;
}
- let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
- let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
- let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; };
+ let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else {
+ return;
+ };
+ let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else {
+ return;
+ };
+ let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else {
+ return;
+ };
- let Ok(pick) = self
- .lookup_probe_for_diagnostic(
- path.ident,
- self_ty,
- deref,
- probe::ProbeScope::TraitsInScope,
- None,
- ) else {
- return;
- };
+ let Ok(pick) = self.lookup_probe_for_diagnostic(
+ path.ident,
+ self_ty,
+ deref,
+ probe::ProbeScope::TraitsInScope,
+ None,
+ ) else {
+ return;
+ };
let in_scope_methods = self.probe_for_name_many(
probe::Mode::MethodCall,
path.ident,
@@ -681,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter(|c| c.item.def_id != pick.item.def_id)
.map(|c| {
let m = c.item;
- let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
+ let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| {
self.var_for_def(deref.span, param)
});
let mutability =
@@ -696,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(
"{}({}",
with_no_trimmed_paths!(
- self.tcx.def_path_str_with_substs(m.def_id, substs,)
+ self.tcx.def_path_str_with_args(m.def_id, generic_args,)
),
mutability,
),
@@ -793,8 +816,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
- let ty::Adt(e, substs_e) = expected.kind() else { return false; };
- let ty::Adt(f, substs_f) = found.kind() else { return false; };
+ let ty::Adt(e, args_e) = expected.kind() else {
+ return false;
+ };
+ let ty::Adt(f, args_f) = found.kind() else {
+ return false;
+ };
if e.did() != f.did() {
return false;
}
@@ -811,8 +838,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
return false;
}
- let e = substs_e.type_at(1);
- let f = substs_f.type_at(1);
+ let e = args_e.type_at(1);
+ let f = args_f.type_at(1);
if self
.infcx
.type_implements_trait(
@@ -845,7 +872,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) -> bool {
- if let ty::Adt(expected_adt, substs) = expected.kind() {
+ if in_external_macro(self.tcx.sess, expr.span) {
+ return false;
+ }
+ if let ty::Adt(expected_adt, args) = expected.kind() {
if let hir::ExprKind::Field(base, ident) = expr.kind {
let base_ty = self.typeck_results.borrow().expr_ty(base);
if self.can_eq(self.param_env, base_ty, expected)
@@ -944,7 +974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
.then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
- let sole_field_ty = sole_field.ty(self.tcx, substs);
+ let sole_field_ty = sole_field.ty(self.tcx, args);
if self.can_coerce(expr_ty, sole_field_ty) {
let variant_path =
with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
@@ -962,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect();
let suggestions_for = |variant: &_, ctor_kind, field_name| {
- let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "),
None => String::new(),
};
@@ -1037,9 +1067,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
- ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
+ ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
- let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
+ let ty::Adt(adt, _) = args.type_at(0).kind() else {
+ return false;
+ };
(adt, "")
}
@@ -1061,10 +1093,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(sym::NonZeroI128, tcx.types.i128),
];
- let Some((s, _)) = map
- .iter()
- .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
- else { return false; };
+ let Some((s, _)) = map.iter().find(|&&(s, t)| {
+ self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)
+ }) else {
+ return false;
+ };
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
@@ -1152,7 +1185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let local_parent = self.tcx.hir().parent_id(local_id);
- let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else {
+ let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) =
+ self.tcx.hir().find(local_parent)
+ else {
return None;
};
@@ -1161,7 +1196,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_id: expr_hir_id,
kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
..
- })) = self.tcx.hir().find(param_parent) else {
+ })) = self.tcx.hir().find(param_parent)
+ else {
return None;
};
@@ -1174,7 +1210,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
..
})),
1,
- ) = (hir, closure_params_len) else {
+ ) = (hir, closure_params_len)
+ else {
return None;
};
@@ -1198,39 +1235,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub(crate) fn maybe_get_struct_pattern_shorthand_field(
- &self,
- expr: &hir::Expr<'_>,
- ) -> Option<Symbol> {
- let hir = self.tcx.hir();
- let local = match expr {
- hir::Expr {
- kind:
- hir::ExprKind::Path(hir::QPath::Resolved(
- None,
- hir::Path {
- res: hir::def::Res::Local(_),
- segments: [hir::PathSegment { ident, .. }],
- ..
- },
- )),
- ..
- } => Some(ident),
- _ => None,
- }?;
-
- match hir.find_parent(expr.hir_id)? {
- Node::ExprField(field) => {
- if field.ident.name == local.name && field.is_shorthand {
- return Some(local.name);
- }
- }
- _ => {}
- }
-
- None
- }
-
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
pub(crate) fn maybe_get_block_expr(
&self,
@@ -1425,7 +1429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
}
- let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "),
None => String::new(),
};
@@ -1619,7 +1623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
- let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "),
None => String::new(),
};
@@ -2028,11 +2032,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !hir::is_range_literal(expr) {
return;
}
- let hir::ExprKind::Struct(
- hir::QPath::LangItem(LangItem::Range, ..),
- [start, end],
- _,
- ) = expr.kind else { return; };
+ let hir::ExprKind::Struct(hir::QPath::LangItem(LangItem::Range, ..), [start, end], _) =
+ expr.kind
+ else {
+ return;
+ };
let parent = self.tcx.hir().parent_id(expr.hir_id);
if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) {
// Ignore `Foo { field: a..Default::default() }`
@@ -2048,8 +2052,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// cannot guide the method probe.
expectation = None;
}
- let hir::ExprKind::Call(method_name, _) = expr.kind else { return; };
- let ty::Adt(adt, _) = checked_ty.kind() else { return; };
+ let hir::ExprKind::Call(method_name, _) = expr.kind else {
+ return;
+ };
+ let ty::Adt(adt, _) = checked_ty.kind() else {
+ return;
+ };
if self.tcx.lang_items().range_struct() != Some(adt.did()) {
return;
}
@@ -2059,8 +2067,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
// Check if start has method named end.
- let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; };
- let [hir::PathSegment { ident, .. }] = p.segments else { return; };
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else {
+ return;
+ };
+ let [hir::PathSegment { ident, .. }] = p.segments else {
+ return;
+ };
let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
let Ok(_pick) = self.lookup_probe_for_diagnostic(
*ident,
@@ -2068,7 +2080,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr,
probe::ProbeScope::AllTraits,
expectation,
- ) else { return; };
+ ) else {
+ return;
+ };
let mut sugg = ".";
let mut span = start.expr.span.between(end.expr.span);
if span.lo() + BytePos(2) == span.hi() {
@@ -2097,17 +2111,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !checked_ty.is_unit() {
return;
}
- let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
- let hir::def::Res::Local(hir_id) = path.res else { return; };
+ let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {
+ return;
+ };
+ let hir::def::Res::Local(hir_id) = path.res else {
+ return;
+ };
let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
return;
};
- let Some(hir::Node::Local(hir::Local {
- ty: None,
- init: Some(init),
- ..
- })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
- let hir::ExprKind::Block(block, None) = init.kind else { return; };
+ let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
+ self.tcx.hir().find_parent(pat.hir_id)
+ else {
+ return;
+ };
+ let hir::ExprKind::Block(block, None) = init.kind else {
+ return;
+ };
if block.expr.is_some() {
return;
}
@@ -2115,8 +2135,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(block.span, "this empty block is missing a tail expression");
return;
};
- let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
- let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
+ let hir::StmtKind::Semi(tail_expr) = stmt.kind else {
+ return;
+ };
+ let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else {
+ return;
+ };
if self.can_eq(self.param_env, expected_ty, ty) {
err.span_suggestion_short(
stmt.span.with_lo(tail_expr.span.hi()),
@@ -2135,7 +2159,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
checked_ty: Ty<'tcx>,
) {
- let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
+ let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else {
+ return;
+ };
enum CallableKind {
Function,
Method,
@@ -2151,7 +2177,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
- let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
+ let Some(&arg) = fn_sig
+ .inputs()
+ .get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 })
+ else {
+ return;
+ };
if matches!(arg.kind(), ty::Param(_))
&& fn_sig.output().contains(arg)
&& self.node_ty(args[arg_idx].hir_id) == checked_ty
@@ -2185,8 +2216,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
match parent_expr.kind {
hir::ExprKind::Call(fun, args) => {
- let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
- let hir::def::Res::Def(kind, def_id) = path.res else { return; };
+ let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else {
+ return;
+ };
+ let hir::def::Res::Def(kind, def_id) = path.res else {
+ return;
+ };
let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
CallableKind::Constructor
} else {
@@ -2195,7 +2230,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
}
hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
- let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
+ let Some(def_id) =
+ self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
+ else {
+ return;
+ };
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
}
_ => return,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 05906a4b9..054d23c71 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -252,6 +252,46 @@ impl HelpUseLatestEdition {
}
}
+#[derive(Subdiagnostic)]
+pub enum OptionResultRefMismatch {
+ #[suggestion(
+ hir_typeck_option_result_copied,
+ code = ".copied()",
+ style = "verbose",
+ applicability = "machine-applicable"
+ )]
+ Copied {
+ #[primary_span]
+ span: Span,
+ def_path: String,
+ },
+ #[suggestion(
+ hir_typeck_option_result_cloned,
+ code = ".cloned()",
+ style = "verbose",
+ applicability = "machine-applicable"
+ )]
+ Cloned {
+ #[primary_span]
+ span: Span,
+ def_path: String,
+ },
+ // FIXME: #114050
+ // #[suggestion(
+ // hir_typeck_option_result_asref,
+ // code = ".as_ref()",
+ // style = "verbose",
+ // applicability = "machine-applicable"
+ // )]
+ // AsRef {
+ // #[primary_span]
+ // span: Span,
+ // def_path: String,
+ // expected_ty: Ty<'tcx>,
+ // expr_ty: Ty<'tcx>,
+ // },
+}
+
#[derive(Diagnostic)]
#[diag(hir_typeck_const_select_must_be_const)]
#[help]
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 4f086cf59..35e5fb769 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -21,8 +21,6 @@ pub enum Expectation<'tcx> {
/// This rvalue expression will be wrapped in `&` or `Box` and coerced
/// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
ExpectRvalueLikeUnsized(Ty<'tcx>),
-
- IsLast(Span),
}
impl<'a, 'tcx> Expectation<'tcx> {
@@ -88,13 +86,12 @@ impl<'a, 'tcx> Expectation<'tcx> {
ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)),
ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)),
ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)),
- IsLast(sp) => IsLast(sp),
}
}
pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self.resolve(fcx) {
- NoExpectation | IsLast(_) => None,
+ NoExpectation => None,
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
}
}
@@ -106,9 +103,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self {
ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
- NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
- None
- }
+ NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
}
}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 72b29f7b6..7cea40fdd 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -13,7 +13,7 @@ use crate::errors::{
YieldExprOutsideOfGenerator,
};
use crate::fatally_break_rust;
-use crate::method::SelfSource;
+use crate::method::{MethodCallComponents, SelfSource};
use crate::type_error_struct;
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::{
@@ -44,7 +44,7 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
-use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_session::parse::feature_err;
@@ -60,28 +60,13 @@ use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) {
- let ty = self.check_expr_with_hint(expr, expected);
- self.demand_eqtype(expr.span, expected, ty);
- }
-
pub fn check_expr_has_type_or_error(
&self,
expr: &'tcx hir::Expr<'tcx>,
- expected: Ty<'tcx>,
- extend_err: impl FnMut(&mut Diagnostic),
- ) -> Ty<'tcx> {
- self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err)
- }
-
- fn check_expr_meets_expectation_or_error(
- &self,
- expr: &'tcx hir::Expr<'tcx>,
- expected: Expectation<'tcx>,
- mut extend_err: impl FnMut(&mut Diagnostic),
+ expected_ty: Ty<'tcx>,
+ extend_err: impl FnOnce(&mut Diagnostic),
) -> Ty<'tcx> {
- let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool);
- let mut ty = self.check_expr_with_expectation(expr, expected);
+ let mut ty = self.check_expr_with_expectation(expr, ExpectHasType(expected_ty));
// While we don't allow *arbitrary* coercions here, we *do* allow
// coercions from ! to `expected`.
@@ -341,9 +326,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(e, t) => {
- let ty = self.to_ty_saving_user_provided_ty(&t);
- self.check_expr_eq_type(&e, ty);
- ty
+ let ascribed_ty = self.to_ty_saving_user_provided_ty(&t);
+ let ty = self.check_expr_with_hint(e, ascribed_ty);
+ self.demand_eqtype(e.span, ascribed_ty, ty);
+ ascribed_ty
}
ExprKind::If(cond, then_expr, opt_else_expr) => {
self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
@@ -359,7 +345,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
}
ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
- ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
+ ExprKind::Index(base, idx, brackets_span) => {
+ self.check_expr_index(base, idx, expr, brackets_span)
+ }
ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
}
@@ -593,8 +581,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation.
- let substs = self.typeck_results.borrow().node_substs(expr.hir_id);
- self.add_wf_bounds(substs, expr);
+ let args = self.typeck_results.borrow().node_args(expr.hir_id);
+ self.add_wf_bounds(args, expr);
ty
}
@@ -650,7 +638,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else {
// Avoid ICE when `break` is inside a closure (#65383).
- return Ty::new_error_with_message(tcx,
+ return Ty::new_error_with_message(
+ tcx,
expr.span,
"break was outside loop, but no error was emitted",
);
@@ -665,7 +654,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coerce.coerce_forced_unit(
self,
&cause,
- &mut |mut err| {
+ |mut err| {
self.suggest_mismatched_types_on_tail(
&mut err, expr, ty, e_ty, target_id,
);
@@ -761,7 +750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coercion.coerce_forced_unit(
self,
&cause,
- &mut |db| {
+ |db| {
let span = fn_decl.output.span();
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
db.span_label(
@@ -773,7 +762,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
true,
);
} else {
- coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
+ coercion.coerce_forced_unit(self, &cause, |_| (), true);
}
}
self.tcx.types.never
@@ -1280,7 +1269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
// trigger this codepath causing `structurally_resolve_type` to emit an error.
- self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs);
+ self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.args);
self.write_method_call(expr.hir_id, method);
Ok(method)
}
@@ -1292,7 +1281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment.ident,
SelfSource::MethodCall(rcvr),
error,
- Some((rcvr, args)),
+ Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }),
expected,
false,
) {
@@ -1333,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
t_cast,
t.span,
expr.span,
- self.param_env.constness(),
+ hir::Constness::NotConst,
) {
Ok(cast_check) => {
debug!(
@@ -1390,11 +1379,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| {
!matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. }))
});
- let Some((_,
+ let Some((
+ _,
hir::Node::Local(hir::Local { ty: Some(ty), .. })
- | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }))
- ) = parent_node else {
- return
+ | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }),
+ )) = parent_node
+ else {
+ return;
};
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
@@ -1425,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a new function context.
let def_id = block.def_id;
- let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id);
+ let fcx = FnCtxt::new(self, self.param_env, def_id);
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
@@ -1617,7 +1608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// re-link the regions that EIfEO can erase.
self.demand_eqtype(span, adt_ty_hint, adt_ty);
- let ty::Adt(adt, substs) = adt_ty.kind() else {
+ let ty::Adt(adt, args) = adt_ty.kind() else {
span_bug!(span, "non-ADT passed to check_expr_struct_fields");
};
let adt_kind = adt.adt_kind();
@@ -1646,7 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.check_stability(v_field.did, Some(expr_id), field.span, None);
}
- self.field_ty(field.span, v_field, substs)
+ self.field_ty(field.span, v_field, args)
} else {
error_happened = true;
let guar = if let Some(prev_span) = seen_fields.get(&ident) {
@@ -1678,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(mut diag) = diag {
if idx == ast_fields.len() - 1 {
if remaining_fields.is_empty() {
- self.suggest_fru_from_range(field, variant, substs, &mut diag);
+ self.suggest_fru_from_range(field, variant, args, &mut diag);
diag.emit();
} else {
diag.stash(field.span, StashKey::MaybeFruTypo);
@@ -1718,7 +1709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fru_tys = if self.tcx.features().type_changing_struct_update {
if adt.is_struct() {
// Make some fresh substitutions for our ADT type.
- let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did());
+ let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did());
// We do subtyping on the FRU fields first, so we can
// learn exactly what types we expect the base expr
// needs constrained to be compatible with the struct
@@ -1727,13 +1718,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.fields
.iter()
.map(|f| {
- let fru_ty = self.normalize(
- expr_span,
- self.field_ty(base_expr.span, f, fresh_substs),
- );
+ let fru_ty = self
+ .normalize(expr_span, self.field_ty(base_expr.span, f, fresh_args));
let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id);
if let Some(_) = remaining_fields.remove(&ident) {
- let target_ty = self.field_ty(base_expr.span, f, substs);
+ let target_ty = self.field_ty(base_expr.span, f, args);
let cause = self.misc(base_expr.span);
match self.at(&cause, self.param_env).sup(
DefineOpaqueTypes::No,
@@ -1760,7 +1749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.resolve_vars_if_possible(fru_ty)
})
.collect();
- // The use of fresh substs that we have subtyped against
+ // The use of fresh args that we have subtyped against
// our base ADT type's fields allows us to guide inference
// along so that, e.g.
// ```
@@ -1778,7 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `MyStruct<'a, _, F2, C>`, as opposed to just `_`...
// This is important to allow coercions to happen in
// `other_struct` itself. See `coerce-in-base-expr.rs`.
- let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_substs);
+ let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_args);
self.check_expr_has_type_or_error(
base_expr,
self.resolve_vars_if_possible(fresh_base_ty),
@@ -1810,10 +1799,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
});
match adt_ty.kind() {
- ty::Adt(adt, substs) if adt.is_struct() => variant
+ ty::Adt(adt, args) if adt.is_struct() => variant
.fields
.iter()
- .map(|f| self.normalize(expr_span, f.ty(self.tcx, substs)))
+ .map(|f| self.normalize(expr_span, f.ty(self.tcx, args)))
.collect(),
_ => {
self.tcx
@@ -1841,7 +1830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
remaining_fields,
variant,
ast_fields,
- substs,
+ args,
);
}
}
@@ -1878,7 +1867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
remaining_fields: FxHashMap<Ident, (FieldIdx, &ty::FieldDef)>,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) {
let len = remaining_fields.len();
@@ -1889,7 +1878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut truncated_fields_error = String::new();
let remaining_fields_names = match &displayable_field_names[..] {
- [field1] => format!("`{}`", field1),
+ [field1] => format!("`{field1}`"),
[field1, field2] => format!("`{field1}` and `{field2}`"),
[field1, field2, field3] => format!("`{field1}`, `{field2}` and `{field3}`"),
_ => {
@@ -1917,7 +1906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
if let Some(last) = ast_fields.last() {
- self.suggest_fru_from_range(last, variant, substs, &mut err);
+ self.suggest_fru_from_range(last, variant, args, &mut err);
}
err.emit();
@@ -1929,7 +1918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
last_expr_field: &hir::ExprField<'tcx>,
variant: &ty::VariantDef,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
err: &mut Diagnostic,
) {
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
@@ -1942,7 +1931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
&& let range_def_id = self.tcx.lang_items().range_struct()
&& variant_field
- .and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
+ .and_then(|field| field.ty(self.tcx, args).ty_adt_def())
.map(|adt| adt.did())
!= range_def_id
{
@@ -2116,16 +2105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
_ => {
- err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty));
+ err.span_label(variant_ident_span, format!("`{ty}` defined here"));
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
- format!(
- "`{adt}` is a tuple {kind_name}, use the appropriate syntax",
- adt = ty,
- kind_name = kind_name,
- ),
- format!("{adt}(/* fields */)", adt = ty),
+ format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",),
+ format!("{ty}(/* fields */)"),
Applicability::HasPlaceholders,
);
}
@@ -2242,7 +2227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// dynamic limit, to never omit just one field
let limit = if names.len() == 6 { 6 } else { 5 };
let mut display =
- names.iter().take(limit).map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
+ names.iter().take(limit).map(|n| format!("`{n}`")).collect::<Vec<_>>().join(", ");
if names.len() > limit {
display = format!("{} ... and {} others", display, names.len() - limit);
}
@@ -2265,7 +2250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
while let Some((deref_base_ty, _)) = autoderef.next() {
debug!("deref_base_ty: {:?}", deref_base_ty);
match deref_base_ty.kind() {
- ty::Adt(base_def, substs) if !base_def.is_enum() => {
+ ty::Adt(base_def, args) if !base_def.is_enum() => {
debug!("struct named {:?}", deref_base_ty);
let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
let (ident, def_scope) =
@@ -2275,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter_enumerated()
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
- let field_ty = self.field_ty(expr.span, field, substs);
+ let field_ty = self.field_ty(expr.span, field, args);
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, index);
@@ -2416,7 +2401,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base: &'tcx hir::Expr<'tcx>,
ty: Ty<'tcx>,
) {
- let Some(output_ty) = self.get_impl_future_output_ty(ty) else { return; };
+ let Some(output_ty) = self.get_impl_future_output_ty(ty) else {
+ return;
+ };
let mut add_label = true;
if let ty::Adt(def, _) = output_ty.kind() {
// no field access on enum type
@@ -2711,7 +2698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// try to add a suggestion in case the field is a nested field of a field of the Adt
let mod_id = self.tcx.parent_module(id).to_def_id();
- if let Some((fields, substs)) =
+ if let Some((fields, args)) =
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
{
let candidate_fields: Vec<_> = fields
@@ -2720,7 +2707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
candidate_field,
- substs,
+ args,
vec![],
mod_id,
)
@@ -2775,12 +2762,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
base_ty: Ty<'tcx>,
mod_id: DefId,
- ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
+ ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, GenericArgsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
for (base_t, _) in self.autoderef(span, base_ty) {
match base_t.kind() {
- ty::Adt(base_def, substs) if !base_def.is_enum() => {
+ ty::Adt(base_def, args) if !base_def.is_enum() => {
let tcx = self.tcx;
let fields = &base_def.non_enum_variant().fields;
// Some struct, e.g. some that impl `Deref`, have all private fields
@@ -2795,7 +2782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
// For compile-time reasons put a limit on number of fields we search
.take(100),
- substs,
+ args,
));
}
_ => {}
@@ -2811,7 +2798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
candidate_field: &ty::FieldDef,
- subst: SubstsRef<'tcx>,
+ subst: GenericArgsRef<'tcx>,
mut field_path: Vec<Ident>,
mod_id: DefId,
) -> Option<Vec<Ident>> {
@@ -2855,6 +2842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base: &'tcx hir::Expr<'tcx>,
idx: &'tcx hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
+ brackets_span: Span,
) -> Ty<'tcx> {
let base_t = self.check_expr(&base);
let idx_t = self.check_expr(&idx);
@@ -2888,7 +2876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut err = type_error_struct!(
self.tcx.sess,
- expr.span,
+ brackets_span,
base_t,
E0608,
"cannot index into a value of type `{base_t}`",
@@ -2902,16 +2890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
&& i < types.len().try_into().expect("expected tuple index to be < usize length")
{
- let snip = self.tcx.sess.source_map().span_to_snippet(base.span);
- if let Ok(snip) = snip {
- err.span_suggestion(
- expr.span,
- "to access tuple elements, use",
- format!("{snip}.{i}"),
- Applicability::MachineApplicable,
- );
- needs_note = false;
- }
+
+ err.span_suggestion(
+ brackets_span,
+ "to access tuple elements, use",
+ format!(".{i}"),
+ Applicability::MachineApplicable,
+ );
+ needs_note = false;
} else if let ExprKind::Path(..) = idx.peel_borrows().kind {
err.span_label(idx.span, "cannot access tuple elements at a variable index");
}
@@ -2970,9 +2956,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.commit_if_ok(|_| {
let ocx = ObligationCtxt::new(self);
- let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id);
+ let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id);
let impl_trait_ref =
- self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs);
+ self.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(self.tcx, impl_args);
let cause = self.misc(base_expr.span);
// Match the impl self type against the base ty. If this fails,
@@ -2989,7 +2975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Binder::dummy(ty::TraitPredicate {
trait_ref: impl_trait_ref,
polarity: ty::ImplPolarity::Positive,
- constness: ty::BoundConstness::NotConst,
}),
|derived| {
traits::ImplDerivedObligation(Box::new(
@@ -3004,7 +2989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
},
self.param_env,
- self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs),
+ self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args),
));
// Normalize the output type, which we can use later on as the
@@ -3012,7 +2997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let element_ty = ocx.normalize(
&cause,
self.param_env,
- Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.substs),
+ Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.args),
);
let errors = ocx.select_where_possible();
@@ -3020,7 +3005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// will still delay a span bug in `report_fulfillment_errors`.
Ok::<_, NoSolution>((
self.err_ctxt().report_fulfillment_errors(&errors),
- impl_trait_ref.substs.type_at(1),
+ impl_trait_ref.args.type_at(1),
element_ty,
))
})
@@ -3152,7 +3137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let container = self.structurally_resolve_type(expr.span, current_container);
match container.kind() {
- ty::Adt(container_def, substs) if !container_def.is_enum() => {
+ ty::Adt(container_def, args) if !container_def.is_enum() => {
let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
@@ -3162,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter_enumerated()
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
- let field_ty = self.field_ty(expr.span, field, substs);
+ let field_ty = self.field_ty(expr.span, field, args);
// FIXME: DSTs with static alignment should be allowed
self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 0d2e0602e..840910732 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -211,7 +211,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.select_from_expr(base);
}
- hir::ExprKind::Index(lhs, rhs) => {
+ hir::ExprKind::Index(lhs, rhs, _) => {
// lhs[rhs]
self.select_from_expr(lhs);
self.consume_expr(rhs);
@@ -549,7 +549,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// Select just those fields of the `with`
// expression that will actually be used
match with_place.place.ty().kind() {
- ty::Adt(adt, substs) if adt.is_struct() => {
+ ty::Adt(adt, args) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
let is_mentioned = fields
@@ -559,7 +559,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let field_place = self.mc.cat_projection(
&*with_expr,
with_place.clone(),
- with_field.ty(self.tcx(), substs),
+ with_field.ty(self.tcx(), args),
ProjectionKind::Field(f_index, FIRST_VARIANT),
);
self.delegate_consume(&field_place, field_place.hir_id);
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index a76db6e73..5b5986a34 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,8 +1,8 @@
use crate::FnCtxt;
use rustc_data_structures::{
- fx::{FxHashMap, FxHashSet},
graph::WithSuccessors,
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
+ unord::{UnordBag, UnordMap, UnordSet},
};
use rustc_middle::ty::{self, Ty};
@@ -83,7 +83,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
fn fallback_if_possible(
&self,
ty: Ty<'tcx>,
- diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+ diverging_fallback: &UnordMap<Ty<'tcx>, Ty<'tcx>>,
) {
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback
@@ -193,7 +193,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
fn calculate_diverging_fallback(
&self,
unsolved_variables: &[Ty<'tcx>],
- ) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
+ ) -> UnordMap<Ty<'tcx>, Ty<'tcx>> {
debug!("calculate_diverging_fallback({:?})", unsolved_variables);
// Construct a coercion graph where an edge `A -> B` indicates
@@ -210,10 +210,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
//
// These variables are the ones that are targets for fallback to
// either `!` or `()`.
- let diverging_roots: FxHashSet<ty::TyVid> = self
+ let diverging_roots: UnordSet<ty::TyVid> = self
.diverging_type_vars
.borrow()
- .iter()
+ .items()
.map(|&ty| self.shallow_resolve(ty))
.filter_map(|ty| ty.ty_vid())
.map(|vid| self.root_var(vid))
@@ -284,8 +284,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// For each diverging variable, figure out whether it can
// reach a member of N. If so, it falls back to `()`. Else
// `!`.
- let mut diverging_fallback = FxHashMap::default();
- diverging_fallback.reserve(diverging_vids.len());
+ let mut diverging_fallback = UnordMap::with_capacity(diverging_vids.len());
for &diverging_vid in &diverging_vids {
let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
let root_vid = self.root_var(diverging_vid);
@@ -293,14 +292,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.depth_first_search(root_vid)
.any(|n| roots_reachable_from_non_diverging.visited(n));
- let mut found_infer_var_info = ty::InferVarInfo { self_in_trait: false, output: false };
+ let infer_var_infos: UnordBag<_> = self
+ .inh
+ .infer_var_info
+ .borrow()
+ .items()
+ .filter(|&(vid, _)| self.infcx.root_var(*vid) == root_vid)
+ .map(|(_, info)| *info)
+ .collect();
- for (vid, info) in self.inh.infer_var_info.borrow().iter() {
- if self.infcx.root_var(*vid) == root_vid {
- found_infer_var_info.self_in_trait |= info.self_in_trait;
- found_infer_var_info.output |= info.output;
- }
- }
+ let found_infer_var_info = ty::InferVarInfo {
+ self_in_trait: infer_var_infos.items().any(|info| info.self_in_trait),
+ output: infer_var_infos.items().any(|info| info.output),
+ };
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
// This case falls back to () to ensure that the code pattern in
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 9a80a9c93..28fe2e062 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_hir_analysis::astconv::generics::{
- check_generic_arg_count_for_call, create_substs_for_generic_args,
+ check_generic_arg_count_for_call, create_args_for_parent_generic_args,
};
use rustc_hir_analysis::astconv::{
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
@@ -28,7 +28,7 @@ use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
};
-use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
+use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
@@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
- let msg = format!("unreachable {}", kind);
+ let msg = format!("unreachable {kind}");
self.tcx().struct_span_lint_hir(
lint::builtin::UNREACHABLE_CODE,
id,
@@ -85,16 +85,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// to get more type information.
// FIXME(-Ztrait-solver=next): A lot of the calls to this method should
// probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead.
- pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
- }
-
- #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)]
- pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
- &self,
- mut ty: Ty<'tcx>,
- mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
- ) -> Ty<'tcx> {
+ #[instrument(skip(self), level = "debug", ret)]
+ pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
// No Infer()? Nothing needs doing.
if !ty.has_non_region_infer() {
debug!("no inference var, nothing needs doing");
@@ -112,7 +104,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// possible. This can help substantially when there are
// indirect dependencies that don't seem worth tracking
// precisely.
- self.select_obligations_where_possible(mutate_fulfillment_errors);
+ self.select_obligations_where_possible(|_| {});
self.resolve_vars_if_possible(ty)
}
@@ -134,7 +126,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub fn tag(&self) -> String {
- format!("{:p}", self)
+ format!("{self:p}")
}
pub fn local_ty(&self, span: Span, nid: hir::HirId) -> Ty<'tcx> {
@@ -169,18 +161,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
- self.write_substs(hir_id, method.substs);
+ self.write_args(hir_id, method.args);
}
- pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
- if !substs.is_empty() {
- debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
+ pub fn write_args(&self, node_id: hir::HirId, args: GenericArgsRef<'tcx>) {
+ if !args.is_empty() {
+ debug!("write_args({:?}, {:?}) in fcx {}", node_id, args, self.tag());
- self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
+ self.typeck_results.borrow_mut().node_args_mut().insert(node_id, args);
}
}
- /// Given the substs that we just converted from the HIR, try to
+ /// Given the args that we just converted from the HIR, try to
/// canonicalize them and store them as user-given substitutions
/// (i.e., substitutions that must be respected by the NLL check).
///
@@ -188,19 +180,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
#[instrument(skip(self), level = "debug")]
- pub fn write_user_type_annotation_from_substs(
+ pub fn write_user_type_annotation_from_args(
&self,
hir_id: hir::HirId,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>,
) {
debug!("fcx {}", self.tag());
- if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+ if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) {
let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf(
def_id,
- UserSubsts { substs, user_self_ty },
+ UserArgs { args, user_self_ty },
));
debug!(?canonicalized);
self.write_user_type_annotation(hir_id, canonicalized);
@@ -221,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.user_provided_types_mut()
.insert(hir_id, canonical_user_type_annotation);
} else {
- debug!("skipping identity substs");
+ debug!("skipping identity args");
}
}
@@ -306,12 +298,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
span: Span,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> ty::InstantiatedPredicates<'tcx> {
let bounds = self.tcx.predicates_of(def_id);
- let result = bounds.instantiate(self.tcx, substs);
+ let result = bounds.instantiate(self.tcx, args);
let result = self.normalize(span, result);
- debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result);
+ debug!("instantiate_bounds(bounds={:?}, args={:?}) = {:?}", bounds, args, result);
result
}
@@ -397,11 +389,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty.normalized
}
- pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> {
+ pub(super) fn user_args_for_adt(ty: RawTy<'tcx>) -> UserArgs<'tcx> {
match (ty.raw.kind(), ty.normalized.kind()) {
- (ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None },
- (_, ty::Adt(adt, substs)) => UserSubsts {
- substs,
+ (ty::Adt(_, args), _) => UserArgs { args, user_self_ty: None },
+ (_, ty::Adt(adt, args)) => UserArgs {
+ args,
user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }),
},
_ => bug!("non-adt type {:?}", ty),
@@ -489,9 +481,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
}
- /// Registers obligations that all `substs` are well-formed.
- pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
- for arg in substs.iter().filter(|arg| {
+ /// Registers obligations that all `args` are well-formed.
+ pub fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) {
+ for arg in args.iter().filter(|arg| {
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
}) {
self.register_wf_obligation(arg, expr.span, traits::WellFormed(None));
@@ -505,9 +497,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
span: Span,
field: &'tcx ty::FieldDef,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> Ty<'tcx> {
- self.normalize(span, field.ty(self.tcx, substs))
+ self.normalize(span, field.ty(self.tcx, args))
}
pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
@@ -554,11 +546,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!(?expr_def_id);
// Create the `GeneratorWitness` type that we will unify with `interior`.
- let substs = ty::InternalSubsts::identity_for_item(
+ let args = ty::GenericArgs::identity_for_item(
self.tcx,
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
- let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), substs);
+ let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), args);
// Unify `interior` with `witness` and collect all the resulting obligations.
let span = self.tcx.hir().body(body_id).value.span;
@@ -626,8 +618,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match *self_ty.kind() {
ty::Infer(ty::TyVar(found_vid)) => {
- // FIXME: consider using `sub_root_var` here so we
- // can see through subtyping.
let found_vid = self.root_var(found_vid);
debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
expected_vid == found_vid
@@ -642,8 +632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self_ty: ty::TyVid,
) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
{
- // FIXME: consider using `sub_root_var` here so we
- // can see through subtyping.
let ty_var_root = self.root_var(self_ty);
trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
@@ -737,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
if formal_ret.has_infer_types() {
for ty in ret_ty.walk() {
- if let ty::subst::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 Some(def_id) = def_id.as_local()
&& self.opaque_type_origin(def_id).is_some() {
@@ -784,8 +772,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
self.tcx.type_of(def_id)
};
- let substs = self.fresh_substs_for_item(span, def_id);
- let ty = item_ty.subst(self.tcx, substs);
+ let args = self.fresh_args_for_item(span, def_id);
+ let ty = item_ty.instantiate(self.tcx, args);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
@@ -802,9 +790,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
if let Some(code) = code {
- self.add_required_obligations_with_code(span, def_id, substs, move |_, _| code.clone());
+ self.add_required_obligations_with_code(span, def_id, args, move |_, _| code.clone());
} else {
- self.add_required_obligations_for_hir(span, def_id, substs, hir_id);
+ self.add_required_obligations_for_hir(span, def_id, args, hir_id);
}
(Res::Def(def_kind, def_id), ty)
@@ -860,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
.and_then(|r| {
// lint bare trait if the method is found in the trait
- if span.edition().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();
}
Ok(r)
@@ -890,7 +878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// emit or cancel the diagnostic for bare traits
- if span.edition().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 {
// cancel the diag for bare traits when meeting `MyTrait::missing_method`
diag.cancel();
@@ -908,7 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error,
None,
Expectation::NoExpectation,
- trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
+ trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
) {
e.emit();
}
@@ -1069,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if let ExprKind::MethodCall(..) = rcvr.kind {
err.span_note(
sp,
- modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.",
+ modifies_rcvr_note + ", it is not meant to be used in method chains.",
);
} else {
err.span_note(sp, modifies_rcvr_note);
@@ -1205,8 +1193,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let has_self =
path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self);
- let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
- let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).subst_identity());
+ let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res {
+ let ty =
+ self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).instantiate_identity());
match ty.normalized.ty_adt_def() {
Some(adt_def) if adt_def.has_ctor() => {
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
@@ -1217,9 +1206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
}
let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
- let user_substs = Self::user_substs_for_adt(ty);
- user_self_ty = user_substs.user_self_ty;
- (new_res, Some(user_substs.substs))
+ let user_args = Self::user_args_for_adt(ty);
+ user_self_ty = user_args.user_self_ty;
+ (new_res, Some(user_args.args))
}
_ => {
let mut err = tcx.sess.struct_span_err(
@@ -1324,7 +1313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn inferred_kind(
&mut self,
- substs: Option<&[ty::GenericArg<'tcx>]>,
+ args: Option<&[ty::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
) -> ty::GenericArg<'tcx> {
@@ -1338,7 +1327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If we have a default, then we it doesn't matter that we're not
// inferring the type arguments: we provide the default where any
// is missing.
- tcx.type_of(param.def_id).subst(tcx, substs.unwrap()).into()
+ tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
} else {
// If no type arguments were provided, we have to infer them.
// This case also occurs as a result of some malformed input, e.g.
@@ -1348,8 +1337,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
GenericParamDefKind::Const { has_default } => {
- if !infer_args && has_default {
- tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
+ if !infer_args
+ && has_default
+ && !tcx.has_attr(param.def_id, sym::rustc_host)
+ {
+ tcx.const_param_default(param.def_id)
+ .instantiate(tcx, args.unwrap())
+ .into()
} else {
self.fcx.var_for_def(self.span, param)
}
@@ -1358,8 +1352,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let substs_raw = self_ctor_substs.unwrap_or_else(|| {
- create_substs_for_generic_args(
+ let args_raw = self_ctor_args.unwrap_or_else(|| {
+ create_args_for_parent_generic_args(
tcx,
def_id,
&[],
@@ -1376,20 +1370,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
- // First, store the "user substs" for later.
- self.write_user_type_annotation_from_substs(hir_id, def_id, substs_raw, user_self_ty);
+ // First, store the "user args" for later.
+ self.write_user_type_annotation_from_args(hir_id, def_id, args_raw, user_self_ty);
// Normalize only after registering type annotations.
- let substs = self.normalize(span, substs_raw);
+ let args = self.normalize(span, args_raw);
- self.add_required_obligations_for_hir(span, def_id, &substs, hir_id);
+ self.add_required_obligations_for_hir(span, def_id, &args, hir_id);
// Substitute the values for the type parameters into the type of
// the referenced item.
let ty = tcx.type_of(def_id);
- assert!(!substs.has_escaping_bound_vars());
+ assert!(!args.has_escaping_bound_vars());
assert!(!ty.skip_binder().has_escaping_bound_vars());
- let ty_substituted = self.normalize(span, ty.subst(tcx, substs));
+ let ty_substituted = self.normalize(span, ty.instantiate(tcx, args));
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
// In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
@@ -1397,7 +1391,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// type parameters, which we can infer by unifying the provided `Self`
// with the substituted impl type.
// This also occurs for an enum variant on a type alias.
- let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs));
+ let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
let self_ty = self.normalize(span, self_ty);
match self.at(&self.misc(span), self.param_env).eq(
DefineOpaqueTypes::No,
@@ -1409,9 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.sess.delay_span_bug(
span,
format!(
- "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
- self_ty,
- impl_ty,
+ "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?",
),
);
}
@@ -1419,7 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
- self.write_substs(hir_id, substs);
+ self.write_args(hir_id, args);
(ty_substituted, res)
}
@@ -1429,10 +1421,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
span: Span,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
hir_id: hir::HirId,
) {
- self.add_required_obligations_with_code(span, def_id, substs, |idx, span| {
+ self.add_required_obligations_with_code(span, def_id, args, |idx, span| {
if span.is_dummy() {
ObligationCauseCode::ExprItemObligation(def_id, hir_id, idx)
} else {
@@ -1441,17 +1433,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
}
- #[instrument(level = "debug", skip(self, code, span, substs))]
+ #[instrument(level = "debug", skip(self, code, span, args))]
fn add_required_obligations_with_code(
&self,
span: Span,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>,
) {
let param_env = self.param_env;
- let bounds = self.instantiate_bounds(span, def_id, &substs);
+ let bounds = self.instantiate_bounds(span, def_id, &args);
for obligation in traits::predicates_for_generics(
|idx, predicate_span| {
@@ -1460,10 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_env,
bounds,
) {
- // N.B. We are remapping all predicates to non-const since we don't know if we just
- // want them as function pointers or we are calling them from a const-context. The
- // actual checking will occur in `rustc_const_eval::transform::check_consts`.
- self.register_predicate(obligation.without_const(self.tcx));
+ self.register_predicate(obligation);
}
}
@@ -1476,7 +1465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_with_obligations(ty);
if self.next_trait_solver()
- && let ty::Alias(ty::Projection, _) = ty.kind()
+ && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind()
{
match self
.at(&self.misc(sp), self.param_env)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index ed9bb4945..c44d12e61 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -2,7 +2,7 @@ use crate::FnCtxt;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
-use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::{infer::type_variable::TypeVariableOriginKind, traits::ObligationCauseCode};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_span::{self, symbol::kw, Span};
use rustc_trait_selection::traits;
@@ -14,19 +14,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
error: &mut traits::FulfillmentError<'tcx>,
) -> bool {
- let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
- = *error.obligation.cause.code().peel_derives() else { return false; };
+ let (traits::ExprItemObligation(def_id, hir_id, idx)
+ | traits::ExprBindingObligation(def_id, _, hir_id, idx)) =
+ *error.obligation.cause.code().peel_derives()
+ else {
+ return false;
+ };
let hir = self.tcx.hir();
- let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
+ let hir::Node::Expr(expr) = hir.get(hir_id) else {
+ return false;
+ };
- let Some(unsubstituted_pred) =
- self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
- else { return false; };
+ let Some(unsubstituted_pred) = self
+ .tcx
+ .predicates_of(def_id)
+ .instantiate_identity(self.tcx)
+ .predicates
+ .into_iter()
+ .nth(idx)
+ else {
+ return false;
+ };
let generics = self.tcx.generics_of(def_id);
- let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::ClauseKind::Trait(pred) => pred.trait_ref.substs.to_vec(),
- ty::ClauseKind::Projection(pred) => pred.projection_ty.substs.to_vec(),
+ let predicate_args = match unsubstituted_pred.kind().skip_binder() {
+ ty::ClauseKind::Trait(pred) => pred.trait_ref.args.to_vec(),
+ ty::ClauseKind::Projection(pred) => pred.projection_ty.args.to_vec(),
ty::ClauseKind::ConstArgHasType(arg, ty) => {
vec![ty.into(), arg.into()]
}
@@ -35,7 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| {
- predicate_substs.iter().find_map(|arg| {
+ predicate_args.iter().find_map(|arg| {
arg.walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Param(param_ty) = *ty.kind()
@@ -225,18 +238,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_to_point_at: ty::GenericArg<'tcx>,
segment: &hir::PathSegment<'tcx>,
) -> bool {
- let own_substs = self
+ let own_args = self
.tcx
.generics_of(def_id)
- .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
- let Some((index, _)) = own_substs
- .iter()
- .enumerate()
- .find(|(_, arg)| **arg == param_to_point_at) else { return false };
- let Some(arg) = segment
- .args()
- .args
- .get(index) else { return false; };
+ .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
+ let Some((index, _)) =
+ own_args.iter().enumerate().find(|(_, arg)| **arg == param_to_point_at)
+ else {
+ return false;
+ };
+ let Some(arg) = segment.args().args.get(index) else {
+ return false;
+ };
error.obligation.cause.span = arg
.span()
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
@@ -254,11 +267,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
type BreakTy = ty::GenericArg<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
if let Some(origin) = self.0.type_var_origin(ty)
- && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) =
- origin.kind
+ && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
&& 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(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
+ && let Some(subst) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1)
.get(index as usize)
{
ControlFlow::Break(*subst)
@@ -298,13 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
let def = self.tcx.adt_def(def_id);
- let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
+ let identity_args = ty::GenericArgs::identity_for_item(self.tcx, def_id);
let fields_referencing_param: Vec<_> = def
.variant_with_id(variant_def_id)
.fields
.iter()
.filter(|field| {
- let field_ty = field.ty(self.tcx, identity_substs);
+ let field_ty = field.ty(self.tcx, identity_args);
find_param_in_ty(field_ty.into(), param_to_point_at)
})
.collect();
@@ -315,7 +327,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// same rules that check_expr_struct uses for macro hygiene.
if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
{
- return Some((expr_field.expr, self.tcx.type_of(field.did).subst_identity()));
+ return Some((
+ expr_field.expr,
+ self.tcx.type_of(field.did).instantiate_identity(),
+ ));
}
}
}
@@ -342,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
receiver: Option<&'tcx hir::Expr<'tcx>>,
args: &'tcx [hir::Expr<'tcx>],
) -> bool {
- let ty = self.tcx.type_of(def_id).subst_identity();
+ let ty = self.tcx.type_of(def_id).instantiate_identity();
if !ty.is_fn() {
return false;
}
@@ -484,7 +499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::TraitRef::new(
self.tcx,
obligation.impl_or_alias_def_id,
- ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
+ ty::GenericArgs::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
)
} else {
self.tcx
@@ -573,9 +588,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Find out which of `in_ty_elements` refer to `param`.
// FIXME: It may be better to take the first if there are multiple,
// just so that the error points to a smaller expression.
- let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| {
- find_param_in_ty((*in_ty_elem).into(), param)
- })) else {
+ let Some((drill_expr, drill_ty)) =
+ is_iterator_singleton(expr_elements.iter().zip(in_ty_elements.iter()).filter(
+ |(_expr_elem, in_ty_elem)| find_param_in_ty((*in_ty_elem).into(), param),
+ ))
+ else {
// The param is not mentioned, or it is mentioned in multiple indexes.
return Err(expr);
};
@@ -594,7 +611,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// First, confirm that this struct is the same one as in the types, and if so,
// find the right variant.
- let Res::Def(expr_struct_def_kind, expr_struct_def_id) = self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id) else {
+ let Res::Def(expr_struct_def_kind, expr_struct_def_id) =
+ self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id)
+ else {
return Err(expr);
};
@@ -621,16 +640,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We need to know which of the generic parameters mentions our target param.
// We expect that at least one of them does, since it is expected to be mentioned.
- let Some((drill_generic_index, generic_argument_type)) =
- is_iterator_singleton(
- in_ty_adt_generic_args.iter().enumerate().filter(
- |(_index, in_ty_generic)| {
- find_param_in_ty(*in_ty_generic, param)
- },
- ),
- ) else {
- return Err(expr);
- };
+ let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
+ in_ty_adt_generic_args
+ .iter()
+ .enumerate()
+ .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
+ ) else {
+ return Err(expr);
+ };
let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
if drill_generic_index >= struct_generic_parameters.params.len() {
@@ -703,7 +720,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// This is (possibly) a constructor call, like `Some(...)` or `MyStruct(a, b, c)`.
- let Res::Def(expr_struct_def_kind, expr_ctor_def_id) = self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id) else {
+ let Res::Def(expr_struct_def_kind, expr_ctor_def_id) =
+ self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id)
+ else {
return Err(expr);
};
@@ -744,16 +763,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We need to know which of the generic parameters mentions our target param.
// We expect that at least one of them does, since it is expected to be mentioned.
- let Some((drill_generic_index, generic_argument_type)) =
- is_iterator_singleton(
- in_ty_adt_generic_args.iter().enumerate().filter(
- |(_index, in_ty_generic)| {
- find_param_in_ty(*in_ty_generic, param)
- },
- ),
- ) else {
- return Err(expr);
- };
+ let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
+ in_ty_adt_generic_args
+ .iter()
+ .enumerate()
+ .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
+ ) else {
+ return Err(expr);
+ };
let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
if drill_generic_index >= struct_generic_parameters.params.len() {
@@ -794,7 +811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.map(|field| field.ty(self.tcx, *in_ty_adt_generic_args))
.enumerate()
- .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param))
+ .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)),
) else {
return Err(expr);
};
@@ -846,7 +863,7 @@ fn find_param_in_ty<'tcx>(
// This logic may seem a bit strange, but typically when
// we have a projection type in a function signature, the
// argument that's being passed into that signature is
- // not actually constraining that projection's substs in
+ // not actually constraining that projection's args in
// a meaningful way. So we skip it, and see improvements
// in some UI tests.
walk.skip_current_subtree();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 41f5fafe7..4def78673 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -45,12 +45,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
for cast in deferred_cast_checks.drain(..) {
- let prev_env = self.param_env;
- self.param_env = self.param_env.with_constness(cast.constness);
-
cast.check(self);
-
- self.param_env = prev_env;
}
*self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
@@ -93,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let has_error = match method {
- Ok(method) => method.substs.references_error() || method.sig.references_error(),
+ Ok(method) => method.args.references_error() || method.sig.references_error(),
Err(_) => true,
};
if has_error {
@@ -265,9 +260,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// fulfillment error to be more accurate.
let coerced_ty = self.resolve_vars_with_obligations(coerced_ty);
- let coerce_error = self
- .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None)
- .err();
+ let coerce_error =
+ self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err();
if coerce_error.is_some() {
return Compatibility::Incompatible(coerce_error);
@@ -524,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// suggestions and labels are (more) correct when an arg is a
// macro invocation.
let normalize_span = |span: Span| -> Span {
- let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span);
+ let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span);
// Sometimes macros mess up the spans, so do not normalize the
// arg span to equal the error span, because that's less useful
// than pointing out the arg expr in the wrong context.
@@ -689,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(
full_call_span,
- format!("arguments to this {} are incorrect", call_name),
+ format!("arguments to this {call_name} are incorrect"),
);
} else {
err = tcx.sess.struct_span_err_with_code(
@@ -753,11 +747,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
errors.retain(|error| {
- let Error::Invalid(
- provided_idx,
- expected_idx,
- Compatibility::Incompatible(Some(e)),
- ) = error else { return true };
+ let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
+ error
+ else {
+ return true;
+ };
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
@@ -796,10 +790,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None,
None,
);
- err.span_label(
- full_call_span,
- format!("arguments to this {} are incorrect", call_name),
- );
+ err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect"));
if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
&& provided_idx.as_usize() == expected_idx.as_usize()
@@ -874,7 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if ty.is_unit() {
"()".to_string()
} else if ty.is_suggestable(tcx, false) {
- format!("/* {} */", ty)
+ format!("/* {ty} */")
} else if let Some(fn_def_id) = fn_def_id
&& self.tcx.def_kind(fn_def_id).is_fn_like()
&& let self_implicit =
@@ -931,14 +922,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_span) = provided_arg_tys[arg_idx];
let provided_ty_name = if !has_error_or_infer([provided_ty]) {
// FIXME: not suggestable, use something else
- format!(" of type `{}`", provided_ty)
+ format!(" of type `{provided_ty}`")
} else {
"".to_string()
};
- labels
- .push((provided_span, format!("unexpected argument{}", provided_ty_name)));
+ labels.push((provided_span, format!("unexpected argument{provided_ty_name}")));
let mut span = provided_span;
- if span.can_be_used_for_suggestions() {
+ if span.can_be_used_for_suggestions()
+ && error_span.can_be_used_for_suggestions()
+ {
if arg_idx.index() > 0
&& let Some((_, prev)) = provided_arg_tys
.get(ProvidedIdx::from_usize(arg_idx.index() - 1)
@@ -1009,11 +1001,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
args_span
};
let rendered = if !has_error_or_infer([input_ty]) {
- format!(" of type `{}`", input_ty)
+ format!(" of type `{input_ty}`")
} else {
"".to_string()
};
- labels.push((span, format!("an argument{} is missing", rendered)));
+ labels.push((span, format!("an argument{rendered} is missing")));
suggestion_text = match suggestion_text {
SuggestionText::None => SuggestionText::Provide(false),
SuggestionText::Provide(_) => SuggestionText::Provide(true),
@@ -1034,13 +1026,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rendered =
if !has_error_or_infer([first_expected_ty, second_expected_ty]) {
format!(
- " of type `{}` and `{}`",
- first_expected_ty, second_expected_ty
+ " of type `{first_expected_ty}` and `{second_expected_ty}`"
)
} else {
"".to_string()
};
- labels.push((span, format!("two arguments{} are missing", rendered)));
+ labels.push((span, format!("two arguments{rendered} are missing")));
suggestion_text = match suggestion_text {
SuggestionText::None | SuggestionText::Provide(_) => {
SuggestionText::Provide(true)
@@ -1066,13 +1057,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
third_expected_ty,
]) {
format!(
- " of type `{}`, `{}`, and `{}`",
- first_expected_ty, second_expected_ty, third_expected_ty
+ " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`"
)
} else {
"".to_string()
};
- labels.push((span, format!("three arguments{} are missing", rendered)));
+ labels.push((span, format!("three arguments{rendered} are missing")));
suggestion_text = match suggestion_text {
SuggestionText::None | SuggestionText::Provide(_) => {
SuggestionText::Provide(true)
@@ -1113,25 +1103,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx];
let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx];
let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) {
- format!(", found `{}`", first_provided_ty)
+ format!(", found `{first_provided_ty}`")
} else {
String::new()
};
labels.push((
first_span,
- format!("expected `{}`{}", first_expected_ty, first_provided_ty_name),
+ format!("expected `{first_expected_ty}`{first_provided_ty_name}"),
));
let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx];
let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx];
let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) {
- format!(", found `{}`", second_provided_ty)
+ format!(", found `{second_provided_ty}`")
} else {
String::new()
};
labels.push((
second_span,
- format!("expected `{}`{}", second_expected_ty, second_provided_ty_name),
+ format!("expected `{second_expected_ty}`{second_provided_ty_name}"),
));
suggestion_text = match suggestion_text {
@@ -1144,13 +1134,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (_, expected_ty) = formal_and_expected_inputs[dst_arg];
let (provided_ty, provided_span) = provided_arg_tys[dest_input];
let provided_ty_name = if !has_error_or_infer([provided_ty]) {
- format!(", found `{}`", provided_ty)
+ format!(", found `{provided_ty}`")
} else {
String::new()
};
labels.push((
provided_span,
- format!("expected `{}`{}", expected_ty, provided_ty_name),
+ format!("expected `{expected_ty}`{provided_ty_name}"),
));
}
@@ -1231,22 +1221,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Some(suggestion_text) = suggestion_text {
let source_map = self.sess().source_map();
- let (mut suggestion, suggestion_span) =
- if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) {
- ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
- } else {
- (
- format!(
- "{}(",
- source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
- fn_def_id.map_or("".to_string(), |fn_def_id| {
- tcx.item_name(fn_def_id).to_string()
- })
+ let (mut suggestion, suggestion_span) = if let Some(call_span) =
+ full_call_span.find_ancestor_inside_same_ctxt(error_span)
+ {
+ ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
+ } else {
+ (
+ format!(
+ "{}(",
+ source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
+ fn_def_id.map_or("".to_string(), |fn_def_id| {
+ tcx.item_name(fn_def_id).to_string()
})
- ),
- error_span,
- )
- };
+ })
+ ),
+ error_span,
+ )
+ };
let mut needs_comma = false;
for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
if needs_comma {
@@ -1366,29 +1357,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
Some(adt) => {
- Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty)))
+ Some((adt.variant_of_res(def), adt.did(), Self::user_args_for_adt(ty)))
}
_ => bug!("unexpected type: {:?}", ty.normalized),
},
- Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+ Res::Def(
+ DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+ _,
+ )
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
Some(adt) if !adt.is_enum() => {
- Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty)))
+ Some((adt.non_enum_variant(), adt.did(), Self::user_args_for_adt(ty)))
}
_ => None,
},
_ => bug!("unexpected definition: {:?}", def),
};
- if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant {
- debug!("check_struct_path: did={:?} substs={:?}", did, substs);
+ if let Some((variant, did, ty::UserArgs { args, user_self_ty })) = variant {
+ debug!("check_struct_path: did={:?} args={:?}", did, args);
// Register type annotation.
- self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty);
+ self.write_user_type_annotation_from_args(hir_id, did, args, user_self_ty);
// Check bounds on type arguments used in the path.
- self.add_required_obligations_for_hir(path_span, did, substs, hir_id);
+ self.add_required_obligations_for_hir(path_span, did, args, hir_id);
Ok((variant, ty.normalized))
} else {
@@ -1474,11 +1468,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Type check the pattern. Override if necessary to avoid knock-on errors.
- self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
+ self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin));
let pat_ty = self.node_ty(decl.pat.hir_id);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
- if let Some(blk) = decl.els {
+ if let Some(blk) = decl.origin.try_get_else() {
let previous_diverges = self.diverges.get();
let else_ty = self.check_block_with_expected(blk, NoExpectation);
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
@@ -1496,7 +1490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_decl(local.into());
}
- pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) {
+ pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
// Don't do all the complex logic below for `DeclItem`.
match stmt.kind {
hir::StmtKind::Item(..) => return,
@@ -1523,14 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
}
hir::StmtKind::Semi(ref expr) => {
- // All of this is equivalent to calling `check_expr`, but it is inlined out here
- // in order to capture the fact that this `match` is the last statement in its
- // function. This is done for better suggestions to remove the `;`.
- let expectation = match expr.kind {
- hir::ExprKind::Match(..) if is_last => IsLast(stmt.span),
- _ => NoExpectation,
- };
- self.check_expr_with_expectation(expr, expectation);
+ self.check_expr(expr);
}
}
@@ -1581,8 +1568,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
- for (pos, s) in blk.stmts.iter().enumerate() {
- self.check_stmt(s, blk.stmts.len() - 1 == pos);
+ for s in blk.stmts {
+ self.check_stmt(s);
}
// check the tail expression **without** holding the
@@ -1595,7 +1582,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let coerce = ctxt.coerce.as_mut().unwrap();
if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty {
let span = self.get_expr_coercion_span(tail_expr);
- let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
+ let cause = self.cause(
+ span,
+ ObligationCauseCode::BlockTailExpression(blk.hir_id, hir::MatchSource::Normal),
+ );
let ty_for_diagnostic = coerce.merged_ty();
// We use coerce_inner here because we want to augment the error
// suggesting to wrap the block in square brackets if it might've
@@ -1605,9 +1595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&cause,
Some(tail_expr),
tail_expr_ty,
- Some(&mut |diag: &mut Diagnostic| {
+ |diag| {
self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic);
- }),
+ },
false,
);
} else {
@@ -1644,7 +1634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coerce.coerce_forced_unit(
self,
&self.misc(sp),
- &mut |err| {
+ |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
if blk.stmts.is_empty() && blk.expr.is_none() {
self.suggest_boxing_when_appropriate(
@@ -1867,19 +1857,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.adjust_fulfillment_error_for_expr_obligation(error)
|| before_span != error.obligation.cause.span
{
- // Store both the predicate and the predicate *without constness*
- // since sometimes we instantiate and check both of these in a
- // method call, for example.
remap_cause.insert((
before_span,
error.obligation.predicate,
error.obligation.cause.clone(),
));
- remap_cause.insert((
- before_span,
- error.obligation.predicate.without_const(self.tcx),
- error.obligation.cause.clone(),
- ));
} else {
// If it failed to be adjusted once around, it may be adjusted
// via the "remap cause" mapping the second time...
@@ -2031,7 +2013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
("closure", self.tcx.def_span(def_id))
};
- err.span_note(span, format!("{} defined here", kind));
+ err.span_note(span, format!("{kind} defined here"));
} else {
err.span_note(
self.tcx.def_span(def_id),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 20b34df99..6a82b0021 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -288,21 +288,23 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
poly_trait_ref,
);
- let item_substs = self.astconv().create_substs_for_associated_item(
+ let item_args = self.astconv().create_args_for_associated_item(
span,
item_def_id,
item_segment,
- trait_ref.substs,
+ trait_ref.args,
);
- Ty::new_projection(self.tcx(), item_def_id, item_substs)
+ Ty::new_projection(self.tcx(), item_def_id, item_args)
}
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
match ty.kind() {
ty::Adt(adt_def, _) => Some(*adt_def),
// FIXME(#104767): Should we handle bound regions here?
- ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
+ ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _)
+ if !ty.has_escaping_bound_vars() =>
+ {
self.normalize(span, ty).ty_adt_def()
}
_ => None,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 79a7c0161..d2a53ee8b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,8 +1,6 @@
use super::FnCtxt;
-use crate::errors::{
- AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod,
-};
+use crate::errors;
use crate::fluent_generated as fluent;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -97,8 +95,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
) -> bool {
- let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
- else { return false; };
+ let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) else {
+ return false;
+ };
if can_satisfy(output) {
let (sugg_call, mut applicability) = match inputs.len() {
0 => ("".to_string(), Applicability::MachineApplicable),
@@ -180,10 +179,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
) -> bool {
- let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
- else { return false; };
- let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
- else { return false; };
+ let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else {
+ return false;
+ };
+ let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) else {
+ return false;
+ };
if can_satisfy(lhs_output_ty, rhs_output_ty) {
let mut sugg = vec![];
@@ -392,9 +393,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
};
let struct_pat_shorthand_field =
- self.maybe_get_struct_pattern_shorthand_field(expr);
+ self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr);
if let Some(name) = struct_pat_shorthand_field {
- sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
+ sugg.insert(0, (expr.span.shrink_to_lo(), format!("{name}: ")));
}
Some(sugg)
})
@@ -431,7 +432,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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 {
- err.subdiagnostic(SuggestConvertViaMethod {
+ err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(),
sugg: ".as_ref()",
expected,
@@ -444,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.can_eq(self.param_env, deref_ty, peeled)
&& error_tys_equate_as_ref
{
- err.subdiagnostic(SuggestConvertViaMethod {
+ err.subdiagnostic(errors::SuggestConvertViaMethod {
span: expr.span.shrink_to_hi(),
sugg: ".as_deref()",
expected,
@@ -478,23 +479,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> {
- let ty::Adt(found_adt, found_substs) = found_ty.peel_refs().kind() else {
+ let ty::Adt(found_adt, found_args) = found_ty.peel_refs().kind() else {
return None;
};
- let ty::Adt(expected_adt, expected_substs) = expected_ty.kind() else {
+ let ty::Adt(expected_adt, expected_args) = expected_ty.kind() else {
return None;
};
if self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
&& self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
{
- Some((found_substs.type_at(0), expected_substs.type_at(0), None))
+ Some((found_args.type_at(0), expected_args.type_at(0), None))
} else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did())
&& self.tcx.is_diagnostic_item(sym::Result, expected_adt.did())
{
Some((
- found_substs.type_at(0),
- expected_substs.type_at(0),
- Some((found_substs.type_at(1), expected_substs.type_at(1))),
+ found_args.type_at(0),
+ expected_args.type_at(0),
+ Some((found_args.type_at(1), expected_args.type_at(1))),
))
} else {
None
@@ -518,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.can_coerce(Ty::new_box(self.tcx, found), expected) {
let suggest_boxing = match found.kind() {
ty::Tuple(tuple) if tuple.is_empty() => {
- SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
+ errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
}
ty::Generator(def_id, ..)
if matches!(
@@ -526,9 +527,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(GeneratorKind::Async(AsyncGeneratorKind::Closure))
) =>
{
- SuggestBoxing::AsyncBody
+ errors::SuggestBoxing::AsyncBody
}
- _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() },
+ _ => errors::SuggestBoxing::Other {
+ start: span.shrink_to_lo(),
+ end: span.shrink_to_hi(),
+ },
};
err.subdiagnostic(suggest_boxing);
@@ -555,7 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.take(4)
.map(|(var_hir_id, upvar)| {
let var_name = self.tcx.hir().name(*var_hir_id).to_string();
- let msg = format!("`{}` captured here", var_name);
+ let msg = format!("`{var_name}` captured here");
(upvar.span, msg)
})
.collect::<Vec<_>>();
@@ -635,7 +639,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
// can suggest Box::pin.
let parent = self.tcx.hir().parent_id(expr.hir_id);
- let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = self.tcx.hir().find(parent) else {
+ let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) =
+ self.tcx.hir().find(parent)
+ else {
return false;
};
match fn_name.kind {
@@ -751,23 +757,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &fn_decl.output {
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
// `fn main()` must return `()`, do not suggest changing return type
- err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
+ err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
return true;
}
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
if let Some(found) = found.make_suggestable(self.tcx, false) {
- err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
+ err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() });
return true;
- } else if let ty::Closure(_, substs) = found.kind()
+ } else if let ty::Closure(_, args) = found.kind()
// FIXME(compiler-errors): Get better at printing binders...
- && let closure = substs.as_closure()
+ && let closure = args.as_closure()
&& closure.sig().is_suggestable(self.tcx, false)
{
- err.subdiagnostic(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;
} else {
// FIXME: if `found` could be `impl Iterator` we should suggest that.
- err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
+ err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
return true
}
}
@@ -789,10 +795,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!(?found);
if found.is_suggestable(self.tcx, false) {
if term.span.is_empty() {
- err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
+ err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() });
return true;
} else {
- err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected });
+ err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected });
}
}
}
@@ -808,7 +814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.normalize(span, ty);
let ty = self.tcx.erase_late_bound_regions(ty);
if self.can_coerce(expected, ty) {
- err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected });
+ err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected });
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
return true;
}
@@ -850,12 +856,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Fn(
- hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. },
+ hir::FnSig {
+ decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. },
+ ..
+ },
hir::Generics { params, predicates, .. },
_body_id,
),
..
- })) = fn_node else { return };
+ })) = fn_node
+ else {
+ return;
+ };
if params.get(expected_ty_as_param.index as usize).is_none() {
return;
@@ -920,7 +932,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion(
fn_return.span(),
"consider using an impl return type",
- format!("impl {}", all_bounds_str),
+ format!("impl {all_bounds_str}"),
Applicability::MaybeIncorrect,
);
}
@@ -938,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !expected.is_unit() {
return;
}
- let found = self.resolve_vars_with_obligations(found);
+ let found = self.resolve_vars_if_possible(found);
let in_loop = self.is_loop(id)
|| self
@@ -982,14 +994,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let ty = self.normalize(expr.span, ty);
if self.can_coerce(found, ty) {
- err.multipart_suggestion(
- "you might have meant to return this value",
- vec![
- (expr.span.shrink_to_lo(), "return ".to_string()),
- (expr.span.shrink_to_hi(), ";".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
+ if let Some(node) = self.tcx.hir().find(fn_id)
+ && let Some(owner_node) = node.as_owner()
+ && let Some(span) = expr.span.find_ancestor_inside(owner_node.span())
+ {
+ err.multipart_suggestion(
+ "you might have meant to return this value",
+ vec![
+ (span.shrink_to_lo(), "return ".to_string()),
+ (span.shrink_to_hi(), ";".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
}
@@ -1058,8 +1075,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.must_apply_modulo_regions()
{
- let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
- Some(ident) => format!(": {}.clone()", ident),
+ let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!(": {ident}.clone()"),
None => ".clone()".to_string()
};
@@ -1074,68 +1091,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
- pub(crate) fn suggest_copied_or_cloned(
+ pub(crate) fn suggest_copied_cloned_or_as_ref(
&self,
diag: &mut Diagnostic,
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool {
- let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; };
- let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; };
+ let ty::Adt(adt_def, args) = expr_ty.kind() else {
+ return false;
+ };
+ let ty::Adt(expected_adt_def, expected_args) = expected_ty.kind() else {
+ return false;
+ };
if adt_def != expected_adt_def {
return false;
}
- let mut suggest_copied_or_cloned = || {
- let expr_inner_ty = substs.type_at(0);
- let expected_inner_ty = expected_substs.type_at(0);
- if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
- && self.can_eq(self.param_env, ty, expected_inner_ty)
- {
- let def_path = self.tcx.def_path_str(adt_def.did());
- if self.type_is_copy_modulo_regions(self.param_env, ty) {
- diag.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
- format!(
- "use `{def_path}::copied` to copy the value inside the `{def_path}`"
- ),
- ".copied()",
- Applicability::MachineApplicable,
- );
- 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,
- )
+ if Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Result)
+ && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1))
+ || Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+ {
+ let expr_inner_ty = args.type_at(0);
+ let expected_inner_ty = expected_args.type_at(0);
+ if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
+ && self.can_eq(self.param_env, ty, expected_inner_ty)
{
- diag.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
- format!(
- "use `{def_path}::cloned` to clone the value inside the `{def_path}`"
- ),
- ".cloned()",
- Applicability::MachineApplicable,
- );
+ 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,
+ )
+ {
+ errors::OptionResultRefMismatch::Cloned {
+ span, def_path
+ }
+ } else {
+ return false;
+ };
+ diag.subdiagnostic(subdiag);
return true;
}
- }
- false
- };
-
- if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
- && adt_def.did() == result_did
- // Check that the error types are equal
- && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1))
- {
- return suggest_copied_or_cloned();
- } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
- && adt_def.did() == option_did
- {
- return suggest_copied_or_cloned();
}
false
@@ -1177,10 +1181,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
))
{
+ let mut span = expr.span;
+ while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite()
+ {
+ span = parent_callsite;
+ }
+
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
- vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
+ vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else {
- vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
+ vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())]
};
diag.multipart_suggestion(
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
@@ -1205,7 +1215,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
}
- let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
+ let ty::Adt(def, _) = expr_ty.peel_refs().kind() else {
+ return false;
+ };
if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
return false;
}
@@ -1230,8 +1242,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
}
- let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
- Some(ident) => format!(": {}.is_some()", ident),
+ let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!(": {ident}.is_some()"),
None => ".is_some()".to_string(),
};
@@ -1327,7 +1339,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
span,
}) => {
- let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; };
+ let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else {
+ return false;
+ };
if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
return false;
}
@@ -1367,10 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Provided expression needs to be a literal `0`.
- let ExprKind::Lit(Spanned {
- node: rustc_ast::LitKind::Int(0, _),
- span,
- }) = expr.kind else {
+ let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(0, _), span }) = expr.kind else {
return false;
};
@@ -1401,7 +1412,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected_ty: Ty<'tcx>,
) -> bool {
- let Some((DefKind::AssocFn, old_def_id)) = self.typeck_results.borrow().type_dependent_def(expr.hir_id) else {
+ let Some((DefKind::AssocFn, old_def_id)) =
+ self.typeck_results.borrow().type_dependent_def(expr.hir_id)
+ else {
return false;
};
let old_item_name = self.tcx.item_name(old_def_id);
@@ -1457,7 +1470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Same item
return false;
}
- let item_ty = self.tcx.type_of(item.def_id).subst_identity();
+ let item_ty = self.tcx.type_of(item.def_id).instantiate_identity();
// FIXME(compiler-errors): This check is *so* rudimentary
if item_ty.has_param() {
return false;
@@ -1494,8 +1507,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found_ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
) {
- let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
- let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
+ // When `expr` is `x` in something like `let x = foo.clone(); x`, need to recurse up to get
+ // `foo` and `clone`.
+ let expr = self.note_type_is_not_clone_inner_expr(expr);
+
+ // If we've recursed to an `expr` of `foo.clone()`, get `foo` and `clone`.
+ let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else {
+ return;
+ };
+
+ let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else {
+ return;
+ };
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
let results = self.typeck_results.borrow();
// First, look for a `Clone::clone` call
@@ -1545,6 +1568,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// Given a type mismatch error caused by `&T` being cloned instead of `T`, and
+ /// the `expr` as the source of this type mismatch, try to find the method call
+ /// as the source of this error and return that instead. Otherwise, return the
+ /// original expression.
+ fn note_type_is_not_clone_inner_expr<'b>(
+ &'b self,
+ expr: &'b hir::Expr<'b>,
+ ) -> &'b hir::Expr<'b> {
+ match expr.peel_blocks().kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { segments: [_], res: crate::Res::Local(binding), .. },
+ )) => {
+ let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding)
+ else {
+ return expr;
+ };
+ let Some(parent) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) else {
+ return expr;
+ };
+
+ match parent {
+ // foo.clone()
+ hir::Node::Local(hir::Local { init: Some(init), .. }) => {
+ self.note_type_is_not_clone_inner_expr(init)
+ }
+ // When `expr` is more complex like a tuple
+ hir::Node::Pat(hir::Pat {
+ hir_id: pat_hir_id,
+ kind: hir::PatKind::Tuple(pats, ..),
+ ..
+ }) => {
+ let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) =
+ self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else {
+ return expr;
+ };
+
+ match init.peel_blocks().kind {
+ ExprKind::Tup(init_tup) => {
+ if let Some(init) = pats
+ .iter()
+ .enumerate()
+ .filter(|x| x.1.hir_id == *hir_id)
+ .find_map(|(i, _)| init_tup.get(i))
+ {
+ self.note_type_is_not_clone_inner_expr(init)
+ } else {
+ expr
+ }
+ }
+ _ => expr,
+ }
+ }
+ _ => expr,
+ }
+ }
+ // If we're calling into a closure that may not be typed recurse into that call. no need
+ // to worry if it's a call to a typed function or closure as this would ne handled
+ // previously.
+ hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind
+ && 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 hir::Node::Local(hir::Local { init: Some(init), .. }) = closure
+ && let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init
+ {
+ let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
+ self.note_type_is_not_clone_inner_expr(body_expr)
+ } else {
+ expr
+ }
+ }
+ _ => expr,
+ }
+ }
+
/// A common error is to add an extra semicolon:
///
/// ```compile_fail,E0308
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 4f45a24b2..ed4c63f17 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -9,6 +9,26 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
use rustc_trait_selection::traits;
+/// Provides context for checking patterns in declarations. More specifically this
+/// allows us to infer array types if the pattern is irrefutable and allows us to infer
+/// the size of the array. See issue #76342.
+#[derive(Debug, Copy, Clone)]
+pub(super) enum DeclOrigin<'a> {
+ // from an `if let` expression
+ LetExpr,
+ // from `let x = ..`
+ LocalDecl { els: Option<&'a hir::Block<'a>> },
+}
+
+impl<'a> DeclOrigin<'a> {
+ pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> {
+ match self {
+ Self::LocalDecl { els } => *els,
+ Self::LetExpr => None,
+ }
+ }
+}
+
/// A declaration is an abstraction of [hir::Local] and [hir::Let].
///
/// It must have a hir_id, as this is how we connect gather_locals to the check functions.
@@ -18,20 +38,20 @@ pub(super) struct Declaration<'a> {
pub ty: Option<&'a hir::Ty<'a>>,
pub span: Span,
pub init: Option<&'a hir::Expr<'a>>,
- pub els: Option<&'a hir::Block<'a>>,
+ pub origin: DeclOrigin<'a>,
}
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
fn from(local: &'a hir::Local<'a>) -> Self {
let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
- Declaration { hir_id, pat, ty, span, init, els }
+ Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
}
}
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
fn from(let_expr: &'a hir::Let<'a>) -> Self {
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
- Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
+ Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
}
}
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index b84c49186..cfedcee99 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -6,7 +6,7 @@ use hir::{
intravisit::{self, Visitor},
Body, Expr, ExprKind, Guard, HirId, LoopIdError,
};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_index::IndexVec;
use rustc_infer::infer::InferCtxt;
@@ -28,7 +28,7 @@ pub(super) fn build_control_flow_graph<'tcx>(
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
body: &'tcx Body<'tcx>,
num_exprs: usize,
-) -> (DropRangesBuilder, FxHashSet<HirId>) {
+) -> (DropRangesBuilder, UnordSet<HirId>) {
let mut drop_range_visitor = DropRangeVisitor::new(
infcx,
typeck_results,
@@ -443,9 +443,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
// We add an edge to the hir_id of the expression/block we are breaking out of, and
// then in process_deferred_edges we will map this hir_id to its PostOrderId, which
// will refer to the end of the block due to the post order traversal.
- self.find_target_expression_from_destination(destination).map_or((), |target| {
+ if let Ok(target) = self.find_target_expression_from_destination(destination) {
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
- });
+ }
if let Some(value) = value {
self.visit_expr(value);
@@ -528,7 +528,7 @@ impl DropRangesBuilder {
hir: Map<'_>,
num_exprs: usize,
) -> Self {
- let mut tracked_value_map = FxHashMap::<_, TrackedValueIndex>::default();
+ let mut tracked_value_map = UnordMap::<_, TrackedValueIndex>::default();
let mut next = <_>::from(0u32);
for value in tracked_values {
for_each_consumable(hir, value, |value| {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index ecafbd668..e563bd40b 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -17,7 +17,7 @@ use self::record_consumed_borrow::find_consumed_and_borrowed;
use crate::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
@@ -63,7 +63,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
// If drop range tracking is not enabled, skip all the analysis and produce an
// empty set of DropRanges.
DropRanges {
- tracked_value_map: FxHashMap::default(),
+ tracked_value_map: UnordMap::default(),
nodes: IndexVec::new(),
borrowed_temporaries: None,
}
@@ -125,8 +125,8 @@ impl Debug for TrackedValue {
write!(f, "{}", tcx.hir().node_to_string(self.hir_id()))
} else {
match self {
- Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id),
- Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id),
+ Self::Variable(hir_id) => write!(f, "Variable({hir_id:?})"),
+ Self::Temporary(hir_id) => write!(f, "Temporary({hir_id:?})"),
}
}
})
@@ -182,9 +182,9 @@ impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
}
pub struct DropRanges {
- tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+ tracked_value_map: UnordMap<TrackedValue, TrackedValueIndex>,
nodes: IndexVec<PostOrderId, NodeInfo>,
- borrowed_temporaries: Option<FxHashSet<HirId>>,
+ borrowed_temporaries: Option<UnordSet<HirId>>,
}
impl DropRanges {
@@ -227,7 +227,7 @@ struct DropRangesBuilder {
/// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
/// from HirIds to the HirIdIndex that is used to represent that value in
/// bitvector.
- tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+ tracked_value_map: UnordMap<TrackedValue, TrackedValueIndex>,
/// When building the control flow graph, we don't always know the
/// post-order index of the target node at the point we encounter it.
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index 8ab0bd535..29413f080 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -4,7 +4,7 @@ use crate::{
FnCtxt,
};
use hir::{def_id::DefId, Body, HirId, HirIdMap};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::{fx::FxIndexSet, unord::UnordSet};
use rustc_hir as hir;
use rustc_middle::ty::{ParamEnv, TyCtxt};
use rustc_middle::{
@@ -30,13 +30,13 @@ pub(super) struct ConsumedAndBorrowedPlaces {
///
/// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
/// not considered a drop of `x`, although it would be a drop of `x.y`.
- pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
+ pub(super) consumed: HirIdMap<FxIndexSet<TrackedValue>>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
- pub(super) borrowed: FxHashSet<TrackedValue>,
+ pub(super) borrowed: UnordSet<TrackedValue>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
- pub(super) borrowed_temporaries: FxHashSet<HirId>,
+ pub(super) borrowed_temporaries: UnordSet<HirId>,
}
/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
@@ -150,9 +150,10 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
hir.node_to_string(diag_expr_id),
hir.node_to_string(parent)
);
- place_with_id
- .try_into()
- .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+
+ if let Ok(tracked_value) = place_with_id.try_into() {
+ self.mark_consumed(parent, tracked_value)
+ }
}
fn borrow(
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 86ea092bc..6a8171224 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -112,7 +112,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
self.fcx
.tcx
.sess
- .delay_span_bug(span, format!("Encountered var {:?}", unresolved_term));
+ .delay_span_bug(span, format!("Encountered var {unresolved_term:?}"));
} else {
let note = format!(
"the type is part of the {} because of this {}",
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index d5619af2a..7064484a4 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -1,6 +1,6 @@
use super::callee::DeferredCallResolution;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
@@ -61,9 +61,9 @@ pub struct Inherited<'tcx> {
/// Whenever we introduce an adjustment from `!` into a type variable,
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
- pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
+ pub(super) diverging_type_vars: RefCell<UnordSet<Ty<'tcx>>>,
- pub(super) infer_var_info: RefCell<FxHashMap<ty::TyVid, ty::InferVarInfo>>,
+ pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, ty::InferVarInfo>>,
}
impl<'tcx> Deref for Inherited<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index e58efc9d1..4e65182f1 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -11,7 +11,7 @@ use super::FnCtxt;
/// If the type is `Option<T>`, it will return `T`, otherwise
/// the type itself. Works on most `Option`-like types.
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
- let ty::Adt(def, substs) = *ty.kind() else { return ty };
+ let ty::Adt(def, args) = *ty.kind() else { return ty };
if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
let data_idx;
@@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
}
if def.variant(data_idx).fields.len() == 1 {
- return def.variant(data_idx).single_field().ty(tcx, substs);
+ return def.variant(data_idx).single_field().ty(tcx, args);
}
}
@@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
Ok(SizeSkeleton::Known(size)) => {
if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
- format!("{} bits", v)
+ format!("{v} bits")
} else {
// `u128` should definitely be able to hold the size of different architectures
// larger sizes should be reported as error `are too big for the current architecture`
@@ -122,14 +122,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
- let mut should_delay_as_bug = false;
- if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() {
- should_delay_as_bug = true;
- }
- if let Err(LayoutError::Unknown(bad_to)) = sk_to && bad_to.references_error() {
- should_delay_as_bug = true;
- }
- if should_delay_as_bug {
+ if let Err(LayoutError::ReferencesError(_)) = sk_from {
+ err.delay_as_bug();
+ } else if let Err(LayoutError::ReferencesError(_)) = sk_to {
err.delay_as_bug();
}
}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6f82ffcfe..c4d3cbc9f 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -6,7 +6,6 @@
#![feature(min_specialization)]
#![feature(control_flow_enum)]
#![feature(option_as_slice)]
-#![allow(rustc::potential_query_instability)]
#![recursion_limit = "256"]
#[macro_use]
@@ -72,7 +71,7 @@ use rustc_middle::traits;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
use rustc_span::def_id::{DefId, LocalDefId};
-use rustc_span::{sym, Span};
+use rustc_span::Span;
fluent_messages! { "../messages.ftl" }
@@ -102,7 +101,7 @@ fn primary_body_of(
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
match node {
Node::Item(item) => match item.kind {
- hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
+ hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => {
Some((body, Some(ty), None))
}
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
@@ -141,11 +140,11 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
- &*tcx.typeck(def_id).used_trait_imports
+ &tcx.typeck(def_id).used_trait_imports
}
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity();
+ let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity();
typeck_with_fallback(tcx, def_id, fallback)
}
@@ -183,11 +182,7 @@ fn typeck_with_fallback<'tcx>(
let body = tcx.hir().body(body_id);
let param_env = tcx.param_env(def_id);
- let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
- param_env.without_const()
- } else {
- param_env
- };
+
let inh = Inherited::new(tcx, def_id);
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
@@ -195,7 +190,7 @@ fn typeck_with_fallback<'tcx>(
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
} else {
- tcx.fn_sig(def_id).subst_identity()
+ tcx.fn_sig(def_id).instantiate_identity()
};
check_abi(tcx, id, span, fn_sig.abi());
@@ -264,11 +259,7 @@ fn typeck_with_fallback<'tcx>(
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
- // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
- let prev_constness = fcx.param_env.constness();
- fcx.param_env = fcx.param_env.without_const();
fcx.closure_analyze(body);
- fcx.param_env = fcx.param_env.with_constness(prev_constness);
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
// Before the generator analysis, temporary scopes shall be marked to provide more
// precise information on types to be captured.
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index a1aa09084..9574da021 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
/// Like `pat_ty`, but ignores implicit `&` patterns.
+ #[instrument(level = "debug", skip(self), ret)]
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
let base_ty = self.node_ty(pat.hir_id)?;
- debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
+ trace!(?base_ty);
// This code detects whether we are looking at a `ref x`,
// and if so, figures out what the type *being borrowed* is.
- let ret_ty = match pat.kind {
+ match pat.kind {
PatKind::Binding(..) => {
let bm = *self
.typeck_results
@@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false) {
- Some(t) => t.ty,
+ Some(t) => Ok(t.ty),
None => {
- debug!("By-ref binding of non-derefable type {:?}", base_ty);
- return Err(());
+ debug!("By-ref binding of non-derefable type");
+ Err(())
}
}
} else {
- base_ty
+ Ok(base_ty)
}
}
- _ => base_ty,
- };
- debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
-
- Ok(ret_ty)
+ _ => Ok(base_ty),
+ }
}
pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
@@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub(crate) fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
-
let expr_ty = self.expr_ty(expr)?;
match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
@@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
hir::ExprKind::Field(ref base, _) => {
let base = self.cat_expr(base)?;
- debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
+ debug!(?base);
let field_idx = self
.typeck_results
@@ -336,7 +332,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
))
}
- hir::ExprKind::Index(ref base, _) => {
+ hir::ExprKind::Index(ref base, _, _) => {
if self.typeck_results.is_method_call(expr) {
// If this is an index implemented by a method call, then it
// will include an implicit deref of the result.
@@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
- #[instrument(level = "debug", skip(self, span))]
+ #[instrument(level = "debug", skip(self, span), ret)]
pub(crate) fn cat_res(
&self,
hir_id: hir::HirId,
@@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// Note: the actual upvar access contains invisible derefs of closure
/// environment and upvar reference as appropriate. Only regionck cares
/// about these dereferences, so we let it compute them as needed.
+ #[instrument(level = "debug", skip(self), ret)]
fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
let closure_expr_def_id = self.body_owner;
@@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
};
let var_ty = self.node_ty(var_id)?;
- let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
-
- debug!("cat_upvar ret={:?}", ret);
- Ok(ret)
+ Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
}
+ #[instrument(level = "debug", skip(self), ret)]
pub(crate) fn cat_rvalue(
&self,
hir_id: hir::HirId,
span: Span,
expr_ty: Ty<'tcx>,
) -> PlaceWithHirId<'tcx> {
- debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
- let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
- debug!("cat_rvalue ret={:?}", ret);
- ret
+ PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
}
+ #[instrument(level = "debug", skip(self, node), ret)]
pub(crate) fn cat_projection<N: HirNode>(
&self,
node: &N,
@@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ty: Ty<'tcx>,
kind: ProjectionKind,
) -> PlaceWithHirId<'tcx> {
+ let place_ty = base_place.place.ty();
let mut projections = base_place.place.projections;
+
+ let node_ty = self.typeck_results.node_type(node.hir_id());
+ // Opaque types can't have field projections, but we can instead convert
+ // the current place in-place (heh) to the hidden type, and then apply all
+ // follow up projections on that.
+ if node_ty != place_ty && matches!(place_ty.kind(), ty::Alias(ty::Opaque, ..)) {
+ projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+ }
projections.push(Projection { kind, ty });
- let ret = PlaceWithHirId::new(
+ PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
base_place.place.base,
projections,
- );
- debug!("cat_field ret {:?}", ret);
- ret
+ )
}
#[instrument(level = "debug", skip(self))]
@@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_deref(expr, base)
}
- #[instrument(level = "debug", skip(self, node))]
+ #[instrument(level = "debug", skip(self, node), ret)]
fn cat_deref(
&self,
node: &impl HirNode,
@@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
let mut projections = base_place.place.projections;
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
- let ret = PlaceWithHirId::new(
+ Ok(PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
base_place.place.base,
projections,
- );
- debug!("cat_deref ret {:?}", ret);
- Ok(ret)
+ ))
}
pub(crate) fn cat_pattern<F>(
@@ -559,7 +557,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
}
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
- | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+ | Res::Def(
+ DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+ _,
+ )
| Res::SelfCtor(..)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. } => {
@@ -595,7 +596,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<usize> {
let ty = self.typeck_results.node_type(pat_hir_id);
match ty.kind() {
- ty::Tuple(substs) => Ok(substs.len()),
+ ty::Tuple(args) => Ok(args.len()),
_ => {
self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
Err(())
@@ -603,6 +604,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
+ /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
+ /// is being matched against.
+ ///
+ /// In general, the way that this works is that we walk down the pattern,
+ /// constructing a `PlaceWithHirId` that represents the path that will be taken
+ /// to reach the value being matched.
+ #[instrument(skip(self, op), ret, level = "debug")]
fn cat_pattern_<F>(
&self,
mut place_with_id: PlaceWithHirId<'tcx>,
@@ -612,15 +620,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
where
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{
- // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
- // is being matched against.
- //
- // In general, the way that this works is that we walk down the pattern,
- // constructing a `PlaceWithHirId` that represents the path that will be taken
- // to reach the value being matched.
-
- debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
-
// If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
// `PlaceWithHirId`s are constructed differently from patterns. For example, in
//
@@ -654,11 +653,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
- debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
+ debug!("applying adjustment to place_with_id={:?}", place_with_id);
place_with_id = self.cat_deref(pat, place_with_id)?;
}
let place_with_id = place_with_id; // lose mutability
- debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
+ debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
// Invoke the callback, but only now, after the `place_with_id` has adjusted.
//
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 87edb8031..7c73f6a89 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_hir_analysis::astconv::generics::{
- check_generic_arg_count_for_call, create_substs_for_generic_args,
+ check_generic_arg_count_for_call, create_args_for_parent_generic_args,
};
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
@@ -13,9 +13,9 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{self, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt};
-use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType};
+use rustc_middle::ty::{
+ self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, UserArgs, UserType,
+};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;
@@ -96,13 +96,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
// Create substitutions for the method's type parameters.
- let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
- let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs);
+ let rcvr_args = self.fresh_receiver_args(self_ty, &pick);
+ let all_args = self.instantiate_method_args(&pick, segment, rcvr_args);
- debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}");
+ debug!("rcvr_args={rcvr_args:?}, all_args={all_args:?}");
// Create the final signature for the method, replacing late-bound regions.
- let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
+ let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_args);
// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
// something which derefs to `Self` actually implements the trait and the caller
@@ -112,10 +112,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// In that case, we'll error anyway, but we'll also re-run the search with all traits
// in scope, and if we find another method which can be used, we'll output an
// appropriate hint suggesting to import the trait.
- let filler_substs = rcvr_substs
+ let filler_args = rcvr_args
.extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
- self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
+ self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_args),
);
// Unify the (adjusted) self type with what the method expects.
@@ -129,7 +129,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
"confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
self_ty, method_sig_rcvr, method_sig, method_predicates
);
- self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
+ self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_args);
let (method_sig, method_predicates) =
self.normalize(self.span, (method_sig, method_predicates));
@@ -144,7 +144,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
if illegal_sized_bound.is_none() {
self.add_obligations(
Ty::new_fn_ptr(self.tcx, method_sig),
- all_substs,
+ all_args,
method_predicates,
pick.item.def_id,
);
@@ -153,7 +153,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Create the final `MethodCallee`.
let callee = MethodCallee {
def_id: pick.item.def_id,
- substs: all_substs,
+ args: all_args,
sig: method_sig.skip_binder(),
};
ConfirmResult { callee, illegal_sized_bound }
@@ -171,7 +171,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// time writing the results into the various typeck results.
let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
- return Ty::new_error_with_message(self.tcx,
+ return Ty::new_error_with_message(
+ self.tcx,
rustc_span::DUMMY_SP,
format!("failed autoderef {}", pick.autoderefs),
);
@@ -224,7 +225,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
assert!(mutbl.is_mut());
Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
}
- other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
+ other => panic!("Cannot adjust receiver type {other:?} to const ptr"),
};
adjustments.push(Adjustment {
@@ -251,20 +252,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
///
/// Note that this substitution may include late-bound regions from the impl level. If so,
/// these are instantiated later in the `instantiate_method_sig` routine.
- fn fresh_receiver_substs(
+ fn fresh_receiver_args(
&mut self,
self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>,
- ) -> SubstsRef<'tcx> {
+ ) -> GenericArgsRef<'tcx> {
match pick.kind {
probe::InherentImplPick => {
let impl_def_id = pick.item.container_id(self.tcx);
assert!(
self.tcx.impl_trait_ref(impl_def_id).is_none(),
- "impl {:?} is not an inherent impl",
- impl_def_id
+ "impl {impl_def_id:?} is not an inherent impl"
);
- self.fresh_substs_for_item(self.span, impl_def_id)
+ self.fresh_args_for_item(self.span, impl_def_id)
}
probe::ObjectPick => {
@@ -288,7 +288,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
"original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
original_poly_trait_ref, upcast_trait_ref, trait_def_id
);
- upcast_trait_ref.substs
+ upcast_trait_ref.args
})
}
@@ -300,13 +300,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// the process we will unify the transformed-self-type
// of the method with the actual type in order to
// unify some of these variables.
- self.fresh_substs_for_item(self.span, trait_def_id)
+ self.fresh_args_for_item(self.span, trait_def_id)
}
probe::WhereClausePick(poly_trait_ref) => {
// Where clauses can have bound regions in them. We need to instantiate
// those to convert from a poly-trait-ref to a trait-ref.
- self.instantiate_binder_with_fresh_vars(poly_trait_ref).substs
+ self.instantiate_binder_with_fresh_vars(poly_trait_ref).args
}
}
}
@@ -343,12 +343,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
})
}
- fn instantiate_method_substs(
+ fn instantiate_method_args(
&mut self,
pick: &probe::Pick<'tcx>,
seg: &hir::PathSegment<'_>,
- parent_substs: SubstsRef<'tcx>,
- ) -> SubstsRef<'tcx> {
+ parent_args: GenericArgsRef<'tcx>,
+ ) -> GenericArgsRef<'tcx> {
// Determine the values for the generic parameters of the method.
// If they were not explicitly supplied, just construct fresh
// variables.
@@ -365,7 +365,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Create subst for early-bound lifetime parameters, combining
// parameters from the type and those from the method.
- assert_eq!(generics.parent_count, parent_substs.len());
+ assert_eq!(generics.parent_count, parent_args.len());
struct MethodSubstsCtxt<'a, 'tcx> {
cfcx: &'a ConfirmContext<'a, 'tcx>,
@@ -389,7 +389,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.cfcx.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
@@ -421,31 +421,31 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
fn inferred_kind(
&mut self,
- _substs: Option<&[subst::GenericArg<'tcx>]>,
+ _args: Option<&[ty::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
_infer_args: bool,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
self.cfcx.var_for_def(self.cfcx.span, param)
}
}
- let substs = create_substs_for_generic_args(
+ let args = create_args_for_parent_generic_args(
self.tcx,
pick.item.def_id,
- parent_substs,
+ parent_args,
false,
None,
&arg_count_correct,
&mut MethodSubstsCtxt { cfcx: self, pick, seg },
);
- // When the method is confirmed, the `substs` includes
+ // When the method is confirmed, the `args` includes
// parameters from not just the method, but also the impl of
// the method -- in particular, the `Self` type will be fully
// resolved. However, those are not something that the "user
// specified" -- i.e., those types come from the inferred type
// of the receiver, not something the user wrote. So when we
- // create the user-substs, we want to replace those earlier
+ // create the user-args, we want to replace those earlier
// types with just the types that the user actually wrote --
// that is, those that appear on the *method itself*.
//
@@ -453,15 +453,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
// type of `foo` (possibly adjusted), but we don't want to
// include that. We want just the `[_, u32]` part.
- if !substs.is_empty() && !generics.params.is_empty() {
+ if !args.is_empty() && !generics.params.is_empty() {
let user_type_annotation = self.probe(|_| {
- let user_substs = UserSubsts {
- substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| {
+ let user_args = UserArgs {
+ args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
let i = param.index as usize;
if i < generics.parent_count {
self.fcx.var_for_def(DUMMY_SP, param)
} else {
- substs[i]
+ args[i]
}
}),
user_self_ty: None, // not relevant here
@@ -469,18 +469,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
pick.item.def_id,
- user_substs,
+ user_args,
))
});
- debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
+ debug!("instantiate_method_args: user_type_annotation={:?}", user_type_annotation);
if !self.skip_record_for_diagnostics {
self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
}
}
- self.normalize(self.span, substs)
+ self.normalize(self.span, args)
}
fn unify_receivers(
@@ -488,7 +488,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_ty: Ty<'tcx>,
method_self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) {
debug!(
"unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
@@ -499,7 +499,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
assoc_item: pick.item,
param_env: self.param_env,
- substs,
+ args,
})),
);
match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
@@ -509,7 +509,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
Err(terr) => {
// FIXME(arbitrary_self_types): We probably should limit the
// situations where this can occur by adding additional restrictions
- // to the feature, like the self type can't reference method substs.
+ // to the feature, like the self type can't reference method args.
if self.tcx.features().arbitrary_self_types {
self.err_ctxt()
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
@@ -532,19 +532,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
fn instantiate_method_sig(
&mut self,
pick: &probe::Pick<'tcx>,
- all_substs: SubstsRef<'tcx>,
+ all_args: GenericArgsRef<'tcx>,
) -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
- debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs);
+ debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. There can
// be no late-bound regions appearing here.
let def_id = pick.item.def_id;
- let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_substs);
+ let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
debug!("method_predicates after subst = {:?}", method_predicates);
- let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs);
+ let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
debug!("type scheme substituted, sig={:?}", sig);
let sig = self.instantiate_binder_with_fresh_vars(sig);
@@ -556,18 +556,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
fn add_obligations(
&mut self,
fty: Ty<'tcx>,
- all_substs: SubstsRef<'tcx>,
+ all_args: GenericArgsRef<'tcx>,
method_predicates: ty::InstantiatedPredicates<'tcx>,
def_id: DefId,
) {
debug!(
- "add_obligations: fty={:?} all_substs={:?} method_predicates={:?} def_id={:?}",
- fty, all_substs, method_predicates, def_id
+ "add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}",
+ fty, all_args, method_predicates, def_id
);
// FIXME: could replace with the following, but we already calculated `method_predicates`,
// so we just call `predicates_for_generics` directly to avoid redoing work.
- // `self.add_required_obligations(self.span, def_id, &all_substs);`
+ // `self.add_required_obligations(self.span, def_id, &all_args);`
for obligation in traits::predicates_for_generics(
|idx, span| {
let code = if span.is_dummy() {
@@ -590,10 +590,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// this is a projection from a trait reference, so we have to
// make sure that the trait reference inputs are well-formed.
- self.add_wf_bounds(all_substs, self.call_expr);
+ self.add_wf_bounds(all_args, self.call_expr);
// the function type must also be well-formed (this is not
- // implied by the substs being well-formed because of inherent
+ // implied by the args being well-formed because of inherent
// impls and late-bound regions - see issue #28609).
self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None));
}
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index e52cea188..6dd131aa2 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -7,12 +7,11 @@ mod prelude2021;
pub mod probe;
mod suggest;
-pub use self::suggest::SelfSource;
+pub use self::suggest::{MethodCallComponents, SelfSource};
pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;
use crate::FnCtxt;
-use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
@@ -20,8 +19,8 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -37,7 +36,7 @@ pub fn provide(providers: &mut Providers) {
pub struct MethodCallee<'tcx> {
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
pub def_id: DefId,
- pub substs: SubstsRef<'tcx>,
+ pub args: GenericArgsRef<'tcx>,
/// Instantiated method signature, i.e., it has been
/// substituted, normalized, and has had late-bound
@@ -190,11 +189,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
- for import_id in &pick.import_ids {
+ for &import_id in &pick.import_ids {
debug!("used_trait_import: {:?}", import_id);
- Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports)
- .unwrap()
- .insert(*import_id);
+ self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
}
self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None);
@@ -324,9 +321,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
- ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) {
+ ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::GenericArg<'tcx>>) {
// Construct a trait-reference `self_ty : Trait<input_tys>`
- let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+ let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
GenericParamDefKind::Type { .. } => {
@@ -340,19 +337,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.var_for_def(cause.span, param)
});
- let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, substs);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, args);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
- (
- traits::Obligation::new(
- self.tcx,
- cause,
- self.param_env,
- poly_trait_ref.without_const(),
- ),
- substs,
- )
+ (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args)
}
/// `lookup_method_in_trait` is used for overloaded operators.
@@ -369,9 +358,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- let (obligation, substs) =
+ let (obligation, args) =
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
- self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
+ self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args)
}
// FIXME(#18741): it seems likely that we can consolidate some of this
@@ -382,7 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
- substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
+ args: &'tcx ty::List<ty::GenericArg<'tcx>>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);
@@ -428,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// N.B., instantiate late-bound regions before normalizing the
// function signature so that normalization does not need to deal
// with bound regions.
- let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs);
+ let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args);
let fn_sig =
self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
@@ -447,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// Note that as the method comes from a trait, it should not have
// any late-bound regions appearing in its bounds.
- let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
+ let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(bounds);
@@ -480,7 +469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
))),
));
- let callee = MethodCallee { def_id, substs, sig: fn_sig };
+ let callee = MethodCallee { def_id, args, sig: fn_sig };
debug!("callee = {:?}", callee);
@@ -567,10 +556,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!(?pick);
{
let mut typeck_results = self.typeck_results.borrow_mut();
- let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
for import_id in pick.import_ids {
debug!(used_trait_import=?import_id);
- used_trait_imports.insert(import_id);
+ typeck_results.used_trait_imports.insert(import_id);
}
}
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index ec4e7f7f8..3f1dca5b1 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -14,6 +14,7 @@ use rustc_span::symbol::kw::{Empty, Underscore};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
+use std::fmt::Write;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn lint_dot_call_from_2018(
@@ -32,7 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
// Rust 2021 and later is already using the new prelude
- if span.rust_2021() {
+ if span.at_least_rust_2021() {
return;
}
@@ -97,28 +98,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
{
- format!("{}{} as *const _", derefs, self_expr)
+ format!("{derefs}{self_expr} as *const _")
} else {
- format!("{}{}{}", autoref, derefs, self_expr)
+ format!("{autoref}{derefs}{self_expr}")
};
lint.span_suggestion(
sp,
"disambiguate the method call",
- format!("({})", self_adjusted),
+ format!("({self_adjusted})"),
Applicability::MachineApplicable,
);
} else {
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
{
- format!("{}(...) as *const _", derefs)
+ format!("{derefs}(...) as *const _")
} else {
- format!("{}{}...", autoref, derefs)
+ format!("{autoref}{derefs}...")
};
lint.span_help(
sp,
- format!("disambiguate the method call with `({})`", self_adjusted,),
+ format!("disambiguate the method call with `({self_adjusted})`",),
);
}
@@ -143,16 +144,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
- let args = args
- .iter()
- .map(|arg| {
- let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
- format!(
- ", {}",
- self.sess().source_map().span_to_snippet(span).unwrap()
- )
- })
- .collect::<String>();
+ let args = args.iter().fold(String::new(), |mut string, arg| {
+ let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
+ write!(
+ string,
+ ", {}",
+ self.sess().source_map().span_to_snippet(span).unwrap()
+ )
+ .unwrap();
+ string
+ });
lint.span_suggestion(
sp,
@@ -168,7 +169,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.ok())
{
// Keep turbofish.
- format!("::{}", args)
+ format!("::{args}")
} else {
String::new()
},
@@ -203,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pick: &Pick<'tcx>,
) {
// Rust 2021 and later is already using the new prelude
- if span.rust_2021() {
+ if span.at_least_rust_2021() {
return;
}
@@ -347,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Glob import, so just use its name.
return None;
} else {
- return Some(format!("{}", any_id));
+ return Some(format!("{any_id}"));
}
}
@@ -396,9 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
{
- format!("{}{} as *const _", derefs, expr_text)
+ format!("{derefs}{expr_text} as *const _")
} else {
- format!("{}{}{}", autoref, derefs, expr_text)
+ format!("{autoref}{derefs}{expr_text}")
};
(adjusted_text, precise)
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 03a3eebbd..7164102a3 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_middle::ty::{InternalSubsts, SubstsRef};
+use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
use rustc_span::def_id::LocalDefId;
@@ -100,10 +100,10 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
#[derive(Debug, Clone)]
pub(crate) struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
- // some metadata on top of a `ty::AssocItem` (without substs).
+ // some metadata on top of a `ty::AssocItem` (without args).
//
// However, method probing wants to be able to evaluate the predicates
- // for a function with the substs applied - for example, if a function
+ // for a function with the args applied - for example, if a function
// has `where Self: Sized`, we don't want to consider it unless `Self`
// is actually `Sized`, and similarly, return-type suggestions want
// to consider the "actual" return type.
@@ -140,7 +140,7 @@ pub(crate) struct Candidate<'tcx> {
#[derive(Debug, Clone)]
pub(crate) enum CandidateKind<'tcx> {
InherentImplCandidate(
- SubstsRef<'tcx>,
+ GenericArgsRef<'tcx>,
// Normalize obligations
Vec<traits::PredicateObligation<'tcx>>,
),
@@ -437,7 +437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// this case used to be allowed by the compiler,
// so we do a future-compat lint here for the 2015 edition
// (see https://github.com/rust-lang/rust/issues/46906)
- if self.tcx.sess.rust_2018() {
+ if self.tcx.sess.at_least_rust_2018() {
self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
} else {
self.tcx.struct_span_lint_hir(
@@ -738,13 +738,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
continue;
}
- let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
- let impl_ty = impl_ty.subst(self.tcx, impl_substs);
+ let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id);
+ let impl_ty = impl_ty.instantiate(self.tcx, impl_args);
debug!("impl_ty: {:?}", impl_ty);
// Determine the receiver type that the method itself expects.
- let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_substs);
+ let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use normalize_associated_types_in as it will pollute the
@@ -770,7 +770,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
xform_self_ty,
xform_ret_ty,
item,
- kind: InherentImplCandidate(impl_substs, obligations),
+ kind: InherentImplCandidate(impl_args, obligations),
import_ids: smallvec![],
},
true,
@@ -813,7 +813,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
let (xform_self_ty, xform_ret_ty) =
- this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs);
+ this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
this.push_candidate(
Candidate {
xform_self_ty,
@@ -859,7 +859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
);
let (xform_self_ty, xform_ret_ty) =
- this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.substs);
+ this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args);
this.push_candidate(
Candidate {
@@ -929,8 +929,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
) -> bool {
match method.kind {
ty::AssocKind::Fn => self.probe(|_| {
- let substs = self.fresh_substs_for_item(self.span, method.def_id);
- let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs);
+ let args = self.fresh_args_for_item(self.span, method.def_id);
+ let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
if let Some(self_ty) = self_ty {
@@ -954,8 +954,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
trait_def_id: DefId,
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
- let trait_substs = self.fresh_substs_for_item(self.span, trait_def_id);
- let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs);
+ let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, recursively assume all explicitly named traits are relevant
@@ -977,7 +977,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
);
let (xform_self_ty, xform_ret_ty) =
- self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs);
+ self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
self.push_candidate(
Candidate {
xform_self_ty,
@@ -1005,7 +1005,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
let (xform_self_ty, xform_ret_ty) =
- self.xform_self_ty(item, trait_ref.self_ty(), trait_substs);
+ self.xform_self_ty(item, trait_ref.self_ty(), trait_args);
self.push_candidate(
Candidate {
xform_self_ty,
@@ -1510,7 +1510,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
- InherentImplCandidate(ref substs, ref ref_obligations) => {
+ InherentImplCandidate(ref args, ref ref_obligations) => {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
@@ -1524,7 +1524,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// Check whether the impl imposes obligations we have to worry about.
let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
- let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
+ let impl_bounds = impl_bounds.instantiate(self.tcx, args);
let InferOk { value: impl_bounds, obligations: norm_obligations } =
self.fcx.at(&cause, self.param_env).normalize(impl_bounds);
@@ -1592,15 +1592,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some(method_name) = self.method_name {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
- if self_ty.is_array() && !method_name.span.rust_2021() {
+ if self_ty.is_array() && !method_name.span.at_least_rust_2021() {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
if trait_def.skip_array_during_method_dispatch {
return ProbeResult::NoMatch;
}
}
}
- let predicate =
- ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
+ let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx);
parent_pred = Some(predicate);
let obligation =
traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate);
@@ -1843,10 +1842,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
item: ty::AssocItem,
impl_ty: Ty<'tcx>,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall {
- let sig = self.xform_method_sig(item.def_id, substs);
+ let sig = self.xform_method_sig(item.def_id, args);
(sig.inputs()[0], Some(sig.output()))
} else {
(impl_ty, None)
@@ -1854,11 +1853,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
- fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
+ fn xform_method_sig(&self, method: DefId, args: GenericArgsRef<'tcx>) -> ty::FnSig<'tcx> {
let fn_sig = self.tcx.fn_sig(method);
debug!(?fn_sig);
- assert!(!substs.has_escaping_bound_vars());
+ assert!(!args.has_escaping_bound_vars());
// It is possible for type parameters or early-bound lifetimes
// to appear in the signature of `self`. The substitutions we
@@ -1866,15 +1865,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// method yet. So create fresh variables here for those too,
// if there are any.
let generics = self.tcx.generics_of(method);
- assert_eq!(substs.len(), generics.parent_count as usize);
+ assert_eq!(args.len(), generics.parent_count as usize);
let xform_fn_sig = if generics.params.is_empty() {
- fn_sig.subst(self.tcx, substs)
+ fn_sig.instantiate(self.tcx, args)
} else {
- let substs = InternalSubsts::for_item(self.tcx, method, |param, _| {
+ let args = GenericArgs::for_item(self.tcx, method, |param, _| {
let i = param.index as usize;
- if i < substs.len() {
- substs[i]
+ if i < args.len() {
+ args[i]
} else {
match param.kind {
GenericParamDefKind::Lifetime => {
@@ -1887,18 +1886,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
});
- fn_sig.subst(self.tcx, substs)
+ fn_sig.instantiate(self.tcx, args)
};
self.erase_late_bound_regions(xform_fn_sig)
}
/// Gets the type of an impl and generate substitutions with inference vars.
- fn impl_ty_and_substs(
+ fn impl_ty_and_args(
&self,
impl_def_id: DefId,
- ) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) {
- (self.tcx.type_of(impl_def_id), self.fresh_substs_for_item(self.span, impl_def_id))
+ ) -> (ty::EarlyBinder<Ty<'tcx>>, GenericArgsRef<'tcx>) {
+ (self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id))
}
/// Replaces late-bound-regions bound by `value` with `'static` using
@@ -1938,13 +1937,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Determine if the associated item withe the given DefId matches
/// the desired name via a doc alias.
fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
- let Some(name) = self.method_name else { return false; };
- let Some(local_def_id) = def_id.as_local() else { return false; };
+ let Some(name) = self.method_name else {
+ return false;
+ };
+ let Some(local_def_id) = def_id.as_local() else {
+ return false;
+ };
let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id);
let attrs = self.fcx.tcx.hir().attrs(hir_id);
for attr in attrs {
- let sym::doc = attr.name_or_empty() else { continue; };
- let Some(values) = attr.meta_item_list() else { continue; };
+ let sym::doc = attr.name_or_empty() else {
+ continue;
+ };
+ let Some(values) = attr.meta_item_list() else {
+ continue;
+ };
for v in values {
if v.name_or_empty() != sym::alias {
continue;
@@ -2032,8 +2039,8 @@ impl<'tcx> Candidate<'tcx> {
// means they are safe to put into the
// `WhereClausePick`.
assert!(
- !trait_ref.skip_binder().substs.has_infer()
- && !trait_ref.skip_binder().substs.has_placeholders()
+ !trait_ref.skip_binder().args.has_infer()
+ && !trait_ref.skip_binder().args.has_placeholders()
);
WhereClausePick(*trait_ref)
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 5f924f309..72a04a02b 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2,12 +2,13 @@
//! found or is otherwise invalid.
use crate::errors;
-use crate::errors::CandidateTraitNote;
-use crate::errors::NoAssociatedItem;
+use crate::errors::{CandidateTraitNote, NoAssociatedItem};
use crate::Expectation;
use crate::FnCtxt;
use rustc_ast::ast::Mutability;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_attr::parse_confusables;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::StashKey;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -31,6 +32,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
use rustc_middle::ty::IsSuggestable;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@@ -48,6 +50,15 @@ use rustc_hir::intravisit::Visitor;
use std::cmp::{self, Ordering};
use std::iter;
+/// After identifying that `full_expr` is a method call, we use this type to keep the expression's
+/// components readily available to us to point at the right place in diagnostics.
+#[derive(Debug, Clone, Copy)]
+pub struct MethodCallComponents<'tcx> {
+ pub receiver: &'tcx hir::Expr<'tcx>,
+ pub args: &'tcx [hir::Expr<'tcx>],
+ pub full_expr: &'tcx hir::Expr<'tcx>,
+}
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
let tcx = self.tcx;
@@ -92,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
self.body_id,
self.param_env,
- poly_trait_ref.without_const(),
+ poly_trait_ref,
);
self.predicate_may_hold(&obligation)
})
@@ -113,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
source: SelfSource<'tcx>,
error: MethodError<'tcx>,
- args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ args: Option<MethodCallComponents<'tcx>>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
@@ -151,7 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
E0034,
"multiple applicable items in scope"
);
- err.span_label(item_name.span, format!("multiple `{}` found", item_name));
+ err.span_label(item_name.span, format!("multiple `{item_name}` found"));
self.note_candidates_on_method_error(
rcvr_ty,
@@ -175,13 +186,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind,
item_name
);
- err.span_label(item_name.span, format!("private {}", kind));
+ err.span_label(item_name.span, format!("private {kind}"));
let sp = self
.tcx
.hir()
.span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id));
- err.span_label(sp, format!("private {} defined here", kind));
+ err.span_label(sp, format!("private {kind} defined here"));
self.suggest_valid_traits(&mut err, out_of_scope_traits);
err.emit();
}
@@ -216,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
*region,
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
);
- let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
+ let msg = format!("you need `{trait_type}` instead of `{rcvr_ty}`");
let mut kind = &self_expr.kind;
while let hir::ExprKind::AddrOf(_, _, expr)
| hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
@@ -255,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_missing_writer(
&self,
rcvr_ty: Ty<'tcx>,
- args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
+ args: MethodCallComponents<'tcx>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
- let mut err =
- struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ args.receiver.span,
+ E0599,
+ "cannot write into `{}`",
+ ty_str
+ );
err.span_note(
- args.0.span,
+ args.receiver.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
);
- if let ExprKind::Lit(_) = args.0.kind {
+ if let ExprKind::Lit(_) = args.receiver.kind {
err.span_help(
- args.0.span.shrink_to_lo(),
+ args.receiver.span.shrink_to_lo(),
"a writer is needed before this format string",
);
};
@@ -280,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
- args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ args: Option<MethodCallComponents<'tcx>>,
sugg_span: Span,
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
@@ -536,11 +552,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
}
} else if !unsatisfied_predicates.is_empty() {
- let mut type_params = FxHashMap::default();
+ let mut type_params = FxIndexMap::default();
// Pick out the list of unimplemented traits on the receiver.
// This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
- let mut unimplemented_traits = FxHashMap::default();
+ let mut unimplemented_traits = FxIndexMap::default();
let mut unimplemented_traits_only = true;
for (predicate, _parent_pred, cause) in unsatisfied_predicates {
if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) =
@@ -606,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
type_params
.entry(key)
- .or_insert_with(FxHashSet::default)
+ .or_insert_with(UnordSet::default)
.insert(obligation.to_owned());
return true;
}
@@ -635,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Point at the closure that couldn't satisfy the bound.
ty::Closure(def_id, _) => bound_spans
- .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+ .push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))),
_ => {}
}
};
@@ -647,17 +663,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `<Foo as Iterator>::Item = String`.
let projection_ty = pred.skip_binder().projection_ty;
- let substs_with_infer_self = tcx.mk_substs_from_iter(
+ let args_with_infer_self = tcx.mk_args_from_iter(
iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
- .chain(projection_ty.substs.iter().skip(1)),
+ .chain(projection_ty.args.iter().skip(1)),
);
let quiet_projection_ty =
- tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
+ tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self);
let term = pred.skip_binder().term;
- let obligation = format!("{} = {}", projection_ty, term);
+ let obligation = format!("{projection_ty} = {term}");
let quiet = with_forced_trimmed_paths!(format!(
"{} = {}",
quiet_projection_ty, term
@@ -670,7 +686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
- let obligation = format!("{}: {}", self_ty, path);
+ let obligation = format!("{self_ty}: {path}");
let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
bound_span_label(self_ty, &obligation, &quiet);
Some((obligation, self_ty))
@@ -680,8 +696,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Find all the requirements that come from a local `impl` block.
- let mut skip_list: FxHashSet<_> = Default::default();
- let mut spanned_predicates = FxHashMap::default();
+ let mut skip_list: UnordSet<_> = Default::default();
+ let mut spanned_predicates = FxIndexMap::default();
for (p, parent_p, cause) in unsatisfied_predicates {
// Extract the predicate span and parent def id of the cause,
// if we have one.
@@ -723,7 +739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = self_ty.span.ctxt().outer_expn_data().call_site;
let entry = spanned_predicates.entry(span);
let entry = entry.or_insert_with(|| {
- (FxHashSet::default(), FxHashSet::default(), Vec::new())
+ (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
});
entry.0.insert(span);
entry.1.insert((
@@ -771,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
skip_list.insert(p);
let entry = spanned_predicates.entry(self_ty.span);
let entry = entry.or_insert_with(|| {
- (FxHashSet::default(), FxHashSet::default(), Vec::new())
+ (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
});
entry.2.push(p);
if cause_span != *item_span {
@@ -806,7 +822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
skip_list.insert(p);
let entry = spanned_predicates.entry(ident.span);
let entry = entry.or_insert_with(|| {
- (FxHashSet::default(), FxHashSet::default(), Vec::new())
+ (FxIndexSet::default(), FxIndexSet::default(), Vec::new())
});
entry.0.insert(cause_span);
entry.1.insert((ident.span, ""));
@@ -823,12 +839,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut preds: Vec<_> = predicates
.iter()
.filter_map(|pred| format_pred(**pred))
- .map(|(p, _)| format!("`{}`", p))
+ .map(|(p, _)| format!("`{p}`"))
.collect();
preds.sort();
preds.dedup();
let msg = if let [pred] = &preds[..] {
- format!("trait bound {} was not satisfied", pred)
+ format!("trait bound {pred} was not satisfied")
} else {
format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
};
@@ -840,7 +856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unsatisfied_bounds = true;
}
- let mut suggested_bounds = FxHashSet::default();
+ let mut suggested_bounds = UnordSet::default();
// The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
@@ -873,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggested_bounds.insert(pred);
}
}
- format!("`{}`\nwhich is required by `{}`", p, parent_p)
+ format!("`{p}`\nwhich is required by `{parent_p}`")
}
},
},
@@ -889,8 +905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
restrict_type_params = true;
// #74886: Sort here so that the output is always the same.
- let mut obligations = obligations.into_iter().collect::<Vec<_>>();
- obligations.sort();
+ let obligations = obligations.to_sorted_stable_ord();
err.span_suggestion_verbose(
span,
format!(
@@ -952,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unsatisfied_bounds = true;
}
+ } 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
+ // mutability difference, like calling a method on `Pin<&mut Self>` that is on
+ // `Pin<&Self>`.
+ if targs.len() == 1 {
+ let mut item_segment = hir::PathSegment::invalid();
+ item_segment.ident = item_name;
+ for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
+ let new_args = tcx.mk_args_from_iter(
+ targs
+ .iter()
+ .map(|arg| match arg.as_type() {
+ Some(ty) => ty::GenericArg::from(
+ t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()),
+ ),
+ _ => arg,
+ })
+ );
+ let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
+ if let Ok(method) = self.lookup_method_for_diagnostic(
+ rcvr_ty,
+ &item_segment,
+ span,
+ args.full_expr,
+ args.receiver,
+ ) {
+ err.span_note(
+ tcx.def_span(method.def_id),
+ format!("{item_kind} is available for `{rcvr_ty}`"),
+ );
+ }
+ }
+ }
}
let label_span_not_found = |err: &mut Diagnostic| {
@@ -993,9 +1041,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// different from the received one
// So we avoid suggestion method with Box<Self>
// for instance
- self.tcx.at(span).type_of(*def_id).subst_identity()
+ self.tcx.at(span).type_of(*def_id).instantiate_identity()
!= rcvr_ty
- && self.tcx.at(span).type_of(*def_id).subst_identity()
+ && self
+ .tcx
+ .at(span)
+ .type_of(*def_id)
+ .instantiate_identity()
!= rcvr_ty
}
(Mode::Path, false, _) => true,
@@ -1018,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|impl_item| {
format!(
"- `{}`",
- self.tcx.at(span).type_of(*impl_item).subst_identity()
+ self.tcx.at(span).type_of(*impl_item).instantiate_identity()
)
})
.collect::<Vec<_>>()
@@ -1029,9 +1081,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"".to_string()
};
err.note(format!(
- "the {item_kind} was found for\n{}{}",
- type_candidates, additional_types
+ "the {item_kind} was found for\n{type_candidates}{additional_types}"
));
+ } else {
+ 'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) {
+ for inherent_method in
+ 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)
+ && let Some(candidates) = parse_confusables(attr)
+ && candidates.contains(&item_name.name)
+ {
+ err.span_suggestion_verbose(
+ item_name.span,
+ format!(
+ "you might have meant to use `{}`",
+ inherent_method.name.as_str()
+ ),
+ inherent_method.name.as_str(),
+ Applicability::MaybeIncorrect,
+ );
+ break 'outer;
+ }
+ }
+ }
}
}
} else {
@@ -1085,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
rcvr_ty,
item_name,
- args.map(|(_, args)| args.len() + 1),
+ args.map(|MethodCallComponents { args, .. }| args.len() + 1),
source,
no_match_data.out_of_scope_traits.clone(),
&unsatisfied_predicates,
@@ -1166,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
- args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ args: Option<MethodCallComponents<'tcx>>,
span: Span,
err: &mut Diagnostic,
sources: &mut Vec<CandidateSource>,
@@ -1197,7 +1270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
};
- let impl_ty = self.tcx.at(span).type_of(impl_did).subst_identity();
+ let impl_ty = self.tcx.at(span).type_of(impl_did).instantiate_identity();
let insertion = match self.tcx.impl_trait_ref(impl_did) {
None => String::new(),
@@ -1222,8 +1295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
(
format!(
- "the candidate is defined in an impl{} for the type `{}`",
- insertion, impl_ty,
+ "the candidate is defined in an impl{insertion} for the type `{impl_ty}`",
),
None,
)
@@ -1243,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::AssocKind::Fn => self
.tcx
.fn_sig(item.def_id)
- .subst_identity()
+ .instantiate_identity()
.inputs()
.skip_binder()
.get(0)
@@ -1318,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>,
item_name: Ident,
- args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
+ args: Option<MethodCallComponents<'tcx>>,
sugg_span: Span,
) {
let mut has_unsuggestable_args = false;
@@ -1326,7 +1398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// When the "method" is resolved through dereferencing, we really want the
// original type that has the associated function for accurate suggestions.
// (#61411)
- let impl_ty = self.tcx.type_of(*impl_did).subst_identity();
+ let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
let target_ty = self
.autoderef(sugg_span, rcvr_ty)
.find(|(rcvr_ty, _)| {
@@ -1335,10 +1407,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
.map_or(impl_ty, |(ty, _)| ty)
.peel_refs();
- if let ty::Adt(def, substs) = target_ty.kind() {
+ if let ty::Adt(def, args) = target_ty.kind() {
// If there are any inferred arguments, (`{integer}`), we should replace
// them with underscores to allow the compiler to infer them
- let infer_substs = self.tcx.mk_substs_from_iter(substs.into_iter().map(|arg| {
+ let infer_args = self.tcx.mk_args_from_iter(args.into_iter().map(|arg| {
if !arg.is_suggestable(self.tcx, true) {
has_unsuggestable_args = true;
match arg.unpack() {
@@ -1368,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}));
- self.tcx.value_path_str_with_substs(def.did(), infer_substs)
+ self.tcx.value_path_str_with_args(def.did(), infer_args)
} else {
self.ty_to_value_string(target_ty)
}
@@ -1380,7 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(assoc) = self.associated_value(*impl_did, item_name)
&& assoc.kind == ty::AssocKind::Fn
{
- let sig = self.tcx.fn_sig(assoc.def_id).subst_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() {
None
} else {
@@ -1390,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
};
let mut applicability = Applicability::MachineApplicable;
- let args = if let Some((receiver, args)) = args {
+ let args = if let Some(MethodCallComponents { receiver, args, .. }) = args {
// The first arg is the same kind as the receiver
let explicit_args = if first_arg.is_some() {
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
@@ -1425,11 +1497,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion(
sugg_span,
"use associated function syntax instead",
- format!("{}::{}{}", ty_str, item_name, args),
+ format!("{ty_str}::{item_name}{args}"),
applicability,
);
} else {
- err.help(format!("try with `{}::{}`", ty_str, item_name,));
+ err.help(format!("try with `{ty_str}::{item_name}`",));
}
}
@@ -1445,11 +1517,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool {
let tcx = self.tcx;
let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
- ty::Adt(def, substs) if !def.is_enum() => {
+ ty::Adt(def, args) if !def.is_enum() => {
let variant = &def.non_enum_variant();
tcx.find_field_index(item_name, variant).map(|index| {
let field = &variant.fields[index];
- let field_ty = field.ty(tcx, substs);
+ let field_ty = field.ty(tcx, args);
(field, field_ty)
})
}
@@ -1464,9 +1536,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr_span = expr.span.to(item_name.span);
err.multipart_suggestion(
format!(
- "to call the function stored in `{}`, \
+ "to call the function stored in `{item_name}`, \
surround the field access with parentheses",
- item_name,
),
vec![
(expr_span.shrink_to_lo(), '('.to_string()),
@@ -1489,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let field_kind = if is_accessible { "field" } else { "private field" };
- err.span_label(item_name.span, format!("{}, not a method", field_kind));
+ err.span_label(item_name.span, format!("{field_kind}, not a method"));
return true;
}
false
@@ -1546,7 +1617,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
- let range_ty = self.tcx.type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+ let range_ty =
+ self.tcx.type_of(range_def_id).instantiate(self.tcx, &[actual.into()]);
let pick = self.lookup_probe_for_diagnostic(
item_name,
@@ -1609,7 +1681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| found_assoc(tcx.types.u64)
|| found_assoc(tcx.types.u128)
|| found_assoc(tcx.types.f32)
- || found_assoc(tcx.types.f32);
+ || found_assoc(tcx.types.f64);
if found_candidate
&& actual.is_numeric()
&& !actual.has_concrete_skeleton()
@@ -1641,8 +1713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lit.span,
format!(
"you must specify a concrete type for this numeric value, \
- like `{}`",
- concrete_type
+ like `{concrete_type}`"
),
format!("{snippet}_{concrete_type}"),
Applicability::MaybeIncorrect,
@@ -1657,8 +1728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let parent_node =
self.tcx.hir().get_parent(hir_id);
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}`",
);
match (filename, parent_node) {
@@ -1699,10 +1769,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// we try to suggest `rect.area()`
pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
debug!("suggest_assoc_method_call segs: {:?}", segs);
- let [seg1, seg2] = segs else { return; };
+ let [seg1, seg2] = segs else {
+ return;
+ };
let Some(mut diag) =
- self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
- else { return };
+ self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+ else {
+ return;
+ };
let map = self.infcx.tcx.hir();
let body_id = self.tcx.hir().body_owned_by(self.body_id);
@@ -1766,7 +1840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
if let SelfSource::MethodCall(expr) = source
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
- && let Some((fields, substs)) =
+ && let Some((fields, args)) =
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));
@@ -1801,7 +1875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
},
candidate_field,
- substs,
+ args,
vec![],
mod_id,
)
@@ -1839,18 +1913,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
) {
let tcx = self.tcx;
- let SelfSource::MethodCall(expr) = source else { return; };
+ let SelfSource::MethodCall(expr) = source else {
+ return;
+ };
let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
- let ty::Adt(kind, substs) = actual.kind() else { return; };
+ let ty::Adt(kind, args) = actual.kind() else {
+ return;
+ };
match kind.adt_kind() {
ty::AdtKind::Enum => {
let matching_variants: Vec<_> = kind
.variants()
.iter()
.flat_map(|variant| {
- let [field] = &variant.fields.raw[..] else { return None; };
- let field_ty = field.ty(tcx, substs);
+ let [field] = &variant.fields.raw[..] else {
+ return None;
+ };
+ let field_ty = field.ty(tcx, args);
// Skip `_`, since that'll just lead to ambiguity.
if self.resolve_vars_if_possible(field_ty).is_ty_var() {
@@ -1885,7 +1965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &matching_variants[..] {
[(_, field, pick)] => {
- let self_ty = field.ty(tcx, substs);
+ let self_ty = field.ty(tcx, args);
err.span_note(
tcx.def_span(pick.item.def_id),
format!("the method `{item_name}` exists on the type `{self_ty}`"),
@@ -1927,15 +2007,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Target wrapper types - types that wrap or pretend to wrap another type,
// perhaps this inner type is meant to be called?
ty::AdtKind::Struct | ty::AdtKind::Union => {
- let [first] = ***substs else { return; };
- let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
+ let [first] = ***args else {
+ return;
+ };
+ let ty::GenericArgKind::Type(ty) = first.unpack() else {
+ return;
+ };
let Ok(pick) = self.lookup_probe_for_diagnostic(
item_name,
ty,
call_expr,
ProbeScope::TraitsInScope,
None,
- ) else { return; };
+ ) else {
+ return;
+ };
let name = self.ty_to_value_string(actual);
let inner_id = kind.did();
@@ -2037,7 +2123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Adt(def, _) => Some(def.did()),
_ => None,
})
- .collect::<FxHashSet<_>>();
+ .collect::<FxIndexSet<_>>();
let mut spans: MultiSpan = def_ids
.iter()
.filter_map(|def_id| {
@@ -2100,7 +2186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) =
pred.kind().no_bound_vars()
else {
- continue
+ continue;
};
let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt,
@@ -2150,7 +2236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut()
{
if last_self_name == &self_name {
- last_trait_names.push_str(format!(", {}", trait_name).as_str());
+ last_trait_names.push_str(format!(", {trait_name}").as_str());
continue;
}
}
@@ -2182,8 +2268,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (self_name, self_span, traits) in &derives_grouped {
err.span_suggestion_verbose(
self_span.shrink_to_lo(),
- format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
- format!("#[derive({})]\n", traits),
+ format!("consider annotating `{self_name}` with `#[derive({traits})]`"),
+ format!("#[derive({traits})]\n"),
Applicability::MaybeIncorrect,
);
}
@@ -2197,7 +2283,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
expected: Expectation<'tcx>,
) {
- let SelfSource::QPath(ty) = self_source else { return; };
+ let SelfSource::QPath(ty) = self_source else {
+ return;
+ };
for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
if let Ok(pick) = self.probe_for_name(
Mode::Path,
@@ -2214,7 +2302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// just changing the path.
&& pick.item.fn_has_self_parameter
&& let Some(self_ty) =
- self.tcx.fn_sig(pick.item.def_id).subst_identity().inputs().skip_binder().get(0)
+ self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
&& self_ty.is_ref()
{
let suggested_path = match deref_ty.kind() {
@@ -2255,7 +2343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Print out the type for use in value namespace.
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
match ty.kind() {
- ty::Adt(def, substs) => self.tcx.def_path_str_with_substs(def.did(), substs),
+ ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args),
_ => self.ty_to_string(ty),
}
}
@@ -2429,7 +2517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- format!("the method is available for `{}` here", rcvr_ty),
+ format!("the method is available for `{rcvr_ty}` here"),
);
}
break;
@@ -2475,13 +2563,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- format!("the method is available for `{}` here", new_rcvr_t),
+ format!("the method is available for `{new_rcvr_t}` here"),
);
err.multipart_suggestion(
"consider wrapping the receiver expression with the \
appropriate type",
vec![
- (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
+ (rcvr.span.shrink_to_lo(), format!("{pre}({post}")),
(rcvr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
@@ -2651,7 +2739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Nothing,
}
let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
- let trait_def_ids: FxHashSet<DefId> = ast_generics
+ let trait_def_ids: DefIdSet = ast_generics
.bounds_for_param(def_id)
.flat_map(|bp| bp.bounds.iter())
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
@@ -2721,7 +2809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
err.span_suggestions(
sp,
- message(format!("add {} supertrait for", article)),
+ message(format!("add {article} supertrait for")),
candidates.iter().map(|t| {
format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
}),
@@ -2752,7 +2840,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
})
.any(|imp_did| {
- let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
+ let imp =
+ self.tcx.impl_trait_ref(imp_did).unwrap().instantiate_identity();
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
imp_simp.is_some_and(|s| s == simp_rcvr_ty)
@@ -2789,7 +2878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trait_infos => {
let mut msg = message(param_type.map_or_else(
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
- |param| format!("restrict type parameter `{}` with", param),
+ |param| format!("restrict type parameter `{param}` with"),
));
for (i, trait_info) in trait_infos.iter().enumerate() {
msg.push_str(&format!(
@@ -2813,8 +2902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
trait_infos => {
let mut msg = format!(
- "the following traits define an item `{}`, but are explicitly unimplemented:",
- item_name
+ "the following traits define an item `{item_name}`, but are explicitly unimplemented:"
);
for trait_info in trait_infos {
msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
@@ -2834,9 +2922,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found: Ty<'tcx>,
expected: Ty<'tcx>,
) -> bool {
- let Some((_def_id_or_name, output, _inputs)) =
- self.extract_callable_info(found) else {
- return false;
+ let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(found) else {
+ return false;
};
if !self.can_coerce(output, expected) {
@@ -2907,7 +2994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This occurs for UFCS desugaring of `T::method`, where there is no
// receiver expression for the method call, and thus no autoderef.
if let SelfSource::QPath(_) = source {
- return is_local(self.resolve_vars_with_obligations(rcvr_ty));
+ return is_local(rcvr_ty);
}
self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
@@ -2955,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
fn print_disambiguation_help<'tcx>(
item_name: Ident,
- args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ args: Option<MethodCallComponents<'tcx>>,
err: &mut Diagnostic,
trait_name: String,
rcvr_ty: Ty<'_>,
@@ -2967,7 +3054,11 @@ fn print_disambiguation_help<'tcx>(
fn_has_self_parameter: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
+ let (span, sugg) = if let (
+ ty::AssocKind::Fn,
+ Some(MethodCallComponents { receiver, args, .. }),
+ ) = (kind, args)
+ {
let args = format!(
"({}{})",
rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
@@ -2981,13 +3072,13 @@ fn print_disambiguation_help<'tcx>(
.join(", "),
);
let trait_name = if !fn_has_self_parameter {
- format!("<{} as {}>", rcvr_ty, trait_name)
+ format!("<{rcvr_ty} as {trait_name}>")
} else {
trait_name
};
- (span, format!("{}::{}{}", trait_name, item_name, args))
+ (span, format!("{trait_name}::{item_name}{args}"))
} else {
- (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name))
+ (span.with_hi(item_name.span.lo()), format!("<{rcvr_ty} as {trait_name}>::"))
};
err.span_suggestion_verbose(
span,
@@ -2995,7 +3086,7 @@ fn print_disambiguation_help<'tcx>(
"disambiguate the {} for {}",
def_kind_descr,
if let Some(candidate) = candidate {
- format!("candidate #{}", candidate)
+ format!("candidate #{candidate}")
} else {
"the candidate".to_string()
},
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 1eae258c1..a283cd1ab 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -4,7 +4,7 @@ use super::method::MethodCallee;
use super::{has_expected_num_generic_args, FnCtxt};
use crate::Expectation;
use rustc_ast as ast;
-use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
+use rustc_errors::{self, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::ObligationCauseCode;
@@ -380,33 +380,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
- if self
- .lookup_op_method(
- lhs_deref_ty,
- Some((rhs_expr, rhs_ty)),
- Op::Binary(op, is_assign),
- expected,
- )
- .is_ok()
- {
- let msg = format!(
- "`{}{}` can be used on `{}` if you dereference the left-hand side",
- op.node.as_str(),
- match is_assign {
- IsAssign::Yes => "=",
- IsAssign::No => "",
- },
- lhs_deref_ty,
- );
- err.span_suggestion_verbose(
- lhs_expr.span.shrink_to_lo(),
- msg,
- "*",
- rustc_errors::Applicability::MachineApplicable,
- );
- }
- };
+ let suggest_deref_binop =
+ |err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| {
+ if self
+ .lookup_op_method(
+ lhs_deref_ty,
+ Some((rhs_expr, rhs_ty)),
+ Op::Binary(op, is_assign),
+ expected,
+ )
+ .is_ok()
+ {
+ let msg = format!(
+ "`{}{}` can be used on `{}` if you dereference the left-hand side",
+ op.node.as_str(),
+ match is_assign {
+ IsAssign::Yes => "=",
+ IsAssign::No => "",
+ },
+ lhs_deref_ty,
+ );
+ err.span_suggestion_verbose(
+ lhs_expr.span.shrink_to_lo(),
+ msg,
+ "*",
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ };
+
+ let suggest_different_borrow =
+ |err: &mut DiagnosticBuilder<'_, _>,
+ lhs_adjusted_ty,
+ lhs_new_mutbl: Option<ast::Mutability>,
+ rhs_adjusted_ty,
+ rhs_new_mutbl: Option<ast::Mutability>| {
+ if self
+ .lookup_op_method(
+ lhs_adjusted_ty,
+ Some((rhs_expr, rhs_adjusted_ty)),
+ Op::Binary(op, is_assign),
+ expected,
+ )
+ .is_ok()
+ {
+ let op_str = op.node.as_str();
+ err.note(format!("an implementation for `{lhs_adjusted_ty} {op_str} {rhs_adjusted_ty}` exists"));
+
+ if let Some(lhs_new_mutbl) = lhs_new_mutbl
+ && let Some(rhs_new_mutbl) = rhs_new_mutbl
+ && lhs_new_mutbl.is_not()
+ && rhs_new_mutbl.is_not() {
+ err.multipart_suggestion_verbose(
+ "consider reborrowing both sides",
+ vec![
+ (lhs_expr.span.shrink_to_lo(), "&*".to_string()),
+ (rhs_expr.span.shrink_to_lo(), "&*".to_string())
+ ],
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ } else {
+ let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| {
+ // Can reborrow (&mut -> &)
+ if new_mutbl.is_not() {
+ err.span_suggestion_verbose(
+ sp.shrink_to_lo(),
+ "consider reborrowing this side",
+ "&*",
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ // Works on &mut but have &
+ } else {
+ err.span_help(
+ sp,
+ "consider making this expression a mutable borrow",
+ );
+ }
+ };
+
+ if let Some(lhs_new_mutbl) = lhs_new_mutbl {
+ suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
+ }
+ if let Some(rhs_new_mutbl) = rhs_new_mutbl {
+ suggest_new_borrow(rhs_new_mutbl, rhs_expr.span);
+ }
+ }
+ }
+ };
let is_compatible_after_call = |lhs_ty, rhs_ty| {
self.lookup_op_method(
@@ -429,15 +489,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if is_assign == IsAssign::Yes
&& let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
{
- suggest_deref_binop(lhs_deref_ty);
+ suggest_deref_binop(&mut err, lhs_deref_ty);
} else if is_assign == IsAssign::No
- && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind()
+ && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
{
if self.type_is_copy_modulo_regions(
self.param_env,
*lhs_deref_ty,
) {
- suggest_deref_binop(*lhs_deref_ty);
+ suggest_deref_binop(&mut err, *lhs_deref_ty);
+ } else {
+ let lhs_inv_mutbl = mutbl.invert();
+ let lhs_inv_mutbl_ty = Ty::new_ref(
+ self.tcx,
+ *region,
+ ty::TypeAndMut {
+ ty: *lhs_deref_ty,
+ mutbl: lhs_inv_mutbl,
+ },
+ );
+
+ suggest_different_borrow(
+ &mut err,
+ lhs_inv_mutbl_ty,
+ Some(lhs_inv_mutbl),
+ rhs_ty,
+ None,
+ );
+
+ if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
+ let rhs_inv_mutbl = mutbl.invert();
+ let rhs_inv_mutbl_ty = Ty::new_ref(
+ self.tcx,
+ *region,
+ ty::TypeAndMut {
+ ty: *rhs_deref_ty,
+ mutbl: rhs_inv_mutbl,
+ },
+ );
+
+ suggest_different_borrow(
+ &mut err,
+ lhs_ty,
+ None,
+ rhs_inv_mutbl_ty,
+ Some(rhs_inv_mutbl),
+ );
+ suggest_different_borrow(
+ &mut err,
+ lhs_inv_mutbl_ty,
+ Some(lhs_inv_mutbl),
+ rhs_inv_mutbl_ty,
+ Some(rhs_inv_mutbl),
+ );
+ }
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
is_compatible_after_call(lhs_ty, rhs_ty)
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 42f4531c0..8fc236f46 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,3 +1,4 @@
+use crate::gather_locals::DeclOrigin;
use crate::{errors, FnCtxt, RawTy};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
@@ -77,6 +78,13 @@ struct TopInfo<'tcx> {
span: Option<Span>,
}
+#[derive(Copy, Clone)]
+struct PatInfo<'tcx, 'a> {
+ binding_mode: BindingMode,
+ top_info: TopInfo<'tcx>,
+ decl_origin: Option<DeclOrigin<'a>>,
+}
+
impl<'tcx> FnCtxt<'_, 'tcx> {
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
let code =
@@ -135,15 +143,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// Otherwise, `Some(span)` represents the span of a type expression
/// which originated the `expected` type.
- pub fn check_pat_top(
+ pub(crate) fn check_pat_top(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
span: Option<Span>,
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
+ decl_origin: Option<DeclOrigin<'tcx>>,
) {
let info = TopInfo { expected, origin_expr, span };
- self.check_pat(pat, expected, INITIAL_BM, info);
+ let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin };
+ self.check_pat(pat, expected, pat_info);
}
/// Type check the given `pat` against the `expected` type
@@ -151,14 +161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// Outside of this module, `check_pat_top` should always be used.
/// Conversely, inside this module, `check_pat_top` should never be used.
- #[instrument(level = "debug", skip(self, ti))]
- fn check_pat(
- &self,
- pat: &'tcx Pat<'tcx>,
- expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
- ) {
+ #[instrument(level = "debug", skip(self, pat_info))]
+ fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
+ let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
let path_res = match &pat.kind {
PatKind::Path(qpath) => {
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
@@ -167,38 +172,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
+ let pat_info =
+ PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };
let ty = match pat.kind {
PatKind::Wild => expected,
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
PatKind::Binding(ba, var_id, _, sub) => {
- self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti)
+ self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
}
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
- self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
+ self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
}
PatKind::Path(ref qpath) => {
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
}
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
- self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti)
+ self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
}
PatKind::Or(pats) => {
for pat in pats {
- self.check_pat(pat, expected, def_bm, ti);
+ self.check_pat(pat, expected, pat_info);
}
expected
}
PatKind::Tuple(elements, ddpos) => {
- self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti)
- }
- PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti),
- PatKind::Ref(inner, mutbl) => {
- self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti)
+ self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
}
+ PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
+ PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
PatKind::Slice(before, slice, after) => {
- self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti)
+ self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
}
};
@@ -335,8 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
mut def_bm: BindingMode,
) -> (Ty<'tcx>, BindingMode) {
- let mut expected = self.resolve_vars_with_obligations(expected);
-
+ let mut expected = self.try_structurally_resolve_type(pat.span, expected);
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
// the `Some(5)` which is not of type Ref.
@@ -353,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Preserve the reference type. We'll need it later during THIR lowering.
pat_adjustments.push(expected);
- expected = inner_ty;
+ expected = self.try_structurally_resolve_type(pat.span, inner_ty);
def_bm = ty::BindByReference(match def_bm {
// If default binding mode is by value, make it `ref` or `ref mut`
// (depending on whether we observe `&` or `&mut`).
@@ -517,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) {
if !ty.references_error() {
- err.span_label(span, format!("this is of type `{}`", ty));
+ err.span_label(span, format!("this is of type `{ty}`"));
}
}
@@ -541,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
let msg = |ty| {
let ty = self.resolve_vars_if_possible(ty);
- format!("this is of type `{}` but it should be `char` or numeric", ty)
+ format!("this is of type `{ty}` but it should be `char` or numeric")
};
let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
err.span_label(first_span, msg(first_ty));
@@ -581,9 +585,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
var_id: HirId,
sub: Option<&'tcx Pat<'tcx>>,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
+ let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
+
// Determine the binding mode...
let bm = match ba {
hir::BindingAnnotation::NONE => def_bm,
@@ -621,12 +626,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(p) = sub {
- self.check_pat(p, expected, def_bm, ti);
+ self.check_pat(p, expected, pat_info);
}
local_ty
}
+ /// When a variable is bound several times in a `PatKind::Or`, it'll resolve all of the
+ /// subsequent bindings of the same name to the first usage. Verify that all of these
+ /// bindings have the same type by comparing them all against the type of that first pat.
fn check_binding_alt_eq_ty(
&self,
ba: hir::BindingAnnotation,
@@ -638,7 +646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let var_ty = self.local_ty(span, var_id);
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
let hir = self.tcx.hir();
- let var_ty = self.resolve_vars_with_obligations(var_ty);
+ let var_ty = self.resolve_vars_if_possible(var_ty);
let msg = format!("first introduced with type `{var_ty}` here");
err.span_label(hir.span(var_id), msg);
let in_match = hir.parent_iter(var_id).any(|(_, n)| {
@@ -651,12 +659,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
let pre = if in_match { "in the same arm, " } else { "" };
- err.note(format!("{}a binding must have the same type in all alternatives", pre));
+ err.note(format!("{pre}a binding must have the same type in all alternatives"));
self.suggest_adding_missing_ref_or_removing_ref(
&mut err,
span,
var_ty,
- self.resolve_vars_with_obligations(ty),
+ self.resolve_vars_if_possible(ty),
ba,
);
err.emit();
@@ -753,7 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match binding_parent {
// Check that there is explicit type (ie this is not a closure param with inferred type)
// so we don't suggest moving something to the type that does not exist
- hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => {
+ hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
err.multipart_suggestion_verbose(
format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
vec![
@@ -841,8 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &'tcx [hir::PatField<'tcx>],
has_rest_pat: bool,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
// Resolve the path and check the definition for errors.
let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
@@ -850,18 +857,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(guar) => {
let err = Ty::new_error(self.tcx, guar);
for field in fields {
- let ti = ti;
- self.check_pat(field.pat, err, def_bm, ti);
+ self.check_pat(field.pat, err, pat_info);
}
return err;
}
};
// Type-check the path.
- self.demand_eqtype_pat(pat.span, expected, pat_ty, ti);
+ self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info);
// Type-check subpatterns.
- if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
+ if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, pat_info) {
pat_ty
} else {
Ty::new_misc_error(self.tcx)
@@ -922,7 +928,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match opt_def_id {
Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Const(_, body_id), ..
+ kind: hir::ItemKind::Const(_, _, body_id),
+ ..
})) => match self.tcx.hir().get(body_id.hir_id) {
hir::Node::Expr(expr) => {
if hir::is_range_literal(expr) {
@@ -1026,13 +1033,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
subpats: &'tcx [Pat<'tcx>],
ddpos: hir::DotDotPos,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
+ let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;
let tcx = self.tcx;
let on_error = |e| {
for pat in subpats {
- self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti);
+ self.check_pat(
+ pat,
+ Ty::new_error(tcx, e),
+ PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
+ );
}
};
let report_unexpected_res = |res: Res| {
@@ -1092,13 +1103,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if subpats.len() == variant.fields.len()
|| subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
{
- let ty::Adt(_, substs) = pat_ty.kind() else {
+ let ty::Adt(_, args) = pat_ty.kind() else {
bug!("unexpected pattern type {:?}", pat_ty);
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
let field = &variant.fields[FieldIdx::from_usize(i)];
- let field_ty = self.field_ty(subpat.span, field, substs);
- self.check_pat(subpat, field_ty, def_bm, ti);
+ let field_ty = self.field_ty(subpat.span, field, args);
+ self.check_pat(
+ subpat,
+ field_ty,
+ PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
+ );
self.tcx.check_stability(
variant.fields[FieldIdx::from_usize(i)].did,
@@ -1180,10 +1195,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
let missing_parentheses = match (&expected.kind(), fields, had_err) {
// #67037: only do this if we could successfully type-check the expected type against
- // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
+ // the tuple struct pattern. Otherwise the args could get out of range on e.g.,
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
- (ty::Adt(_, substs), [field], false) => {
- let field_ty = self.field_ty(pat_span, field, substs);
+ (ty::Adt(_, args), [field], false) => {
+ let field_ty = self.field_ty(pat_span, field, args);
match field_ty.kind() {
ty::Tuple(fields) => fields.len() == subpats.len(),
_ => false,
@@ -1282,8 +1297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
elements: &'tcx [Pat<'tcx>],
ddpos: hir::DotDotPos,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let mut expected_len = elements.len();
@@ -1304,18 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
let pat_ty = Ty::new_tup(tcx, element_tys);
- if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
+ if let Some(mut err) =
+ self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info)
+ {
let reported = err.emit();
// Walk subpatterns with an expected type of `err` in this case to silence
// further errors being emitted when using the bindings. #50333
let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti);
+ self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
}
Ty::new_tup_from_iter(tcx, element_tys_iter)
} else {
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, element_tys[i], def_bm, ti);
+ self.check_pat(elem, element_tys[i], pat_info);
}
pat_ty
}
@@ -1328,12 +1344,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant: &'tcx ty::VariantDef,
fields: &'tcx [hir::PatField<'tcx>],
has_rest_pat: bool,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> bool {
let tcx = self.tcx;
- let ty::Adt(adt, substs) = adt_ty.kind() else {
+ let ty::Adt(adt, args) = adt_ty.kind() else {
span_bug!(pat.span, "struct pattern is not an ADT");
};
@@ -1366,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|(i, f)| {
self.write_field_index(field.hir_id, *i);
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
- self.field_ty(span, f, substs)
+ self.field_ty(span, f, args)
})
.unwrap_or_else(|| {
inexistent_fields.push(field);
@@ -1376,7 +1391,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- self.check_pat(field.pat, field_ty, def_bm, ti);
+ self.check_pat(field.pat, field_ty, pat_info);
}
let mut unmentioned_fields = variant
@@ -1394,7 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&inexistent_fields,
&mut unmentioned_fields,
variant,
- substs,
+ args,
))
} else {
None
@@ -1564,7 +1579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
inexistent_fields: &[&hir::PatField<'tcx>],
unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
variant: &ty::VariantDef,
- substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
+ args: &'tcx ty::List<ty::GenericArg<'tcx>>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let tcx = self.tcx;
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
@@ -1634,7 +1649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.field_ty(
unmentioned_fields[0].1.span,
unmentioned_fields[0].0,
- substs,
+ args,
),
) => {}
_ => {
@@ -1708,7 +1723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
"use the tuple variant pattern syntax instead",
- format!("({})", sugg),
+ format!("({sugg})"),
appl,
);
return Some(err);
@@ -1810,7 +1825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
const LIMIT: usize = 3;
match witnesses {
[] => bug!(),
- [witness] => format!("`{}`", witness),
+ [witness] => format!("`{witness}`"),
[head @ .., tail] if head.len() < LIMIT => {
let head: Vec<_> = head.iter().map(<_>::to_string).collect();
format!("`{}` and `{}`", head.join("`, `"), tail)
@@ -1832,8 +1847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
lint.note(format!(
- "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
- ty,
+ "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
));
lint
@@ -1862,10 +1876,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
let fields = unmentioned_fields
.iter()
- .map(|(_, name)| format!("`{}`", name))
+ .map(|(_, name)| format!("`{name}`"))
.collect::<Vec<String>>()
.join(", ");
- format!("fields {}{}", fields, inaccessible)
+ format!("fields {fields}{inaccessible}")
};
let mut err = struct_span_err!(
self.tcx.sess,
@@ -1874,7 +1888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"pattern does not mention {}",
field_names
);
- err.span_label(pat.span, format!("missing {}", field_names));
+ err.span_label(pat.span, format!("missing {field_names}"));
let len = unmentioned_fields.len();
let (prefix, postfix, sp) = match fields {
[] => match &pat.kind {
@@ -1907,11 +1921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.map(|(_, name)| {
let field_name = name.to_string();
- if is_number(&field_name) {
- format!("{}: _", field_name)
- } else {
- field_name
- }
+ if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
})
.collect::<Vec<_>>()
.join(", "),
@@ -1928,7 +1938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
s = pluralize!(len),
them = if len == 1 { "it" } else { "them" },
),
- format!("{}..{}", prefix, postfix),
+ format!("{prefix}..{postfix}"),
Applicability::MachineApplicable,
);
err
@@ -1939,8 +1949,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
inner: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) {
@@ -1952,7 +1961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: inner.span,
});
let box_ty = Ty::new_box(tcx, inner_ty);
- self.demand_eqtype_pat(span, expected, box_ty, ti);
+ self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info);
(box_ty, inner_ty)
}
Err(guar) => {
@@ -1960,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(err, err)
}
};
- self.check_pat(inner, inner_ty, def_bm, ti);
+ self.check_pat(inner, inner_ty, pat_info);
box_ty
}
@@ -1971,8 +1980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
inner: &'tcx Pat<'tcx>,
mutbl: hir::Mutability,
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
@@ -1994,7 +2002,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
- let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
+ let err = self.demand_eqtype_pat_diag(
+ pat.span,
+ expected,
+ ref_ty,
+ pat_info.top_info,
+ );
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
@@ -2011,7 +2024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(err, err)
}
};
- self.check_pat(inner, inner_ty, def_bm, ti);
+ self.check_pat(inner, inner_ty, pat_info);
ref_ty
}
@@ -2022,6 +2035,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ty::new_ref(self.tcx, region, mt)
}
+ fn try_resolve_slice_ty_to_array_ty(
+ &self,
+ before: &'tcx [Pat<'tcx>],
+ slice: Option<&'tcx Pat<'tcx>>,
+ span: Span,
+ ) -> Option<Ty<'tcx>> {
+ if !slice.is_none() {
+ return None;
+ }
+
+ let tcx = self.tcx;
+ let len = before.len();
+ let ty_var_origin =
+ TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+ let inner_ty = self.next_ty_var(ty_var_origin);
+
+ Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
+ }
+
+ /// Used to determines whether we can infer the expected type in the slice pattern to be of type array.
+ /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable
+ /// patterns we wouldn't e.g. report ambiguity in the following situation:
+ ///
+ /// ```ignore(rust)
+ /// struct Zeroes;
+ /// const ARR: [usize; 2] = [0; 2];
+ /// const ARR2: [usize; 2] = [2; 2];
+ ///
+ /// impl Into<&'static [usize; 2]> for Zeroes {
+ /// fn into(self) -> &'static [usize; 2] {
+ /// &ARR
+ /// }
+ /// }
+ ///
+ /// impl Into<&'static [usize]> for Zeroes {
+ /// fn into(self) -> &'static [usize] {
+ /// &ARR2
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let &[a, b]: &[usize] = Zeroes.into() else {
+ /// ..
+ /// };
+ /// }
+ /// ```
+ ///
+ /// If we're in an irrefutable pattern we prefer the array impl candidate given that
+ /// the slice impl candidate would be be rejected anyway (if no ambiguity existed).
+ fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
+ match decl_origin {
+ Some(DeclOrigin::LocalDecl { els: None }) => true,
+ Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
+ }
+ }
+
/// Type check a slice pattern.
///
/// Syntactically, these look like `[pat_0, ..., pat_n]`.
@@ -2039,10 +2108,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
slice: Option<&'tcx Pat<'tcx>>,
after: &'tcx [Pat<'tcx>],
expected: Ty<'tcx>,
- def_bm: BindingMode,
- ti: TopInfo<'tcx>,
+ pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
+ let expected = self.try_structurally_resolve_type(span, expected);
+
+ // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it
+ // to an array if the given pattern allows it. See issue #76342
+ if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
+ if let Some(resolved_arr_ty) =
+ self.try_resolve_slice_ty_to_array_ty(before, slice, span)
+ {
+ debug!(?resolved_arr_ty);
+ self.demand_eqtype(span, expected, resolved_arr_ty);
+ }
+ }
+
let expected = self.structurally_resolve_type(span, expected);
+ debug!(?expected);
+
let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
ty::Array(element_ty, len) => {
@@ -2057,10 +2140,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Slice(element_ty) => (element_ty, Some(expected), expected),
// The expected type must be an array or slice, but was neither, so error.
_ => {
- let guar = expected
- .error_reported()
- .err()
- .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti));
+ let guar = expected.error_reported().err().unwrap_or_else(|| {
+ self.error_expected_array_or_slice(span, expected, pat_info.top_info)
+ });
let err = Ty::new_error(self.tcx, guar);
(err, Some(err), err)
}
@@ -2068,15 +2150,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type check all the patterns before `slice`.
for elt in before {
- self.check_pat(elt, element_ty, def_bm, ti);
+ self.check_pat(elt, element_ty, pat_info);
}
// Type check the `slice`, if present, against its expected type.
if let Some(slice) = slice {
- self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti);
+ self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
}
// Type check the elements after `slice`, if present.
for elt in after {
- self.check_pat(elt, element_ty, def_bm, ti);
+ self.check_pat(elt, element_ty, pat_info);
}
inferred
}
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index fd43b475e..406434e09 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut exprs = vec![expr];
while let hir::ExprKind::Field(ref expr, _)
- | hir::ExprKind::Index(ref expr, _)
+ | hir::ExprKind::Index(ref expr, _, _)
| hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind
{
exprs.push(expr);
@@ -392,7 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We also could not use `expr_ty_adjusted` of index_expr because reborrowing
// during coercions can also cause type of index_expr to differ from `T`,
// which can potentially cause regionck failure (#74933).
- Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1))
+ Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1))
}
};
let arg_tys = arg_ty.as_slice();
diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 22c9e7961..04d841023 100644
--- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
@@ -40,7 +40,7 @@ fn record_rvalue_scope_rec(
hir::ExprKind::AddrOf(_, _, subexpr)
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
| hir::ExprKind::Field(subexpr, _)
- | hir::ExprKind::Index(subexpr, _) => {
+ | hir::ExprKind::Index(subexpr, _, _) => {
expr = subexpr;
}
_ => {
@@ -74,9 +74,7 @@ pub fn resolve_rvalue_scopes<'a, 'tcx>(
debug!("start resolving rvalue scopes, def_id={def_id:?}");
debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
- let Some(Node::Expr(expr)) = hir_map.find(hir_id) else {
- bug!("hir node does not exist")
- };
+ let Some(Node::Expr(expr)) = hir_map.find(hir_id) else { bug!("hir node does not exist") };
record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
}
rvalue_scopes
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 208c40a39..1a41786d2 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -33,6 +33,7 @@
use super::FnCtxt;
use crate::expr_use_visitor as euv;
+use rustc_data_structures::unord::{ExtendUnord, UnordSet};
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
@@ -41,14 +42,14 @@ use rustc_infer::infer::UpvarRegion;
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{
- self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarCapture, UpvarSubsts,
+ self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture,
};
use rustc_session::lint;
use rustc_span::sym;
use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_target::abi::FIRST_VARIANT;
use std::iter;
@@ -108,11 +109,11 @@ impl MigrationWarningReason {
fn migration_message(&self) -> String {
let base = "changes to closure capture in Rust 2021 will affect";
if !self.auto_traits.is_empty() && self.drop_order {
- format!("{} drop order and which traits the closure implements", base)
+ format!("{base} drop order and which traits the closure implements")
} else if self.drop_order {
- format!("{} drop order", base)
+ format!("{base} drop order")
} else {
- format!("{} which traits the closure implements", base)
+ format!("{base} which traits the closure implements")
}
}
}
@@ -168,9 +169,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
// Extract the type of the closure.
let ty = self.node_ty(closure_hir_id);
- let (closure_def_id, substs) = match *ty.kind() {
- ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
- ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
+ let (closure_def_id, args) = match *ty.kind() {
+ ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)),
+ ty::Generator(def_id, args, _) => (def_id, UpvarArgs::Generator(args)),
ty::Error(_) => {
// #51714: skip analysis when we have already encountered type errors
return;
@@ -186,8 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let closure_def_id = closure_def_id.expect_local();
- let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
- self.closure_kind(closure_substs).is_none().then_some(closure_substs)
+ let infer_kind = if let UpvarArgs::Closure(closure_args) = args {
+ self.closure_kind(closure_args).is_none().then_some(closure_args)
} else {
None
};
@@ -256,19 +257,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let before_feature_tys = self.final_upvar_tys(closure_def_id);
- if let Some(closure_substs) = infer_kind {
+ if let Some(closure_args) = infer_kind {
// Unify the (as yet unbound) type variable in the closure
- // substs with the kind we inferred.
- let closure_kind_ty = closure_substs.as_closure().kind_ty();
+ // args with the kind we inferred.
+ let closure_kind_ty = closure_args.as_closure().kind_ty();
self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
// If we have an origin, store it.
- if let Some(origin) = origin {
- let origin = if enable_precise_capture(span) {
- (origin.0, origin.1)
- } else {
- (origin.0, Place { projections: vec![], ..origin.1 })
- };
+ if let Some(mut origin) = origin {
+ if !enable_precise_capture(span) {
+ // Without precise captures, we just capture the base and ignore
+ // the projections.
+ origin.1.projections.clear()
+ }
self.typeck_results
.borrow_mut()
@@ -293,15 +294,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Equate the type variables for the upvars with the actual types.
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
- debug!(
- "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
- closure_hir_id, substs, final_upvar_tys
- );
+ debug!(?closure_hir_id, ?args, ?final_upvar_tys);
// Build a tuple (U0..Un) of the final upvar types U0..Un
// and unify the upvar tuple type in the closure with it:
let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
- self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
+ self.demand_suptype(span, args.tupled_upvars_ty(), final_tupled_upvars_type);
let fake_reads = delegate
.fake_reads
@@ -337,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let upvar_ty = captured_place.place.ty();
let capture = captured_place.info.capture_kind;
- debug!(
- "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
- captured_place.place, upvar_ty, capture, captured_place.mutability,
- );
+ debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability);
apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
})
@@ -644,7 +639,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for capture in captures {
match capture.info.capture_kind {
ty::UpvarCapture::ByRef(_) => {
- let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") };
+ let PlaceBase::Upvar(upvar_id) = capture.place.base else {
+ bug!("expected upvar")
+ };
let origin = UpvarRegion(upvar_id, closure_span);
let upvar_region = self.next_region_var(origin);
capture.region = Some(upvar_region);
@@ -676,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match (p1.kind, p2.kind) {
// Paths are the same, continue to next loop.
(ProjectionKind::Deref, ProjectionKind::Deref) => {}
+ (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
(ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
if i1 == i2 => {}
@@ -698,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
l @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
+ | ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
r @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
+ | ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
) => bug!(
"ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
@@ -821,8 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let diagnostic_msg = format!(
- "add a dummy let to cause {} to be fully captured",
- migrated_variables_concat
+ "add a dummy let to cause {migrated_variables_concat} to be fully captured"
);
let closure_span = self.tcx.hir().span_with_body(closure_hir_id);
@@ -908,19 +907,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Combines all the reasons for 2229 migrations
fn compute_2229_migrations_reasons(
&self,
- auto_trait_reasons: FxHashSet<&'static str>,
+ auto_trait_reasons: UnordSet<&'static str>,
drop_order: bool,
) -> MigrationWarningReason {
- let mut reasons = MigrationWarningReason::default();
-
- reasons.auto_traits.extend(auto_trait_reasons);
- reasons.drop_order = drop_order;
-
- // `auto_trait_reasons` are in hashset order, so sort them to put the
- // diagnostics we emit later in a cross-platform-consistent order.
- reasons.auto_traits.sort_unstable();
-
- reasons
+ MigrationWarningReason {
+ auto_traits: auto_trait_reasons.to_sorted_stable_ord(),
+ drop_order,
+ }
}
/// Figures out the list of root variables (and their types) that aren't completely
@@ -934,8 +927,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
var_hir_id: hir::HirId,
closure_clause: hir::CaptureBy,
- ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> {
- let auto_traits_def_id = vec![
+ ) -> Option<FxIndexMap<UpvarMigrationInfo, UnordSet<&'static str>>> {
+ let auto_traits_def_id = [
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().sync_trait(),
self.tcx.get_diagnostic_item(sym::Send),
@@ -979,7 +972,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}));
}
- let mut problematic_captures = FxHashMap::default();
+ let mut problematic_captures = FxIndexMap::default();
// Check whether captured fields also implement the trait
for capture in root_var_min_capture_list.iter() {
let ty = apply_capture_kind_on_capture_ty(
@@ -999,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}));
}
- let mut capture_problems = FxHashSet::default();
+ let mut capture_problems = UnordSet::default();
// Checks if for any of the auto traits, one or more trait is implemented
// by the root variable but not by the capture
@@ -1045,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
closure_clause: hir::CaptureBy,
var_hir_id: hir::HirId,
- ) -> Option<FxHashSet<UpvarMigrationInfo>> {
+ ) -> Option<FxIndexSet<UpvarMigrationInfo>> {
let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id)) {
@@ -1064,14 +1057,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ```
debug!("no path starting from it is used");
-
match closure_clause {
// Only migrate if closure is a move closure
hir::CaptureBy::Value => {
- let mut diagnostics_info = FxHashSet::default();
- let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
+ let mut diagnostics_info = FxIndexSet::default();
+ let upvars =
+ self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
let upvar = upvars[&var_hir_id];
- diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
+ diagnostics_info
+ .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
return Some(diagnostics_info);
}
hir::CaptureBy::Ref => {}
@@ -1082,7 +1076,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!(?root_var_min_capture_list);
let mut projections_list = Vec::new();
- let mut diagnostics_info = FxHashSet::default();
+ let mut diagnostics_info = FxIndexSet::default();
for captured_place in root_var_min_capture_list.iter() {
match captured_place.info.capture_kind {
@@ -1152,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut need_migrations = Vec::new();
- let mut auto_trait_migration_reasons = FxHashSet::default();
+ let mut auto_trait_migration_reasons = UnordSet::default();
let mut drop_migration_needed = false;
// Perform auto-trait analysis
@@ -1164,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
diagnostics_info
} else {
- FxHashMap::default()
+ FxIndexMap::default()
};
let drop_reorder_diagnostic = if let Some(diagnostics_info) = self
@@ -1178,7 +1172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
drop_migration_needed = true;
diagnostics_info
} else {
- FxHashSet::default()
+ FxIndexSet::default()
};
// Combine all the captures responsible for needing migrations into one HashSet
@@ -1195,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) {
reasons.clone()
} else {
- FxHashSet::default()
+ UnordSet::default()
};
// Check if migration is needed because of drop reorder as a result of that capture
@@ -1203,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Combine all the reasons of why the root variable should be captured as a result of
// auto trait implementation issues
- auto_trait_migration_reasons.extend(capture_trait_reasons.iter().copied());
+ auto_trait_migration_reasons.extend_unord(capture_trait_reasons.items().copied());
diagnostics_info.push(MigrationLintNote {
captures_info,
@@ -1385,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Ref(..) => unreachable!(),
ty::RawPtr(..) => unreachable!(),
- ty::Adt(def, substs) => {
+ ty::Adt(def, args) => {
// Multi-variant enums are captured in entirety,
// which would've been handled in the case of single empty slice in `captured_by_move_projs`.
assert_eq!(def.variants().len(), 1);
@@ -1412,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
.collect();
- let after_field_ty = field.ty(self.tcx, substs);
+ let after_field_ty = field.ty(self.tcx, args);
self.has_significant_drop_outside_of_captures(
closure_def_id,
closure_span,
@@ -1893,6 +1887,7 @@ fn restrict_capture_precision(
return (place, curr_mode);
}
ProjectionKind::Deref => {}
+ ProjectionKind::OpaqueCast => {}
ProjectionKind::Field(..) => {} // ignore
}
}
@@ -1945,10 +1940,11 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
let mut projections_str = String::new();
for (i, item) in place.projections.iter().enumerate() {
let proj = match item.kind {
- ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b),
+ ProjectionKind::Field(a, b) => format!("({a:?}, {b:?})"),
ProjectionKind::Deref => String::from("Deref"),
ProjectionKind::Index => String::from("Index"),
ProjectionKind::Subslice => String::from("Subslice"),
+ ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
};
if i != 0 {
projections_str.push(',');
@@ -1968,7 +1964,7 @@ fn construct_capture_kind_reason_string<'tcx>(
let capture_kind_str = match capture_info.capture_kind {
ty::UpvarCapture::ByValue => "ByValue".into(),
- ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
+ ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
};
format!("{place_str} captured as {capture_kind_str} here")
@@ -1989,7 +1985,7 @@ fn construct_capture_info_string<'tcx>(
let capture_kind_str = match capture_info.capture_kind {
ty::UpvarCapture::ByValue => "ByValue".into(),
- ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
+ ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
};
format!("{place_str} -> {capture_kind_str}")
}
@@ -2003,7 +1999,7 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis(
tcx: TyCtxt<'_>,
closure_id: hir::HirId,
) -> bool {
- if tcx.sess.rust_2021() {
+ if tcx.sess.at_least_rust_2021() {
return false;
}
@@ -2249,5 +2245,5 @@ fn truncate_capture_for_optimization(
fn enable_precise_capture(span: Span) -> bool {
// We use span here to ensure that if the closure was generated by a macro with a different
// edition.
- span.rust_2021()
+ span.at_least_rust_2021()
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 106457536..603681bbc 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -3,23 +3,19 @@
// substitutions.
use crate::FnCtxt;
-use hir::def_id::LocalDefId;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unord::ExtendUnord;
use rustc_errors::{ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_middle::hir::place::Place as HirPlace;
-use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
+use rustc_middle::ty::visit::TypeVisitableExt;
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
use std::mem;
-use std::ops::ControlFlow;
///////////////////////////////////////////////////////////////////////////
// Entry point
@@ -42,9 +38,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This attribute causes us to dump some writeback information
// in the form of errors, which is used for unit tests.
- let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs);
+ let rustc_dump_user_args = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args);
- let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
+ let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args);
for param in body.params {
wbcx.visit_node_id(param.pat.span, param.hir_id);
}
@@ -102,14 +98,14 @@ struct WritebackCx<'cx, 'tcx> {
body: &'tcx hir::Body<'tcx>,
- rustc_dump_user_substs: bool,
+ rustc_dump_user_args: bool,
}
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn new(
fcx: &'cx FnCtxt<'cx, 'tcx>,
body: &'tcx hir::Body<'tcx>,
- rustc_dump_user_substs: bool,
+ rustc_dump_user_args: bool,
) -> WritebackCx<'cx, 'tcx> {
let owner = body.id().hir_id.owner;
@@ -117,7 +113,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fcx,
typeck_results: ty::TypeckResults::new(owner),
body,
- rustc_dump_user_substs,
+ rustc_dump_user_args,
};
// HACK: We specifically don't want the (opaque) error from tainting our
@@ -154,7 +150,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
if inner_ty.is_scalar() {
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- self.typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.node_args_mut().remove(e.hir_id);
}
}
hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => {
@@ -163,7 +159,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- self.typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.node_args_mut().remove(e.hir_id);
match e.kind {
hir::ExprKind::Binary(..) => {
@@ -214,14 +210,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// to use builtin indexing because the index type is known to be
// usize-ish
fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
- if let hir::ExprKind::Index(ref base, ref index) = e.kind {
+ if let hir::ExprKind::Index(ref base, ref index, _) = e.kind {
// All valid indexing looks like this; might encounter non-valid indexes at this point.
let base_ty = self.typeck_results.expr_ty_adjusted_opt(base);
if base_ty.is_none() {
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
// that isn't in the type table. We assume more relevant errors have already been
// emitted, so we delay an ICE if none have. (#64638)
- self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base));
+ self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{base:?}`"));
}
if let Some(base_ty) = base_ty
&& let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
@@ -235,13 +231,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
Ty::new_error_with_message(
self.fcx.tcx,
e.span,
- format!("bad index {:?} for base: `{:?}`", index, base),
+ format!("bad index {index:?} for base: `{base:?}`"),
)
});
if self.is_builtin_index(e, base_ty_inner, index_ty) {
// Remove the method call record
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
- self.typeck_results.node_substs_mut().remove(e.hir_id);
+ self.typeck_results.node_args_mut().remove(e.hir_id);
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) {
// Discard the need for a mutable borrow
@@ -376,66 +372,75 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn eval_closure_size(&mut self) {
- let mut res: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>> = Default::default();
- for (&closure_def_id, data) in self.fcx.typeck_results.borrow().closure_size_eval.iter() {
- let closure_hir_id = self.tcx().hir().local_def_id_to_hir_id(closure_def_id);
-
- let data = self.resolve(*data, &closure_hir_id);
-
- res.insert(closure_def_id, data);
- }
-
- self.typeck_results.closure_size_eval = res;
+ self.tcx().with_stable_hashing_context(|ref hcx| {
+ let fcx_typeck_results = self.fcx.typeck_results.borrow();
+
+ self.typeck_results.closure_size_eval = fcx_typeck_results
+ .closure_size_eval
+ .to_sorted(hcx, false)
+ .into_iter()
+ .map(|(&closure_def_id, data)| {
+ let closure_hir_id = self.tcx().hir().local_def_id_to_hir_id(closure_def_id);
+ let data = self.resolve(*data, &closure_hir_id);
+ (closure_def_id, data)
+ })
+ .collect();
+ })
}
- fn visit_min_capture_map(&mut self) {
- let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
- self.fcx.typeck_results.borrow().closure_min_captures.len(),
- Default::default(),
- );
- for (&closure_def_id, root_min_captures) in
- self.fcx.typeck_results.borrow().closure_min_captures.iter()
- {
- let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher(
- root_min_captures.len(),
- Default::default(),
- );
- for (var_hir_id, min_list) in root_min_captures.iter() {
- let min_list_wb = min_list
- .iter()
- .map(|captured_place| {
- let locatable = captured_place.info.path_expr_id.unwrap_or_else(|| {
- self.tcx().hir().local_def_id_to_hir_id(closure_def_id)
- });
-
- self.resolve(captured_place.clone(), &locatable)
- })
- .collect();
- root_var_map_wb.insert(*var_hir_id, min_list_wb);
- }
- min_captures_wb.insert(closure_def_id, root_var_map_wb);
- }
- self.typeck_results.closure_min_captures = min_captures_wb;
+ fn visit_min_capture_map(&mut self) {
+ self.tcx().with_stable_hashing_context(|ref hcx| {
+ let fcx_typeck_results = self.fcx.typeck_results.borrow();
+
+ self.typeck_results.closure_min_captures = fcx_typeck_results
+ .closure_min_captures
+ .to_sorted(hcx, false)
+ .into_iter()
+ .map(|(&closure_def_id, root_min_captures)| {
+ let root_var_map_wb = root_min_captures
+ .iter()
+ .map(|(var_hir_id, min_list)| {
+ let min_list_wb = min_list
+ .iter()
+ .map(|captured_place| {
+ let locatable =
+ captured_place.info.path_expr_id.unwrap_or_else(|| {
+ self.tcx().hir().local_def_id_to_hir_id(closure_def_id)
+ });
+ self.resolve(captured_place.clone(), &locatable)
+ })
+ .collect();
+ (*var_hir_id, min_list_wb)
+ })
+ .collect();
+ (closure_def_id, root_var_map_wb)
+ })
+ .collect();
+ })
}
fn visit_fake_reads_map(&mut self) {
- let mut resolved_closure_fake_reads: FxHashMap<
- LocalDefId,
- Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>,
- > = Default::default();
- for (&closure_def_id, fake_reads) in
- self.fcx.typeck_results.borrow().closure_fake_reads.iter()
- {
- let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>::new();
- for (place, cause, hir_id) in fake_reads.iter() {
- let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id);
-
- let resolved_fake_read = self.resolve(place.clone(), &locatable);
- resolved_fake_reads.push((resolved_fake_read, *cause, *hir_id));
- }
- resolved_closure_fake_reads.insert(closure_def_id, resolved_fake_reads);
- }
- self.typeck_results.closure_fake_reads = resolved_closure_fake_reads;
+ self.tcx().with_stable_hashing_context(move |ref hcx| {
+ let fcx_typeck_results = self.fcx.typeck_results.borrow();
+
+ self.typeck_results.closure_fake_reads = fcx_typeck_results
+ .closure_fake_reads
+ .to_sorted(hcx, true)
+ .into_iter()
+ .map(|(&closure_def_id, fake_reads)| {
+ let resolved_fake_reads = fake_reads
+ .iter()
+ .map(|(place, cause, hir_id)| {
+ let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id);
+ let resolved_fake_read = self.resolve(place.clone(), &locatable);
+ (resolved_fake_read, *cause, *hir_id)
+ })
+ .collect();
+
+ (closure_def_id, resolved_fake_reads)
+ })
+ .collect();
+ });
}
fn visit_closures(&mut self) {
@@ -470,7 +475,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
let common_hir_owner = fcx_typeck_results.hir_owner;
- if self.rustc_dump_user_substs {
+ if self.rustc_dump_user_args {
let sorted_user_provided_types =
fcx_typeck_results.user_provided_types().items_in_stable_order();
@@ -478,15 +483,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
for (local_id, c_ty) in sorted_user_provided_types {
let hir_id = hir::HirId { owner: common_hir_owner, local_id };
- if let ty::UserType::TypeOf(_, user_substs) = c_ty.value {
+ if let ty::UserType::TypeOf(_, user_args) = c_ty.value {
// This is a unit-testing mechanism.
let span = self.tcx().hir().span(hir_id);
// We need to buffer the errors in order to guarantee a consistent
// order when emitting them.
- let err = self
- .tcx()
- .sess
- .struct_span_err(span, format!("user substs: {:?}", user_substs));
+ let err =
+ self.tcx().sess.struct_span_err(span, format!("user args: {user_args:?}"));
err.buffer(&mut errors_buffer);
}
}
@@ -520,7 +523,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let fcx_typeck_results = self.fcx.typeck_results.borrow();
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
- self.typeck_results.user_provided_sigs.extend(
+ self.typeck_results.user_provided_sigs.extend_unord(
fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| {
if cfg!(debug_assertions) && c_sig.has_infer() {
span_bug!(
@@ -540,10 +543,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
self.typeck_results.generator_interior_types =
fcx_typeck_results.generator_interior_types.clone();
- for (&expr_def_id, predicates) in fcx_typeck_results.generator_interior_predicates.iter() {
- let predicates = self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
- self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates);
- }
+ self.tcx().with_stable_hashing_context(move |ref hcx| {
+ for (&expr_def_id, predicates) in
+ fcx_typeck_results.generator_interior_predicates.to_sorted(hcx, false).into_iter()
+ {
+ let predicates =
+ self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
+ self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates);
+ }
+ })
}
#[instrument(skip(self), level = "debug")]
@@ -553,23 +561,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
- struct RecursionChecker {
- def_id: LocalDefId,
- }
- impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for RecursionChecker {
- type BreakTy = ();
- fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
- if def_id == self.def_id.to_def_id() {
- return ControlFlow::Break(());
- }
- }
- t.super_visit_with(self)
- }
- }
- if hidden_type
- .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
- .is_break()
+ if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
+ && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
+ && alias_ty.args == opaque_type_key.args
{
continue;
}
@@ -619,11 +613,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
debug!(?n_ty);
// Resolve any substitutions
- if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
- let substs = self.resolve(substs, &span);
- debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
- assert!(!substs.has_infer() && !substs.has_placeholders());
- self.typeck_results.node_substs_mut().insert(hir_id, substs);
+ if let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(hir_id) {
+ let args = self.resolve(args, &span);
+ debug!("write_args_to_tcx({:?}, {:?})", hir_id, args);
+ assert!(!args.has_infer() && !args.has_placeholders());
+ self.typeck_results.node_args_mut().insert(hir_id, args);
}
}