diff options
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt')
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 159 | ||||
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs | 129 | ||||
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 156 | ||||
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 320 |
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 |