diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
30 files changed, 1566 insertions, 1597 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index cb38d0ac8..ba5000da6 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -97,7 +97,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { orig_env, ty::TraitPredicate { trait_ref, - constness: ty::BoundConstness::NotConst, polarity: if polarity { ImplPolarity::Positive } else { @@ -152,21 +151,16 @@ impl<'tcx> AutoTraitFinder<'tcx> { // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing // SelectionContext to return it back to us. - let Some((new_env, user_env)) = self.evaluate_predicates( - &infcx, - trait_did, - ty, - orig_env, - orig_env, - &mut fresh_preds, - ) else { + let Some((new_env, user_env)) = + self.evaluate_predicates(&infcx, trait_did, ty, orig_env, orig_env, &mut fresh_preds) + else { return AutoTraitResult::NegativeImpl; }; let (full_env, full_user_env) = self .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds) .unwrap_or_else(|| { - panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) + panic!("Failed to fully process: {ty:?} {trait_did:?} {orig_env:?}") }); debug!( @@ -183,7 +177,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); + panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}"); } let outlives_env = OutlivesEnvironment::new(full_env); @@ -265,7 +259,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { predicates.push_back(ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]), - constness: ty::BoundConstness::NotConst, // Auto traits are positive polarity: ty::ImplPolarity::Positive, })); @@ -329,7 +322,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } Ok(None) => {} Err(SelectionError::Unimplemented) => { - if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { + if self.is_param_no_infer(pred.skip_binder().trait_ref.args) { already_visited.remove(&pred); self.add_user_pred(&mut user_computed_preds, pred.to_predicate(self.tcx)); predicates.push_back(pred); @@ -339,12 +332,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { {:?} {:?} {:?}", ty, pred, - pred.skip_binder().trait_ref.substs + pred.skip_binder().trait_ref.args ); return None; } } - _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), + _ => panic!("Unexpected error for '{ty:?}': {result:?}"), }; let normalized_preds = @@ -352,14 +345,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { new_env = ty::ParamEnv::new( tcx.mk_clauses_from_iter(normalized_preds.filter_map(|p| p.as_clause())), param_env.reveal(), - param_env.constness(), ); } let final_user_env = ty::ParamEnv::new( tcx.mk_clauses_from_iter(user_computed_preds.into_iter().filter_map(|p| p.as_clause())), user_env.reveal(), - user_env.constness(), ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ @@ -406,17 +397,17 @@ impl<'tcx> AutoTraitFinder<'tcx> { ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder()) { if new_trait.def_id() == old_trait.def_id() { - let new_substs = new_trait.trait_ref.substs; - let old_substs = old_trait.trait_ref.substs; + let new_args = new_trait.trait_ref.args; + let old_args = old_trait.trait_ref.args; - if !new_substs.types().eq(old_substs.types()) { + if !new_args.types().eq(old_args.types()) { // We can't compare lifetimes if the types are different, // so skip checking `old_pred`. return true; } for (new_region, old_region) in - iter::zip(new_substs.regions(), old_substs.regions()) + iter::zip(new_args.regions(), old_args.regions()) { match (*new_region, *old_region) { // If both predicates have an `ReLateBound` (a HRTB) in the @@ -569,8 +560,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { finished_map } - fn is_param_no_infer(&self, substs: SubstsRef<'_>) -> bool { - self.is_of_param(substs.type_at(0)) && !substs.types().any(|t| t.has_infer_types()) + fn is_param_no_infer(&self, args: GenericArgsRef<'_>) -> bool { + self.is_of_param(args.type_at(0)) && !args.types().any(|t| t.has_infer_types()) } pub fn is_of_param(&self, ty: Ty<'_>) -> bool { @@ -641,7 +632,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // an inference variable. // Additionally, we check if we've seen this predicate before, // to avoid rendering duplicate bounds to the user. - if self.is_param_no_infer(p.skip_binder().projection_ty.substs) + if self.is_param_no_infer(p.skip_binder().projection_ty.args) && !p.term().skip_binder().has_infer_types() && is_new_pred { @@ -754,7 +745,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // subobligations or getting an error) when we started off with // inference variables if p.term().skip_binder().has_infer_types() { - panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) + panic!("Unexpected result when selecting {ty:?} {obligation:?}") } } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 1b1285e1b..5746781ae 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -7,7 +7,7 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; use crate::traits::outlives_bounds::InferCtxtExt as _; -use crate::traits::select::IntercrateAmbiguityCause; +use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; use crate::traits::util::impl_subject_and_oblig; use crate::traits::SkipLeakCheck; use crate::traits::{ @@ -24,6 +24,7 @@ use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; @@ -96,9 +97,7 @@ pub fn overlapping_impls( let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { - (Some(a), Some(b)) => { - drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs) - } + (Some(a), Some(b)) => drcx.args_refs_may_unify(a.skip_binder().args, b.skip_binder().args), (None, None) => { let self_ty1 = tcx.type_of(impl1_def_id).skip_binder(); let self_ty2 = tcx.type_of(impl2_def_id).skip_binder(); @@ -143,24 +142,26 @@ fn with_fresh_ty_vars<'cx, 'tcx>( impl_def_id: DefId, ) -> ty::ImplHeader<'tcx> { let tcx = selcx.tcx(); - let impl_substs = selcx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + let impl_args = selcx.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); let header = ty::ImplHeader { impl_def_id, - self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), - trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)), + self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args), + trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)), predicates: tcx .predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) + .instantiate(tcx, impl_args) .iter() - .map(|(c, _)| c.as_predicate()) + .map(|(c, s)| (c.as_predicate(), s)) .collect(), }; - let InferOk { value: mut header, obligations } = - selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header); + let InferOk { value: mut header, obligations } = selcx + .infcx + .at(&ObligationCause::dummy_with_span(tcx.def_span(impl_def_id)), param_env) + .normalize(header); - header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); + header.predicates.extend(obligations.into_iter().map(|o| (o.predicate, o.cause.span))); header } @@ -209,16 +210,76 @@ fn overlap<'tcx>( let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; debug!("overlap: unification check succeeded"); - if overlap_mode.use_implicit_negative() - && impl_intersection_has_impossible_obligation( - selcx, - param_env, - &impl1_header, - impl2_header, - equate_obligations, - ) - { - return None; + if overlap_mode.use_implicit_negative() { + for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] { + if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| { + impl_intersection_has_impossible_obligation( + selcx, + param_env, + &impl1_header, + &impl2_header, + &equate_obligations, + ) + }) { + if matches!(mode, TreatInductiveCycleAs::Recur) { + let first_local_impl = impl1_header + .impl_def_id + .as_local() + .or(impl2_header.impl_def_id.as_local()) + .expect("expected one of the impls to be local"); + infcx.tcx.struct_span_lint_hir( + COINDUCTIVE_OVERLAP_IN_COHERENCE, + infcx.tcx.local_def_id_to_hir_id(first_local_impl), + infcx.tcx.def_span(first_local_impl), + format!( + "implementations {} will conflict in the future", + match impl1_header.trait_ref { + Some(trait_ref) => { + let trait_ref = infcx.resolve_vars_if_possible(trait_ref); + format!( + "of `{}` for `{}`", + trait_ref.print_only_trait_path(), + trait_ref.self_ty() + ) + } + None => format!( + "for `{}`", + infcx.resolve_vars_if_possible(impl1_header.self_ty) + ), + }, + ), + |lint| { + lint.note( + "impls that are not considered to overlap may be considered to \ + overlap in the future", + ) + .span_label( + infcx.tcx.def_span(impl1_header.impl_def_id), + "the first impl is here", + ) + .span_label( + infcx.tcx.def_span(impl2_header.impl_def_id), + "the second impl is here", + ); + if !failing_obligation.cause.span.is_dummy() { + lint.span_label( + failing_obligation.cause.span, + format!( + "`{}` may be considered to hold in future releases, \ + causing the impls to overlap", + infcx + .resolve_vars_if_possible(failing_obligation.predicate) + ), + ); + } + lint + }, + ); + } + + return None; + } + } } // We toggle the `leak_check` by using `skip_leak_check` when constructing the @@ -286,40 +347,30 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, impl1_header: &ty::ImplHeader<'tcx>, - impl2_header: ty::ImplHeader<'tcx>, - obligations: PredicateObligations<'tcx>, -) -> bool { + impl2_header: &ty::ImplHeader<'tcx>, + obligations: &PredicateObligations<'tcx>, +) -> Option<PredicateObligation<'tcx>> { let infcx = selcx.infcx; - let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| { - if infcx.next_trait_solver() { - infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) - } else { - // We use `evaluate_root_obligation` to correctly track - // intercrate ambiguity clauses. We do not need this in the - // new solver. - selcx.evaluate_root_obligation(obligation).map_or( - false, // Overflow has occurred, and treat the obligation as possibly holding. - |result| !result.may_apply(), - ) - } - }; - - let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates] + [&impl1_header.predicates, &impl2_header.predicates] .into_iter() .flatten() - .map(|&predicate| { - Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate) + .map(|&(predicate, span)| { + Obligation::new(infcx.tcx, ObligationCause::dummy_with_span(span), param_env, predicate) + }) + .chain(obligations.into_iter().cloned()) + .find(|obligation: &PredicateObligation<'tcx>| { + if infcx.next_trait_solver() { + infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) + } else { + // We use `evaluate_root_obligation` to correctly track intercrate + // ambiguity clauses. We cannot use this in the new solver. + selcx.evaluate_root_obligation(obligation).map_or( + false, // Overflow has occurred, and treat the obligation as possibly holding. + |result| !result.may_apply(), + ) + } }) - .chain(obligations) - .find(obligation_guaranteed_to_fail); - - if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - true - } else { - false - } } /// Check if both impls can be satisfied by a common type by considering whether @@ -353,13 +404,13 @@ fn impl_intersection_has_negative_obligation( &infcx, ObligationCause::dummy(), impl_env, - tcx.impl_subject(impl1_def_id).subst_identity(), + tcx.impl_subject(impl1_def_id).instantiate_identity(), ) { Ok(s) => s, Err(err) => { tcx.sess.delay_span_bug( tcx.def_span(impl1_def_id), - format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), + format!("failed to fully normalize {impl1_def_id:?}: {err:?}"), ); return false; } @@ -367,16 +418,16 @@ fn impl_intersection_has_negative_obligation( // Attempt to prove that impl2 applies, given all of the above. let selcx = &mut SelectionContext::new(&infcx); - let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); + let impl2_args = infcx.fresh_args_for_item(DUMMY_SP, impl2_def_id); let (subject2, normalization_obligations) = - impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| { + impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_args, |_, _| { ObligationCause::dummy() }); // do the impls unify? If not, then it's not currently possible to prove any // obligations about their intersection. let Ok(InferOk { obligations: equate_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2) + infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No, subject1, subject2) else { debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); return false; @@ -437,8 +488,7 @@ fn prove_negated_obligation<'tcx>( let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID); let ocx = ObligationCtxt::new(&infcx); - let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) - else { + let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) else { return false; }; @@ -455,22 +505,23 @@ fn prove_negated_obligation<'tcx>( /// This both checks whether any downstream or sibling crates could /// implement it and whether an upstream crate can add this impl /// without breaking backwards compatibility. -#[instrument(level = "debug", skip(tcx), ret)] -pub fn trait_ref_is_knowable<'tcx>( +#[instrument(level = "debug", skip(tcx, lazily_normalize_ty), ret)] +pub fn trait_ref_is_knowable<'tcx, E: Debug>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, -) -> Result<(), Conflict> { + mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>, +) -> Result<Result<(), Conflict>, E> { if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() { // The only types implementing `FnPtr` are function pointers, // so if there's no impl of `FnPtr` in the current crate, // then such an impl will never be added in the future. - return Ok(()); + return Ok(Ok(())); } - if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() { + if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() { // A downstream or cousin crate is allowed to implement some // substitution of this trait-ref. - return Err(Conflict::Downstream); + return Ok(Err(Conflict::Downstream)); } if trait_ref_is_local_or_fundamental(tcx, trait_ref) { @@ -479,7 +530,7 @@ pub fn trait_ref_is_knowable<'tcx>( // allowed to implement a substitution of this trait ref, which // means impls could only come from dependencies of this crate, // which we already know about. - return Ok(()); + return Ok(Ok(())); } // This is a remote non-fundamental trait, so if another crate @@ -490,10 +541,10 @@ pub fn trait_ref_is_knowable<'tcx>( // and if we are an intermediate owner, then we don't care // about future-compatibility, which means that we're OK if // we are an owner. - if orphan_check_trait_ref(trait_ref, InCrate::Local).is_ok() { - Ok(()) + if orphan_check_trait_ref(trait_ref, InCrate::Local, &mut lazily_normalize_ty)?.is_ok() { + Ok(Ok(())) } else { - Err(Conflict::Upstream) + Ok(Err(Conflict::Upstream)) } } @@ -520,7 +571,7 @@ pub enum OrphanCheckErr<'tcx> { pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(); + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); debug!(?trait_ref); // If the *trait* is local to the crate, ok. @@ -529,7 +580,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe return Ok(()); } - orphan_check_trait_ref(trait_ref, InCrate::Local) + orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |ty| Ok(ty)).unwrap() } /// Checks whether a trait-ref is potentially implementable by a crate. @@ -618,11 +669,12 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// /// Note that this function is never called for types that have both type /// parameters and inference variables. -#[instrument(level = "trace", ret)] -fn orphan_check_trait_ref<'tcx>( +#[instrument(level = "trace", skip(lazily_normalize_ty), ret)] +fn orphan_check_trait_ref<'tcx, E: Debug>( trait_ref: ty::TraitRef<'tcx>, in_crate: InCrate, -) -> Result<(), OrphanCheckErr<'tcx>> { + lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>, +) -> Result<Result<(), OrphanCheckErr<'tcx>>, E> { if trait_ref.has_infer() && trait_ref.has_param() { bug!( "can't orphan check a trait ref with both params and inference variables {:?}", @@ -630,9 +682,10 @@ fn orphan_check_trait_ref<'tcx>( ); } - let mut checker = OrphanChecker::new(in_crate); - match trait_ref.visit_with(&mut checker) { + let mut checker = OrphanChecker::new(in_crate, lazily_normalize_ty); + Ok(match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), + ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)) => return Err(err), ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { // Does there exist some local type after the `ParamTy`. checker.search_first_local_ty = true; @@ -645,34 +698,39 @@ fn orphan_check_trait_ref<'tcx>( } } ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()), - } + }) } -struct OrphanChecker<'tcx> { +struct OrphanChecker<'tcx, F> { in_crate: InCrate, in_self_ty: bool, + lazily_normalize_ty: F, /// Ignore orphan check failures and exclusively search for the first /// local type. search_first_local_ty: bool, non_local_tys: Vec<(Ty<'tcx>, bool)>, } -impl<'tcx> OrphanChecker<'tcx> { - fn new(in_crate: InCrate) -> Self { +impl<'tcx, F, E> OrphanChecker<'tcx, F> +where + F: FnOnce(Ty<'tcx>) -> Result<Ty<'tcx>, E>, +{ + fn new(in_crate: InCrate, lazily_normalize_ty: F) -> Self { OrphanChecker { in_crate, in_self_ty: true, + lazily_normalize_ty, search_first_local_ty: false, non_local_tys: Vec::new(), } } - fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> { + fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> { self.non_local_tys.push((t, self.in_self_ty)); ControlFlow::Continue(()) } - fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> { + fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> { if self.search_first_local_ty { ControlFlow::Continue(()) } else { @@ -688,18 +746,28 @@ impl<'tcx> OrphanChecker<'tcx> { } } -enum OrphanCheckEarlyExit<'tcx> { +enum OrphanCheckEarlyExit<'tcx, E> { + NormalizationFailure(E), ParamTy(Ty<'tcx>), LocalTy(Ty<'tcx>), } -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> { - type BreakTy = OrphanCheckEarlyExit<'tcx>; +impl<'tcx, F, E> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx, F> +where + F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>, +{ + type BreakTy = OrphanCheckEarlyExit<'tcx, E>; fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + // Need to lazily normalize here in with `-Ztrait-solver=next-coherence`. + let ty = match (self.lazily_normalize_ty)(ty) { + Ok(ty) => ty, + Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)), + }; + let result = match *ty.kind() { ty::Bool | ty::Char @@ -729,11 +797,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> { // For fundamental types, we just look inside of them. ty::Ref(_, ty, _) => ty.visit_with(self), - ty::Adt(def, substs) => { + ty::Adt(def, args) => { if self.def_id_is_local(def.did()) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) } else if def.is_fundamental() { - substs.visit_with(self) + args.visit_with(self) } else { self.found_non_local_ty(ty) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8dc13b827..3d0d3812d 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -191,7 +191,7 @@ fn satisfied_from_param_env<'tcx>( if let ty::ConstKind::Expr(e) = c.kind() { e.visit_with(self) } else { - // FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs. + // FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s args. // This is currently unobservable as `<T as Trait<{ U + 1 }>>::ASSOC` creates an anon const // with its own `ConstEvaluatable` bound in the param env which we will visit separately. // diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 61f693e1b..820973dc0 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { cause, recursion_depth: 0, param_env, - predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx), }); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index f785c4eaf..fd813ca4e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -26,8 +26,8 @@ pub fn recompute_applicable_impls<'tcx>( let obligation_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs); + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args); let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); if let Err(_) = @@ -36,7 +36,7 @@ pub fn recompute_applicable_impls<'tcx>( return false; } - let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs); + let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args); ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) })); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f34218059..457d5420c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -7,6 +7,7 @@ use super::{ ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionError, TraitNotObjectSafe, }; +use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; @@ -100,7 +101,6 @@ pub trait InferCtxtExt<'tcx> { &self, param_env: ty::ParamEnv<'tcx>, ty: ty::Binder<'tcx, Ty<'tcx>>, - constness: ty::BoundConstness, polarity: ty::ImplPolarity, ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>; } @@ -226,7 +226,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) } - _ => panic!("non-FnLike node found: {:?}", node), + _ => panic!("non-FnLike node found: {node:?}"), }) } @@ -273,10 +273,10 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { found_str, ); - err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); + err.span_label(span, format!("expected {kind} that takes {expected_str}")); if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {}", found_str)); + err.span_label(found_span, format!("takes {found_str}")); // Suggest to take and ignore the arguments with expected_args_length `_`s if // found arguments is empty (assume the user just wants to ignore args in this case). @@ -289,7 +289,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { "consider changing the closure to take and ignore the expected argument{}", pluralize!(expected_args.len()) ), - format!("|{}|", underscores), + format!("|{underscores}|"), Applicability::MachineApplicable, ); } @@ -304,7 +304,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { err.span_suggestion_verbose( found_span, "change the closure to take multiple arguments instead of a single tuple", - format!("|{}|", sugg), + format!("|{sugg}|"), Applicability::MachineApplicable, ); } @@ -356,7 +356,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, param_env: ty::ParamEnv<'tcx>, ty: ty::Binder<'tcx, Ty<'tcx>>, - constness: ty::BoundConstness, polarity: ty::ImplPolarity, ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { self.commit_if_ok(|_| { @@ -372,12 +371,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, }); + // FIXME(effects) let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); let obligation = Obligation::new( self.tcx, ObligationCause::dummy(), param_env, - ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }), + ty.rebind(ty::TraitPredicate { trait_ref, polarity }), ); let ocx = ObligationCtxt::new(self); ocx.register_obligation(obligation); @@ -687,11 +687,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); - let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - trait_predicate.remap_constness_diag(obligation.param_env); - let predicate_is_const = ty::BoundConstness::ConstIfConst - == trait_predicate.skip_binder().constness; + // FIXME(effects) + let predicate_is_const = false; if self.tcx.sess.has_errors().is_some() && trait_predicate.references_error() @@ -704,9 +703,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { ( - format!(" in `{}`", t), - format!("within `{}`, ", t), - s.map(|s| (format!("within this `{}`", t), s)), + format!(" in `{t}`"), + format!("within `{t}`, "), + s.map(|s| (format!("within this `{t}`"), s)), ) }) .unwrap_or_default(); @@ -1050,8 +1049,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { report_object_safety_error(self.tcx, span, trait_def_id, violations) } - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { - let found_kind = self.closure_kind(closure_substs).unwrap(); + ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { + let found_kind = self.closure_kind(closure_args).unwrap(); self.report_closure_error(&obligation, closure_def_id, found_kind, kind) } @@ -1071,7 +1070,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // which bounds actually failed to hold. self.tcx.sess.struct_span_err( span, - format!("the type `{}` is not well-formed", ty), + format!("the type `{ty}` is not well-formed"), ) } } @@ -1109,7 +1108,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { let mut diag = self.tcx.sess.struct_span_err( span, - format!("the constant `{}` is not of type `{}`", ct, ty), + format!("the constant `{ct}` is not of type `{ty}`"), ); self.note_type_err( &mut diag, @@ -1627,19 +1626,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::TermKind::Ty(_) => Ty::new_projection( self.tcx, data.projection_ty.def_id, - data.projection_ty.substs, + data.projection_ty.args, ) .into(), ty::TermKind::Const(ct) => ty::Const::new_unevaluated( self.tcx, ty::UnevaluatedConst { def: data.projection_ty.def_id, - substs: data.projection_ty.substs, + args: data.projection_ty.args, }, ct.ty(), ) .into(), }; + // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice + // to deeply normalize this type. let normalized_term = ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); @@ -1908,9 +1909,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .all_impls(trait_pred.def_id()) .filter_map(|def_id| { if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative - || !trait_pred - .skip_binder() - .is_constness_satisfied_by(self.tcx.constness(def_id)) || !self.tcx.is_user_visible_dep(def_id.krate) { return None; @@ -1970,7 +1968,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { traits.sort(); traits.dedup(); // FIXME: this could use a better heuristic, like just checking - // that substs[1..] is the same. + // that args[1..] is the same. let all_traits_equal = traits.len() == 1; let candidates: Vec<String> = candidates @@ -1979,7 +1977,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if all_traits_equal { format!("\n {}", c.self_ty()) } else { - format!("\n {}", c) + format!("\n {c}") } }) .collect(); @@ -2016,7 +2014,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { || self.tcx.is_automatically_derived(def_id) }) .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) - .map(ty::EarlyBinder::subst_identity) + .map(ty::EarlyBinder::instantiate_identity) .filter(|trait_ref| { let self_ty = trait_ref.self_ty(); // Avoid mentioning type parameters. @@ -2177,10 +2175,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { format!("trait impl{} with same name found", pluralize!(trait_impls.len())), ); let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); - let crate_msg = format!( - "perhaps two different versions of crate `{}` are being used?", - trait_crate - ); + let crate_msg = + format!("perhaps two different versions of crate `{trait_crate}` are being used?"); err.note(crate_msg); suggested = true; } @@ -2265,7 +2261,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Pick the first substitution that still contains inference variables as the one // we're going to emit an error for. If there are none (see above), fall back to // a more general error. - let subst = data.trait_ref.substs.iter().find(|s| s.has_non_region_infer()); + let subst = data.trait_ref.args.iter().find(|s| s.has_non_region_infer()); let mut err = if let Some(subst) = subst { self.emit_inference_failure_err( @@ -2290,7 +2286,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &obligation.with(self.tcx, trait_ref), ); let has_non_region_infer = - trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_or_numeric_infer()); + trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer()); // It doesn't make sense to talk about applicable impls if there are more // than a handful of them. if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { @@ -2308,7 +2304,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.cancel(); return; } - err.note(format!("cannot satisfy `{}`", predicate)); + err.note(format!("cannot satisfy `{predicate}`")); let impl_candidates = self .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap()); if impl_candidates.len() < 10 { @@ -2328,7 +2324,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } - if let Some(ty::subst::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) + if let Some(ty::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let mut expr_finder = FindExprBySpan::new(span); @@ -2372,7 +2368,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(local_def_id) = data.trait_ref.def_id.as_local() && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id) && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) { - err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name)); + err.span_label(method_ref.span, format!("`{trait_name}::{assoc_item_name}` defined here")); } err.span_label(span, format!("cannot {verb} associated {noun} of trait")); @@ -2386,14 +2382,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // If there is only one implementation of the trait, suggest using it. // Otherwise, use a placeholder comment for the implementation. let (message, impl_suggestion) = if non_blanket_impl_count == 1 {( - "use the fully-qualified path to the only available implementation".to_string(), - format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity()) - )} else {( - format!( - "use a fully-qualified path to a specific available implementation ({} found)", - non_blanket_impl_count - ), - "</* self type */ as ".to_string() + "use the fully-qualified path to the only available implementation", + format!("<{} as ", self.tcx.type_of(impl_def_id).instantiate_identity()) + )} else { + ("use a fully-qualified path to a specific available implementation", + "</* self type */ as ".to_string() )}; let mut suggestions = vec![( path.span.shrink_to_lo(), @@ -2464,7 +2457,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let subst = data .projection_ty - .substs + .args .iter() .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); @@ -2476,7 +2469,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ErrorCode::E0284, true, ); - err.note(format!("cannot satisfy `{}`", predicate)); + err.note(format!("cannot satisfy `{predicate}`")); err } else { // If we can't find a substitution, just print a generic error @@ -2487,7 +2480,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "type annotations needed: cannot satisfy `{}`", predicate, ); - err.span_label(span, format!("cannot satisfy `{}`", predicate)); + err.span_label(span, format!("cannot satisfy `{predicate}`")); err } } @@ -2515,7 +2508,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "type annotations needed: cannot satisfy `{}`", predicate, ); - err.span_label(span, format!("cannot satisfy `{}`", predicate)); + err.span_label(span, format!("cannot satisfy `{predicate}`")); err } } @@ -2530,7 +2523,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "type annotations needed: cannot satisfy `{}`", predicate, ); - err.span_label(span, format!("cannot satisfy `{}`", predicate)); + err.span_label(span, format!("cannot satisfy `{predicate}`")); err } }; @@ -2567,7 +2560,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } } - let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect(); + let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect(); crate_names.sort(); crate_names.dedup(); post.sort(); @@ -2594,7 +2587,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate ); let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { - format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),) + format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),) } else if post.len() == 1 { format!(": `{}`", post[0]) } else { @@ -2603,7 +2596,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { match (spans.len(), crates.len(), crate_names.len()) { (0, 0, 0) => { - err.note(format!("cannot satisfy `{}`", predicate)); + err.note(format!("cannot satisfy `{predicate}`")); } (0, _, 1) => { err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,)); @@ -2706,10 +2699,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { - let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; }; + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + obligation.predicate.kind().skip_binder() + else { + return; + }; let (ObligationCauseCode::BindingObligation(item_def_id, span) - | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) - = *obligation.cause.code().peel_derives() else { return; }; + | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) = + *obligation.cause.code().peel_derives() + else { + return; + }; debug!(?pred, ?item_def_id, ?span); let (Some(node), true) = ( @@ -2767,7 +2767,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion_verbose( span, "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), + format!("{separator} ?Sized"), Applicability::MachineApplicable, ); } @@ -2820,9 +2820,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if obligated_types.iter().any(|ot| ot == &self_ty) { return true; } - if let ty::Adt(def, substs) = self_ty.kind() - && let [arg] = &substs[..] - && let ty::subst::GenericArgKind::Type(ty) = arg.unpack() + if let ty::Adt(def, args) = self_ty.kind() + && let [arg] = &args[..] + && let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Adt(inner_def, _) = ty.kind() && inner_def == def { @@ -2858,7 +2858,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }) .unwrap_or_else(|| { - format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message) + format!("the trait bound `{trait_predicate}` is not satisfied{post_message}") }) } @@ -2874,14 +2874,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref)); let src_and_dst = rustc_transmute::Types { - dst: trait_ref.substs.type_at(0), - src: trait_ref.substs.type_at(1), + dst: trait_ref.args.type_at(0), + src: trait_ref.args.type_at(1), + }; + let scope = trait_ref.args.type_at(2); + let Some(assume) = rustc_transmute::Assume::from_const( + self.infcx.tcx, + obligation.param_env, + trait_ref.args.const_at(3), + ) else { + span_bug!( + span, + "Unable to construct rustc_transmute::Assume where it was previously possible" + ); }; - let scope = trait_ref.substs.type_at(2); - let Some(assume) = - rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else { - span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible"); - }; match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( obligation.cause, @@ -2890,8 +2896,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assume, ) { Answer::No(reason) => { - let dst = trait_ref.substs.type_at(0); - let src = trait_ref.substs.type_at(1); + let dst = trait_ref.args.type_at(0); + let src = trait_ref.args.type_at(1); let err_msg = format!( "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`" ); @@ -2982,12 +2988,19 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { unsatisfied_const: bool, ) { let body_def_id = obligation.cause.body_id; + let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } = + obligation.cause.code() + { + *rhs_span + } else { + span + }; + // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( obligation.param_env, trait_ref.self_ty(), - trait_predicate.skip_binder().constness, trait_predicate.skip_binder().polarity, ) { @@ -3021,8 +3034,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err); } - self.maybe_suggest_convert_to_slice( + self.suggest_convert_to_slice( err, + obligation, trait_ref, impl_candidates.as_slice(), span, @@ -3058,7 +3072,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Note any argument mismatches let given_ty = params.skip_binder(); - let expected_ty = trait_ref.skip_binder().substs.type_at(1); + let expected_ty = trait_ref.skip_binder().args.type_at(1); if let ty::Tuple(given) = given_ty.kind() && let ty::Tuple(expected) = expected_ty.kind() { @@ -3089,34 +3103,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, - span: Span, + _obligation: &PredicateObligation<'tcx>, + _trait_ref: ty::PolyTraitRef<'tcx>, + _trait_predicate: &ty::PolyTraitPredicate<'tcx>, + _err: &mut Diagnostic, + _span: Span, ) -> UnsatisfiedConst { - let mut unsatisfied_const = UnsatisfiedConst(false); - if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { - let non_const_predicate = trait_ref.without_const(); - let non_const_obligation = Obligation { - cause: obligation.cause.clone(), - param_env: obligation.param_env.without_const(), - predicate: non_const_predicate.to_predicate(self.tcx), - recursion_depth: obligation.recursion_depth, - }; - if self.predicate_may_hold(&non_const_obligation) { - unsatisfied_const = UnsatisfiedConst(true); - err.span_note( - span, - format!( - "the trait `{}` is implemented for `{}`, \ - but that implementation is not `const`", - non_const_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), - ), - ); - } - } + let unsatisfied_const = UnsatisfiedConst(false); + // FIXME(effects) unsatisfied_const } @@ -3128,24 +3122,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { kind: ty::ClosureKind, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let closure_span = self.tcx.def_span(closure_def_id); - let mut err = struct_span_err!( - self.tcx.sess, - closure_span, - E0525, - "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", - kind, - found_kind - ); - err.span_label( + let mut err = ClosureKindMismatch { closure_span, - format!("this closure implements `{}`, not `{}`", found_kind, kind), - ); - err.span_label( - obligation.cause.span, - format!("the requirement to implement `{}` derives from here", kind), - ); + expected: kind, + found: found_kind, + cause_span: obligation.cause.span, + fn_once_label: None, + fn_mut_label: None, + }; // Additional context information explaining why the closure only implements // a particular trait. @@ -3153,30 +3138,22 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { (ty::ClosureKind::FnOnce, Some((span, place))) => { - err.span_label( - *span, - format!( - "closure is `FnOnce` because it moves the \ - variable `{}` out of its environment", - ty::place_to_string_for_capture(self.tcx, place) - ), - ); + err.fn_once_label = Some(ClosureFnOnceLabel { + span: *span, + place: ty::place_to_string_for_capture(self.tcx, &place), + }) } (ty::ClosureKind::FnMut, Some((span, place))) => { - err.span_label( - *span, - format!( - "closure is `FnMut` because it mutates the \ - variable `{}` here", - ty::place_to_string_for_capture(self.tcx, place) - ), - ); + err.fn_mut_label = Some(ClosureFnMutLabel { + span: *span, + place: ty::place_to_string_for_capture(self.tcx, &place), + }) } _ => {} } } - err + self.tcx.sess.create_err(err) } fn report_type_parameter_mismatch_cyclic_type_error( @@ -3273,7 +3250,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut not_tupled = false; - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { + let found = match found_trait_ref.skip_binder().args.type_at(1).kind() { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], _ => { not_tupled = true; @@ -3281,7 +3258,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; - let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); + let expected_ty = expected_trait_ref.skip_binder().args.type_at(1); let expected = match expected_ty.kind() { ty::Tuple(ref tys) => { tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() @@ -3371,8 +3348,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let const_span = self.tcx.def_span(uv.def); match self.tcx.sess.source_map().span_to_snippet(const_span) { Ok(snippet) => err.help(format!( - "try adding a `where` bound using this expression: `where [(); {}]:`", - snippet + "try adding a `where` bound using this expression: `where [(); {snippet}]:`" )), _ => err.help("consider adding a `where` bound using this expression"), }; @@ -3554,7 +3530,7 @@ pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: & .1 .expect("proof tree should have been generated"); let mut lock = std::io::stdout().lock(); - let _ = lock.write_fmt(format_args!("{tree:?}")); + let _ = lock.write_fmt(format_args!("{tree:?}\n")); let _ = lock.flush(); }); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index b16d2eb5f..0e73bad19 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -25,7 +25,7 @@ pub trait TypeErrCtxtExt<'tcx> { &self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, - ) -> Option<(DefId, SubstsRef<'tcx>)>; + ) -> Option<(DefId, GenericArgsRef<'tcx>)>; /*private*/ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>; @@ -56,7 +56,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, - ) -> Option<(DefId, SubstsRef<'tcx>)> { + ) -> Option<(DefId, GenericArgsRef<'tcx>)> { let tcx = self.tcx; let param_env = obligation.param_env; let trait_ref = self.instantiate_binder_with_placeholders(trait_ref); @@ -66,26 +66,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut fuzzy_match_impls = vec![]; self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { - let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); - let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); + let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id); + let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args); let impl_self_ty = impl_trait_ref.self_ty(); if self.can_eq(param_env, trait_self_ty, impl_self_ty) { - self_match_impls.push((def_id, impl_substs)); + self_match_impls.push((def_id, impl_args)); - if iter::zip( - trait_ref.substs.types().skip(1), - impl_trait_ref.substs.types().skip(1), - ) - .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) + if iter::zip(trait_ref.args.types().skip(1), impl_trait_ref.args.types().skip(1)) + .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) { - fuzzy_match_impls.push((def_id, impl_substs)); + fuzzy_match_impls.push((def_id, impl_args)); } } }); - let impl_def_id_and_substs = if self_match_impls.len() == 1 { + let impl_def_id_and_args = if self_match_impls.len() == 1 { self_match_impls[0] } else if fuzzy_match_impls.len() == 1 { fuzzy_match_impls[0] @@ -93,8 +90,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return None; }; - tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented) - .then_some(impl_def_id_and_substs) + tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented) + .then_some(impl_def_id_and_args) } /// Used to set on_unimplemented's `ItemContext` @@ -143,9 +140,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> OnUnimplementedNote { - let (def_id, substs) = self + let (def_id, args) = self .impl_similar_to(trait_ref, obligation) - .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); + .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().args)); let trait_ref = trait_ref.skip_binder(); let mut flags = vec![]; @@ -173,7 +170,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); + flags.push((sym::from_desugaring, Some(format!("{k:?}")))); } if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { @@ -192,14 +189,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // signature with no type arguments resolved flags.push(( sym::_Self, - Some(self.tcx.type_of(def.did()).subst_identity().to_string()), + Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), )); } for param in generics.params.iter() { let value = match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - substs[param.index as usize].to_string() + args[param.index as usize].to_string() } GenericParamDefKind::Lifetime => continue, }; @@ -207,13 +204,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((name, Some(value))); if let GenericParamDefKind::Type { .. } = param.kind { - let param_ty = substs[param.index as usize].expect_ty(); + let param_ty = args[param.index as usize].expect_ty(); if let Some(def) = param_ty.ty_adt_def() { // We also want to be able to select the parameter's // original signature with no type arguments resolved flags.push(( name, - Some(self.tcx.type_of(def.did()).subst_identity().to_string()), + Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), )); } } @@ -249,7 +246,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // signature with no type arguments resolved flags.push(( sym::_Self, - Some(format!("[{}]", self.tcx.type_of(def.did()).subst_identity())), + Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())), )); } if aty.is_integral() { @@ -261,14 +258,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_string()))); let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx)); - flags.push((sym::_Self, Some(format!("[{}; _]", aty)))); + flags.push((sym::_Self, Some(format!("[{aty}; _]")))); if let Some(n) = len { - flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n)))); + flags.push((sym::_Self, Some(format!("[{aty}; {n}]")))); } if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the array's type's original // signature with no type arguments resolved - let def_ty = self.tcx.type_of(def.did()).subst_identity(); + let def_ty = self.tcx.type_of(def.did()).instantiate_identity(); flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); if let Some(n) = len { flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); @@ -332,18 +329,13 @@ pub struct OnUnimplementedNote { } /// Append a message for `~const Trait` errors. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub enum AppendConstMessage { + #[default] Default, Custom(Symbol), } -impl Default for AppendConstMessage { - fn default() -> Self { - AppendConstMessage::Default - } -} - impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -587,7 +579,7 @@ impl<'tcx> OnUnimplementedFormatString { "there is no parameter `{}` on {}", s, if trait_def_id == item_def_id { - format!("trait `{}`", trait_name) + format!("trait `{trait_name}`") } else { "impl".to_string() } @@ -629,7 +621,7 @@ impl<'tcx> OnUnimplementedFormatString { .filter_map(|param| { let value = match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - trait_ref.substs[param.index as usize].to_string() + trait_ref.args[param.index as usize].to_string() } GenericParamDefKind::Lifetime => return None, }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9ac1ba027..611ec6b00 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -5,6 +5,7 @@ use super::{ PredicateObligation, }; +use crate::errors; use crate::infer::InferCtxt; use crate::traits::{NormalizeExt, ObligationCtxt}; @@ -30,7 +31,7 @@ use rustc_middle::hir::map; use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, GenericArgs, InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; @@ -40,7 +41,6 @@ use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::borrow::Cow; use std::iter; -use std::ops::Deref; use super::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; @@ -398,9 +398,10 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>; - fn maybe_suggest_convert_to_slice( + fn suggest_convert_to_slice( &self, err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], span: Span, @@ -435,7 +436,7 @@ fn suggest_restriction<'tcx>( ) { if hir_generics.where_clause_span.from_expansion() || hir_generics.where_clause_span.desugaring_kind().is_some() - || projection.is_some_and(|projection| tcx.opt_rpitit_info(projection.def_id).is_some()) + || projection.is_some_and(|projection| tcx.is_impl_trait_in_trait(projection.def_id)) { return; } @@ -479,13 +480,13 @@ fn suggest_restriction<'tcx>( .visit_ty(input); } // The type param `T: Trait` we will suggest to introduce. - let type_param = format!("{}: {}", type_param_name, bound_str); + let type_param = format!("{type_param_name}: {bound_str}"); let mut sugg = vec![ if let Some(span) = hir_generics.span_for_param_suggestion() { - (span, format!(", {}", type_param)) + (span, format!(", {type_param}")) } else { - (hir_generics.span, format!("<{}>", type_param)) + (hir_generics.span, format!("<{type_param}>")) }, // `fn foo(t: impl Trait)` // ^ suggest `where <T as Trait>::A: Bound` @@ -530,7 +531,7 @@ fn suggest_restriction<'tcx>( err.span_suggestion_verbose( sp, - format!("consider further restricting {}", msg), + format!("consider further restricting {msg}"), suggestion, Applicability::MachineApplicable, ); @@ -654,6 +655,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. @@ -670,7 +672,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // this that we do in `suggest_restriction` and pull the // `impl Trait` into a new generic if it shows up somewhere // else in the predicate. - if !trait_pred.skip_binder().trait_ref.substs[1..] + if !trait_pred.skip_binder().trait_ref.args[1..] .iter() .all(|g| g.is_suggestable(self.tcx, false)) { @@ -693,7 +695,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { term ); } else { - constraint.push_str(&format!("<{} = {}>", name, term)); + constraint.push_str(&format!("<{name} = {term}>")); } } @@ -719,6 +721,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. @@ -752,14 +755,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It only make sense when suggesting dereferences for arguments - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = obligation.cause.code() - else { return false; }; - let Some(typeck_results) = &self.typeck_results - else { return false; }; - let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) - else { return false; }; - let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) - else { return false; }; + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = + obligation.cause.code() + else { + return false; + }; + let Some(typeck_results) = &self.typeck_results else { + return false; + }; + let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) else { + return false; + }; + let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) else { + return false; + }; let span = obligation.cause.span; let mut real_trait_pred = trait_pred; @@ -770,18 +779,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { real_trait_pred = parent_trait_pred; } - let real_ty = real_trait_pred.self_ty(); // We `erase_late_bound_regions` here because `make_subregion` does not handle // `ReLateBound`, and we don't particularly care about the regions. - if !self.can_eq( - obligation.param_env, - self.tcx.erase_late_bound_regions(real_ty), - arg_ty, - ) { + let real_ty = self.tcx.erase_late_bound_regions(real_trait_pred.self_ty()); + if !self.can_eq(obligation.param_env, real_ty, arg_ty) { continue; } - if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() { + if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { let autoderef = (self.autoderef_steps)(base_ty); if let Some(steps) = autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| { @@ -933,11 +938,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.self_ty(), ); - let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( - obligation.cause.body_id, - obligation.param_env, - self_ty, - ) else { return false; }; + let Some((def_id_or_name, output, inputs)) = + self.extract_callable_info(obligation.cause.body_id, obligation.param_env, self_ty) + else { + return false; + }; // Remapping bound vars here let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output)); @@ -1012,7 +1017,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let name = self.tcx.def_path_str(def_id); err.span_label( self.tcx.def_span(def_id), - format!("consider calling the constructor for `{}`", name), + format!("consider calling the constructor for `{name}`"), ); name } @@ -1035,26 +1040,40 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.remove_mark(); } let mut expr_finder = FindExprBySpan::new(span); - let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { + return; + }; let body = self.tcx.hir().body(body_id); expr_finder.visit_expr(body.value); - let Some(expr) = expr_finder.result else { return; }; - let Some(typeck) = &self.typeck_results else { return; }; - let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; + let Some(expr) = expr_finder.result else { + return; + }; + let Some(typeck) = &self.typeck_results else { + return; + }; + let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { + return; + }; if !ty.is_unit() { return; }; - let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; - let hir::def::Res::Local(hir_id) = path.res else { return; }; + let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { + return; + }; + let hir::def::Res::Local(hir_id) = path.res else { + return; + }; let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { return; }; - let Some(hir::Node::Local(hir::Local { - ty: None, - init: Some(init), - .. - })) = self.tcx.hir().find_parent(pat.hir_id) else { return; }; - let hir::ExprKind::Block(block, None) = init.kind else { return; }; + let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = + self.tcx.hir().find_parent(pat.hir_id) + else { + return; + }; + let hir::ExprKind::Block(block, None) = init.kind else { + return; + }; if block.expr.is_some() { return; } @@ -1062,7 +1081,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_label(block.span, "this empty block is missing a tail expression"); return; }; - let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; }; + let hir::StmtKind::Semi(tail_expr) = stmt.kind else { + return; + }; let Some(ty) = typeck.expr_ty_opt(tail_expr) else { err.span_label(block.span, "this block is missing a tail expression"); return; @@ -1092,12 +1113,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let ty = self.instantiate_binder_with_placeholders(self_ty); - let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false }; + let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { + return false; + }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; let ty::Param(param) = inner_ty.kind() else { return false }; - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false }; + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + else { + return false; + }; let arg_node = self.tcx.hir().get(*arg_hir_id); - let Node::Expr(Expr { kind: hir::ExprKind::Path(_), ..}) = arg_node else { return false }; + let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false }; let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); let has_clone = |ty| { @@ -1143,24 +1170,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { // Autoderef is useful here because sometimes we box callables, etc. - let Some((def_id_or_name, output, inputs)) = (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| { - match *found.kind() { - ty::FnPtr(fn_sig) => - Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())), - ty::FnDef(def_id, _) => { - let fn_sig = found.fn_sig(self.tcx); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) - } - ty::Closure(def_id, substs) => { - let fn_sig = substs.as_closure().sig(); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() + let Some((def_id_or_name, output, inputs)) = + (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| { + match *found.kind() { + ty::FnPtr(fn_sig) => Some(( + DefIdOrName::Name("function pointer"), + fn_sig.output(), + fn_sig.inputs(), + )), + ty::FnDef(def_id, _) => { + let fn_sig = found.fn_sig(self.tcx); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) + } + ty::Closure(def_id, args) => { + let fn_sig = args.as_closure().sig(); + Some(( + DefIdOrName::DefId(def_id), + fn_sig.output(), + fn_sig.inputs().map_bound(|inputs| &inputs[1..]), + )) + } + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { + self.tcx.item_bounds(def_id).instantiate(self.tcx, args).iter().find_map( + |pred| { + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + // args tuple will always be args[1] + && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind() { Some(( DefIdOrName::DefId(def_id), @@ -1170,14 +1206,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } else { None } - }) - } - ty::Dynamic(data, _, ty::Dyn) => { - data.iter().find_map(|pred| { - if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() + }, + ) + } + ty::Dynamic(data, _, ty::Dyn) => { + data.iter().find_map(|pred| { + if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() - // for existential projection, substs are shifted over by 1 - && let ty::Tuple(args) = proj.substs.type_at(0).kind() + // for existential projection, args are shifted over by 1 + && let ty::Tuple(args) = proj.args.type_at(0).kind() { Some(( DefIdOrName::Name("trait object"), @@ -1187,11 +1224,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } else { None } - }) - } - ty::Param(param) => { - let generics = self.tcx.generics_of(body_id); - let name = if generics.count() > param.index as usize + }) + } + ty::Param(param) => { + let generics = self.tcx.generics_of(body_id); + let name = if generics.count() > param.index as usize && let def = generics.param_at(param.index as usize, self.tcx) && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) && def.name == param.name @@ -1200,12 +1237,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } else { DefIdOrName::Name("type parameter") }; - param_env.caller_bounds().iter().find_map(|pred| { - if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() + param_env.caller_bounds().iter().find_map(|pred| { + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() && proj.projection_ty.self_ty() == found - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + // args tuple will always be args[1] + && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind() { Some(( name, @@ -1215,11 +1252,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } else { None } - }) + }) + } + _ => None, } - _ => None, - } - }) else { return None; }; + }) + else { + return None; + }; let output = self.instantiate_binder_with_fresh_vars( DUMMY_SP, @@ -1356,7 +1396,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Because of this, we modify the error to refer to the original obligation and // return early in the caller. - let msg = format!("the trait bound `{}` is not satisfied", old_pred); + let msg = format!("the trait bound `{old_pred}` is not satisfied"); if has_custom_message { err.note(msg); } else { @@ -1389,30 +1429,34 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Issue #109436, we need to add parentheses properly for method calls // for example, `foo.into()` should be `(&foo).into()` - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet( - self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)), - ) { - if snippet == "." { - err.multipart_suggestion_verbose( - sugg_msg, - vec![ - (span.shrink_to_lo(), format!("({}", sugg_prefix)), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - return true; - } + if let Some(_) = + self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)) + { + err.multipart_suggestion_verbose( + sugg_msg, + vec![ + (span.shrink_to_lo(), format!("({sugg_prefix}")), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; } // Issue #104961, we need to add parentheses properly for compound expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` - let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; + let Some(body_id) = + self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) + else { + return false; + }; let body = self.tcx.hir().body(body_id); let mut expr_finder = FindExprBySpan::new(span); expr_finder.visit_expr(body.value); - let Some(expr) = expr_finder.result else { return false; }; + let Some(expr) = expr_finder.result else { + return false; + }; let needs_parens = match expr.kind { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, @@ -1423,10 +1467,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let span = if needs_parens { span } else { span.shrink_to_lo() }; let suggestions = if !needs_parens { - vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))] + vec![(span.shrink_to_lo(), sugg_prefix)] } else { vec![ - (span.shrink_to_lo(), format!("{}(", sugg_prefix)), + (span.shrink_to_lo(), format!("{sugg_prefix}(")), (span.shrink_to_hi(), ")".to_string()), ] }; @@ -1463,8 +1507,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) { - let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; }; - let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; + let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { + return; + }; + let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { + return; + }; let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { @@ -1566,7 +1614,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`. - let Some(mut expr) = expr_finder.result else { return false; }; + let Some(mut expr) = expr_finder.result else { + return false; + }; let mut count = 0; let mut suggestions = vec![]; // Skipping binder here, remapping below @@ -1646,13 +1696,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let Some(typeck_results) = &self.typeck_results && let ty = typeck_results.expr_ty_adjusted(base) - && let ty::FnDef(def_id, _substs) = ty.kind() + && let ty::FnDef(def_id, _args) = ty.kind() && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = hir.get_if_local(*def_id) { let msg = format!( - "alternatively, consider making `fn {}` asynchronous", - ident + "alternatively, consider making `fn {ident}` asynchronous" ); if vis_span.is_empty() { err.span_suggestion_verbose( @@ -1798,7 +1847,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { let hir = self.tcx.hir(); - let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find_by_def_id(obligation.cause.body_id) else { + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = + hir.find_by_def_id(obligation.cause.body_id) + else { return None; }; @@ -1901,10 +1952,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // don't print out the [type error] here err.delay_as_bug(); } else { - err.span_label( - expr.span, - format!("this returned value is of type `{}`", ty), - ); + err.span_label(expr.span, format!("this returned value is of type `{ty}`")); } } } @@ -1925,7 +1973,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { infcx: &InferCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { - let inputs = trait_ref.skip_binder().substs.type_at(1); + let inputs = trait_ref.skip_binder().args.type_at(1); let sig = match inputs.kind() { ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id()) => { infcx.tcx.mk_fn_sig( @@ -2006,12 +2054,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { let expected_self = self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty())); - let expected_substs = self + let expected_args = self .tcx - .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.substs)); + .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args)); // Find another predicate whose self-type is equal to the expected self type, - // but whose substs don't match. + // but whose args don't match. let other_pred = predicates.into_iter() .enumerate() .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { @@ -2024,10 +2072,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { == self.tcx.anonymize_bound_vars( pred.kind().rebind(trait_pred.self_ty()), ) - // But the substs don't match (i.e. incompatible args) - && expected_substs + // But the args don't match (i.e. incompatible args) + && expected_args != self.tcx.anonymize_bound_vars( - pred.kind().rebind(trait_pred.trait_ref.substs), + pred.kind().rebind(trait_pred.trait_ref.args), ) => { true @@ -2222,7 +2270,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Only continue if a generator was found. debug!(?generator, ?trait_ref, ?target_ty); - let (Some(generator_did), Some(trait_ref), Some(target_ty)) = (generator, trait_ref, target_ty) else { + let (Some(generator_did), Some(trait_ref), Some(target_ty)) = + (generator, trait_ref, target_ty) + else { return false; }; @@ -2403,8 +2453,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.clear_code(); err.set_primary_message(format!( - "{} cannot be {} between threads safely", - future_or_generator, trait_verb + "{future_or_generator} cannot be {trait_verb} between threads safely" )); let original_span = err.span.primary_span().unwrap(); @@ -2413,7 +2462,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let message = outer_generator .and_then(|generator_did| { Some(match self.tcx.generator_kind(generator_did).unwrap() { - GeneratorKind::Gen => format!("generator is not {}", trait_name), + GeneratorKind::Gen => format!("generator is not {trait_name}"), GeneratorKind::Async(AsyncGeneratorKind::Fn) => self .tcx .parent(generator_did) @@ -2421,73 +2470,73 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) .map(|name| { - format!("future returned by `{}` is not {}", name, trait_name) + format!("future returned by `{name}` is not {trait_name}") })?, GeneratorKind::Async(AsyncGeneratorKind::Block) => { - format!("future created by async block is not {}", trait_name) + format!("future created by async block is not {trait_name}") } GeneratorKind::Async(AsyncGeneratorKind::Closure) => { - format!("future created by async closure is not {}", trait_name) + format!("future created by async closure is not {trait_name}") } }) }) - .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name)); + .unwrap_or_else(|| format!("{future_or_generator} is not {trait_name}")); span.push_span_label(original_span, message); err.set_span(span); - format!("is not {}", trait_name) + format!("is not {trait_name}") } else { format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path()) }; - let mut explain_yield = - |interior_span: Span, yield_span: Span, scope_span: Option<Span>| { - let mut span = MultiSpan::from_span(yield_span); - let snippet = match source_map.span_to_snippet(interior_span) { - // #70935: If snippet contains newlines, display "the value" instead - // so that we do not emit complex diagnostics. - Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet), - _ => "the value".to_string(), - }; - // note: future is not `Send` as this value is used across an await - // --> $DIR/issue-70935-complex-spans.rs:13:9 - // | - // LL | baz(|| async { - // | ______________- - // | | - // | | - // LL | | foo(tx.clone()); - // LL | | }).await; - // | | - ^^^^^^ await occurs here, with value maybe used later - // | |__________| - // | has type `closure` which is not `Send` - // note: value is later dropped here - // LL | | }).await; - // | | ^ - // - span.push_span_label( - yield_span, - format!("{} occurs here, with {} maybe used later", await_or_yield, snippet), - ); - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - if let Some(scope_span) = scope_span { - let scope_span = source_map.end_point(scope_span); + let mut explain_yield = |interior_span: Span, + yield_span: Span, + scope_span: Option<Span>| { + let mut span = MultiSpan::from_span(yield_span); + let snippet = match source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + Ok(snippet) if !snippet.contains('\n') => format!("`{snippet}`"), + _ => "the value".to_string(), + }; + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | baz(|| async { + // | ______________- + // | | + // | | + // LL | | foo(tx.clone()); + // LL | | }).await; + // | | - ^^^^^^ await occurs here, with value maybe used later + // | |__________| + // | has type `closure` which is not `Send` + // note: value is later dropped here + // LL | | }).await; + // | | ^ + // + span.push_span_label( + yield_span, + format!("{await_or_yield} occurs here, with {snippet} maybe used later"), + ); + span.push_span_label( + interior_span, + format!("has type `{target_ty}` which {trait_explanation}"), + ); + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); - let msg = format!("{} is later dropped here", snippet); - span.push_span_label(scope_span, msg); - } - err.span_note( + let msg = format!("{snippet} is later dropped here"); + span.push_span_label(scope_span, msg); + } + err.span_note( span, format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield + "{future_or_generator} {trait_explanation} as this value is used across {an_await_or_yield}" ), ); - }; + }; match interior_or_upvar_span { GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { @@ -2497,15 +2546,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.push_span_label( await_span, format!( - "await occurs here on type `{}`, which {}", - target_ty, trait_explanation + "await occurs here on type `{target_ty}`, which {trait_explanation}" ), ); err.span_note( span, format!( - "future {not_trait} as it awaits another future which {not_trait}", - not_trait = trait_explanation + "future {trait_explanation} as it awaits another future which {trait_explanation}" ), ); } else { @@ -2588,18 +2635,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ref_kind = if is_mut { "&mut" } else { "&" }; ( format!( - "has type `{}` which {}, because `{}` is not `{}`", - target_ty, trait_explanation, ref_ty, ref_ty_trait + "has type `{target_ty}` which {trait_explanation}, because `{ref_ty}` is not `{ref_ty_trait}`" ), format!( - "captured value {} because `{}` references cannot be sent unless their referent is `{}`", - trait_explanation, ref_kind, ref_ty_trait + "captured value {trait_explanation} because `{ref_kind}` references cannot be sent unless their referent is `{ref_ty_trait}`" ), ) } None => ( - format!("has type `{}` which {}", target_ty, trait_explanation), - format!("captured value {}", trait_explanation), + format!("has type `{target_ty}` which {trait_explanation}"), + format!("captured value {trait_explanation}"), ), }; @@ -2655,7 +2700,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark @@ -2688,8 +2733,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::ObjectTypeBound(object_ty, region) => { err.note(format!( - "required so that the lifetime bound of `{}` for `{}` is satisfied", - region, object_ty, + "required so that the lifetime bound of `{region}` for `{object_ty}` is satisfied", )); } ObligationCauseCode::ItemObligation(_) @@ -2743,7 +2787,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // implement this trait and list them. err.note(format!( "`{short_item_name}` is a \"sealed trait\", because to implement \ - it you also need to implelement `{}`, which is not accessible; \ + it you also need to implement `{}`, which is not accessible; \ this is usually done to force you to use one of the provided \ types that already implement it", with_no_trimmed_paths!(tcx.def_path_str(def_id)), @@ -2808,7 +2852,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all local variables must have a statically known size"); } Some(Node::Local(hir::Local { - init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), + init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }), .. })) => { // When encountering an assignment of an unsized trait, like @@ -3009,11 +3053,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut msg = "required because it captures the following types: ".to_owned(); for ty in bound_tys.skip_binder() { - with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap()); + with_forced_trimmed_paths!(write!(msg, "`{ty}`, ").unwrap()); } err.note(msg.trim_end_matches(", ").to_string()) } - ty::GeneratorWitnessMIR(def_id, substs) => { + ty::GeneratorWitnessMIR(def_id, args) => { use std::fmt::Write; // FIXME: this is kind of an unusual format for rustc, can we make it more clear? @@ -3022,8 +3066,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut msg = "required because it captures the following types: ".to_owned(); for bty in tcx.generator_hidden_types(*def_id) { - let ty = bty.subst(tcx, substs); - write!(msg, "`{}`, ", ty).unwrap(); + let ty = bty.instantiate(tcx, args); + write!(msg, "`{ty}`, ").unwrap(); } err.note(msg.trim_end_matches(", ").to_string()) } @@ -3082,7 +3126,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::ImplDerivedObligation(ref data) => { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); - parent_trait_pred.remap_constness_diag(param_env); let parent_def_id = parent_trait_pred.def_id(); let (self_ty, file) = self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); @@ -3350,7 +3393,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Ty::new_projection( self.tcx, item_def_id, - // Future::Output has no substs + // Future::Output has no args [trait_pred.self_ty()], ) }); @@ -3391,7 +3434,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => return, }; if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind() - && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind() + && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().args.type_at(1).kind() { err.span_suggestion_verbose( rhs_span.shrink_to_hi(), @@ -3411,15 +3454,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { return; }; - let (adt, substs) = match trait_pred.skip_binder().self_ty().kind() { - ty::Adt(adt, substs) if adt.did().is_local() => (adt, substs), + let (adt, args) = match trait_pred.skip_binder().self_ty().kind() { + ty::Adt(adt, args) if adt.did().is_local() => (adt, args), _ => return, }; let can_derive = { let is_derivable_trait = match diagnostic_name { sym::Default => !adt.is_enum(), sym::PartialEq | sym::PartialOrd => { - let rhs_ty = trait_pred.skip_binder().trait_ref.substs.type_at(1); + let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); trait_pred.skip_binder().self_ty() == rhs_ty } sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, @@ -3428,8 +3471,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { is_derivable_trait && // Ensure all fields impl the trait. adt.all_fields().all(|field| { - let field_ty = field.ty(self.tcx, substs); - let trait_substs = match diagnostic_name { + let field_ty = field.ty(self.tcx, args); + let trait_args = match diagnostic_name { sym::PartialEq | sym::PartialOrd => { Some(field_ty) } @@ -3438,7 +3481,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { trait_ref: ty::TraitRef::new(self.tcx, trait_pred.def_id(), - [field_ty].into_iter().chain(trait_substs), + [field_ty].into_iter().chain(trait_args), ), ..*tr }); @@ -3459,7 +3502,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.skip_binder().self_ty(), diagnostic_name, ), - format!("#[derive({})]\n", diagnostic_name), + format!("#[derive({diagnostic_name})]\n"), Applicability::MaybeIncorrect, ); } @@ -3473,7 +3516,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) { if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) - && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.substs.type_at(1).kind() + && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind() && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() { @@ -3522,9 +3565,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // to an associated type (as seen from `trait_pred`) in the predicate. Like in // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>` let mut type_diffs = vec![]; - if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref() - && let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id) - && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs) + if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code + && let Some(node_args) = typeck_results.node_args_opt(call_hir_id) + && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args) && let Some(where_pred) = where_clauses.predicates.get(*idx) { if let Some(where_pred) = where_pred.as_trait_clause() @@ -3538,7 +3581,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); let zipped = - iter::zip(where_pred.trait_ref.substs, failed_pred.trait_ref.substs); + iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); for (expected, actual) in zipped { self.probe(|_| { match self @@ -3617,7 +3660,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let Some(typeck_results) = self.typeck_results.as_ref() else { return }; // Make sure we're dealing with the `Option` type. - let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { return }; + let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { + return; + }; if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) { return; } @@ -3627,7 +3672,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. })) = failed_pred.kind().skip_binder() && tcx.is_fn_trait(trait_ref.def_id) - && let [self_ty, found_ty] = trait_ref.substs.as_slice() + && let [self_ty, found_ty] = trait_ref.args.as_slice() && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn()) && let fn_sig @ ty::FnSig { abi: abi::Abi::Rust, @@ -3647,7 +3692,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Extract `<U as Deref>::Target` assoc type and check that it is `T` && let Some(deref_target_did) = tcx.lang_items().deref_target() - && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)])) + && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_args(&[ty::GenericArg::from(found_ty)])) && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection) && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation)) && infcx.can_eq(param_env, deref_target, target_ty) @@ -3749,11 +3794,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { while let Some(assocs_in_method) = assocs.next() { let Some(prev_assoc_in_method) = assocs.peek() else { for entry in assocs_in_method { - let Some((span, (assoc, ty))) = entry else { continue; }; - if primary_spans.is_empty() || type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { return false; }; - self.can_eq(param_env, expected_found.found, ty) - }) { + let Some((span, (assoc, ty))) = entry else { + continue; + }; + if primary_spans.is_empty() + || type_diffs.iter().any(|diff| { + let Sorts(expected_found) = diff else { + return false; + }; + self.can_eq(param_env, expected_found.found, ty) + }) + { // FIXME: this doesn't quite work for `Iterator::collect` // because we have `Vec<i32>` and `()`, but we'd want `i32` // to point at the `.into_iter()` call, but as long as we @@ -3781,7 +3832,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); if !self.can_eq(param_env, ty, *prev_ty) { if type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { return false; }; + let Sorts(expected_found) = diff else { + return false; + }; self.can_eq(param_env, expected_found.found, ty) }) { primary_spans.push(span); @@ -3829,15 +3882,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ocx = ObligationCtxt::new(self.infcx); let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); for diff in type_diffs { - let Sorts(expected_found) = diff else { continue; }; - let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; }; + let Sorts(expected_found) = diff else { + continue; + }; + let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { + continue; + }; let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; let trait_def_id = proj.trait_def_id(self.tcx); // Make `Self` be equivalent to the type of the call chain // expression we're looking at now, so that we can tell what // for example `Iterator::Item` is at this point in the chain. - let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { + let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { ty::GenericParamDefKind::Type { .. } => { if param.index == 0 { @@ -3855,7 +3912,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // This corresponds to `<ExprTy as Iterator>::Item = _`. let projection = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs), + projection_ty: self.tcx.mk_alias_ty(proj.def_id, args), term: ty_var.into(), }), )); @@ -3886,13 +3943,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// If the type that failed selection is an array or a reference to an array, /// but the trait is implemented for slices, suggest that the user converts /// the array into a slice. - fn maybe_suggest_convert_to_slice( + fn suggest_convert_to_slice( &self, err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { + // We can only suggest the slice coersion for function and binary operation arguments, + // since the suggestion would make no sense in turbofish or call + let (ObligationCauseCode::BinOp { .. } + | ObligationCauseCode::FunctionArgumentObligation { .. }) = obligation.cause.code() + else { + return; + }; + // Three cases where we can make a suggestion: // 1. `[T; _]` (array of T) // 2. `&[T; _]` (reference to array of T) @@ -3931,7 +3997,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|trait_ref| trait_ref.trait_ref.self_ty()) .find(|t| is_slice(*t)) { - let msg = format!("convert the array to a `{}` slice instead", slice_ty); + let msg = format!("convert the array to a `{slice_ty}` slice instead"); if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let mut suggestions = vec![]; @@ -3960,6 +4026,10 @@ fn hint_missing_borrow<'tcx>( found_node: Node<'_>, err: &mut Diagnostic, ) { + if matches!(found_node, Node::TraitItem(..)) { + return; + } + let found_args = match found.kind() { ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), kind => { @@ -3974,7 +4044,9 @@ fn hint_missing_borrow<'tcx>( }; // This could be a variant constructor, for example. - let Some(fn_decl) = found_node.fn_decl() else { return; }; + let Some(fn_decl) = found_node.fn_decl() else { + return; + }; let args = fn_decl.inputs.iter(); @@ -4029,19 +4101,11 @@ fn hint_missing_borrow<'tcx>( } if !to_borrow.is_empty() { - err.multipart_suggestion_verbose( - "consider borrowing the argument", - to_borrow, - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow }); } if !remove_borrow.is_empty() { - err.multipart_suggestion_verbose( - "do not borrow the argument", - remove_borrow, - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow }); } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index cf9d9315f..3ebf1246a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -8,7 +8,7 @@ use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt}; use std::marker::PhantomData; @@ -410,8 +410,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { - match self.selcx.infcx.closure_kind(closure_substs) { + ty::PredicateKind::ClosureKind(_, closure_args, kind) => { + match self.selcx.infcx.closure_kind(closure_args) { Some(closure_kind) => { if closure_kind.extends(kind) { ProcessResult::Changed(vec![]) @@ -536,7 +536,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(DefineOpaqueTypes::No, a.substs, b.substs) + .eq(DefineOpaqueTypes::No, a.args, b.args) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), @@ -559,31 +559,30 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let stalled_on = &mut pending_obligation.stalled_on; - let mut evaluate = |c: Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match self.selcx.infcx.try_const_eval_resolve( - obligation.param_env, - unevaluated, - c.ty(), - Some(obligation.cause.span), - ) { - Ok(val) => Ok(val), - Err(e) => match e { - ErrorHandled::TooGeneric => { - stalled_on.extend( - unevaluated.substs.iter().filter_map( + let mut evaluate = + |c: Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { + match self.selcx.infcx.try_const_eval_resolve( + obligation.param_env, + unevaluated, + c.ty(), + Some(obligation.cause.span), + ) { + Ok(val) => Ok(val), + Err(e) => match e { + ErrorHandled::TooGeneric => { + stalled_on.extend(unevaluated.args.iter().filter_map( TyOrConstInferVar::maybe_from_generic_arg, - ), - ); - Err(ErrorHandled::TooGeneric) - } - _ => Err(e), - }, + )); + Err(ErrorHandled::TooGeneric) + } + _ => Err(e), + }, + } + } else { + Ok(c) } - } else { - Ok(c) - } - }; + }; match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { @@ -671,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx; - if obligation.predicate.is_global() { + if obligation.predicate.is_global() && !self.selcx.is_intercrate() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { @@ -696,9 +695,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { // trait selection is because we don't have enough // information about the types in the trait. stalled_on.clear(); - stalled_on.extend(substs_infer_vars( + stalled_on.extend(args_infer_vars( &self.selcx, - trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), + trait_obligation.predicate.map_bound(|pred| pred.trait_ref.args), )); debug!( @@ -725,7 +724,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let tcx = self.selcx.tcx(); - if obligation.predicate.is_global() { + if obligation.predicate.is_global() && !self.selcx.is_intercrate() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) { @@ -753,9 +752,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); - stalled_on.extend(substs_infer_vars( + stalled_on.extend(args_infer_vars( &self.selcx, - project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), + project_obligation.predicate.map_bound(|pred| pred.projection_ty.args), )); ProcessResult::Unchanged } @@ -770,14 +769,14 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } } -/// Returns the set of inference variables contained in `substs`. -fn substs_infer_vars<'a, 'tcx>( +/// Returns the set of inference variables contained in `args`. +fn args_infer_vars<'a, 'tcx>( selcx: &SelectionContext<'a, 'tcx>, - substs: ty::Binder<'tcx, SubstsRef<'tcx>>, + args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> { selcx .infcx - .resolve_vars_if_possible(substs) + .resolve_vars_if_possible(args) .skip_binder() // ok because this check doesn't care about regions .iter() .filter(|arg| arg.has_non_region_infer()) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index e9cfd63e2..ab07b10c6 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -43,7 +43,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( self_type: Ty<'tcx>, parent_cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { - let (adt, substs) = match self_type.kind() { + let (adt, args) = match self_type.kind() { // These types used to have a builtin impl. // Now libcore provides that impl. ty::Uint(_) @@ -56,7 +56,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( | ty::Ref(_, _, hir::Mutability::Not) | ty::Array(..) => return Ok(()), - &ty::Adt(adt, substs) => (adt, substs), + &ty::Adt(adt, args) => (adt, args), _ => return Err(CopyImplementationError::NotAnAdt), }; @@ -66,7 +66,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( param_env, self_type, adt, - substs, + args, parent_cause, hir::LangItem::Copy, ) @@ -91,7 +91,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( self_type: Ty<'tcx>, parent_cause: ObligationCause<'tcx>, ) -> Result<(), ConstParamTyImplementationError<'tcx>> { - let (adt, substs) = match self_type.kind() { + let (adt, args) = match self_type.kind() { // `core` provides these impls. ty::Uint(_) | ty::Int(_) @@ -103,7 +103,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( | ty::Ref(.., hir::Mutability::Not) | ty::Tuple(_) => return Ok(()), - &ty::Adt(adt, substs) => (adt, substs), + &ty::Adt(adt, args) => (adt, args), _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed), }; @@ -113,7 +113,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( param_env, self_type, adt, - substs, + args, parent_cause, hir::LangItem::ConstParamTy, ) @@ -128,7 +128,7 @@ pub fn all_fields_implement_trait<'tcx>( param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, adt: AdtDef<'tcx>, - substs: &'tcx List<GenericArg<'tcx>>, + args: &'tcx List<GenericArg<'tcx>>, parent_cause: ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { @@ -141,7 +141,7 @@ pub fn all_fields_implement_trait<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = traits::ObligationCtxt::new(&infcx); - let unnormalized_ty = field.ty(tcx, substs); + let unnormalized_ty = field.ty(tcx, args); if unnormalized_ty.references_error() { continue; } @@ -154,11 +154,11 @@ pub fn all_fields_implement_trait<'tcx>( // FIXME(compiler-errors): This gives us better spans for bad // projection types like in issue-50480. - // If the ADT has substs, point to the cause we are given. + // If the ADT has args, point to the cause we are given. // If it does not, then this field probably doesn't normalize // to begin with, and point to the bad field's span instead. let normalization_cause = if field - .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) + .ty(tcx, traits::GenericArgs::identity_for_item(tcx, adt.did())) .has_non_region_param() { parent_cause.clone() diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1af8323b6..d2210c6d5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -13,12 +13,12 @@ mod object_safety; pub mod outlives_bounds; pub mod project; pub mod query; -#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] +#[allow(hidden_glob_reexports)] mod select; mod specialize; mod structural_match; mod structural_normalize; -#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] +#[allow(hidden_glob_reexports)] mod util; pub mod vtable; pub mod wf; @@ -32,7 +32,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable}; -use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_span::def_id::DefId; use rustc_span::Span; @@ -61,13 +61,13 @@ pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{ - specialization_graph, translate_substs, translate_substs_with_cause, OverlapError, + specialization_graph, translate_args, translate_args_with_cause, OverlapError, }; pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{ - check_substs_compatible, supertrait_def_ids, supertraits, transitive_bounds, + check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, SupertraitDefIds, }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; @@ -133,7 +133,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( def_id: DefId, ) -> bool { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const()) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) } /// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? @@ -328,11 +328,7 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new( - tcx.mk_clauses(&predicates), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ); + let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -362,12 +358,9 @@ pub fn normalize_param_env_or_error<'tcx>( "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", predicates, outlives_predicates ); - let Ok(non_outlives_predicates) = do_normalize_predicates( - tcx, - cause.clone(), - elaborated_env, - predicates, - ) else { + let Ok(non_outlives_predicates) = + do_normalize_predicates(tcx, cause.clone(), elaborated_env, predicates) + else { // An unnormalized env is better than nothing. debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); return elaborated_env; @@ -379,17 +372,11 @@ pub fn normalize_param_env_or_error<'tcx>( // here. I believe they should not matter, because we are ignoring TypeOutlives param-env // predicates here anyway. Keeping them here anyway because it seems safer. let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned(); - let outlives_env = ty::ParamEnv::new( - tcx.mk_clauses_from_iter(outlives_env), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ); - let Ok(outlives_predicates) = do_normalize_predicates( - tcx, - cause, - outlives_env, - outlives_predicates, - ) else { + let outlives_env = + ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env), unnormalized_env.reveal()); + let Ok(outlives_predicates) = + do_normalize_predicates(tcx, cause, outlives_env, outlives_predicates) + else { // An unnormalized env is better than nothing. debug!("normalize_param_env_or_error: errored resolving outlives predicates"); return elaborated_env; @@ -399,11 +386,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.mk_clauses(&predicates), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ) + ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } /// Normalize a type and process all resulting obligations, returning any errors. @@ -460,7 +443,7 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause fn subst_and_check_impossible_predicates<'tcx>( tcx: TyCtxt<'tcx>, - key: (DefId, SubstsRef<'tcx>), + key: (DefId, GenericArgsRef<'tcx>), ) -> bool { debug!("subst_and_check_impossible_predicates(key={:?})", key); @@ -480,11 +463,14 @@ fn subst_and_check_impossible_predicates<'tcx>( result } -/// Checks whether a trait's method is impossible to call on a given impl. +/// Checks whether a trait's associated item is impossible to reference on a given impl. /// /// This only considers predicates that reference the impl's generics, and not /// those that reference the method's generics. -fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefId, DefId)) -> bool { +fn is_impossible_associated_item( + tcx: TyCtxt<'_>, + (impl_def_id, trait_item_def_id): (DefId, DefId), +) -> bool { struct ReferencesOnlyParentGenerics<'tcx> { tcx: TyCtxt<'tcx>, generics: &'tcx ty::Generics, @@ -527,7 +513,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI let impl_trait_ref = tcx .impl_trait_ref(impl_def_id) .expect("expected impl to correspond to trait") - .subst_identity(); + .instantiate_identity(); let param_env = tcx.param_env(impl_def_id); let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; @@ -537,7 +523,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI tcx, ObligationCause::dummy_with_span(*span), param_env, - ty::EarlyBinder::bind(*pred).subst(tcx, impl_trait_ref.substs), + ty::EarlyBinder::bind(*pred).instantiate(tcx, impl_trait_ref.args), ) }) }); @@ -562,7 +548,7 @@ pub fn provide(providers: &mut Providers) { specializes: specialize::specializes, subst_and_check_impossible_predicates, check_tys_might_be_eq: misc::check_tys_might_be_eq, - is_impossible_method, + is_impossible_associated_item, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c31944c16..5823b4508 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -17,10 +17,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; -use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; +use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; @@ -270,7 +270,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied()) + .flat_map(|item| tcx.explicit_item_bounds(item.def_id).instantiate_identity_iter_copied()) .filter_map(|c| predicate_references_self(tcx, c)) .collect() } @@ -284,7 +284,7 @@ fn predicate_references_self<'tcx>( match predicate.kind().skip_binder() { ty::ClauseKind::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp) + data.trait_ref.args[1..].iter().any(has_self_ty).then_some(sp) } ty::ClauseKind::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -302,7 +302,7 @@ fn predicate_references_self<'tcx>( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp) + data.projection_ty.args[1..].iter().any(has_self_ty).then_some(sp) } ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp), @@ -393,7 +393,7 @@ fn object_safety_violation_for_assoc_item( ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended && !tcx.generics_of(item.def_id).params.is_empty() - && item.opt_rpitit_info.is_none() + && !item.is_impl_trait_in_trait() { Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)) } else { @@ -414,7 +414,7 @@ fn virtual_call_violation_for_method<'tcx>( trait_def_id: DefId, method: ty::AssocItem, ) -> Option<MethodViolationCode> { - let sig = tcx.fn_sig(method.def_id).subst_identity(); + let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` if !method.fn_has_self_parameter { @@ -517,8 +517,7 @@ fn virtual_call_violation_for_method<'tcx>( tcx.sess.delay_span_bug( tcx.def_span(method.def_id), format!( - "receiver when `Self = ()` should have a Scalar ABI; found {:?}", - abi + "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}" ), ); } @@ -536,8 +535,7 @@ fn virtual_call_violation_for_method<'tcx>( tcx.sess.delay_span_bug( tcx.def_span(method.def_id), format!( - "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}", - trait_object_ty, abi + "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}" ), ); } @@ -576,7 +574,6 @@ fn virtual_call_violation_for_method<'tcx>( // implement auto traits if the underlying type does as well. if let ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: pred_trait_ref, - constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, }) = pred.kind().skip_binder() && pred_trait_ref.self_ty() == tcx.types.self_param @@ -586,7 +583,7 @@ fn virtual_call_violation_for_method<'tcx>( // allowed to have generic parameters so `auto trait Bound<T> {}` // would already have reported an error at the definition of the // auto trait. - if pred_trait_ref.substs.len() != 1 { + if pred_trait_ref.args.len() != 1 { tcx.sess.diagnostic().delay_span_bug( span, "auto traits cannot have generic parameters", @@ -612,11 +609,11 @@ fn receiver_for_self_ty<'tcx>( method_def_id: DefId, ) -> Ty<'tcx> { debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); - let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { + let args = GenericArgs::for_item(tcx, method_def_id, |param, _| { if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = EarlyBinder::bind(receiver_ty).subst(tcx, substs); + let result = EarlyBinder::bind(receiver_ty).instantiate(tcx, args); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result @@ -751,21 +748,17 @@ fn receiver_is_dispatchable<'tcx>( // U: Trait<Arg1, ..., ArgN> let trait_predicate = { let trait_def_id = method.trait_container(tcx).unwrap(); - let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| { + let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| { if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) } }); - ty::TraitRef::new(tcx, trait_def_id, substs).to_predicate(tcx) + ty::TraitRef::new(tcx, trait_def_id, args).to_predicate(tcx) }; let caller_bounds = param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); - ty::ParamEnv::new( - tcx.mk_clauses_from_iter(caller_bounds), - param_env.reveal(), - param_env.constness(), - ) + ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds), param_env.reveal()) }; // Receiver: DispatchFromDyn<Receiver[Self => U]> diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index ae6fc7cf8..32bbd626d 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -79,7 +79,8 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { &canonical_var_values, canonical_result, &mut constraints, - ) else { + ) + else { return vec![]; }; assert_eq!(&obligations, &[]); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a10bca31f..06a1027e5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1,10 +1,9 @@ //! Code for projecting associated types out of trait references. -use super::check_substs_compatible; +use super::check_args_compatible; use super::specialization_graph; -use super::translate_substs; +use super::translate_args; use super::util; -use super::ImplSourceUserDefinedData; use super::MismatchedProjectionTypes; use super::Obligation; use super::ObligationCause; @@ -13,6 +12,9 @@ use super::Selection; use super::SelectionContext; use super::SelectionError; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; +use rustc_middle::traits::BuiltinImplSource; +use rustc_middle::traits::ImplSource; +use rustc_middle::traits::ImplSourceUserDefinedData; use crate::errors::InherentProjectionNormalizationOverflow; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -131,8 +133,6 @@ enum ProjectionCandidate<'tcx> { /// From an "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), - - ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>), } enum ProjectionCandidateSet<'tcx> { @@ -483,8 +483,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { assert!( !value.has_escaping_bound_vars(), - "Normalizing {:?} without wrapping in a `Binder`", - value + "Normalizing {value:?} without wrapping in a `Binder`" ); if !needs_normalization(&value, self.param_env.reveal()) { @@ -526,7 +525,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx // ``` // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>) // ``` - // We normalize the substs on the projection before the projecting, but + // We normalize the args on the projection before the projecting, but // if we're naive, we'll // replace bound vars on inner, project inner, replace placeholders on inner, // replace bound vars on outer, project outer, replace placeholders on outer @@ -541,7 +540,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx // // On the other hand, this does add a bit of complexity, since we only // replace bound vars if the current type is a `Projection` and we need - // to make sure we don't forget to fold the substs regardless. + // to make sure we don't forget to fold the args regardless. match kind { ty::Opaque => { @@ -560,9 +559,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ); } - let substs = data.substs.fold_with(self); + let args = data.args.fold_with(self); let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.subst(self.interner(), substs); + let concrete_ty = generic_ty.instantiate(self.interner(), args); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); self.depth -= 1; @@ -662,11 +661,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ty::Weak => { let infcx = self.selcx.infcx; self.obligations.extend( - infcx - .tcx - .predicates_of(data.def_id) - .instantiate_own(infcx.tcx, data.substs) - .map(|(mut predicate, span)| { + infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( + |(mut predicate, span)| { if data.has_escaping_bound_vars() { (predicate, ..) = BoundVarReplacer::replace_bound_vars( infcx, @@ -679,9 +675,10 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ObligationCauseCode::TypeAlias(code, span, data.def_id) }); Obligation::new(infcx.tcx, cause, self.param_env, predicate) - }), + }, + ), ); - infcx.tcx.type_of(data.def_id).subst(infcx.tcx, data.substs).fold_with(self) + infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self) } ty::Inherent if !data.has_escaping_bound_vars() => { @@ -1217,7 +1214,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); - let mut result = if projected_term.has_projections() { + let result = if projected_term.has_projections() { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, @@ -1227,19 +1224,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let normalized_ty = normalizer.fold(projected_term); + let mut deduped = SsoHashSet::with_capacity(projected_obligations.len()); + projected_obligations.retain(|obligation| deduped.insert(obligation.clone())); + Normalized { value: normalized_ty, obligations: projected_obligations } } else { Normalized { value: projected_term, obligations: projected_obligations } }; - let mut deduped: SsoHashSet<_> = Default::default(); - result.obligations.retain(|projected_obligation| { - if !deduped.insert(projected_obligation.clone()) { - return false; - } - true - }); - if use_cache { infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } @@ -1309,7 +1301,7 @@ fn normalize_to_error<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.without_const().to_predicate(selcx.tcx()), + predicate: trait_ref.to_predicate(selcx.tcx()), }; let tcx = selcx.infcx.tcx; let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin { @@ -1339,7 +1331,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( }); } - let substs = compute_inherent_assoc_ty_substs( + let args = compute_inherent_assoc_ty_args( selcx, param_env, alias_ty, @@ -1349,7 +1341,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( ); // Register the obligations arising from the impl and from the associated type itself. - let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs); + let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args); for (predicate, span) in predicates { let predicate = normalize_with_depth_to( selcx, @@ -1383,7 +1375,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( )); } - let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs); + let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args); let mut ty = selcx.infcx.resolve_vars_if_possible(ty); if ty.has_projections() { @@ -1393,22 +1385,30 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( ty } -pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>( +pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, alias_ty: ty::AliasTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> ty::SubstsRef<'tcx> { +) -> ty::GenericArgsRef<'tcx> { let tcx = selcx.tcx(); let impl_def_id = tcx.parent(alias_ty.def_id); - let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id); + let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id); - let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs); - let impl_ty = - normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations); + let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); + if !selcx.infcx.next_trait_solver() { + impl_ty = normalize_with_depth_to( + selcx, + param_env, + cause.clone(), + depth + 1, + impl_ty, + obligations, + ); + } // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. @@ -1425,7 +1425,7 @@ pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>( } } - alias_ty.rebase_substs_onto_impl(impl_substs, tcx) + alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx) } enum Projected<'tcx> { @@ -1472,8 +1472,6 @@ fn project<'cx, 'tcx>( let mut candidates = ProjectionCandidateSet::None; - assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates); - // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. @@ -1499,20 +1497,18 @@ fn project<'cx, 'tcx>( ProjectionCandidateSet::None => { let tcx = selcx.tcx(); let term = match tcx.def_kind(obligation.predicate.def_id) { - DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection( - tcx, - obligation.predicate.def_id, - obligation.predicate.substs, - ) - .into(), + DefKind::AssocTy => { + Ty::new_projection(tcx, obligation.predicate.def_id, obligation.predicate.args) + .into() + } DefKind::AssocConst => ty::Const::new_unevaluated( tcx, ty::UnevaluatedConst::new( obligation.predicate.def_id, - obligation.predicate.substs, + obligation.predicate.args, ), tcx.type_of(obligation.predicate.def_id) - .subst(tcx, obligation.predicate.substs), + .instantiate(tcx, obligation.predicate.args), ) .into(), kind => { @@ -1530,47 +1526,6 @@ fn project<'cx, 'tcx>( } } -/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the -/// corresponding trait ref. If this yields an `impl`, then we're able to project -/// to a concrete type, since we have an `impl`'s method to provide the RPITIT. -fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { - let tcx = selcx.tcx(); - if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); - - let trait_def_id = tcx.parent(trait_fn_def_id); - let trait_substs = - obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id)); - let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs); - - let _ = selcx.infcx.commit_if_ok(|_| { - match selcx.select(&obligation.with(tcx, trait_predicate)) { - Ok(Some(super::ImplSource::UserDefined(data))) => { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); - Ok(()) - } - Ok(None) => { - candidate_set.mark_ambiguous(); - Err(()) - } - Ok(Some(_)) => { - // Don't know enough about the impl to provide a useful signature - Err(()) - } - Err(e) => { - debug!(error = ?e, "selection error"); - candidate_set.mark_error(e); - Err(()) - } - } - }); - } -} - /// The first thing we have to do is scan through the parameter /// environment to see whether there are any projection predicates /// there that can answer this question. @@ -1612,7 +1567,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let bounds = match *obligation.predicate.self_ty().kind() { // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, ref data) => { - tcx.item_bounds(data.def_id).subst(tcx, data.substs) + tcx.item_bounds(data.def_id).instantiate(tcx, data.args) } ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up @@ -1739,11 +1694,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { - // Can't assemble candidate from impl for RPITIT - if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - return; - } - // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let trait_ref = obligation.predicate.trait_ref(selcx.tcx()); @@ -1763,7 +1713,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; let eligible = match &impl_source { - super::ImplSource::UserDefined(impl_data) => { + ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // codegen (i.e., projection mode is not "any"), and the @@ -1813,7 +1763,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::ImplSource::Builtin(..) => { + ImplSource::Builtin(BuiltinImplSource::Misc, _) => { // While a builtin impl may be known to exist, the associated type may not yet // be known. Any type with multiple potential associated types is therefore // not eligible. @@ -1912,8 +1862,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( if selcx.infcx.predicate_must_hold_modulo_regions( &obligation.with( selcx.tcx(), - ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]) - .without_const(), + ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]), ), ) => { @@ -1937,7 +1886,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( bug!("unexpected builtin trait with associated type: {trait_ref:?}") } } - super::ImplSource::Param(..) => { + ImplSource::Param(..) => { // This case tell us nothing about the value of an // associated type. Consider: // @@ -1965,17 +1914,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } - super::ImplSource::Object(_) => { + ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) => { // Handled by the `Object` projection candidate. See // `assemble_candidates_from_object_ty` for an explanation of // why we special case object types. false } - | super::ImplSource::TraitUpcasting(_) => { + ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) + | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, - format!("Cannot project an associated type from `{:?}`", impl_source), + format!("Cannot project an associated type from `{impl_source:?}`"), ); return Err(()); } @@ -2012,9 +1962,6 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } - ProjectionCandidate::ImplTraitInTrait(data) => { - confirm_impl_trait_in_trait_candidate(selcx, obligation, data) - } }; // When checking for cycle during evaluation, we compare predicates with @@ -2034,8 +1981,8 @@ fn confirm_select_candidate<'cx, 'tcx>( impl_source: Selection<'tcx>, ) -> Progress<'tcx> { match impl_source { - super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), - super::ImplSource::Builtin(data) => { + ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + ImplSource::Builtin(BuiltinImplSource::Misc, data) => { let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx()); let lang_items = selcx.tcx().lang_items(); if lang_items.gen_trait() == Some(trait_def_id) { @@ -2052,9 +1999,10 @@ fn confirm_select_candidate<'cx, 'tcx>( confirm_builtin_candidate(selcx, obligation, data) } } - super::ImplSource::Object(_) - | super::ImplSource::Param(..) - | super::ImplSource::TraitUpcasting(_) => { + ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) + | ImplSource::Param(..) + | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) + | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, @@ -2070,12 +2018,12 @@ fn confirm_generator_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let ty::Generator(_, substs, _) = + let ty::Generator(_, args, _) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() else { unreachable!() }; - let gen_sig = substs.as_generator().poly_sig(); + let gen_sig = args.as_generator().poly_sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2107,7 +2055,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( }; ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs), + projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args), term: ty.into(), } }); @@ -2122,12 +2070,12 @@ fn confirm_future_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let ty::Generator(_, substs, _) = + let ty::Generator(_, args, _) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() else { unreachable!() }; - let gen_sig = substs.as_generator().poly_sig(); + let gen_sig = args.as_generator().poly_sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2151,7 +2099,7 @@ fn confirm_future_candidate<'cx, 'tcx>( debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs), + projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args), term: return_ty.into(), } }); @@ -2168,7 +2116,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); - let substs = tcx.mk_substs(&[self_ty.into()]); + let args = tcx.mk_args(&[self_ty.into()]); let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); @@ -2198,8 +2146,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( LangItem::Sized, obligation.cause.span(), [self_ty], - ) - .without_const(); + ); obligations.push(obligation.with(tcx, sized_predicate)); } (metadata_ty.into(), obligations) @@ -2208,7 +2155,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( }; let predicate = - ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, substs), term }; + ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, args), term }; confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(obligations) @@ -2240,12 +2187,11 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let ty::Closure(_, substs) = - selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() + let ty::Closure(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() else { unreachable!() }; - let closure_sig = substs.as_closure().sig(); + let closure_sig = args.as_closure().sig(); let Normalized { value: closure_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2282,7 +2228,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( flag, ) .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.substs), + projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.args), term: ret_type.into(), }); @@ -2349,8 +2295,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( } Err(e) => { let msg = format!( - "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", - obligation, poly_cache_entry, e, + "Failed to unify obligation `{obligation:?}` with poly_projection `{poly_cache_entry:?}`: {e:?}", ); debug!("confirm_param_env_candidate: {}", msg); let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg); @@ -2366,7 +2311,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); - let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source; + let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source; let assoc_item_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); @@ -2390,23 +2335,22 @@ fn confirm_impl_candidate<'cx, 'tcx>( // If we're trying to normalize `<Vec<u32> as X>::A<S>` using //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: // - // * `obligation.predicate.substs` is `[Vec<u32>, S]` - // * `substs` is `[u32]` - // * `substs` ends up as `[u32, S]` - let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); - let substs = - translate_substs(selcx.infcx, param_env, impl_def_id, substs, assoc_ty.defining_node); + // * `obligation.predicate.args` is `[Vec<u32>, S]` + // * `args` is `[u32]` + // * `args` ends up as `[u32, S]` + let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); + let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; - let identity_substs = crate::traits::InternalSubsts::identity_for_item(tcx, did); - let uv = ty::UnevaluatedConst::new(did, identity_substs); + let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); + let uv = ty::UnevaluatedConst::new(did, identity_args); ty.map_bound(|ty| ty::Const::new_unevaluated(tcx, uv, ty).into()) } else { ty.map_bound(|ty| ty.into()) }; - if !check_substs_compatible(tcx, assoc_ty.item, substs) { + if !check_args_compatible(tcx, assoc_ty.item, args) { let err = Ty::new_error_with_message( tcx, obligation.cause.span, @@ -2415,107 +2359,10 @@ fn confirm_impl_candidate<'cx, 'tcx>( Progress { term: err.into(), obligations: nested } } else { assoc_ty_own_obligations(selcx, obligation, &mut nested); - Progress { term: term.subst(tcx, substs), obligations: nested } + Progress { term: term.instantiate(tcx, args), obligations: nested } } } -fn confirm_impl_trait_in_trait_candidate<'tcx>( - selcx: &mut SelectionContext<'_, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let mut obligations = data.nested; - - let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); - let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) { - Ok(assoc_ty) => assoc_ty, - Err(guar) => return Progress::error(tcx, guar), - }; - // We don't support specialization for RPITITs anyways... yet. - // Also don't try to project to an RPITIT that has no value - if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() { - return Progress { term: Ty::new_misc_error(tcx).into(), obligations }; - } - - // Use the default `impl Trait` for the trait, e.g., for a default trait body - if leaf_def.item.container == ty::AssocItemContainer::TraitContainer { - return Progress { - term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs) - .into(), - obligations, - }; - } - - // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque}, - // since `data.substs` are the impl substs. - let impl_fn_substs = - obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs); - let impl_fn_substs = translate_substs( - selcx.infcx, - obligation.param_env, - data.impl_def_id, - impl_fn_substs, - leaf_def.defining_node, - ); - - if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) { - let err = Ty::new_error_with_message( - tcx, - obligation.cause.span, - "impl method and trait method have different parameters", - ); - return Progress { term: err.into(), obligations }; - } - - let impl_fn_def_id = leaf_def.item.def_id; - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - super::ItemObligation(impl_fn_def_id), - ); - let predicates = normalize_with_depth_to( - selcx, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs), - &mut obligations, - ); - obligations.extend(predicates.into_iter().map(|(pred, span)| { - Obligation::with_depth( - tcx, - ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - if span.is_dummy() { - super::ItemObligation(impl_fn_def_id) - } else { - super::BindingObligation(impl_fn_def_id, span) - }, - ), - obligation.recursion_depth + 1, - obligation.param_env, - pred, - ) - })); - - let ty = normalize_with_depth_to( - selcx, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else( - |guar| Ty::new_error(tcx, guar), - |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs), - ), - &mut obligations, - ); - - Progress { term: ty.into(), obligations } -} - // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. fn assoc_ty_own_obligations<'cx, 'tcx>( @@ -2526,7 +2373,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( let tcx = selcx.tcx(); let predicates = tcx .predicates_of(obligation.predicate.def_id) - .instantiate_own(tcx, obligation.predicate.substs); + .instantiate_own(tcx, obligation.predicate.args); for (predicate, span) in predicates { let normalized = normalize_with_depth_to( selcx, diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 709c3f432..9484a50e3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -49,8 +49,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), - ty::Closure(_, ref substs) => { - trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) + ty::Closure(_, ref args) => { + trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()) } ty::Adt(def, _) => { @@ -237,8 +237,8 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( Ok::<_, NoSolution>(()) })?, - ty::Closure(_, substs) => { - if !substs.as_closure().is_valid() { + ty::Closure(_, args) => { + if !args.as_closure().is_valid() { // By the time this code runs, all type variables ought to // be fully resolved. @@ -250,14 +250,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( } rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { + for ty in args.as_closure().upvar_tys() { dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; } Ok::<_, NoSolution>(()) })? } - ty::Generator(_, substs, _movability) => { + ty::Generator(_, args, _movability) => { // rust-lang/rust#49918: types can be constructed, stored // in the interior, and sit idle when generator yields // (and is subsequently dropped). @@ -281,7 +281,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // derived from lifetimes attached to the upvars and resume // argument, and we *do* incorporate those here. - if !substs.as_generator().is_valid() { + if !args.as_generator().is_valid() { // By the time this code runs, all type variables ought to // be fully resolved. tcx.sess.delay_span_bug( @@ -291,29 +291,26 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( return Err(NoSolution); } - constraints.outlives.extend( - substs - .as_generator() - .upvar_tys() - .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), - ); - constraints.outlives.push(substs.as_generator().resume_ty().into()); + constraints + .outlives + .extend(args.as_generator().upvar_tys().iter().map(ty::GenericArg::from)); + constraints.outlives.push(args.as_generator().resume_ty().into()); } - ty::Adt(def, substs) => { + ty::Adt(def, args) => { let DropckConstraint { dtorck_types, outlives, overflows } = tcx.at(span).adt_dtorck_constraint(def.did())?; // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. constraints .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args))); constraints .outlives - .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args))); constraints .overflows - .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); + .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args))); } // Objects must be alive in order for their destructor diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a50644bb7..65f32b1c4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,5 +1,4 @@ use rustc_infer::traits::{TraitEngine, TraitEngineExt}; -use rustc_middle::ty; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; @@ -66,17 +65,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { ) -> Result<EvaluationResult, OverflowError> { let mut _orig_values = OriginalQueryValues::default(); - let param_env = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - // we ignore the value set to it. - let mut _constness = pred.constness; - obligation - .param_env - .with_constness(_constness.and(obligation.param_env.constness())) - } - // constness has no effect on the given predicate. - _ => obligation.param_env.without_const(), - }; + let param_env = obligation.param_env; if self.next_trait_solver() { self.probe(|snapshot| { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 7fe79fd86..87beaddc6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -61,8 +61,27 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { self.cause, ); + // This is actually a consequence by the way `normalize_erasing_regions` works currently. + // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds + // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us + // with trying to normalize with escaping bound vars. + // + // Here, we just add the universes that we *would* have created had we passed through the binders. + // + // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary. + // The rest of the code is already set up to be lazy about replacing bound vars, + // and only when we actually have to normalize. + let universes = if value.has_escaping_bound_vars() { + let mut max_visitor = + MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 }; + value.visit_with(&mut max_visitor); + vec![None; max_visitor.escaping] + } else { + vec![] + }; + if self.infcx.next_trait_solver() { - match crate::solve::deeply_normalize(self, value) { + match crate::solve::deeply_normalize_with_skipped_universes(self, value, universes) { Ok(value) => return Ok(Normalized { value, obligations: vec![] }), Err(_errors) => { return Err(NoSolution); @@ -81,27 +100,9 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { obligations: vec![], cache: SsoHashMap::new(), anon_depth: 0, - universes: vec![], + universes, }; - // This is actually a consequence by the way `normalize_erasing_regions` works currently. - // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds - // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us - // with trying to normalize with escaping bound vars. - // - // Here, we just add the universes that we *would* have created had we passed through the binders. - // - // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary. - // The rest of the code is already set up to be lazy about replacing bound vars, - // and only when we actually have to normalize. - if value.has_escaping_bound_vars() { - let mut max_visitor = - MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 }; - value.visit_with(&mut max_visitor); - if max_visitor.escaping > 0 { - normalizer.universes.extend((0..max_visitor.escaping).map(|_| None)); - } - } let result = value.try_fold_with(&mut normalizer); info!( "normalize::<{}>: result={:?} with {} obligations", @@ -217,7 +218,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> }; // See note in `rustc_trait_selection::traits::project` about why we - // wait to fold the substs. + // wait to fold the args. // Wrap this in a closure so we don't accidentally return from the outer function let res = match kind { @@ -227,7 +228,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> Reveal::UserFacing => ty.try_super_fold_with(self)?, Reveal::All => { - let substs = data.substs.try_fold_with(self)?; + let args = data.args.try_fold_with(self)?; let recursion_limit = self.interner().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { // A closure or generator may have itself as in its upvars. @@ -243,14 +244,14 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> } let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.subst(self.interner(), substs); + let concrete_ty = generic_ty.instantiate(self.interner(), args); self.anon_depth += 1; if concrete_ty == ty { bug!( - "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ + "infinite recursion generic_ty: {:#?}, args: {:#?}, \ concrete_ty: {:#?}, ty: {:#?}", generic_ty, - substs, + args, concrete_ty, ty ); @@ -298,7 +299,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> if !tcx.sess.opts.actually_rustdoc { tcx.sess.delay_span_bug( DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), + format!("unexpected ambiguity: {c_data:?} {result:?}"), ); } return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 44671a076..302b6016e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_infer::traits::Obligation; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserType}; pub use rustc_middle::traits::query::type_op::AscribeUserType; use rustc_span::{Span, DUMMY_SP}; @@ -47,8 +47,8 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( let span = span.unwrap_or(DUMMY_SP); match user_ty { UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, - UserType::TypeOf(def_id, user_substs) => { - relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? + UserType::TypeOf(def_id, user_args) => { + relate_mir_and_user_args(ocx, param_env, span, mir_ty, def_id, user_args)? } }; Ok(()) @@ -74,20 +74,19 @@ fn relate_mir_and_user_ty<'tcx>( } #[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_substs<'tcx>( +fn relate_mir_and_user_args<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, mir_ty: Ty<'tcx>, def_id: DefId, - user_substs: UserSubsts<'tcx>, + user_args: UserArgs<'tcx>, ) -> Result<(), NoSolution> { - let param_env = param_env.without_const(); - let UserSubsts { user_self_ty, substs } = user_substs; + let UserArgs { user_self_ty, args } = user_args; let tcx = ocx.infcx.tcx; let cause = ObligationCause::dummy_with_span(span); - let ty = tcx.type_of(def_id).subst(tcx, substs); + let ty = tcx.type_of(def_id).instantiate(tcx, args); let ty = ocx.normalize(&cause, param_env, ty); debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); @@ -98,7 +97,7 @@ fn relate_mir_and_user_substs<'tcx>( // Also, normalize the `instantiated_predicates` // because otherwise we wind up with duplicate "type // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); debug!(?instantiated_predicates); for (instantiated_predicate, predicate_span) in instantiated_predicates { @@ -116,7 +115,7 @@ fn relate_mir_and_user_substs<'tcx>( if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { let self_ty = ocx.normalize(&cause, param_env, self_ty); - let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); + let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args); let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; @@ -128,9 +127,9 @@ fn relate_mir_and_user_substs<'tcx>( // In addition to proving the predicates, we have to // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being + // the WF of `ty` is predicated on the args being // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they + // want to prove the WF of types from `args` directly because they // haven't been normalized. // // FIXME(nmatsakis): Well, perhaps we should normalize diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 5420caee3..c99e018e9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -77,8 +77,7 @@ where let pre_obligations = infcx.take_registered_region_obligations(); assert!( pre_obligations.is_empty(), - "scrape_region_constraints: incoming region obligations = {:#?}", - pre_obligations, + "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}", ); let value = infcx.commit_if_ok(|_| { @@ -92,7 +91,7 @@ where } else { Err(infcx.tcx.sess.delay_span_bug( DUMMY_SP, - format!("errors selecting obligation during MIR typeck: {:?}", errors), + format!("errors selecting obligation during MIR typeck: {errors:?}"), )) } })?; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 988942633..59f4a22ac 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -31,16 +31,6 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { - // Subtle: note that we are not invoking - // `infcx.at(...).dropck_outlives(...)` here, but rather the - // underlying `dropck_outlives` query. This same underlying - // query is also used by the - // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the - // wrapper means we don't need an infcx in this code, which is - // good because the interface doesn't give us one (so that we - // know we are not registering any subregion relations or - // other things). - // FIXME convert to the type expected by the `dropck_outlives` // query. This should eventually be fixed by changing the // *underlying query*. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d5f6aaa7f..e3da87a22 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -124,11 +124,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_projected_tys(obligation, &mut candidates); self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates); - } + self.assemble_candidates_from_auto_impls(obligation, &mut candidates); } debug!("candidate list size: {}", candidates.vec.len()); Ok(candidates) @@ -158,9 +154,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); - candidates - .vec - .extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness))); + // FIXME(effects) proper constness needed? + candidates.vec.extend( + result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)), + ); } /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller @@ -209,7 +206,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - // Okay to skip binder because the substs on generator types never + // Okay to skip binder because the args on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = obligation.self_ty().skip_binder(); @@ -261,14 +258,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; }; - // Okay to skip binder because the substs on closure types never + // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters match *obligation.self_ty().skip_binder().kind() { - ty::Closure(def_id, closure_substs) => { + ty::Closure(def_id, closure_args) => { let is_const = self.tcx().is_const_fn_raw(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); - match self.infcx.closure_kind(closure_substs) { + match self.infcx.closure_kind(closure_args) { Some(closure_kind) => { debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { @@ -351,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs; + let obligation_args = obligation.predicate.skip_binder().trait_ref.args; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), @@ -360,9 +357,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx - .substs_refs_may_unify(obligation_substs, impl_trait_ref.skip_binder().substs) - { + if !drcx.args_refs_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { return; } if self.reject_fn_ptr_impls( @@ -374,7 +369,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } self.infcx.probe(|_| { - if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { + if let Ok(_args) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { candidates.vec.push(ImplCandidate(impl_def_id)); } }); @@ -402,8 +397,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates { - let ty::ClauseKind::Trait(pred) - = predicate.kind().skip_binder() else { continue }; + let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder() else { continue }; if fn_ptr_trait != pred.trait_ref.def_id { continue; } @@ -516,7 +510,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // for an example of a test case that exercises // this path. } - ty::Infer(ty::TyVar(_)) => { + ty::Infer(ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_)) => { // The auto impl might apply; we don't know. candidates.ambiguous = true; } @@ -536,7 +530,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - _ => candidates.vec.push(AutoImplCandidate), + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!( + "asked to assemble auto trait candidates of unexpected type: {:?}", + self_ty + ); + } + + ty::Alias(_, _) + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) => + { + // We do not generate an auto impl candidate for `impl Trait`s which already + // reference our auto trait. + // + // For example during candidate assembly for `impl Send: Send`, we don't have + // to look at the constituent types for this opaque types to figure out that this + // trivially holds. + // + // Note that this is only sound as projection candidates of opaque types + // are always applicable for auto traits. + } + ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate), + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::Adt(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Closure(_, _) + | ty::Generator(..) + | ty::Never + | ty::Tuple(_) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) => { + // Only consider auto impls if there are no manual impls for the root of `self_ty`. + // + // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl + // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls + // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. + // + // Generally, we have to guarantee that for all `SimplifiedType`s the only crate + // which may define impls for that type is either the crate defining the type + // or the trait. This should be guaranteed by the orphan check. + let mut has_impl = false; + self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true); + if !has_impl { + candidates.vec.push(AutoImplCandidate) + } + } + ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now. } } } @@ -651,7 +701,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let ty = traits::normalize_projection_type( self, param_env, - tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.substs), + tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.args), cause.clone(), 0, // We're *intentionally* throwing these away, @@ -689,13 +739,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Don't add any candidates if there are bound regions. return; }; - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); debug!(?source, ?target, "assemble_candidates_for_unsizing"); match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => { + ( + &ty::Dynamic(ref a_data, a_region, ty::Dyn), + &ty::Dynamic(ref b_data, b_region, ty::Dyn), + ) => { // Upcast coercions permit several things: // // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` @@ -707,19 +760,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // We always perform upcasting coercions when we can because of reason // #2 (region bounds). - let auto_traits_compatible = data_b + let auto_traits_compatible = b_data .auto_traits() // All of a's auto traits need to be in b's auto traits. - .all(|b| data_a.auto_traits().any(|a| a == b)); + .all(|b| a_data.auto_traits().any(|a| a == b)); if auto_traits_compatible { - let principal_def_id_a = data_a.principal_def_id(); - let principal_def_id_b = data_b.principal_def_id(); + let principal_def_id_a = a_data.principal_def_id(); + let principal_def_id_b = b_data.principal_def_id(); if principal_def_id_a == principal_def_id_b { // no cyclic candidates.vec.push(BuiltinUnsizeCandidate); } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { // not casual unsizing, now check whether this is trait upcasting coercion. - let principal_a = data_a.principal().unwrap(); + let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( @@ -735,9 +788,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() { - if upcast_trait_ref.def_id() == target_trait_did { - candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); - } + self.infcx.probe(|_| { + if upcast_trait_ref.def_id() == target_trait_did + && let Ok(nested) = self.match_upcast_principal( + obligation, + upcast_trait_ref, + a_data, + b_data, + a_region, + b_region, + ) + { + if nested.is_none() { + candidates.ambiguous = true; + } + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + } + }) } } } @@ -842,7 +909,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // If the predicate is `~const Destruct` in a non-const environment, we don't actually need // to check anything. We'll short-circuit checking any obligations in confirmation, too. - if !obligation.is_const() { + // FIXME(effects) + if true { candidates.vec.push(ConstDestructCandidate(None)); return; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7adc29bbb..88d030033 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,10 +11,10 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_middle::traits::SelectionOutputTypeParameterMismatch; +use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::{ - self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, - TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, + self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, + TraitPredicate, Ty, TyCtxt, TypeVisitableExt, }; use rustc_span::def_id::DefId; @@ -26,9 +26,9 @@ use crate::traits::vtable::{ }; use crate::traits::{ BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, - ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, - Obligation, ObligationCause, OutputTypeParameterMismatch, PolyTraitObligation, - PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, Unimplemented, + ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, + OutputTypeParameterMismatch, PolyTraitObligation, PredicateObligation, Selection, + SelectionError, TraitNotObjectSafe, Unimplemented, }; use super::BuiltinImplConditions; @@ -48,18 +48,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut impl_src = match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } TransmutabilityCandidate => { let data = self.confirm_transmutability_candidate(obligation)?; - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); - ImplSource::Param(obligations, param.skip_binder().constness) + ImplSource::Param(obligations) } ImplCandidate(impl_def_id) => { @@ -68,64 +68,57 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { AutoImplCandidate => { let data = self.confirm_auto_impl_candidate(obligation)?; - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } - ProjectionCandidate(idx, constness) => { + ProjectionCandidate(idx, _) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; - ImplSource::Param(obligations, constness) + ImplSource::Param(obligations) } - ObjectCandidate(idx) => { - let data = self.confirm_object_candidate(obligation, idx)?; - ImplSource::Object(data) - } + ObjectCandidate(idx) => self.confirm_object_candidate(obligation, idx)?, ClosureCandidate { .. } => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - ImplSource::Builtin(vtable_closure) + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - ImplSource::Builtin(vtable_generator) + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_generator) } FutureCandidate => { let vtable_future = self.confirm_future_candidate(obligation)?; - ImplSource::Builtin(vtable_future) + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future) } FnPointerCandidate { is_const } => { let data = self.confirm_fn_pointer_candidate(obligation, is_const)?; - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } TraitAliasCandidate => { let data = self.confirm_trait_alias_candidate(obligation); - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } BuiltinObjectCandidate => { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - ImplSource::Builtin(Vec::new()) + ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new()) } - BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; - ImplSource::Builtin(data) - } + BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?, TraitUpcastingUnsizeCandidate(idx) => { - let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; - ImplSource::TraitUpcasting(data) + self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? } ConstDestructCandidate(def_id) => { let data = self.confirm_const_destruct_candidate(obligation, def_id)?; - ImplSource::Builtin(data) + ImplSource::Builtin(BuiltinImplSource::Misc, data) } }; @@ -135,14 +128,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { subobligation.set_depth_from_parent(obligation.recursion_depth); } - if !obligation.predicate.is_const_if_const() { - // normalize nested predicates according to parent predicate's constness. - impl_src = impl_src.map(|mut o| { - o.predicate = o.predicate.without_const(self.tcx()); - o - }); - } - Ok(impl_src) } @@ -158,15 +143,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); - let (def_id, substs) = match *placeholder_self_ty.kind() { + let (def_id, args) = match *placeholder_self_ty.kind() { // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - (def_id, substs) + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { + (def_id, args) } _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; - let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); + let candidate_predicate = + tcx.item_bounds(def_id).map_bound(|i| i[idx]).instantiate(tcx, args); let candidate = candidate_predicate .as_trait_clause() .expect("projection candidate is not a trait predicate") @@ -190,7 +176,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { })?); if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); for (predicate, _) in predicates { let normalized = normalize_with_depth_to( self, @@ -298,8 +284,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .collect(), Condition::IfTransmutable { src, dst } => { let trait_def_id = obligation.predicate.def_id(); - let scope = predicate.trait_ref.substs.type_at(2); - let assume_const = predicate.trait_ref.substs.const_at(3); + let scope = predicate.trait_ref.args.type_at(2); + let assume_const = predicate.trait_ref.args.const_at(3); let make_obl = |from_ty, to_ty| { let trait_ref1 = ty::TraitRef::new( tcx, @@ -342,19 +328,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let Some(assume) = rustc_transmute::Assume::from_const( self.infcx.tcx, obligation.param_env, - predicate.trait_ref.substs.const_at(3) + predicate.trait_ref.args.const_at(3), ) else { return Err(Unimplemented); }; - let dst = predicate.trait_ref.substs.type_at(0); - let src = predicate.trait_ref.substs.type_at(1); + let dst = predicate.trait_ref.args.type_at(0); + let src = predicate.trait_ref.args.type_at(1); debug!(?src, ?dst); let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); let maybe_transmutable = transmute_env.is_transmutable( obligation.cause.clone(), rustc_transmute::Types { dst, src }, - predicate.trait_ref.substs.type_at(2), + predicate.trait_ref.args.type_at(2), assume, ); @@ -402,7 +388,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, obligation.param_env, trait_def_id, - &trait_ref.substs, + &trait_ref.args, obligation.predicate, ); @@ -433,12 +419,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); - debug!(?substs, "impl substs"); + let args = self.rematch_impl(impl_def_id, obligation); + debug!(?args, "impl args"); ensure_sufficient_stack(|| { self.vtable_impl( impl_def_id, - substs, + args, &obligation.cause, obligation.recursion_depth + 1, obligation.param_env, @@ -450,40 +436,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn vtable_impl( &mut self, impl_def_id: DefId, - substs: Normalized<'tcx, SubstsRef<'tcx>>, + args: Normalized<'tcx, GenericArgsRef<'tcx>>, cause: &ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); + debug!(?impl_def_id, ?args, ?recursion_depth, "vtable_impl"); let mut impl_obligations = self.impl_or_trait_obligations( cause, recursion_depth, param_env, impl_def_id, - &substs.value, + &args.value, parent_trait_pred, ); debug!(?impl_obligations, "vtable_impl"); // Because of RFC447, the impl-trait-ref and obligations - // are sufficient to determine the impl substs, without + // are sufficient to determine the impl args, without // relying on projections in the impl-trait-ref. // // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` - impl_obligations.extend(substs.obligations); + impl_obligations.extend(args.obligations); - ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations } + ImplSourceUserDefinedData { impl_def_id, args: args.value, nested: impl_obligations } } fn confirm_object_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, index: usize, - ) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); @@ -531,7 +517,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // will be checked in the code below. for super_trait in tcx .super_predicates_of(trait_predicate.def_id()) - .instantiate(tcx, trait_predicate.trait_ref.substs) + .instantiate(tcx, trait_predicate.trait_ref.args) .predicates .into_iter() { @@ -569,68 +555,65 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // higher-ranked things. // Prevent, e.g., `dyn Iterator<Item = str>`. for bound in self.tcx().item_bounds(assoc_type).transpose_iter() { - let subst_bound = - if defs.count() == 0 { - bound.subst(tcx, trait_predicate.trait_ref.substs) - } else { - let mut substs = smallvec::SmallVec::with_capacity(defs.count()); - substs.extend(trait_predicate.trait_ref.substs.iter()); - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity( - bound.skip_binder().kind().bound_vars().len() + defs.count(), - ); - bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter()); - InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param - .kind - { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind, - }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind, - }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() - } - }); - let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); - let assoc_ty_substs = tcx.mk_substs(&substs); - let bound = - bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); - ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx) - }; + let subst_bound = if defs.count() == 0 { + bound.instantiate(tcx, trait_predicate.trait_ref.args) + } else { + let mut args = smallvec::SmallVec::with_capacity(defs.count()); + args.extend(trait_predicate.trait_ref.args.iter()); + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity( + bound.skip_binder().kind().bound_vars().len() + defs.count(), + ); + bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter()); + GenericArgs::fill_single(&mut args, defs, &mut |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); + let assoc_ty_args = tcx.mk_args(&args); + let bound = + bound.map_bound(|b| b.kind().skip_binder()).instantiate(tcx, assoc_ty_args); + ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx) + }; let normalized_bound = normalize_with_depth_to( self, obligation.param_env, @@ -650,22 +633,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)), ); - Ok(ImplSourceObjectData { vtable_base, nested }) + Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested)) } fn confirm_fn_pointer_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - is_const: bool, + // FIXME(effects) + _is_const: bool, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!(?obligation, "confirm_fn_pointer_candidate"); let tcx = self.tcx(); - let Some(self_ty) = self - .infcx - .shallow_resolve(obligation.self_ty().no_bound_vars()) else - { + let Some(self_ty) = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars()) else { // FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`, // but we do not currently. Luckily, such a bound is not // particularly useful, so we don't expect users to write @@ -686,16 +667,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; let cause = obligation.derived_cause(BuiltinDerivedObligation); - if obligation.is_const() && !is_const { - // function is a trait method - if let ty::FnDef(def_id, substs) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) { - let trait_ref = TraitRef::from_method(tcx, trait_id, *substs); - let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst); - let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred); - nested.push(obligation); - } - } - // Confirm the `type Output: Sized;` bound that is present on `FnOnce` let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output()); let output_ty = normalize_with_depth_to( @@ -721,14 +692,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; - let substs = trait_ref.substs; + let args = trait_ref.args; let trait_obligations = self.impl_or_trait_obligations( &obligation.cause, obligation.recursion_depth, obligation.param_env, trait_def_id, - &substs, + &args, obligation.predicate, ); @@ -741,17 +712,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // Okay to skip binder because the substs on generator types never + // Okay to skip binder because the args on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let ty::Generator(generator_def_id, substs, _) = *self_ty.kind() else { + let ty::Generator(generator_def_id, args, _) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); }; - debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate"); + debug!(?obligation, ?generator_def_id, ?args, "confirm_generator_candidate"); - let gen_sig = substs.as_generator().poly_sig(); + let gen_sig = args.as_generator().poly_sig(); // NOTE: The self-type is a generator type and hence is // in fact unparameterized (or at least does not reference any @@ -780,17 +751,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // Okay to skip binder because the substs on generator types never + // Okay to skip binder because the args on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let ty::Generator(generator_def_id, substs, _) = *self_ty.kind() else { + let ty::Generator(generator_def_id, args, _) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); }; - debug!(?obligation, ?generator_def_id, ?substs, "confirm_future_candidate"); + debug!(?obligation, ?generator_def_id, ?args, "confirm_future_candidate"); - let gen_sig = substs.as_generator().poly_sig(); + let gen_sig = args.as_generator().poly_sig(); let trait_ref = super::util::future_trait_ref_and_outputs( self.tcx(), @@ -816,22 +787,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .fn_trait_kind_from_def_id(obligation.predicate.def_id()) .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - // Okay to skip binder because the substs on closure types never + // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let ty::Closure(closure_def_id, substs) = *self_ty.kind() else { + let ty::Closure(closure_def_id, args) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); }; - let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); + let trait_ref = self.closure_trait_ref_unnormalized(obligation, args); let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); nested.push(obligation.with( self.tcx(), - ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)), + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, args, kind)), )); Ok(nested) @@ -902,73 +873,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, idx: usize, - ) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { let tcx = self.tcx(); // `assemble_candidates_for_unsizing` should ensure there are no late-bound // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - let target = self.infcx.shallow_resolve(target); - - debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate"); - - let mut nested = vec![]; - let source_trait_ref; - let upcast_trait_ref; - match (source.kind(), target.kind()) { - // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). - ( - &ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn), - &ty::Dynamic(ref data_b, r_b, ty::Dyn), - ) => { - // See `assemble_candidates_for_unsizing` for more info. - // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. - let principal_a = data_a.principal().unwrap(); - source_trait_ref = principal_a.with_self_ty(tcx, source); - upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap(); - assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id())); - let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty( - tcx, trait_ref, - )) - }); - let iter = Some(existential_predicate) - .into_iter() - .chain( - data_a - .projection_bounds() - .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), - ) - .chain( - data_b - .auto_traits() - .map(ty::ExistentialPredicate::AutoTrait) - .map(ty::Binder::dummy), - ); - let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); - let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, repr_a); - - // Require that the traits involved in this upcast are **equal**; - // only the **lifetime bound** is changed. - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .sup(DefineOpaqueTypes::No, target, source_trait) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - obligation.predicate.rebind(outlives), - )); - } - _ => bug!(), - }; + let predicate = obligation.predicate.no_bound_vars().unwrap(); + let a_ty = self.infcx.shallow_resolve(predicate.self_ty()); + let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1)); + + let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { bug!() }; + let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() }; + + let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty); + let unnormalized_upcast_principal = + util::supertraits(tcx, source_principal).nth(idx).unwrap(); + + let nested = self + .match_upcast_principal( + obligation, + unnormalized_upcast_principal, + a_data, + b_data, + a_region, + b_region, + )? + .expect("did not expect ambiguity during confirmation"); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -979,7 +909,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { vptr_offset += count_own_vtable_entries(tcx, trait_ref); - if trait_ref == upcast_trait_ref { + if trait_ref == unnormalized_upcast_principal { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -997,27 +927,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let vtable_vptr_slot = - prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap(); + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap(); - Ok(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested }) + Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested)) } fn confirm_builtin_unsize_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { let tcx = self.tcx(); // `assemble_candidates_for_unsizing` should ensure there are no late-bound // regions here. See the comment there for more details. let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); let target = self.infcx.shallow_resolve(target); - debug!(?source, ?target, "confirm_builtin_unsize_candidate"); - let mut nested = vec![]; - match (source.kind(), target.kind()) { + Ok(match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b)) if dyn_a == dyn_b => @@ -1044,22 +972,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. - let InferOk { obligations, .. } = self + let InferOk { mut obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; - nested.extend(obligations); // Register one obligation for 'a: 'b. let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( + obligations.push(Obligation::with_depth( tcx, obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, obligation.predicate.rebind(outlives), )); + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } // `T` -> `Trait` @@ -1085,11 +1014,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // words, if the object type is `Foo + Send`, this would create an obligation for // the `Send` check.) // - Projection predicates - nested.extend( - data.iter().map(|predicate| { - predicate_to_obligation(predicate.with_self_ty(tcx, source)) - }), - ); + let mut nested: Vec<_> = data + .iter() + .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source))) + .collect(); // We can only make objects from sized types. let tr = ty::TraitRef::from_lang_item( @@ -1106,6 +1034,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.push(predicate_to_obligation( ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx), )); + + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } // `[T; n]` -> `[T]` @@ -1115,11 +1045,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, b, a) .map_err(|_| Unimplemented)?; - nested.extend(obligations); + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } // `Struct<T>` -> `Struct<U>` - (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { + (&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => { let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { return Err(Unimplemented); @@ -1128,6 +1059,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tail_field = def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); + let mut nested = vec![]; + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). @@ -1136,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - tail_field_ty.subst(tcx, substs_a), + tail_field_ty.instantiate(tcx, args_a), &mut nested, ); let target_tail = normalize_with_depth_to( @@ -1144,16 +1077,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - tail_field_ty.subst(tcx, substs_b), + tail_field_ty.instantiate(tcx, args_b), &mut nested, ); // Check that the source struct with the target's // unsizing parameters is equal to the target. - let substs = tcx.mk_substs_from_iter(substs_a.iter().enumerate().map(|(i, k)| { - if unsizing_params.contains(i as u32) { substs_b[i] } else { k } - })); - let new_struct = Ty::new_adt(tcx, def, substs); + let args = + tcx.mk_args_from_iter(args_a.iter().enumerate().map(|(i, k)| { + if unsizing_params.contains(i as u32) { args_b[i] } else { k } + })); + let new_struct = Ty::new_adt(tcx, def, args); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) @@ -1171,6 +1105,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ), ); nested.push(tail_unsize_obligation); + + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } // `(.., T)` -> `(.., U)` @@ -1185,25 +1121,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // last element is equal to the target. let new_tuple = Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last))); - let InferOk { obligations, .. } = self + let InferOk { mut obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, target, new_tuple) .map_err(|_| Unimplemented)?; - nested.extend(obligations); // Add a nested `T: Unsize<U>` predicate. let last_unsize_obligation = obligation.with( tcx, ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]), ); - nested.push(last_unsize_obligation); + obligations.push(last_unsize_obligation); + + ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations) } _ => bug!("source: {source}, target: {target}"), - }; - - Ok(nested) + }) } fn confirm_const_destruct_candidate( @@ -1212,7 +1147,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: Option<DefId>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` - if !obligation.is_const() { + // FIXME(effects) + if true { return Ok(vec![]); } @@ -1233,8 +1169,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_pred.trait_ref.def_id = drop_trait; trait_pred }); - let substs = self.rematch_impl(impl_def_id, &new_obligation); - debug!(?substs, "impl substs"); + let args = self.rematch_impl(impl_def_id, &new_obligation); + debug!(?args, "impl args"); let cause = obligation.derived_cause(|derived| { ImplDerivedObligation(Box::new(ImplDerivedObligationCause { @@ -1247,7 +1183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let obligations = ensure_sufficient_stack(|| { self.vtable_impl( impl_def_id, - substs, + args, &cause, new_obligation.recursion_depth + 1, new_obligation.param_env, @@ -1259,7 +1195,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We want to confirm the ADT's fields if we have an ADT let mut stack = match *self_ty.skip_binder().kind() { - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(), + ty::Adt(def, args) => def.all_fields().map(|f| f.ty(tcx, args)).collect(), _ => vec![self_ty.skip_binder()], }; @@ -1292,20 +1228,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Tuple(tys) => { stack.extend(tys.iter()); } - ty::Closure(_, substs) => { - stack.push(substs.as_closure().tupled_upvars_ty()); + ty::Closure(_, args) => { + stack.push(args.as_closure().tupled_upvars_ty()); } - ty::Generator(_, substs, _) => { - let generator = substs.as_generator(); + ty::Generator(_, args, _) => { + let generator = args.as_generator(); stack.extend([generator.tupled_upvars_ty(), generator.witness()]); } ty::GeneratorWitness(tys) => { stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); } - ty::GeneratorWitnessMIR(def_id, substs) => { + ty::GeneratorWitnessMIR(def_id, args) => { let tcx = self.tcx(); stack.extend(tcx.generator_hidden_types(def_id).map(|bty| { - let ty = bty.subst(tcx, substs); + let ty = bty.instantiate(tcx, args); debug_assert!(!ty.has_late_bound_regions()); ty })) @@ -1314,6 +1250,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable ty::Alias(ty::Projection | ty::Inherent, ..) => { + // FIXME(effects) this needs constness let predicate = normalize_with_depth_to( self, obligation.param_env, @@ -1326,7 +1263,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.span, [nested_ty], ), - constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }), &mut nested, @@ -1345,6 +1281,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // since it's either not `const Drop` (and we raise an error during selection), // or it's an ADT (and we need to check for a custom impl during selection) _ => { + // FIXME(effects) this needs constness let predicate = self_ty.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( self.tcx(), @@ -1352,7 +1289,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.span, [nested_ty], ), - constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7f31ab751..19385e2d7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -40,7 +40,7 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; @@ -74,22 +74,21 @@ impl IntercrateAmbiguityCause { match self { IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => { let self_desc = if let Some(ty) = self_desc { - format!(" for type `{}`", ty) + format!(" for type `{ty}`") } else { String::new() }; - format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) + format!("downstream crates may implement trait `{trait_desc}`{self_desc}") } IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => { let self_desc = if let Some(ty) = self_desc { - format!(" for type `{}`", ty) + format!(" for type `{ty}`") } else { String::new() }; format!( - "upstream crates may add a new impl of trait `{}`{} \ - in future versions", - trait_desc, self_desc + "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ + in future versions" ) } IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(), @@ -119,6 +118,8 @@ pub struct SelectionContext<'cx, 'tcx> { /// policy. In essence, canonicalized queries need their errors propagated /// rather than immediately reported because we do not have accurate spans. query_mode: TraitQueryMode, + + treat_inductive_cycle: TreatInductiveCycleAs, } // A stack that walks back up the stack frame. @@ -199,6 +200,27 @@ enum BuiltinImplConditions<'tcx> { Ambiguous, } +#[derive(Copy, Clone)] +pub enum TreatInductiveCycleAs { + /// This is the previous behavior, where `Recur` represents an inductive + /// cycle that is known not to hold. This is not forwards-compatible with + /// coinduction, and will be deprecated. This is the default behavior + /// of the old trait solver due to back-compat reasons. + Recur, + /// This is the behavior of the new trait solver, where inductive cycles + /// are treated as ambiguous and possibly holding. + Ambig, +} + +impl From<TreatInductiveCycleAs> for EvaluationResult { + fn from(treat: TreatInductiveCycleAs) -> EvaluationResult { + match treat { + TreatInductiveCycleAs::Ambig => EvaluatedToUnknown, + TreatInductiveCycleAs::Recur => EvaluatedToRecur, + } + } +} + impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { @@ -206,9 +228,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { freshener: infcx.freshener(), intercrate_ambiguity_causes: None, query_mode: TraitQueryMode::Standard, + treat_inductive_cycle: TreatInductiveCycleAs::Recur, } } + // Sets the `TreatInductiveCycleAs` mode temporarily in the selection context + pub fn with_treat_inductive_cycle_as<T>( + &mut self, + treat_inductive_cycle: TreatInductiveCycleAs, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + // Should be executed in a context where caching is disabled, + // otherwise the cache is poisoned with the temporary result. + assert!(self.is_intercrate()); + let treat_inductive_cycle = + std::mem::replace(&mut self.treat_inductive_cycle, treat_inductive_cycle); + let value = f(self); + self.treat_inductive_cycle = treat_inductive_cycle; + value + } + pub fn with_query_mode( infcx: &'cx InferCtxt<'tcx>, query_mode: TraitQueryMode, @@ -720,7 +759,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack.update_reached_depth(stack_arg.1); return Ok(EvaluatedToOk); } else { - return Ok(EvaluatedToRecur); + return Ok(self.treat_inductive_cycle.into()); } } return Ok(EvaluatedToOk); @@ -838,13 +877,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), - ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur), + ProjectAndUnifyResult::Recursive => Ok(self.treat_inductive_cycle.into()), ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), } } - ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { - match self.infcx.closure_kind(closure_substs) { + ty::PredicateKind::ClosureKind(_, closure_args, kind) => { + match self.infcx.closure_kind(closure_args) { Some(closure_kind) => { if closure_kind.extends(kind) { Ok(EvaluatedToOk) @@ -895,7 +934,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(DefineOpaqueTypes::No, a.substs, b.substs) + .eq(DefineOpaqueTypes::No, a.args, b.args) { return self.evaluate_predicates_recursively( previous_stack, @@ -1000,13 +1039,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let stack = self.push_stack(previous_stack, &obligation); - let mut fresh_trait_pred = stack.fresh_trait_pred; - let mut param_env = obligation.param_env; - - fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { - pred.remap_constness(&mut param_env); - pred - }); + let fresh_trait_pred = stack.fresh_trait_pred; + let param_env = obligation.param_env; debug!(?fresh_trait_pred); @@ -1157,7 +1191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(EvaluatedToOk) } else { debug!("evaluate_stack --> recursive, inductive"); - Some(EvaluatedToRecur) + Some(self.treat_inductive_cycle.into()) } } else { None @@ -1194,7 +1228,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let unbound_input_types = - stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh()); + stack.fresh_trait_pred.skip_binder().trait_ref.args.types().any(|ty| ty.is_fresh()); if unbound_input_types && stack.iter().skip(1).any(|prev| { @@ -1386,8 +1420,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (result, dep_node) } - /// filter_impls filters constant trait obligations and candidates that have a positive impl - /// for a negative goal and a negative impl for a positive goal + /// filter_impls filters candidates that have a positive impl for a negative + /// goal and a negative impl for a positive goal #[instrument(level = "debug", skip(self, candidates))] fn filter_impls( &mut self, @@ -1399,42 +1433,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut result = Vec::with_capacity(candidates.len()); for candidate in candidates { - // Respect const trait obligations - if obligation.is_const() { - match candidate { - // const impl - ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {} - // const param - ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} - // const projection - ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) - // auto trait impl - | AutoImplCandidate - // generator / future, this will raise error in other places - // or ignore error with const_async_blocks feature - | GeneratorCandidate - | FutureCandidate - // FnDef where the function is const - | FnPointerCandidate { is_const: true } - | ConstDestructCandidate(_) - | ClosureCandidate { is_const: true } => {} - - FnPointerCandidate { is_const: false } => { - if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() { - // Trait methods are not seen as const unless the trait is implemented as const. - // We do not filter that out in here, but nested obligations will be needed to confirm this. - } else { - continue - } - } - - _ => { - // reject all other types of candidates - continue; - } - } - } - if let ImplCandidate(def_id) = candidate { if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id) || obligation.polarity() == tcx.impl_polarity(def_id) @@ -1487,7 +1485,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative { + if !self.is_intercrate() { return Ok(()); } @@ -1499,7 +1497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // bound regions. let trait_ref = predicate.skip_binder().trait_ref; - coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + coherence::trait_ref_is_knowable::<!>(self.tcx(), trait_ref, |ty| Ok(ty)).unwrap() } /// Returns `true` if the global caches can be used. @@ -1528,7 +1526,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { // Neither the global nor local cache is aware of intercrate @@ -1539,8 +1537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + let pred = cache_fresh_trait_pred.skip_binder(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { @@ -1586,15 +1583,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")] fn insert_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, dep_node: DepNodeIndex, candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) { let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - - pred.remap_constness(&mut param_env); + let pred = cache_fresh_trait_pred.skip_binder(); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); @@ -1628,16 +1623,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &PolyTraitObligation<'tcx>, - ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> { + ) -> smallvec::SmallVec<[usize; 2]> { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); debug!(?placeholder_trait_predicate); let tcx = self.infcx.tcx; - let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - (def_id, substs) + let (def_id, args) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { + (def_id, args) } _ => { span_bug!( @@ -1648,7 +1643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - let bounds = tcx.item_bounds(def_id).subst(tcx, substs); + let bounds = tcx.item_bounds(def_id).instantiate(tcx, args); // The bounds returned by `item_bounds` may contain duplicates after // normalization, so try to deduplicate when possible to avoid @@ -1677,7 +1672,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => false, } }) { - return Some((idx, pred.constness)); + return Some(idx); } } None @@ -1785,11 +1780,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if is_match { let generics = self.tcx().generics_of(obligation.predicate.def_id); // FIXME(generic-associated-types): Addresses aggressive inference in #92917. - // If this type is a GAT, and of the GAT substs resolve to something new, + // If this type is a GAT, and of the GAT args resolve to something new, // that means that we must have newly inferred something about the GAT. // We should give up in that case. if !generics.params.is_empty() - && obligation.predicate.substs[generics.parent_count..] + && obligation.predicate.args[generics.parent_count..] .iter() .any(|&p| p.has_non_region_infer() && self.infcx.shallow_resolve(p) != p) { @@ -1827,6 +1822,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { /// candidates and prefer where-clause candidates. /// /// See the comment for "SelectionCandidate" for more details. + #[instrument(level = "debug", skip(self))] fn candidate_should_be_dropped_in_favor_of( &mut self, victim: &EvaluatedCandidate<'tcx>, @@ -1850,13 +1846,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. match (&other.candidate, &victim.candidate) { - (_, AutoImplCandidate) | (AutoImplCandidate, _) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // FIXME(@jswrenn): this should probably be more sophisticated (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, @@ -1871,7 +1860,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { (ParamCandidate(other), ParamCandidate(victim)) => { let same_except_bound_vars = other.skip_binder().trait_ref == victim.skip_binder().trait_ref - && other.skip_binder().constness == victim.skip_binder().constness && other.skip_binder().polarity == victim.skip_binder().polarity && !other.skip_binder().trait_ref.has_escaping_bound_vars(); if same_except_bound_vars { @@ -1881,12 +1869,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // probably best characterized as a "hack", since we might prefer to just do our // best to *not* create essentially duplicate candidates in the first place. DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len()) - } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref - && victim.skip_binder().constness == ty::BoundConstness::NotConst - && other.skip_binder().polarity == victim.skip_binder().polarity - { - // Drop otherwise equivalent non-const candidates in favor of const candidates. - DropVictim::Yes } else { DropVictim::No } @@ -1898,6 +1880,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ParamCandidate(ref other_cand), ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1925,6 +1908,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ( ImplCandidate(_) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1958,6 +1942,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ObjectCandidate(_) | ProjectionCandidate(..), ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1971,6 +1956,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -2061,6 +2047,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + (AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => { + DropVictim::No + } + + (AutoImplCandidate, _) | (_, AutoImplCandidate) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other global candidates: {:?} {:?}", + other, + victim + ); + } + // Everything else is ambiguous ( ImplCandidate(_) @@ -2127,13 +2126,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])), ), - ty::Adt(def, substs) => { + ty::Adt(def, args) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where( obligation .predicate - .rebind(sized_crit.subst_iter_copied(self.tcx(), substs).collect()), + .rebind(sized_crit.iter_instantiated(self.tcx(), args).collect()), ) } @@ -2159,14 +2158,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; match *self_ty.kind() { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())), + ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())), ty::Uint(_) | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Bool | ty::Float(_) | ty::Char @@ -2190,20 +2186,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Where(obligation.predicate.rebind(tys.iter().collect())) } - ty::Generator(_, substs, hir::Movability::Movable) => { + ty::Generator(_, args, hir::Movability::Movable) => { if self.tcx().features().generator_clone { let resolved_upvars = - self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + self.infcx.shallow_resolve(args.as_generator().tupled_upvars_ty()); let resolved_witness = - self.infcx.shallow_resolve(substs.as_generator().witness()); + self.infcx.shallow_resolve(args.as_generator().witness()); if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { // Not yet resolved. Ambiguous } else { - let all = substs + let all = args .as_generator() .upvar_tys() - .chain(iter::once(substs.as_generator().witness())) + .iter() + .chain([args.as_generator().witness()]) .collect::<Vec<_>>(); Where(obligation.predicate.rebind(all)) } @@ -2227,24 +2224,24 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) } - ty::GeneratorWitnessMIR(def_id, ref substs) => { + ty::GeneratorWitnessMIR(def_id, ref args) => { let hidden_types = bind_generator_hidden_types_above( self.infcx, def_id, - substs, + args, obligation.predicate.bound_vars(), ); Where(hidden_types) } - ty::Closure(_, substs) => { + ty::Closure(_, args) => { // (*) binder moved here - let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); if let ty::Infer(ty::TyVar(_)) = ty.kind() { // Not yet resolved. Ambiguous } else { - Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect())) + Where(obligation.predicate.rebind(args.as_closure().upvar_tys().to_vec())) } } @@ -2321,14 +2318,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { t.rebind(tys.iter().collect()) } - ty::Closure(_, ref substs) => { - let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + ty::Closure(_, ref args) => { + let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); t.rebind(vec![ty]) } - ty::Generator(_, ref substs, _) => { - let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); - let witness = substs.as_generator().witness(); + ty::Generator(_, ref args, _) => { + let ty = self.infcx.shallow_resolve(args.as_generator().tupled_upvars_ty()); + let witness = args.as_generator().witness(); t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) } @@ -2337,18 +2334,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { types.map_bound(|types| types.to_vec()) } - ty::GeneratorWitnessMIR(def_id, ref substs) => { - bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars()) + ty::GeneratorWitnessMIR(def_id, ref args) => { + bind_generator_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) } // For `PhantomData<T>`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), + ty::Adt(def, args) if def.is_phantom_data() => t.rebind(args.types().collect()), - ty::Adt(def, substs) => { - t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect()) + ty::Adt(def, args) => { + t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { let ty = self.tcx().type_of(def_id); if ty.skip_binder().references_error() { return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); @@ -2356,7 +2353,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - t.rebind(vec![ty.subst(self.tcx(), substs)]) + t.rebind(vec![ty.instantiate(self.tcx(), args)]) } }) } @@ -2428,13 +2425,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &mut self, impl_def_id: DefId, obligation: &PolyTraitObligation<'tcx>, - ) -> Normalized<'tcx, SubstsRef<'tcx>> { + ) -> Normalized<'tcx, GenericArgsRef<'tcx>> { let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); match self.match_impl(impl_def_id, impl_trait_ref, obligation) { - Ok(substs) => substs, + Ok(args) => args, Err(()) => { // FIXME: A rematch may fail when a candidate cache hit occurs - // on thefreshened form of the trait predicate, but the match + // on the freshened form of the trait predicate, but the match // fails for some reason that is not captured in the freshened // cache key. For example, equating an impl trait ref against // the placeholder trait ref may fail due the Generalizer relation @@ -2443,11 +2440,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let guar = self.infcx.tcx.sess.delay_span_bug( obligation.cause.span, format!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, obligation + "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not" ), ); - let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + let value = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); let err = Ty::new_error(self.tcx(), guar); let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx(), @@ -2466,14 +2462,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { impl_def_id: DefId, impl_trait_ref: EarlyBinder<ty::TraitRef<'tcx>>, obligation: &PolyTraitObligation<'tcx>, - ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { + ) -> Result<Normalized<'tcx, GenericArgsRef<'tcx>>, ()> { let placeholder_obligation = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; - let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + let impl_trait_ref = impl_trait_ref.instantiate(self.tcx(), impl_args); if impl_trait_ref.references_error() { return Err(()); } @@ -2515,7 +2511,99 @@ impl<'tcx> SelectionContext<'_, 'tcx> { return Err(()); } - Ok(Normalized { value: impl_substs, obligations: nested_obligations }) + Ok(Normalized { value: impl_args, obligations: nested_obligations }) + } + + fn match_upcast_principal( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + unnormalized_upcast_principal: ty::PolyTraitRef<'tcx>, + a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, + b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, + a_region: ty::Region<'tcx>, + b_region: ty::Region<'tcx>, + ) -> SelectionResult<'tcx, Vec<PredicateObligation<'tcx>>> { + let tcx = self.tcx(); + let mut nested = vec![]; + + let upcast_principal = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + unnormalized_upcast_principal, + &mut nested, + ); + + for bound in b_data { + match bound.skip_binder() { + // Check that a_ty's supertrait (upcast_principal) is compatible + // with the target (b_ty). + ty::ExistentialPredicate::Trait(target_principal) => { + nested.extend( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup( + DefineOpaqueTypes::No, + upcast_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }), + bound.rebind(target_principal), + ) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(), + ); + } + // Check that b_ty's projection is satisfied by exactly one of + // a_ty's projections. First, we look through the list to see if + // any match. If not, error. Then, if *more* than one matches, we + // return ambiguity. Otherwise, if exactly one matches, equate + // it with b_ty's projection. + ty::ExistentialPredicate::Projection(target_projection) => { + let target_projection = bound.rebind(target_projection); + let mut matching_projections = + a_data.projection_bounds().filter(|source_projection| { + // Eager normalization means that we can just use can_eq + // here instead of equating and processing obligations. + source_projection.item_def_id() == target_projection.item_def_id() + && self.infcx.can_eq( + obligation.param_env, + *source_projection, + target_projection, + ) + }); + let Some(source_projection) = matching_projections.next() else { + return Err(SelectionError::Unimplemented); + }; + if matching_projections.next().is_some() { + return Ok(None); + } + nested.extend( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(DefineOpaqueTypes::No, source_projection, target_projection) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(), + ); + } + // Check that b_ty's auto traits are present in a_ty's bounds. + ty::ExistentialPredicate::AutoTrait(def_id) => { + if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + return Err(SelectionError::Unimplemented); + } + } + } + } + + nested.push(Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), + )); + + Ok(Some(nested)) } /// Normalize `where_clause_trait_ref` and try to match it against @@ -2580,9 +2668,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { fn closure_trait_ref_unnormalized( &mut self, obligation: &PolyTraitObligation<'tcx>, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - let closure_sig = substs.as_closure().sig(); + let closure_sig = args.as_closure().sig(); debug!(?closure_sig); @@ -2615,8 +2703,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { cause: &ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, - def_id: DefId, // of impl or trait - substs: SubstsRef<'tcx>, // for impl or trait + def_id: DefId, // of impl or trait + args: GenericArgsRef<'tcx>, // for impl or trait parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ) -> Vec<PredicateObligation<'tcx>> { let tcx = self.tcx(); @@ -2637,7 +2725,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // that order. let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); - let predicates = predicates.instantiate_own(tcx, substs); + let predicates = predicates.instantiate_own(tcx, args); let mut obligations = Vec::with_capacity(predicates.len()); for (index, (predicate, span)) in predicates.into_iter().enumerate() { let cause = @@ -2990,7 +3078,7 @@ pub enum ProjectionMatchesProjection { fn bind_generator_hidden_types_above<'tcx>( infcx: &InferCtxt<'tcx>, def_id: DefId, - substs: ty::SubstsRef<'tcx>, + args: ty::GenericArgsRef<'tcx>, bound_vars: &ty::List<ty::BoundVariableKind>, ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { let tcx = infcx.tcx; @@ -3006,7 +3094,7 @@ fn bind_generator_hidden_types_above<'tcx>( // Deduplicate tys to avoid repeated work. .filter(|bty| seen_tys.insert(*bty)) .map(|bty| { - let mut ty = bty.subst(tcx, substs); + let mut ty = bty.instantiate(tcx, args); // Only remap erased regions if we use them. if considering_regions { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 96f128741..729cf2f33 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{error_code, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::{Span, DUMMY_SP}; @@ -48,7 +48,7 @@ pub struct OverlapError<'tcx> { /// When we have selected one impl, but are actually using item definitions from /// a parent impl providing a default, we need a way to translate between the /// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_substs` is a substitution of its generics. +/// selected, and `source_args` is a substitution of its generics. /// And `target_node` is the impl/trait we're actually going to get the /// definition from. The resulting substitution will map from `target_node`'s /// generics to `source_impl`'s generics as instantiated by `source_subst`. @@ -76,51 +76,46 @@ pub struct OverlapError<'tcx> { /// through associated type projection. We deal with such cases by using /// *fulfillment* to relate the two impls, requiring that all projections are /// resolved. -pub fn translate_substs<'tcx>( +pub fn translate_args<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_impl: DefId, - source_substs: SubstsRef<'tcx>, + source_args: GenericArgsRef<'tcx>, target_node: specialization_graph::Node, -) -> SubstsRef<'tcx> { - translate_substs_with_cause( - infcx, - param_env, - source_impl, - source_substs, - target_node, - |_, _| ObligationCause::dummy(), - ) +) -> GenericArgsRef<'tcx> { + translate_args_with_cause(infcx, param_env, source_impl, source_args, target_node, |_, _| { + ObligationCause::dummy() + }) } -/// Like [translate_substs], but obligations from the parent implementation +/// Like [translate_args], but obligations from the parent implementation /// are registered with the provided `ObligationCause`. /// /// This is for reporting *region* errors from those bounds. Type errors should /// not happen because the specialization graph already checks for those, and /// will result in an ICE. -pub fn translate_substs_with_cause<'tcx>( +pub fn translate_args_with_cause<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_impl: DefId, - source_substs: SubstsRef<'tcx>, + source_args: GenericArgsRef<'tcx>, target_node: specialization_graph::Node, cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, -) -> SubstsRef<'tcx> { +) -> GenericArgsRef<'tcx> { debug!( - "translate_substs({:?}, {:?}, {:?}, {:?})", - param_env, source_impl, source_substs, target_node + "translate_args({:?}, {:?}, {:?}, {:?})", + param_env, source_impl, source_args, target_node ); let source_trait_ref = - infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); + infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, &source_args); // translate the Self and Param parts of the substitution, since those // vary across impls - let target_substs = match target_node { + let target_args = match target_node { specialization_graph::Node::Impl(target_impl) => { // no need to translate if we're targeting the impl we started with if source_impl == target_impl { - return source_substs; + return source_args; } fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause) @@ -131,11 +126,11 @@ pub fn translate_substs_with_cause<'tcx>( ) }) } - specialization_graph::Node::Trait(..) => source_trait_ref.substs, + specialization_graph::Node::Trait(..) => source_trait_ref.args, }; // directly inherent the method generics, since those do not vary across impls - source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) + source_args.rebase_onto(infcx.tcx, source_impl, target_args) } /// Is `impl1` a specialization of `impl2`? @@ -172,7 +167,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // create a parameter environment corresponding to a (placeholder) instantiation of impl1 let penv = tcx.param_env(impl1_def_id); - let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity(); + let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity(); // Create an infcx, taking the predicates of impl1 as assumptions: let infcx = tcx.infer_ctxt().build(); @@ -196,7 +191,7 @@ fn fulfill_implication<'tcx>( source_impl: DefId, target_impl: DefId, error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, -) -> Result<SubstsRef<'tcx>, ()> { +) -> Result<GenericArgsRef<'tcx>, ()> { debug!( "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", param_env, source_trait_ref, target_impl @@ -221,18 +216,16 @@ fn fulfill_implication<'tcx>( let source_trait = ImplSubject::Trait(source_trait_ref); let selcx = &mut SelectionContext::new(&infcx); - let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); + let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl); let (target_trait, obligations) = - util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause); + util::impl_subject_and_oblig(selcx, param_env, target_impl, target_args, error_cause); // do the impls unify? If not, no specialization. - let Ok(InferOk { obligations: more_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait) + let Ok(InferOk { obligations: more_obligations, .. }) = infcx + .at(&ObligationCause::dummy(), param_env) + .eq(DefineOpaqueTypes::No, source_trait, target_trait) else { - debug!( - "fulfill_implication: {:?} does not unify with {:?}", - source_trait, target_trait - ); + debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait); return Err(()); }; @@ -261,7 +254,7 @@ fn fulfill_implication<'tcx>( // Now resolve the *substitution* we built for the target earlier, replacing // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(target_substs)) + Ok(infcx.resolve_vars_if_possible(target_args)) } /// Query provider for `specialization_graph_of`. @@ -395,16 +388,16 @@ fn report_conflicting_impls<'tcx>( impl_span, format!( "conflicting implementation{}", - overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{}`", ty)) + overlap.self_ty.map_or_else(String::new, |ty| format!(" for `{ty}`")) ), ); } Err(cname) => { let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { Some(s) => { - format!("conflicting implementation in crate `{}`:\n- {}", cname, s) + format!("conflicting implementation in crate `{cname}`:\n- {s}") } - None => format!("conflicting implementation in crate `{}`", cname), + None => format!("conflicting implementation in crate `{cname}`"), }; err.note(msg); } @@ -469,21 +462,21 @@ fn report_conflicting_impls<'tcx>( pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> { use std::fmt::Write; - let trait_ref = tcx.impl_trait_ref(impl_def_id)?.subst_identity(); + let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity(); let mut w = "impl".to_owned(); - let substs = InternalSubsts::identity_for_item(tcx, impl_def_id); + let args = GenericArgs::identity_for_item(tcx, impl_def_id); // FIXME: Currently only handles ?Sized. // Needs to support ?Move and ?DynSized when they are implemented. let mut types_without_default_bounds = FxIndexSet::default(); let sized_trait = tcx.lang_items().sized_trait(); - if !substs.is_empty() { - types_without_default_bounds.extend(substs.types()); + if !args.is_empty() { + types_without_default_bounds.extend(args.types()); w.push('<'); w.push_str( - &substs + &args .iter() .map(|k| k.to_string()) .filter(|k| k != "'_") @@ -497,7 +490,7 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti w, " {} for {}", trait_ref.print_only_trait_path(), - tcx.type_of(impl_def_id).subst_identity() + tcx.type_of(impl_def_id).instantiate_identity() ) .unwrap(); @@ -507,22 +500,17 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti let mut pretty_predicates = Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); - for (mut p, _) in predicates { + for (p, _) in predicates { if let Some(poly_trait_ref) = p.as_trait_clause() { if Some(poly_trait_ref.def_id()) == sized_trait { types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder()); continue; } - - if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness { - p = p.without_const(tcx); - } } pretty_predicates.push(p.to_string()); } - pretty_predicates - .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty))); + pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized"))); if !pretty_predicates.is_empty() { write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index aa5c624f4..e9a592bde 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -180,7 +180,7 @@ impl<'tcx> ChildrenExt<'tcx> for Children { if le && !ge { debug!( "descending as child of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity() + tcx.impl_trait_ref(possible_sibling).unwrap().instantiate_identity() ); // The impl specializes `possible_sibling`. @@ -188,7 +188,7 @@ impl<'tcx> ChildrenExt<'tcx> for Children { } else if ge && !le { debug!( "placing as parent of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity() + tcx.impl_trait_ref(possible_sibling).unwrap().instantiate_identity() ); replace_children.push(possible_sibling); diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 420f8c5dc..0864e4dc8 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -62,8 +62,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("Search visiting ty: {:?}", ty); - let (adt_def, substs) = match *ty.kind() { - ty::Adt(adt_def, substs) => (adt_def, substs), + let (adt_def, args) = match *ty.kind() { + ty::Adt(adt_def, args) => (adt_def, args), ty::Param(_) => { return ControlFlow::Break(ty); } @@ -157,15 +157,15 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { // instead looks directly at its fields outside // this match), so we skip super_visit_with. // - // (Must not recur on substs for `PhantomData<T>` cf + // (Must not recur on args for `PhantomData<T>` cf // rust-lang/rust#55028 and rust-lang/rust#55837; but also - // want to skip substs when only uses of generic are + // want to skip args when only uses of generic are // behind unsafe pointers `*const T`/`*mut T`.) // even though we skip super_visit_with, we must recur on // fields of ADT. let tcx = self.tcx; - adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { + adt_def.all_fields().map(|field| field.ty(tcx, args)).try_for_each(|field_ty| { let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); ty.visit_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 84746eba3..d3c4dc459 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -22,7 +22,9 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { + while let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) = + *ty.kind() + { let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, span: self.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 302b6cacf..a76272e9d 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; -use rustc_middle::ty::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use smallvec::SmallVec; @@ -50,7 +50,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { diag.span_label(self.top().1, top_label); if self.path.len() > 1 { for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({})", use_desc)); + diag.span_label(*sp, format!("referenced here ({use_desc})")); } } if self.top().1 != self.bottom().1 { @@ -58,7 +58,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { // redundant labels. diag.span_label( self.bottom().1, - format!("trait alias used in trait object type ({})", use_desc), + format!("trait alias used in trait object type ({use_desc})"), ); } } @@ -101,7 +101,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { let tcx = self.tcx; let trait_ref = item.trait_ref(); - let pred = trait_ref.without_const().to_predicate(tcx); + let pred = trait_ref.to_predicate(tcx); debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); @@ -113,9 +113,13 @@ impl<'tcx> TraitAliasExpander<'tcx> { // Don't recurse if this trait alias is already on the stack for the DFS search. let anon_pred = anonymize_predicate(tcx, pred); - if item.path.iter().rev().skip(1).any(|&(tr, _)| { - anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred - }) { + if item + .path + .iter() + .rev() + .skip(1) + .any(|&(tr, _)| anonymize_predicate(tcx, tr.to_predicate(tcx)) == anon_pred) + { return false; } @@ -194,24 +198,24 @@ impl Iterator for SupertraitDefIds<'_> { // Other /////////////////////////////////////////////////////////////////////////// -/// Instantiate all bound parameters of the impl subject with the given substs, +/// Instantiate all bound parameters of the impl subject with the given args, /// returning the resulting subject and all obligations that arise. /// The obligations are closed under normalization. pub fn impl_subject_and_oblig<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, - impl_substs: SubstsRef<'tcx>, + impl_args: GenericArgsRef<'tcx>, cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) { let subject = selcx.tcx().impl_subject(impl_def_id); - let subject = subject.subst(selcx.tcx(), impl_substs); + let subject = subject.instantiate(selcx.tcx(), impl_args); let InferOk { value: subject, obligations: normalization_obligations1 } = selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject); let predicates = selcx.tcx().predicates_of(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); + let predicates = predicates.instantiate(selcx.tcx(), impl_args); let InferOk { value: predicates, obligations: normalization_obligations2 } = selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates); let impl_obligations = super::predicates_for_generics(cause, param_env, predicates); @@ -241,9 +245,9 @@ pub fn upcast_choices<'tcx>( /// Given an upcast trait object described by `object`, returns the /// index of the method `method_def_id` (which should be part of /// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<'tcx, N>( +pub fn get_vtable_index_of_object_method<'tcx>( tcx: TyCtxt<'tcx>, - object: &super::ImplSourceObjectData<N>, + vtable_base: usize, method_def_id: DefId, ) -> Option<usize> { // Count number of methods preceding the one we are selecting and @@ -252,7 +256,7 @@ pub fn get_vtable_index_of_object_method<'tcx, N>( .iter() .copied() .position(|def_id| def_id == method_def_id) - .map(|index| object.vtable_base + index) + .map(|index| vtable_base + index) } pub fn closure_trait_ref_and_return_type<'tcx>( @@ -303,13 +307,13 @@ pub enum TupleArgumentsFlag { No, } -// Verify that the trait item and its implementation have compatible substs lists -pub fn check_substs_compatible<'tcx>( +// Verify that the trait item and its implementation have compatible args lists +pub fn check_args_compatible<'tcx>( tcx: TyCtxt<'tcx>, assoc_item: ty::AssocItem, - substs: ty::SubstsRef<'tcx>, + args: ty::GenericArgsRef<'tcx>, ) -> bool { - fn check_substs_compatible_inner<'tcx>( + fn check_args_compatible_inner<'tcx>( tcx: TyCtxt<'tcx>, generics: &'tcx ty::Generics, args: &'tcx [ty::GenericArg<'tcx>], @@ -322,7 +326,7 @@ pub fn check_substs_compatible<'tcx>( if let Some(parent) = generics.parent && let parent_generics = tcx.generics_of(parent) - && !check_substs_compatible_inner(tcx, parent_generics, parent_args) { + && !check_args_compatible_inner(tcx, parent_generics, parent_args) { return false; } @@ -339,7 +343,7 @@ pub fn check_substs_compatible<'tcx>( } let generics = tcx.generics_of(assoc_item.def_id); - // Chop off any additional substs (RPITIT) substs - let substs = &substs[0..generics.count().min(substs.len())]; - check_substs_compatible_inner(tcx, generics, substs) + // Chop off any additional args (RPITIT) args + let args = &args[0..generics.count().min(args.len())]; + check_args_compatible_inner(tcx, generics, args) } diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 1f83f1f44..427ac3684 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -5,8 +5,9 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::ImplSource; use rustc_middle::query::Providers; +use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::InternalSubsts; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -24,8 +25,18 @@ pub enum VtblSegment<'tcx> { pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, - mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>, + segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>, ) -> Option<T> { + prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value() +} + +/// Helper for [`prepare_vtable_segments`] that returns `ControlFlow`, +/// such that we can use `?` in the body. +fn prepare_vtable_segments_inner<'tcx, T>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>, +) -> ControlFlow<T> { // The following constraints holds for the final arrangement. // 1. The whole virtual table of the first direct super trait is included as the // the prefix. If this trait doesn't have any super traits, then this step @@ -71,20 +82,18 @@ pub fn prepare_vtable_segments<'tcx, T>( // N, N-vptr, O // emit dsa segment first. - if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) { - return Some(v); - } + segment_visitor(VtblSegment::MetadataDSA)?; let mut emit_vptr_on_new_entry = false; let mut visited = PredicateSet::new(tcx); - let predicate = trait_ref.without_const().to_predicate(tcx); + let predicate = trait_ref.to_predicate(tcx); let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> = - smallvec![(trait_ref, emit_vptr_on_new_entry, None)]; + smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))]; visited.insert(predicate); // the main traversal loop: // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes - // that each node is emitted after all its descendents have been emitted. + // such that each node is emitted after all its descendants have been emitted. // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set. // this is done on the fly. // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it @@ -105,98 +114,107 @@ pub fn prepare_vtable_segments<'tcx, T>( // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node. // Loop run #1: Stack after exiting out is []. Now the function exits. - loop { + 'outer: loop { // dive deeper into the stack, recording the path 'diving_in: loop { - if let Some((inner_most_trait_ref, _, _)) = stack.last() { - let inner_most_trait_ref = *inner_most_trait_ref; - let mut direct_super_traits_iter = tcx - .super_predicates_of(inner_most_trait_ref.def_id()) - .predicates - .into_iter() - .filter_map(move |(pred, _)| { - pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() - }); + let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); + + let mut direct_super_traits_iter = tcx + .super_predicates_of(inner_most_trait_ref.def_id()) + .predicates + .into_iter() + .filter_map(move |(pred, _)| { + pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + }); - 'diving_in_skip_visited_traits: loop { - if let Some(next_super_trait) = direct_super_traits_iter.next() { - if visited.insert(next_super_trait.to_predicate(tcx)) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); - stack.push(( - next_super_trait, - emit_vptr_on_new_entry, - Some(direct_super_traits_iter), - )); - break 'diving_in_skip_visited_traits; - } else { - continue 'diving_in_skip_visited_traits; - } - } else { - break 'diving_in; - } + // Find an unvisited supertrait + match direct_super_traits_iter + .find(|&super_trait| visited.insert(super_trait.to_predicate(tcx))) + { + // Push it to the stack for the next iteration of 'diving_in to pick up + Some(unvisited_super_trait) => { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref); + stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + maybe_iter(Some(direct_super_traits_iter)), + )) } + + // There are no more unvisited direct super traits, dive-in finished + None => break 'diving_in, } } - // Other than the left-most path, vptr should be emitted for each trait. - emit_vptr_on_new_entry = true; - // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. - 'exiting_out: loop { - if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() { - if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries { - trait_ref: *inner_most_trait_ref, - emit_vptr: *emit_vptr, - }) { - return Some(v); - } + while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { + segment_visitor(VtblSegment::TraitOwnEntries { + trait_ref: inner_most_trait_ref, + emit_vptr, + })?; + + // If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable, + // we'll need to emit vptrs from now on. + if !emit_vptr_on_new_entry + && has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id()) + { + emit_vptr_on_new_entry = true; + } - 'exiting_out_skip_visited_traits: loop { - if let Some(siblings) = siblings_opt { - if let Some(next_inner_most_trait_ref) = siblings.next() { - if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_inner_most_trait_ref = - next_inner_most_trait_ref.map_bound(|t| t.trait_ref); - *inner_most_trait_ref = next_inner_most_trait_ref; - *emit_vptr = emit_vptr_on_new_entry; - break 'exiting_out; - } else { - continue 'exiting_out_skip_visited_traits; - } - } - } - stack.pop(); - continue 'exiting_out; - } + if let Some(next_inner_most_trait_ref) = + siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx))) + { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_inner_most_trait_ref = + next_inner_most_trait_ref.map_bound(|t| t.trait_ref); + + stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings)); + + // just pushed a new trait onto the stack, so we need to go through its super traits + continue 'outer; } - // all done - return None; } + + // the stack is empty, all done + return ControlFlow::Continue(()); } } +/// Turns option of iterator into an iterator (this is just flatten) +fn maybe_iter<I: Iterator>(i: Option<I>) -> impl Iterator<Item = I::Item> { + // Flatten is bad perf-vise, we could probably implement a special case here that is better + i.into_iter().flatten() +} + fn dump_vtable_entries<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - tcx.sess.emit_err(DumpVTableEntries { - span: sp, - trait_ref, - entries: format!("{:#?}", entries), - }); + tcx.sess.emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") }); +} + +fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some() } fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[DefId] { + tcx.arena.alloc_from_iter(own_existential_vtable_entries_iter(tcx, trait_def_id)) +} + +fn own_existential_vtable_entries_iter( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> impl Iterator<Item = DefId> + '_ { let trait_methods = tcx .associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Fn); + // Now list each method's DefId (for within its trait). let own_entries = trait_methods.filter_map(move |&trait_method| { debug!("own_existential_vtable_entry: trait_method={:?}", trait_method); @@ -211,7 +229,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def Some(def_id) }); - tcx.arena.alloc_from_iter(own_entries.into_iter()) + own_entries } /// Given a trait `trait_ref`, iterates the vtable entries @@ -241,12 +259,12 @@ fn vtable_entries<'tcx>( debug!("vtable_entries: trait_method={:?}", def_id); // The method may have some early-bound lifetimes; add regions for those. - let substs = trait_ref.map_bound(|trait_ref| { - InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { + let args = trait_ref.map_bound(|trait_ref| { + GenericArgs::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - trait_ref.substs[param.index as usize] + trait_ref.args[param.index as usize] } }) }); @@ -254,14 +272,14 @@ fn vtable_entries<'tcx>( // The trait type may have higher-ranked lifetimes in it; // erase them if they appear, so that we get the type // at some particular call site. - let substs = tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs); + let args = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), args); // It's possible that the method relies on where-clauses that // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and codegen it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); if impossible_predicates( tcx, predicates.map(|(predicate, _)| predicate).collect(), @@ -274,7 +292,7 @@ fn vtable_entries<'tcx>( tcx, ty::ParamEnv::reveal_all(), def_id, - substs, + args, ) .expect("resolution failed during building vtable representation"); VtblEntry::Method(instance) @@ -363,8 +381,8 @@ pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]); match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => { - implsrc_traitcasting.vtable_vptr_slot + Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => { + *vtable_vptr_slot } otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"), } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d81722ce2..f26310665 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -2,8 +2,8 @@ use crate::infer::InferCtxt; use crate::traits; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{Span, DUMMY_SP}; @@ -341,18 +341,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let trait_ref = &trait_pred.trait_ref; // Negative trait predicates don't require supertraits to hold, just - // that their substs are WF. + // that their args are WF. if trait_pred.polarity == ty::ImplPolarity::Negative { self.compute_negative_trait_pred(trait_ref); return; } // if the trait predicate is not const, the wf obligations should not be const as well. - let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { - self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) - } else { - self.nominal_obligations(trait_ref.def_id, trait_ref.substs) - }; + let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.args); debug!("compute_trait_pred obligations {:?}", obligations); let param_env = self.param_env; @@ -383,7 +379,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend( trait_ref - .substs + .args .iter() .enumerate() .filter(|(_, arg)| { @@ -416,7 +412,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Compute the obligations that are required for `trait_ref` to be WF, // given that it is a *negative* trait predicate. fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) { - for arg in trait_ref.substs { + for arg in trait_ref.args { self.compute(arg); } } @@ -427,7 +423,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // A projection is well-formed if // // (a) its predicates hold (*) - // (b) its substs are wf + // (b) its args are wf // // (*) The predicates of an associated type include the predicates of // the trait that it's contained in. For example, given @@ -445,18 +441,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // `i32: Clone` // `i32: Copy` // ] - // Projection types do not require const predicates. - let obligations = self.nominal_obligations_without_const(data.def_id, data.substs); + let obligations = self.nominal_obligations(data.def_id, data.args); self.out.extend(obligations); - self.compute_projection_substs(data.substs); + self.compute_projection_args(data.args); } fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { // An inherent projection is well-formed if // // (a) its predicates hold (*) - // (b) its substs are wf + // (b) its args are wf // // (*) The predicates of an inherent associated type include the // predicates of the impl that it's contained in. @@ -464,7 +459,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !data.self_ty().has_escaping_bound_vars() { // FIXME(inherent_associated_types): Should this happen inside of a snapshot? // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! - let substs = traits::project::compute_inherent_assoc_ty_substs( + let args = traits::project::compute_inherent_assoc_ty_args( &mut traits::SelectionContext::new(self.infcx), self.param_env, data, @@ -472,23 +467,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.recursion_depth, &mut self.out, ); - // Inherent projection types do not require const predicates. - let obligations = self.nominal_obligations_without_const(data.def_id, substs); + let obligations = self.nominal_obligations(data.def_id, args); self.out.extend(obligations); } - self.compute_projection_substs(data.substs); + self.compute_projection_args(data.args); } - fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) { + fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) { let tcx = self.tcx(); let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let depth = self.recursion_depth; self.out.extend( - substs - .iter() + args.iter() .filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) }) @@ -517,7 +510,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - ty::Binder::dummy(trait_ref).without_const(), + ty::Binder::dummy(trait_ref), )); } } @@ -541,7 +534,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { if !ct.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def, uv.substs); + let obligations = self.nominal_obligations(uv.def, uv.args); self.out.extend(obligations); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( @@ -571,7 +564,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { )); } ty::ConstKind::Expr(_) => { - // FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the + // FIXME(generic_const_exprs): this doesn't verify that given `Expr(N + 1)` the // trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` // which means that the `DefId` would have been typeck'd elsewhere. However in @@ -661,14 +654,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.compute_inherent_projection(data); } - ty::Adt(def, substs) => { + ty::Adt(def, args) => { // WfNominalType - let obligations = self.nominal_obligations(def.did(), substs); + let obligations = self.nominal_obligations(def.did(), args); self.out.extend(obligations); } - ty::FnDef(did, substs) => { - let obligations = self.nominal_obligations_without_const(did, substs); + ty::FnDef(did, args) => { + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } @@ -688,7 +681,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } - ty::Generator(did, substs, ..) => { + ty::Generator(did, args, ..) => { // Walk ALL the types in the generator: this will // include the upvar types as well as the yield // type. Note that this is mildly distinct from @@ -696,11 +689,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // about the signature of the closure. We don't // have the problem of implied bounds here since // generators don't take arguments. - let obligations = self.nominal_obligations(did, substs); + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } - ty::Closure(did, substs) => { + ty::Closure(did, args) => { // Only check the upvar types for WF, not the rest // of the types within. This is needed because we // capture the signature and it may not be WF @@ -723,7 +716,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // fn(&'a T) }`, as discussed in #25860. walker.skip_current_subtree(); // subtree handled below // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(substs.as_closure().tupled_upvars_ty().into()); + self.compute(args.as_closure().tupled_upvars_ty().into()); // Note that we cannot skip the generic types // types. Normally, within the fn // body where they are created, the generics will @@ -739,7 +732,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // can cause compiler crashes when the user abuses unsafe // code to procure such a closure. // See tests/ui/type-alias-impl-trait/wf_check_closures.rs - let obligations = self.nominal_obligations(did, substs); + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } @@ -748,18 +741,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // types appearing in the fn signature } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // All of the requirements on type parameters // have already been checked for `impl Trait` in // return position. We do need to check type-alias-impl-trait though. if self.tcx().is_type_alias_impl_trait(def_id) { - let obligations = self.nominal_obligations(def_id, substs); + let obligations = self.nominal_obligations(def_id, args); self.out.extend(obligations); } } - ty::Alias(ty::Weak, ty::AliasTy { def_id, substs, .. }) => { - let obligations = self.nominal_obligations(def_id, substs); + ty::Alias(ty::Weak, ty::AliasTy { def_id, args, .. }) => { + let obligations = self.nominal_obligations(def_id, args); self.out.extend(obligations); } @@ -823,11 +816,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn nominal_obligations_inner( + fn nominal_obligations( &mut self, def_id: DefId, - substs: SubstsRef<'tcx>, - remap_constness: bool, + args: GenericArgsRef<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { let predicates = self.tcx().predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; @@ -837,21 +829,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { origins.extend(iter::repeat(parent).take(head.predicates.len())); } - let predicates = predicates.instantiate(self.tcx(), substs); + let predicates = predicates.instantiate(self.tcx(), args); trace!("{:#?}", predicates); debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(predicates, origins.into_iter().rev()) - .map(|((mut pred, span), origin_def_id)| { + .map(|((pred, span), origin_def_id)| { let code = if span.is_dummy() { traits::ItemObligation(origin_def_id) } else { traits::BindingObligation(origin_def_id, span) }; let cause = self.cause(code); - if remap_constness { - pred = pred.without_const(self.tcx()); - } traits::Obligation::with_depth( self.tcx(), cause, @@ -864,22 +853,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { .collect() } - fn nominal_obligations( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec<traits::PredicateObligation<'tcx>> { - self.nominal_obligations_inner(def_id, substs, false) - } - - fn nominal_obligations_without_const( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec<traits::PredicateObligation<'tcx>> { - self.nominal_obligations_inner(def_id, substs, true) - } - fn from_object_ty( &mut self, ty: Ty<'tcx>, |