diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_trait_selection/src/traits/select | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/select')
3 files changed, 519 insertions, 427 deletions
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 { |