summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/select
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/select')
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs90
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs135
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs165
3 files changed, 225 insertions, 165 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 f4b6d3bcf..38b1046ac 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -115,6 +115,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_future_candidates(obligation, &mut candidates);
} else if lang_items.iterator_trait() == Some(def_id) {
self.assemble_iterator_candidates(obligation, &mut candidates);
+ } else if lang_items.async_iterator_trait() == Some(def_id) {
+ self.assemble_async_iterator_candidates(obligation, &mut candidates);
}
self.assemble_closure_candidates(obligation, &mut candidates);
@@ -155,10 +157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
- // FIXME(effects) proper constness needed?
- candidates.vec.extend(
- result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)),
- );
+ candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
@@ -261,6 +260,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
+ fn assemble_async_iterator_candidates(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let self_ty = obligation.self_ty().skip_binder();
+ if let ty::Coroutine(did, args, _) = *self_ty.kind() {
+ // gen constructs get lowered to a special kind of coroutine that
+ // should directly `impl AsyncIterator`.
+ if self.tcx().coroutine_is_async_gen(did) {
+ debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
+
+ // Can only confirm this candidate if we have constrained
+ // the `Yield` type to at least `Poll<Option<?0>>`..
+ let ty::Adt(_poll_def, args) = *args.as_coroutine().yield_ty().kind() else {
+ candidates.ambiguous = true;
+ return;
+ };
+ let ty::Adt(_option_def, _) = *args.type_at(0).kind() else {
+ candidates.ambiguous = true;
+ return;
+ };
+
+ candidates.vec.push(AsyncIteratorCandidate);
+ }
+ }
+ }
+
/// Checks for the artificial impl that the compiler will create for an obligation like `X :
/// FnMut<..>` where `X` is a closure type.
///
@@ -291,8 +318,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
None => {
- debug!("assemble_unboxed_candidates: closure_kind not yet known");
- candidates.vec.push(ClosureCandidate { is_const });
+ if kind == ty::ClosureKind::FnOnce {
+ candidates.vec.push(ClosureCandidate { is_const });
+ } else {
+ candidates.ambiguous = true;
+ }
}
}
}
@@ -328,17 +358,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig) => {
if sig.is_fn_trait_compatible() {
- candidates.vec.push(FnPointerCandidate { is_const: false });
+ candidates
+ .vec
+ .push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
}
}
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
- ty::FnDef(def_id, _) => {
- if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
- && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
+ ty::FnDef(def_id, args) => {
+ let tcx = self.tcx();
+ if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+ && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{
- candidates
- .vec
- .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
+ candidates.vec.push(FnPointerCandidate {
+ fn_host_effect: tcx
+ .generics_of(def_id)
+ .host_effect_index
+ .map_or(tcx.consts.true_, |idx| args.const_at(idx)),
+ });
}
}
_ => {}
@@ -375,7 +411,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.args_refs_may_unify(obligation_args, impl_trait_ref.skip_binder().args) {
+ if !drcx.args_may_unify(obligation_args, impl_trait_ref.skip_binder().args) {
return;
}
if self.reject_fn_ptr_impls(
@@ -555,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::Alias(ty::Opaque, _) => {
- if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) {
+ 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.
//
@@ -634,7 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = placeholder_trait_predicate.self_ty();
let principal_trait_ref = match self_ty.kind() {
- ty::Dynamic(ref data, ..) => {
+ ty::Dynamic(data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!(
"assemble_candidates_from_object_ty: matched builtin bound, \
@@ -759,10 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (
- &ty::Dynamic(ref a_data, a_region, ty::Dyn),
- &ty::Dynamic(ref b_data, b_region, ty::Dyn),
- ) => {
+ (&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => {
// Upcast coercions permit several things:
//
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -923,9 +956,18 @@ 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.
- // FIXME(effects)
- if true {
- candidates.vec.push(ConstDestructCandidate(None));
+ let Some(host_effect_index) =
+ self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
+ else {
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
+ return;
+ };
+ // If the obligation has `host = true`, then the obligation is non-const and it's always
+ // trivially implemented.
+ if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index)
+ == self.tcx().consts.true_
+ {
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
return;
}
@@ -1051,7 +1093,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) {
// The regions of a type don't affect the size of the type
let tcx = self.tcx();
- let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty());
+ let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
// We should erase regions from both the param-env and type, since both
// may have infer regions. Specifically, after canonicalizing and instantiating,
// early bound regions turn into region vars in both the new and old solver.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 4bfa341e3..ce3fc2185 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -9,7 +9,7 @@
use rustc_ast::Mutability;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch};
use rustc_middle::ty::{
@@ -71,7 +71,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
- ProjectionCandidate(idx, _) => {
+ ProjectionCandidate(idx) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
ImplSource::Param(obligations)
}
@@ -98,8 +98,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
}
- FnPointerCandidate { is_const } => {
- let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
+ AsyncIteratorCandidate => {
+ let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?;
+ ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
+ }
+
+ FnPointerCandidate { fn_host_effect } => {
+ let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
@@ -327,8 +332,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// care about other regions. Erasing late-bound regions is equivalent
// to instantiating the binder with placeholders then erasing those
// placeholder regions.
- let predicate =
- self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
+ let predicate = self
+ .tcx()
+ .erase_regions(self.tcx().instantiate_bound_regions_with_erased(obligation.predicate));
let Some(assume) = rustc_transmute::Assume::from_const(
self.infcx.tcx,
@@ -393,7 +399,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
- &trait_ref.args,
+ trait_ref.args,
obligation.predicate,
);
@@ -454,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth,
param_env,
impl_def_id,
- &args.value,
+ args.value,
parent_trait_pred,
);
@@ -552,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let defs: &ty::Generics = tcx.generics_of(assoc_type);
if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
obligation.cause.span,
"GATs in trait object shouldn't have been considered",
);
@@ -592,7 +598,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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(
+ ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion {
@@ -647,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_fn_pointer_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
- // FIXME(effects)
- _is_const: bool,
+ fn_host_effect: ty::Const<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate");
@@ -669,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
+ fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref);
@@ -707,7 +713,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth,
obligation.param_env,
trait_def_id,
- &args,
+ args,
obligation.predicate,
);
@@ -730,7 +736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate");
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
// NOTE: The self-type is a coroutine type and hence is
// in fact unparameterized (or at least does not reference any
@@ -741,15 +747,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.no_bound_vars()
.expect("unboxed closure type should not capture bound vars from the predicate");
- let trait_ref = super::util::coroutine_trait_ref_and_outputs(
+ let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
self_ty,
coroutine_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "coroutine candidate obligations");
Ok(nested)
@@ -769,17 +774,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate");
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
- let trait_ref = super::util::future_trait_ref_and_outputs(
+ let (trait_ref, _) = super::util::future_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
coroutine_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "future candidate obligations");
Ok(nested)
@@ -799,17 +803,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate");
- let gen_sig = args.as_coroutine().poly_sig();
+ let gen_sig = args.as_coroutine().sig();
- let trait_ref = super::util::iterator_trait_ref_and_outputs(
+ let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
gen_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+ debug!(?trait_ref, ?nested, "iterator candidate obligations");
+
+ Ok(nested)
+ }
+
+ fn confirm_async_iterator_candidate(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ // Okay to skip binder because the args on coroutine 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::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+ bug!("closure candidate for non-closure {:?}", obligation);
+ };
+
+ debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_iterator_candidate");
+
+ let gen_sig = args.as_coroutine().sig();
+
+ let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+ gen_sig,
+ );
+
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "iterator candidate obligations");
Ok(nested)
@@ -820,11 +852,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- let kind = self
- .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 args on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
@@ -833,16 +860,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bug!("closure candidate for non-closure {:?}", obligation);
};
- let trait_ref = self.closure_trait_ref_unnormalized(obligation, args);
- let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let trait_ref =
+ self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_);
+ let 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, args, kind)),
- ));
-
Ok(nested)
}
@@ -920,8 +943,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
+ bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
+ };
+ let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
+ bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
+ };
let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty);
let unnormalized_upcast_principal =
@@ -985,7 +1012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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))
+ (&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b))
if dyn_a == dyn_b =>
{
// See `assemble_candidates_for_unsizing` for more info.
@@ -1030,7 +1057,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// `T` -> `Trait`
- (_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
+ (_, &ty::Dynamic(data, r, ty::Dyn)) => {
let mut object_dids = data.auto_traits().chain(data.principal_def_id());
if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) {
return Err(TraitNotObjectSafe(did));
@@ -1184,11 +1211,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'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`
- // FIXME(effects)
- if true {
- return Ok(vec![]);
- }
+ let Some(host_effect_index) =
+ self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
+ else {
+ bug!()
+ };
+ let host_effect_param: ty::GenericArg<'tcx> =
+ obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into();
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
@@ -1277,7 +1306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
let ty = bty.instantiate(tcx, args);
- debug_assert!(!ty.has_late_bound_regions());
+ debug_assert!(!ty.has_bound_regions());
ty
}))
}
@@ -1285,7 +1314,6 @@ 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,
@@ -1296,7 +1324,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.tcx(),
LangItem::Destruct,
cause.span,
- [nested_ty],
+ [nested_ty.into(), host_effect_param],
),
polarity: ty::ImplPolarity::Positive,
}),
@@ -1316,13 +1344,12 @@ 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(),
LangItem::Destruct,
cause.span,
- [nested_ty],
+ [nested_ty.into(), host_effect_param],
),
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 08208cc60..23f7bdd15 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,8 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_infer::infer::BoundRegionConversionTime;
use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitObligation;
use rustc_middle::dep_graph::dep_kinds;
use rustc_middle::dep_graph::DepNodeIndex;
@@ -46,6 +46,7 @@ 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;
+use rustc_span::Symbol;
use std::cell::{Cell, RefCell};
use std::cmp;
@@ -59,13 +60,13 @@ mod candidate_assembly;
mod confirmation;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub enum IntercrateAmbiguityCause {
- DownstreamCrate { trait_desc: String, self_desc: Option<String> },
- UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
- ReservationImpl { message: String },
+pub enum IntercrateAmbiguityCause<'tcx> {
+ DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
+ UpstreamCrateUpdate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
+ ReservationImpl { message: Symbol },
}
-impl IntercrateAmbiguityCause {
+impl<'tcx> IntercrateAmbiguityCause<'tcx> {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) {
@@ -73,28 +74,32 @@ impl IntercrateAmbiguityCause {
}
pub fn intercrate_ambiguity_hint(&self) -> String {
- match self {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => {
- let self_desc = if let Some(ty) = self_desc {
- format!(" for type `{ty}`")
- } else {
- String::new()
- };
- format!("downstream crates may implement trait `{trait_desc}`{self_desc}")
+ with_no_trimmed_paths!(match self {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => {
+ format!(
+ "downstream crates may implement trait `{trait_desc}`{self_desc}",
+ trait_desc = trait_ref.print_trait_sugared(),
+ self_desc = if let Some(self_ty) = self_ty {
+ format!(" for type `{self_ty}`")
+ } else {
+ String::new()
+ }
+ )
}
- IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => {
- let self_desc = if let Some(ty) = self_desc {
- format!(" for type `{ty}`")
- } else {
- String::new()
- };
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } => {
format!(
"upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \
- in future versions"
+ in future versions",
+ trait_desc = trait_ref.print_trait_sugared(),
+ self_desc = if let Some(self_ty) = self_ty {
+ format!(" for type `{self_ty}`")
+ } else {
+ String::new()
+ }
)
}
- IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(),
- }
+ IntercrateAmbiguityCause::ReservationImpl { message } => message.to_string(),
+ })
}
}
@@ -114,7 +119,7 @@ pub struct SelectionContext<'cx, 'tcx> {
/// We don't do his until we detect a coherence error because it can
/// lead to false overflow results (#47139) and because always
/// computing it may negatively impact performance.
- intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>,
+ intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause<'tcx>>>,
/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
@@ -217,8 +222,8 @@ pub enum TreatInductiveCycleAs {
impl From<TreatInductiveCycleAs> for EvaluationResult {
fn from(treat: TreatInductiveCycleAs) -> EvaluationResult {
match treat {
- TreatInductiveCycleAs::Ambig => EvaluatedToUnknown,
- TreatInductiveCycleAs::Recur => EvaluatedToRecur,
+ TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent,
+ TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent,
}
}
}
@@ -270,7 +275,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Gets the intercrate ambiguity causes collected since tracking
/// was enabled and disables tracking at the same time. If
/// tracking is not enabled, just returns an empty vector.
- pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
+ pub fn take_intercrate_ambiguity_causes(
+ &mut self,
+ ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
assert!(self.is_intercrate());
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
@@ -367,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug_assert!(!self.infcx.next_trait_solver());
// Watch out for overflow. This intentionally bypasses (and does
// not update) the cache.
- self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
+ self.check_recursion_limit(stack.obligation, stack.obligation)?;
// Check the cache. Note that we freshen the trait-ref
// separately rather than using `stack.fresh_trait_ref` --
@@ -416,7 +423,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut no_candidates_apply = true;
for c in candidate_set.vec.iter() {
- if self.evaluate_candidate(stack, &c)?.may_apply() {
+ if self.evaluate_candidate(stack, c)?.may_apply() {
no_candidates_apply = false;
break;
}
@@ -428,19 +435,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
if !trait_ref.references_error() {
let self_ty = trait_ref.self_ty();
- let (trait_desc, self_desc) = with_no_trimmed_paths!({
- let trait_desc = trait_ref.print_only_trait_path().to_string();
- let self_desc =
- self_ty.has_concrete_skeleton().then(|| self_ty.to_string());
- (trait_desc, self_desc)
- });
+ let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
let cause = if let Conflict::Upstream = conflict {
- IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_desc,
- self_desc,
- }
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
} else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
};
debug!(?cause, "evaluate_stack: pushing cause");
self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
@@ -799,7 +798,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// A global type with no free lifetimes or generic parameters
// outlives anything.
if pred.0.has_free_regions()
- || pred.0.has_late_bound_regions()
+ || pred.0.has_bound_regions()
|| pred.0.has_non_region_infer()
|| pred.0.has_non_region_infer()
{
@@ -885,19 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- ty::PredicateKind::ClosureKind(_, closure_args, kind) => {
- match self.infcx.closure_kind(closure_args) {
- Some(closure_kind) => {
- if closure_kind.extends(kind) {
- Ok(EvaluatedToOk)
- } else {
- Ok(EvaluatedToErr)
- }
- }
- None => Ok(EvaluatedToAmbig),
- }
- }
-
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
match const_evaluatable::is_const_evaluatable(
self.infcx,
@@ -1004,8 +990,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
}
+ ty::PredicateKind::NormalizesTo(..) => {
+ bug!("NormalizesTo is only used by the new solver")
+ }
ty::PredicateKind::AliasRelate(..) => {
- bug!("AliasRelate is only used for new solver")
+ bug!("AliasRelate is only used by the new solver")
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
@@ -1237,15 +1226,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
- && self.match_fresh_trait_refs(
- stack.fresh_trait_pred,
- prev.fresh_trait_pred,
- prev.obligation.param_env,
- )
+ && self.match_fresh_trait_refs(stack.fresh_trait_pred, prev.fresh_trait_pred)
})
{
debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
- return Ok(EvaluatedToUnknown);
+ return Ok(EvaluatedToAmbigStackDependent);
}
match self.candidate_from_obligation(stack) {
@@ -1464,20 +1449,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
- let value = tcx
+ let message = tcx
.get_attr(def_id, sym::rustc_reservation_impl)
.and_then(|a| a.value_str());
- if let Some(value) = value {
+ if let Some(message) = message {
debug!(
"filter_reservation_impls: \
reservation impl ambiguity on {:?}",
def_id
);
- intercrate_ambiguity_clauses.insert(
- IntercrateAmbiguityCause::ReservationImpl {
- message: value.to_string(),
- },
- );
+ intercrate_ambiguity_clauses
+ .insert(IntercrateAmbiguityCause::ReservationImpl { message });
}
}
return Ok(None);
@@ -1751,7 +1733,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut nested_obligations = Vec::new();
let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
- LateBoundRegionConversionTime::HigherRankedType,
+ BoundRegionConversionTime::HigherRankedType,
env_predicate,
);
let infer_projection = if potentially_unnormalized_candidates {
@@ -1841,7 +1823,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
let is_global =
- |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars();
+ |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// `DiscriminantKindCandidate`, `ConstDestructCandidate`
@@ -1879,7 +1861,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
// Drop otherwise equivalent non-const fn pointer candidates
- (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
+ (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
+ DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
+ }
(
ParamCandidate(ref other_cand),
@@ -1889,6 +1873,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1896,7 +1881,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinCandidate { .. }
| TraitAliasCandidate
| ObjectCandidate(_)
- | ProjectionCandidate(..),
+ | ProjectionCandidate(_),
) => {
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
@@ -1906,7 +1891,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// here (see issue #50825).
DropVictim::drop_if(!is_global(other_cand))
}
- (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
+ (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
@@ -1918,6 +1903,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1933,26 +1919,27 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
)
}
- (ProjectionCandidate(i, _), ProjectionCandidate(j, _))
+ (ProjectionCandidate(i), ProjectionCandidate(j))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
DropVictim::drop_if(i < j && !has_non_region_infer)
}
- (ObjectCandidate(_), ProjectionCandidate(..))
- | (ProjectionCandidate(..), ObjectCandidate(_)) => {
+ (ObjectCandidate(_), ProjectionCandidate(_))
+ | (ProjectionCandidate(_), ObjectCandidate(_)) => {
bug!("Have both object and projection candidate")
}
// Arbitrarily give projection and object candidates priority.
(
- ObjectCandidate(_) | ProjectionCandidate(..),
+ ObjectCandidate(_) | ProjectionCandidate(_),
ImplCandidate(..)
| AutoImplCandidate
| ClosureCandidate { .. }
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1968,13 +1955,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate,
- ObjectCandidate(_) | ProjectionCandidate(..),
+ ObjectCandidate(_) | ProjectionCandidate(_),
) => DropVictim::No,
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
@@ -2075,6 +2063,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2086,6 +2075,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2218,7 +2208,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
- ty::CoroutineWitness(def_id, ref args) => {
+ ty::CoroutineWitness(def_id, args) => {
let hidden_types = bind_coroutine_hidden_types_above(
self.infcx,
def_id,
@@ -2307,23 +2297,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
- ty::Tuple(ref tys) => {
+ ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
t.rebind(tys.iter().collect())
}
- ty::Closure(_, ref args) => {
+ ty::Closure(_, args) => {
let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
t.rebind(vec![ty])
}
- ty::Coroutine(_, ref args, _) => {
+ ty::Coroutine(_, args, _) => {
let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let witness = args.as_coroutine().witness();
t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
- ty::CoroutineWitness(def_id, ref args) => {
+ ty::CoroutineWitness(def_id, args) => {
bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
}
@@ -2436,7 +2426,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// the placeholder trait ref may fail due the Generalizer relation
// raising a CyclicalTy error due to a sub_root_var relation
// for a variable being generalized...
- let guar = self.infcx.tcx.sess.delay_span_bug(
+ let guar = self.infcx.tcx.sess.span_delayed_bug(
obligation.cause.span,
format!(
"Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
@@ -2638,9 +2628,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&self,
previous: ty::PolyTraitPredicate<'tcx>,
current: ty::PolyTraitPredicate<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
) -> bool {
- let mut matcher = MatchAgainstFreshVars::new(self.tcx(), param_env);
+ let mut matcher = MatchAgainstFreshVars::new(self.tcx());
matcher.relate(previous, current).is_ok()
}
@@ -2668,6 +2657,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
args: GenericArgsRef<'tcx>,
+ fn_host_effect: ty::Const<'tcx>,
) -> ty::PolyTraitRef<'tcx> {
let closure_sig = args.as_closure().sig();
@@ -2688,6 +2678,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self_ty,
closure_sig,
util::TupleArgumentsFlag::No,
+ fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref)
}
@@ -3103,7 +3094,7 @@ fn bind_coroutine_hidden_types_above<'tcx>(
kind: ty::BrAnon,
};
counter += 1;
- ty::Region::new_late_bound(tcx, current_depth, br)
+ ty::Region::new_bound(tcx, current_depth, br)
}
r => bug!("unexpected region: {r:?}"),
})