summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/fn_ctxt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt')
-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
5 files changed, 432 insertions, 342 deletions
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