summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/select
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_trait_selection/src/traits/select
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-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')
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs134
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs452
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs360
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 {