summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_trait_selection/src/traits
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs43
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs86
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs314
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs137
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs72
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs76
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs41
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs59
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs103
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs205
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs86
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs412
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs47
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs16
25 files changed, 1130 insertions, 834 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 1fb8659bb..182d995c4 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -7,8 +7,8 @@ use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult;
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{ImplPolarity, Region, RegionVid};
@@ -179,13 +179,15 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// At this point, we already have all of the bounds we need. FulfillmentContext is used
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check.
- let errors =
- super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}
- infcx.process_registered_region_obligations(&Default::default(), full_env);
+ let outlives_env = OutlivesEnvironment::new(full_env);
+ infcx.process_registered_region_obligations(&outlives_env);
let region_data =
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
@@ -232,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
/// constructed once for a given type. As part of the construction process, the `ParamEnv` will
/// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
/// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
- /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or
+ /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate`, or
/// else `SelectionContext` will choke on the missing predicates. However, this should never
/// show up in the final synthesized generics: we don't want our generated docs page to contain
/// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a
@@ -344,11 +346,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
_ => panic!("Unexpected error for '{:?}': {:?}", ty, result),
};
- let normalized_preds = elaborate_predicates(
- tcx,
- computed_preds.clone().chain(user_computed_preds.iter().cloned()),
- )
- .map(|o| o.predicate);
+ let normalized_preds =
+ elaborate(tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned()));
new_env = ty::ParamEnv::new(
tcx.mk_predicates_from_iter(normalized_preds),
param_env.reveal(),
@@ -814,7 +813,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => {
- match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
+ match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2)
{
Ok(_) => (),
Err(_) => return false,
@@ -830,7 +829,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// the `ParamEnv`.
ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
@@ -852,23 +851,3 @@ impl<'tcx> AutoTraitFinder<'tcx> {
infcx.freshen(p)
}
}
-
-/// Replaces all ReVars in a type with ty::Region's, using the provided map
-pub struct RegionReplacer<'a, 'tcx> {
- vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
- tcx: TyCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match *r {
- ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
- _ => None,
- })
- .unwrap_or_else(|| r.super_fold_with(self))
- }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index b42a49eb4..28967e1cc 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -40,13 +40,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.obligations.insert(obligation);
}
- fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
+ fn collect_remaining_errors(
+ &mut self,
+ _infcx: &InferCtxt<'tcx>,
+ ) -> Vec<FulfillmentError<'tcx>> {
// any remaining obligations are errors
self.obligations
.iter()
.map(|obligation| FulfillmentError {
obligation: obligation.clone(),
- code: FulfillmentErrorCode::CodeAmbiguity,
+ code: FulfillmentErrorCode::CodeAmbiguity { overflow: false },
// FIXME - does Chalk have a notation of 'root obligation'?
// This is just for diagnostics, so it's okay if this is wrong
root_obligation: obligation.clone(),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 6b688c322..20c2605f2 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,7 +17,7 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -75,12 +75,13 @@ pub fn overlapping_impls(
// Before doing expensive operations like entering an inference context, do
// a quick check via fast_reject to tell if the impl headers could possibly
// unify.
- let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
+ let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
- (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
- .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
+ (Some(a), Some(b)) => {
+ drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs)
+ }
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
@@ -95,8 +96,11 @@ pub fn overlapping_impls(
return None;
}
- let infcx =
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .intercrate(true)
+ .build();
let selcx = &mut SelectionContext::new(&infcx);
let overlaps =
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
@@ -107,8 +111,11 @@ pub fn overlapping_impls(
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
- let infcx =
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .intercrate(true)
+ .build();
let selcx = &mut SelectionContext::new(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
@@ -181,7 +188,7 @@ fn overlap_within_probe<'cx, 'tcx>(
let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
- let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
+ let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded");
if overlap_mode.use_implicit_negative() {
@@ -207,20 +214,25 @@ fn overlap_within_probe<'cx, 'tcx>(
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}
-fn equate_impl_headers<'cx, 'tcx>(
- selcx: &mut SelectionContext<'cx, 'tcx>,
- impl1_header: &ty::ImplHeader<'tcx>,
- impl2_header: &ty::ImplHeader<'tcx>,
+#[instrument(level = "debug", skip(infcx), ret)]
+fn equate_impl_headers<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ impl1: &ty::ImplHeader<'tcx>,
+ impl2: &ty::ImplHeader<'tcx>,
) -> Option<PredicateObligations<'tcx>> {
- // Do `a` and `b` unify? If not, no overlap.
- debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
- selcx
- .infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .define_opaque_types(true)
- .eq_impl_headers(impl1_header, impl2_header)
- .map(|infer_ok| infer_ok.obligations)
- .ok()
+ let result = match (impl1.trait_ref, impl2.trait_ref) {
+ (Some(impl1_ref), Some(impl2_ref)) => infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
+ (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+ DefineOpaqueTypes::Yes,
+ impl1.self_ty,
+ impl2.self_ty,
+ ),
+ _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+ };
+
+ result.map(|infer_ok| infer_ok.obligations).ok()
}
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
@@ -294,7 +306,7 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
&infcx,
ObligationCause::dummy(),
impl_env,
- tcx.impl_subject(impl1_def_id),
+ tcx.impl_subject(impl1_def_id).subst_identity(),
) {
Ok(s) => s,
Err(err) => {
@@ -325,7 +337,7 @@ fn equate<'tcx>(
) -> bool {
// do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
+ infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
else {
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
return true;
@@ -356,8 +368,8 @@ fn negative_impl_exists<'tcx>(
}
// Try to prove a negative obligation exists for super predicates
- for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
- if resolve_negative_obligation(infcx.fork(), &o, body_def_id) {
+ for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
+ if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
return true;
}
}
@@ -378,7 +390,10 @@ fn resolve_negative_obligation<'tcx>(
};
let param_env = o.param_env;
- if !super::fully_solve_obligation(&infcx, o).is_empty() {
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_obligation(o);
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
return false;
}
@@ -388,20 +403,29 @@ fn resolve_negative_obligation<'tcx>(
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
- Some(&infcx),
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
);
-
- infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
-
infcx.resolve_regions(&outlives_env).is_empty()
}
+/// Returns whether all impls which would apply to the `trait_ref`
+/// e.g. `Ty: Trait<Arg>` are already known in the local crate.
+///
+/// This both checks whether any downstream or sibling crates could
+/// implement it and whether an upstream crate can add this impl
+/// without breaking backwards compatibility.
#[instrument(level = "debug", skip(tcx), ret)]
pub fn trait_ref_is_knowable<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), Conflict> {
+ if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() {
+ // The only types implementing `FnPtr` are function pointers,
+ // so if there's no impl of `FnPtr` in the current crate,
+ // then such an impl will never be added in the future.
+ return Ok(());
+ }
+
if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() {
// A downstream or cousin crate is allowed to implement some
// substitution of this trait-ref.
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index b20636174..2beebe94b 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -6,12 +6,14 @@ use super::{ChalkFulfillmentContext, FulfillmentContext};
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
use crate::traits::NormalizeExt;
use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
};
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_infer::traits::query::Fallible;
use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@@ -128,8 +130,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
{
self.infcx
.at(cause, param_env)
- .define_opaque_types(true)
- .eq_exp(a_is_expected, a, b)
+ .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -142,8 +143,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
- .define_opaque_types(true)
- .eq(expected, actual)
+ .eq(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -157,8 +157,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
- .define_opaque_types(true)
- .sup(expected, actual)
+ .sub(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@@ -172,19 +171,37 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
- .define_opaque_types(true)
- .sup(expected, actual)
+ .sup(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
+ #[must_use]
pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
self.engine.borrow_mut().select_where_possible(self.infcx)
}
+ #[must_use]
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
self.engine.borrow_mut().select_all_or_error(self.infcx)
}
+ /// Resolves regions and reports errors.
+ ///
+ /// Takes ownership of the context as doing trait solving afterwards
+ /// will result in region constraints getting ignored.
+ pub fn resolve_regions_and_report_errors(
+ self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) -> Result<(), ErrorGuaranteed> {
+ let errors = self.infcx.resolve_regions(&outlives_env);
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors))
+ }
+ }
+
pub fn assumed_wf_types(
&self,
param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 84045c4d0..0475f24d8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -1,6 +1,6 @@
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
-use rustc_infer::traits::util::elaborate_predicates_with_span;
+use rustc_infer::traits::util::elaborate;
use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
use rustc_middle::ty;
use rustc_span::{Span, DUMMY_SP};
@@ -82,15 +82,15 @@ pub fn recompute_applicable_impls<'tcx>(
let predicates =
tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
- for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
- let kind = obligation.predicate.kind();
+ for (pred, span) in elaborate(tcx, predicates.into_iter()) {
+ let kind = pred.kind();
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
{
if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
} else {
- ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
+ ambiguities.push(Ambiguity::ParamEnv(span))
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index 1174efdbf..7e1dba4ed 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -21,10 +21,6 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- false
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@@ -33,10 +29,6 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
true
}
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
@@ -92,6 +84,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
}
impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ // FIXME(deferred_projection_equality): We really should get rid of this relation.
+ ty::AliasRelationDirection::Equate
+ }
+
fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
// FIXME(deferred_projection_equality)
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index a844a1494..1b741b730 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -24,16 +24,15 @@ use rustc_errors::{
};
use rustc_hir as hir;
use rustc_hir::def::Namespace;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
-use rustc_hir::GenericParam;
-use rustc_hir::Item;
-use rustc_hir::Node;
+use rustc_hir::{GenericParam, Item, Node};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
@@ -126,11 +125,9 @@ pub trait TypeErrCtxtExt<'tcx> {
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
- fn report_fulfillment_errors(
- &self,
- errors: &[FulfillmentError<'tcx>],
- body_id: Option<hir::BodyId>,
- ) -> ErrorGuaranteed;
+ fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
+
+ fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed;
fn report_overflow_obligation<T>(
&self,
@@ -388,11 +385,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
}
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
- fn report_fulfillment_errors(
- &self,
- errors: &[FulfillmentError<'tcx>],
- body_id: Option<hir::BodyId>,
- ) -> ErrorGuaranteed {
+ fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed {
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
predicate: ty::Predicate<'tcx>,
@@ -469,7 +462,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for from_expansion in [false, true] {
for (error, suppressed) in iter::zip(errors, &is_suppressed) {
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
- self.report_fulfillment_error(error, body_id);
+ self.report_fulfillment_error(error);
}
}
}
@@ -611,6 +604,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
+ fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
+ let obligation = self.resolve_vars_if_possible(obligation);
+ let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
+ self.note_obligation_cause(&mut err, &obligation);
+ self.point_at_returns_when_relevant(&mut err, &obligation);
+ err.emit()
+ }
+
fn report_selection_error(
&self,
mut obligation: PredicateObligation<'tcx>,
@@ -672,6 +673,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
let trait_ref = trait_predicate.to_poly_trait_ref();
+
let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
@@ -711,33 +713,45 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
(message, note, append_const_msg)
};
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0277,
- "{}",
- message
- .and_then(|cannot_do_this| {
- match (predicate_is_const, append_const_msg) {
- // do nothing if predicate is not const
- (false, _) => Some(cannot_do_this),
- // suggested using default post message
- (true, Some(None)) => {
- Some(format!("{cannot_do_this} in const contexts"))
- }
- // overridden post message
- (true, Some(Some(post_message))) => {
- Some(format!("{cannot_do_this}{post_message}"))
- }
- // fallback to generic message
- (true, None) => None,
+ let err_msg = message
+ .and_then(|cannot_do_this| {
+ match (predicate_is_const, append_const_msg) {
+ // do nothing if predicate is not const
+ (false, _) => Some(cannot_do_this),
+ // suggested using default post message
+ (true, Some(None)) => {
+ Some(format!("{cannot_do_this} in const contexts"))
}
- })
- .unwrap_or_else(|| format!(
+ // overridden post message
+ (true, Some(Some(post_message))) => {
+ Some(format!("{cannot_do_this}{post_message}"))
+ }
+ // fallback to generic message
+ (true, None) => None,
+ }
+ })
+ .unwrap_or_else(|| {
+ format!(
"the trait bound `{}` is not satisfied{}",
trait_predicate, post_message,
- ))
- );
+ )
+ });
+
+ let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
+ == self.tcx.lang_items().transmute_trait()
+ {
+ // Recompute the safe transmute reason and use that for the error reporting
+ self.get_safe_transmute_error_and_reason(
+ trait_predicate,
+ obligation.clone(),
+ trait_ref,
+ span,
+ )
+ } else {
+ (err_msg, None)
+ };
+
+ let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
@@ -827,6 +841,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// at the type param with a label to suggest constraining it.
err.help(&explanation);
}
+ } else if let Some(custom_explanation) = safe_transmute_explanation {
+ err.span_label(span, custom_explanation);
} else {
err.span_label(span, explanation);
}
@@ -955,8 +971,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
- let body_hir_id =
- self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
+ let body_def_id = obligation.cause.body_id;
// Try to report a help message
if is_fn_trait
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
@@ -1035,9 +1050,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(
- impl_candidates,
+ &impl_candidates,
trait_ref,
- body_hir_id,
+ body_def_id,
&mut err,
true,
) {
@@ -1071,14 +1086,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let impl_candidates =
self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
- impl_candidates,
+ &impl_candidates,
trait_ref,
- body_hir_id,
+ body_def_id,
&mut err,
true,
);
}
}
+
+ self.maybe_suggest_convert_to_slice(
+ &mut err,
+ trait_ref,
+ impl_candidates.as_slice(),
+ span,
+ );
}
// Changing mutability doesn't make a difference to whether we have
@@ -1279,16 +1301,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"TypeWellFormedFromEnv predicate should only exist in the environment"
),
- ty::PredicateKind::AliasEq(..) => span_bug!(
+ ty::PredicateKind::AliasRelate(..) => span_bug!(
span,
- "AliasEq predicate should never be the predicate cause of a SelectionError"
+ "AliasRelate predicate should never be the predicate cause of a SelectionError"
),
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
- self.tcx.sess.struct_span_err(
+ let mut diag = self.tcx.sess.struct_span_err(
span,
&format!("the constant `{}` is not of type `{}`", ct, ty),
- )
+ );
+ self.note_type_err(
+ &mut diag,
+ &obligation.cause,
+ None,
+ None,
+ TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())),
+ false,
+ false,
+ );
+ diag
}
}
}
@@ -1494,11 +1526,7 @@ trait InferCtxtPrivExt<'tcx> {
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
- fn report_fulfillment_error(
- &self,
- error: &FulfillmentError<'tcx>,
- body_id: Option<hir::BodyId>,
- );
+ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>);
fn report_projection_error(
&self,
@@ -1529,9 +1557,9 @@ trait InferCtxtPrivExt<'tcx> {
fn report_similar_impl_candidates(
&self,
- impl_candidates: Vec<ImplCandidate<'tcx>>,
+ impl_candidates: &[ImplCandidate<'tcx>],
trait_ref: ty::PolyTraitRef<'tcx>,
- body_id: hir::HirId,
+ body_def_id: LocalDefId,
err: &mut Diagnostic,
other: bool,
) -> bool;
@@ -1561,11 +1589,7 @@ trait InferCtxtPrivExt<'tcx> {
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
) -> PredicateObligation<'tcx>;
- fn maybe_report_ambiguity(
- &self,
- obligation: &PredicateObligation<'tcx>,
- body_id: Option<hir::BodyId>,
- );
+ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>);
fn predicate_can_apply(
&self,
@@ -1602,6 +1626,14 @@ trait InferCtxtPrivExt<'tcx> {
obligated_types: &mut Vec<Ty<'tcx>>,
cause_code: &ObligationCauseCode<'tcx>,
) -> bool;
+
+ fn get_safe_transmute_error_and_reason(
+ &self,
+ trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
+ trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ span: Span,
+ ) -> (String, Option<String>);
}
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -1625,8 +1657,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
};
- for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
- let bound_predicate = obligation.predicate.kind();
+ for pred in super::elaborate(self.tcx, std::iter::once(cond)) {
+ let bound_predicate = pred.kind();
if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) =
bound_predicate.skip_binder()
{
@@ -1647,11 +1679,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- fn report_fulfillment_error(
- &self,
- error: &FulfillmentError<'tcx>,
- body_id: Option<hir::BodyId>,
- ) {
+ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
self.report_selection_error(
@@ -1663,8 +1691,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
FulfillmentErrorCode::CodeProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e);
}
- FulfillmentErrorCode::CodeAmbiguity => {
- self.maybe_report_ambiguity(&error.obligation, body_id);
+ FulfillmentErrorCode::CodeAmbiguity { overflow: false } => {
+ self.maybe_report_ambiguity(&error.obligation);
+ }
+ FulfillmentErrorCode::CodeAmbiguity { overflow: true } => {
+ self.report_overflow_no_abort(error.obligation.clone());
}
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
self.report_mismatched_types(
@@ -1768,7 +1799,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
- ocx.select_where_possible();
+ //
+ // we intentionally drop errors from normalization here,
+ // since the normalization is just done to improve the error message.
+ let _ = ocx.select_where_possible();
if let Err(new_err) = ocx.eq_exp(
&obligation.cause,
@@ -1815,12 +1849,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
})
.and_then(|(trait_assoc_item, id)| {
let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
- self.tcx.find_map_relevant_impl(id, proj.projection_ty.self_ty(), |did| {
- self.tcx
- .associated_items(did)
- .in_definition_order()
- .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
- })
+ self.tcx.find_map_relevant_impl(
+ id,
+ proj.projection_ty.self_ty(),
+ TreatProjections::ForLookup,
+ |did| {
+ self.tcx
+ .associated_items(did)
+ .in_definition_order()
+ .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
+ },
+ )
})
.and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
Some(
@@ -2027,9 +2066,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn report_similar_impl_candidates(
&self,
- impl_candidates: Vec<ImplCandidate<'tcx>>,
+ impl_candidates: &[ImplCandidate<'tcx>],
trait_ref: ty::PolyTraitRef<'tcx>,
- body_id: hir::HirId,
+ body_def_id: LocalDefId,
err: &mut Diagnostic,
other: bool,
) -> bool {
@@ -2120,9 +2159,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME(compiler-errors): This could be generalized, both to
// be more granular, and probably look past other `#[fundamental]`
// types, too.
- self.tcx
- .visibility(def.did())
- .is_accessible_from(body_id.owner.def_id, self.tcx)
+ self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
} else {
true
}
@@ -2138,7 +2175,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Prefer more similar candidates first, then sort lexicographically
// by their normalized string representation.
let mut normalized_impl_candidates_and_similarities = impl_candidates
- .into_iter()
+ .iter()
+ .copied()
.map(|ImplCandidate { trait_ref, similarity }| {
// FIXME(compiler-errors): This should be using `NormalizeExt::normalize`
let normalized = self
@@ -2193,7 +2231,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_ref: &ty::PolyTraitRef<'tcx>,
) -> bool {
let get_trait_impl = |trait_def_id| {
- self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
+ self.tcx.find_map_relevant_impl(
+ trait_def_id,
+ trait_ref.skip_binder().self_ty(),
+ TreatProjections::ForLookup,
+ Some,
+ )
};
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let traits_with_same_path: std::collections::BTreeSet<_> = self
@@ -2231,11 +2274,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- fn maybe_report_ambiguity(
- &self,
- obligation: &PredicateObligation<'tcx>,
- body_id: Option<hir::BodyId>,
- ) {
+ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
// Unable to successfully determine, probably means
// insufficient type information, but could mean
// ambiguous impls. The latter *ought* to be a
@@ -2277,7 +2316,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
if let None = self.tainted_by_errors() {
self.emit_inference_failure_err(
- body_id,
+ obligation.cause.body_id,
span,
trait_ref.self_ty().skip_binder().into(),
ErrorCode::E0282,
@@ -2304,7 +2343,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let subst = data.trait_ref.substs.iter().find(|s| s.has_non_region_infer());
let mut err = if let Some(subst) = subst {
- self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ subst,
+ ErrorCode::E0283,
+ true,
+ )
} else {
struct_span_err!(
self.tcx.sess,
@@ -2348,12 +2393,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
predicate.to_opt_poly_trait_pred().unwrap(),
);
if impl_candidates.len() < 10 {
- let hir =
- self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
self.report_similar_impl_candidates(
- impl_candidates,
+ impl_candidates.as_slice(),
trait_ref,
- body_id.map(|id| id.hir_id).unwrap_or(hir),
+ obligation.cause.body_id,
&mut err,
false,
);
@@ -2375,8 +2418,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
}
- if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
- (body_id, subst.map(|subst| subst.unpack()))
+ if let Some(ty::subst::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack())
+ && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
{
let mut expr_finder = FindExprBySpan::new(span);
expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
@@ -2473,7 +2516,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
- self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false)
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ arg,
+ ErrorCode::E0282,
+ false,
+ )
}
ty::PredicateKind::Subtype(data) => {
@@ -2487,7 +2536,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let SubtypePredicate { a_is_expected: _, a, b } = data;
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
- self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true)
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ a.into(),
+ ErrorCode::E0282,
+ true,
+ )
}
ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
if predicate.references_error() || self.tainted_by_errors().is_some() {
@@ -2501,7 +2556,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.find(|g| g.has_non_region_infer());
if let Some(subst) = subst {
let mut err = self.emit_inference_failure_err(
- body_id,
+ obligation.cause.body_id,
span,
subst,
ErrorCode::E0284,
@@ -2530,7 +2585,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let subst = data.walk().find(|g| g.is_non_region_infer());
if let Some(subst) = subst {
let err = self.emit_inference_failure_err(
- body_id,
+ obligation.cause.body_id,
span,
subst,
ErrorCode::E0284,
@@ -2863,6 +2918,63 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
false
}
+
+ fn get_safe_transmute_error_and_reason(
+ &self,
+ trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
+ trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ span: Span,
+ ) -> (String, Option<String>) {
+ let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
+ dst: p.trait_ref.substs.type_at(0),
+ src: p.trait_ref.substs.type_at(1),
+ });
+ let scope = trait_ref.skip_binder().substs.type_at(2);
+ let Some(assume) =
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
+ span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
+ };
+ match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
+ obligation.cause,
+ src_and_dst,
+ scope,
+ assume,
+ ) {
+ rustc_transmute::Answer::No(reason) => {
+ let dst = trait_ref.skip_binder().substs.type_at(0);
+ let src = trait_ref.skip_binder().substs.type_at(1);
+ let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string();
+ let reason_msg = match reason {
+ rustc_transmute::Reason::SrcIsUnspecified => {
+ format!("`{src}` does not have a well-specified layout").to_string()
+ }
+ rustc_transmute::Reason::DstIsUnspecified => {
+ format!("`{dst}` does not have a well-specified layout").to_string()
+ }
+ rustc_transmute::Reason::DstIsBitIncompatible => {
+ format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
+ .to_string()
+ }
+ rustc_transmute::Reason::DstIsPrivate => format!(
+ "`{dst}` is or contains a type or field that is not visible in that scope"
+ )
+ .to_string(),
+ // FIXME(bryangarza): Include the number of bytes of src and dst
+ rustc_transmute::Reason::DstIsTooBig => {
+ format!("The size of `{src}` is smaller than the size of `{dst}`")
+ }
+ };
+ (custom_err_msg, Some(reason_msg))
+ }
+ // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
+ rustc_transmute::Answer::Yes => span_bug!(
+ span,
+ "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
+ ),
+ _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
+ }
+ }
}
/// Crude way of getting back an `Expr` from a `Span`.
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index b3bf9ad59..a9c4e1268 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -149,9 +149,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
let trait_ref = trait_ref.skip_binder();
- let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
- let mut flags =
- vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))];
+ let mut flags = vec![];
+ // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
+ // but I guess we could synthesize one here. We don't see any errors that rely on
+ // that yet, though.
+ let enclosure =
+ if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) {
+ self.describe_enclosure(body_hir).map(|s| s.to_owned())
+ } else {
+ None
+ };
+ flags.push((sym::ItemContext, enclosure));
match obligation.cause.code() {
ObligationCauseCode::BuiltinDerivedObligation(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 66d74fd05..fb75ec767 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,7 +1,7 @@
// ignore-tidy-filelength
use super::{
- DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode,
+ DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,
PredicateObligation,
};
@@ -30,7 +30,7 @@ use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{
- self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitableExt, TypeckResults,
@@ -212,7 +212,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn extract_callable_info(
&self,
- hir_id: HirId,
+ body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
found: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
@@ -382,6 +382,14 @@ pub trait TypeErrCtxtExt<'tcx> {
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
+
+ fn maybe_suggest_convert_to_slice(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ candidate_impls: &[ImplCandidate<'tcx>],
+ span: Span,
+ );
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
@@ -412,6 +420,7 @@ fn suggest_restriction<'tcx>(
) {
if hir_generics.where_clause_span.from_expansion()
|| hir_generics.where_clause_span.desugaring_kind().is_some()
+ || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
{
return;
}
@@ -900,9 +909,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred.self_ty(),
);
- let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
- body_hir_id,
+ obligation.cause.body_id,
obligation.param_env,
self_ty,
) else { return false; };
@@ -1104,10 +1112,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// Extracts information about a callable type for diagnostics. This is a
/// heuristic -- it doesn't necessarily mean that a type is always callable,
/// because the callable type must also be well-formed to be called.
- // FIXME(vincenzopalazzo): move the HirId to a LocalDefId
fn extract_callable_info(
&self,
- hir_id: HirId,
+ body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
found: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
@@ -1159,7 +1166,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
})
}
ty::Param(param) => {
- let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
+ let generics = self.tcx.generics_of(body_id);
let name = if generics.count() > param.index as usize
&& let def = generics.param_at(param.index as usize, self.tcx)
&& matches!(def.kind, ty::GenericParamDefKind::Type { .. })
@@ -1349,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Applicability::MaybeIncorrect,
);
} else {
+ let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
+ let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
+ let sugg_msg = &format!(
+ "consider{} borrowing here",
+ if is_mut { " mutably" } else { "" }
+ );
+
+ // Issue #109436, we need to add parentheses properly for method calls
+ // for example, `foo.into()` should be `(&foo).into()`
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(
+ self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)),
+ ) {
+ if snippet == "." {
+ err.multipart_suggestion_verbose(
+ sugg_msg,
+ vec![
+ (span.shrink_to_lo(), format!("({}", sugg_prefix)),
+ (span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+
// Issue #104961, we need to add parentheses properly for compond expressions
// for example, `x.starts_with("hi".to_string() + "you")`
// should be `x.starts_with(&("hi".to_string() + "you"))`
@@ -1365,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => false,
};
- let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
let span = if needs_parens { span } else { span.shrink_to_lo() };
- let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
- let sugg_msg = &format!(
- "consider{} borrowing here",
- if is_mut { " mutably" } else { "" }
- );
-
let suggestions = if !needs_parens {
vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
} else {
@@ -2220,7 +2245,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// - `BuiltinDerivedObligation` with a generator witness (A)
// - `BuiltinDerivedObligation` with a generator (A)
// - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
- // - `BindingObligation` with `impl_send (Send requirement)
+ // - `BindingObligation` with `impl_send` (Send requirement)
//
// The first obligation in the chain is the most useful and has the generator that captured
// the type. The last generator (`outer_generator` below) has information about where the
@@ -2936,9 +2961,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ObligationCauseCode::SizedYieldType => {
err.note("the yield type of a generator must have a statically known size");
}
- ObligationCauseCode::SizedBoxType => {
- err.note("the type of a box expression must have a statically known size");
- }
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
@@ -3025,8 +3047,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
};
- let identity_future = tcx.require_lang_item(LangItem::IdentityFuture, None);
-
// Don't print the tuple of capture types
'print: {
if !is_upvar_tys_infer_tuple {
@@ -3039,12 +3059,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
None => err.note(&msg),
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
- // Avoid printing the future from `core::future::identity_future`, it's not helpful
- if tcx.parent(*def_id) == identity_future {
- break 'print;
- }
-
- // If the previous type is `identity_future`, this is the future generated by the body of an async function.
+ // If the previous type is async fn, this is the future generated by the body of an async function.
// Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
let is_future = tcx.ty_is_opaque_future(ty);
debug!(
@@ -3826,6 +3841,72 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
assocs_in_this_method
}
+
+ /// If the type that failed selection is an array or a reference to an array,
+ /// but the trait is implemented for slices, suggest that the user converts
+ /// the array into a slice.
+ fn maybe_suggest_convert_to_slice(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ candidate_impls: &[ImplCandidate<'tcx>],
+ span: Span,
+ ) {
+ // Three cases where we can make a suggestion:
+ // 1. `[T; _]` (array of T)
+ // 2. `&[T; _]` (reference to array of T)
+ // 3. `&mut [T; _]` (mutable reference to array of T)
+ let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() {
+ ty::Array(element_ty, _) => (element_ty, None),
+
+ ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
+ ty::Array(element_ty, _) => (element_ty, Some(mutability)),
+ _ => return,
+ },
+
+ _ => return,
+ };
+
+ // Go through all the candidate impls to see if any of them is for
+ // slices of `element_ty` with `mutability`.
+ let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() {
+ ty::RawPtr(ty::TypeAndMut { ty: t, mutbl: m }) | ty::Ref(_, t, m) => {
+ if matches!(*t.kind(), ty::Slice(e) if e == element_ty)
+ && m == mutability.unwrap_or(m)
+ {
+ // Use the candidate's mutability going forward.
+ mutability = Some(m);
+ true
+ } else {
+ false
+ }
+ }
+ _ => false,
+ };
+
+ // Grab the first candidate that matches, if any, and make a suggestion.
+ if let Some(slice_ty) = candidate_impls
+ .iter()
+ .map(|trait_ref| trait_ref.trait_ref.self_ty())
+ .find(|t| is_slice(*t))
+ {
+ let msg = &format!("convert the array to a `{}` slice instead", slice_ty);
+
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ let mut suggestions = vec![];
+ if snippet.starts_with('&') {
+ } else if let Some(hir::Mutability::Mut) = mutability {
+ suggestions.push((span.shrink_to_lo(), "&mut ".into()));
+ } else {
+ suggestions.push((span.shrink_to_lo(), "&".into()));
+ }
+ suggestions.push((span.shrink_to_hi(), "[..]".into()));
+ err.multipart_suggestion_verbose(msg, suggestions, Applicability::MaybeIncorrect);
+ } else {
+ err.span_help(span, msg);
+ }
+ }
+ }
}
/// Add a hint to add a missing borrow or remove an unnecessary one.
@@ -3854,7 +3935,7 @@ fn hint_missing_borrow<'tcx>(
// This could be a variant constructor, for example.
let Some(fn_decl) = found_node.fn_decl() else { return; };
- let args = fn_decl.inputs.iter().map(|ty| ty);
+ let args = fn_decl.inputs.iter();
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
let mut refs = vec![];
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 944436ab8..26cadab3e 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -2,6 +2,7 @@ use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ProjectionCacheKey;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
@@ -132,8 +133,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
- self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
+ fn collect_remaining_errors(
+ &mut self,
+ _infcx: &InferCtxt<'tcx>,
+ ) -> Vec<FulfillmentError<'tcx>> {
+ self.predicates
+ .to_errors(CodeAmbiguity { overflow: false })
+ .into_iter()
+ .map(to_fulfillment_error)
+ .collect()
}
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
@@ -210,6 +218,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
type Error = FulfillmentErrorCode<'tcx>;
type OUT = Outcome<Self::Obligation, Self::Error>;
+ /// Compared to `needs_process_obligation` this and its callees
+ /// contain some optimizations that come at the price of false negatives.
+ ///
+ /// They
+ /// - reduce branching by covering only the most common case
+ /// - take a read-only view of the unification tables which allows skipping undo_log
+ /// construction.
+ /// - bail out on value-cache misses in ena to avoid pointer chasing
+ /// - hoist RefCell locking out of the loop
+ #[inline]
+ fn skippable_obligations<'b>(
+ &'b self,
+ it: impl Iterator<Item = &'b Self::Obligation>,
+ ) -> usize {
+ let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged();
+
+ it.take_while(|o| match o.stalled_on.as_slice() {
+ [o] => is_unchanged(*o),
+ _ => false,
+ })
+ .count()
+ }
+
/// Identifies whether a predicate obligation needs processing.
///
/// This is always inlined because it has a single callsite and it is
@@ -337,8 +368,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
- ty::PredicateKind::AliasEq(..) => {
- bug!("AliasEq is only used for new solver")
+ ty::PredicateKind::AliasRelate(..) => {
+ bug!("AliasRelate is only used for new solver")
}
},
Some(pred) => match pred {
@@ -515,7 +546,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
if let Ok(new_obligations) = infcx
.at(&obligation.cause, obligation.param_env)
.trace(c1, c2)
- .eq(a.substs, b.substs)
+ .eq(DefineOpaqueTypes::No, a.substs, b.substs)
{
return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(),
@@ -524,8 +555,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
(_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => {
- if let Ok(new_obligations) =
- infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
+ if let Ok(new_obligations) = infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(DefineOpaqueTypes::No, c1, c2)
{
return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(),
@@ -565,12 +597,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => {
- match self
- .selcx
- .infcx
- .at(&obligation.cause, obligation.param_env)
- .eq(c1, c2)
- {
+ match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
+ DefineOpaqueTypes::No,
+ c1,
+ c2,
+ ) {
Ok(inf_ok) => {
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
}
@@ -606,16 +637,15 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
- ty::PredicateKind::AliasEq(..) => {
- bug!("AliasEq is only used for new solver")
+ ty::PredicateKind::AliasRelate(..) => {
+ bug!("AliasRelate is only used for new solver")
}
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
- match self
- .selcx
- .infcx
- .at(&obligation.cause, obligation.param_env)
- .eq(ct.ty(), ty)
- {
+ match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
+ DefineOpaqueTypes::No,
+ ct.ty(),
+ ty,
+ ) {
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented,
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index b94346b09..af567c074 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -87,7 +87,12 @@ pub fn type_allowed_to_implement_copy<'tcx>(
};
let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
let normalization_errors = ocx.select_where_possible();
- if !normalization_errors.is_empty() {
+
+ // NOTE: The post-normalization type may also reference errors,
+ // such as when we project to a missing type or we have a mismatch
+ // between expected and found const-generic types. Don't report an
+ // additional copy error here, since it's not typically useful.
+ if !normalization_errors.is_empty() || ty.references_error() {
tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
continue;
}
@@ -106,17 +111,12 @@ pub fn type_allowed_to_implement_copy<'tcx>(
// Check regions assuming the self type of the impl is WF
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
- Some(&infcx),
infcx.implied_bounds_tys(
param_env,
parent_cause.body_id,
FxIndexSet::from_iter([self_type]),
),
);
- infcx.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- param_env,
- );
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() {
infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 4e30108be..8a203dec8 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -4,7 +4,7 @@
pub mod auto_trait;
mod chalk_fulfill;
-mod coherence;
+pub(crate) mod coherence;
pub mod const_evaluatable;
mod engine;
pub mod error_reporting;
@@ -28,9 +28,9 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
-use rustc_span::def_id::{DefId, CRATE_DEF_ID};
+use rustc_span::def_id::DefId;
use rustc_span::Span;
use std::fmt::Debug;
@@ -58,17 +58,12 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError}
pub use self::structural_match::{
search_for_adt_const_param_violation, search_for_structural_match_violation,
};
-pub use self::util::{
- elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
- elaborate_trait_ref, elaborate_trait_refs,
-};
+pub use self::util::elaborate;
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
-pub use self::util::{
- get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
-};
+pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
- SupertraitDefIds, Supertraits,
+ SupertraitDefIds,
};
pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
@@ -131,29 +126,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
- span: Span,
) -> bool {
let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty]));
- pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span)
+ pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
}
-#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)]
+/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
+///
+/// Ping me on zulip if you want to use this method and need help with finding
+/// an appropriate replacement.
+#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
fn pred_known_to_hold_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
- span: Span,
) -> bool {
let has_non_region_infer = pred.has_non_region_infer();
- let obligation = Obligation {
- param_env,
- // We can use a dummy node-id here because we won't pay any mind
- // to region obligations that arise (there shouldn't really be any
- // anyhow).
- cause: ObligationCause::misc(span, CRATE_DEF_ID),
- recursion_depth: 0,
- predicate: pred.to_predicate(infcx.tcx),
- };
+ let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result);
@@ -166,14 +155,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
// this function's result remains infallible, we must confirm
// that guess. While imperfect, I believe this is sound.
- // FIXME(@lcnr): this function doesn't seem right.
- //
// The handling of regions in this area of the code is terrible,
// see issue #29149. We should be able to improve on this with
// NLL.
- let errors = fully_solve_obligation(infcx, obligation);
-
- match &errors[..] {
+ let ocx = ObligationCtxt::new(infcx);
+ ocx.register_obligation(obligation);
+ let errors = ocx.select_all_or_error();
+ match errors.as_slice() {
[] => true,
errors => {
debug!(?errors);
@@ -210,7 +198,7 @@ fn do_normalize_predicates<'tcx>(
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
return Err(reported);
}
};
@@ -276,9 +264,7 @@ pub fn normalize_param_env_or_error<'tcx>(
// and errors will get reported then; so outside of type inference we
// can be sure that no errors should occur.
let mut predicates: Vec<_> =
- util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
- .map(|obligation| obligation.predicate)
- .collect();
+ util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
@@ -389,43 +375,6 @@ where
Ok(resolved_value)
}
-/// Process an obligation (and any nested obligations that come from it) to
-/// completion, returning any errors
-pub fn fully_solve_obligation<'tcx>(
- infcx: &InferCtxt<'tcx>,
- obligation: PredicateObligation<'tcx>,
-) -> Vec<FulfillmentError<'tcx>> {
- fully_solve_obligations(infcx, [obligation])
-}
-
-/// Process a set of obligations (and any nested obligations that come from them)
-/// to completion
-pub fn fully_solve_obligations<'tcx>(
- infcx: &InferCtxt<'tcx>,
- obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
-) -> Vec<FulfillmentError<'tcx>> {
- let ocx = ObligationCtxt::new(infcx);
- ocx.register_obligations(obligations);
- ocx.select_all_or_error()
-}
-
-/// Process a bound (and any nested obligations that come from it) to completion.
-/// This is a convenience function for traits that have no generic arguments, such
-/// as auto traits, and builtin traits like Copy or Sized.
-pub fn fully_solve_bound<'tcx>(
- infcx: &InferCtxt<'tcx>,
- cause: ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- bound: DefId,
-) -> Vec<FulfillmentError<'tcx>> {
- let tcx = infcx.tcx;
- let trait_ref = tcx.mk_trait_ref(bound, [ty]);
- let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
-
- fully_solve_obligation(infcx, obligation)
-}
-
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods.
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 4eacb5211..b8ad1925e 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -8,20 +8,19 @@
//! - not reference the erased type `Self` except for in this receiver;
//! - not have generic type parameters.
-use super::{elaborate_predicates, elaborate_trait_ref};
+use super::elaborate;
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
-use hir::def::DefKind;
use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
+use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
@@ -140,6 +139,10 @@ fn object_safety_violations_for_trait(
if !spans.is_empty() {
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
}
+ let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
+ if !spans.is_empty() {
+ violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
+ }
violations.extend(
tcx.associated_items(trait_def_id)
@@ -157,6 +160,7 @@ fn object_safety_violations_for_trait(
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
+ .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
.map(|item| {
let ident = item.ident(tcx);
ObjectSafetyViolation::GAT(ident.name, ident.span)
@@ -331,7 +335,7 @@ fn predicate_references_self<'tcx>(
has_self_ty(&ty.into()).then_some(sp)
}
- ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
+ ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
@@ -348,6 +352,21 @@ fn predicate_references_self<'tcx>(
}
}
+fn super_predicates_have_non_lifetime_binders(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+) -> SmallVec<[Span; 1]> {
+ // If non_lifetime_binders is disabled, then exit early
+ if !tcx.features().non_lifetime_binders {
+ return SmallVec::new();
+ }
+ tcx.super_predicates_of(trait_def_id)
+ .predicates
+ .iter()
+ .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span))
+ .collect()
+}
+
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
generics_require_sized_self(tcx, trait_def_id)
}
@@ -360,26 +379,24 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Search for a predicate like `Self : Sized` amongst the trait bounds.
let predicates = tcx.predicates_of(def_id);
let predicates = predicates.instantiate_identity(tcx).predicates;
- elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
- match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => {
- trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
- }
- ty::PredicateKind::Clause(ty::Clause::Projection(..))
- | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
- | ty::PredicateKind::WellFormed(..)
- | ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::AliasEq(..)
- | ty::PredicateKind::Ambiguous
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
+ elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => {
+ trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
}
+ ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::AliasRelate(..)
+ | ty::PredicateKind::Ambiguous
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
})
}
@@ -649,10 +666,11 @@ fn object_ty_for_trait<'tcx>(
});
debug!(?trait_predicate);
- let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref)
- .filter_map(|obligation| {
- debug!(?obligation);
- let pred = obligation.predicate.to_opt_poly_projection_pred()?;
+ let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
+ let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred])
+ .filter_map(|pred| {
+ debug!(?pred);
+ let pred = pred.to_opt_poly_projection_pred()?;
Some(pred.map_bound(|p| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
tcx, p,
@@ -854,7 +872,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
}
}
ty::Alias(ty::Projection, ref data)
- if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder =>
+ if self.tcx.is_impl_trait_in_trait(data.def_id) =>
{
// We'll deny these later in their own pass
ControlFlow::Continue(())
@@ -921,7 +939,7 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
ty.skip_binder().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Alias(ty::Projection, proj) = ty.kind()
- && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+ && tcx.is_impl_trait_in_trait(proj.def_id)
{
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
} else {
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 6cb64ad57..cff3d277a 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,9 +1,10 @@
use crate::infer::InferCtxt;
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_middle::ty::{self, ParamEnv, Ty};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
@@ -52,6 +53,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
body_id: LocalDefId,
ty: Ty<'tcx>,
) -> Vec<OutlivesBound<'tcx>> {
+ let ty = self.resolve_vars_if_possible(ty);
+ let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
+ assert!(!ty.needs_infer());
+
let span = self.tcx.def_span(body_id);
let result = param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
@@ -71,22 +76,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
if let Some(constraints) = constraints {
debug!(?constraints);
+ if !constraints.member_constraints.is_empty() {
+ span_bug!(span, "{:#?}", constraints.member_constraints);
+ }
+
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
+ let ocx = ObligationCtxt::new(self);
let cause = ObligationCause::misc(span, body_id);
- let errors = super::fully_solve_obligations(
- self,
- constraints.outlives.iter().map(|constraint| {
- self.query_outlives_constraint_to_obligation(
- *constraint,
- cause.clone(),
- param_env,
- )
- }),
- );
- if !constraints.member_constraints.is_empty() {
- span_bug!(span, "{:#?}", constraints.member_constraints);
+ for &constraint in &constraints.outlives {
+ ocx.register_obligation(self.query_outlives_constraint_to_obligation(
+ constraint,
+ cause.clone(),
+ param_env,
+ ));
}
+
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
@@ -104,11 +110,6 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
body_id: LocalDefId,
tys: FxIndexSet<Ty<'tcx>>,
) -> Bounds<'a, 'tcx> {
- tys.into_iter()
- .map(move |ty| {
- let ty = self.resolve_vars_if_possible(ty);
- self.implied_outlives_bounds(param_env, body_id, ty)
- })
- .flatten()
+ tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 870ecc2a9..826fc63ca 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,11 +28,11 @@ use rustc_hir::def::DefKind;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
@@ -286,12 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>(
);
obligations.extend(new);
- match infcx
- .at(&obligation.cause, obligation.param_env)
- // This is needed to support nested opaque types like `impl Fn() -> impl Trait`
- .define_opaque_types(true)
- .eq(normalized, actual)
- {
+ // Need to define opaque types to support nested opaque types like `impl Fn() -> impl Trait`
+ match infcx.at(&obligation.cause, obligation.param_env).eq(
+ DefineOpaqueTypes::Yes,
+ normalized,
+ actual,
+ ) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)
@@ -468,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
return ty;
}
+ let (kind, data) = match *ty.kind() {
+ ty::Alias(kind, alias_ty) => (kind, alias_ty),
+ _ => return ty.super_fold_with(self),
+ };
+
// We try to be a little clever here as a performance optimization in
// cases where there are nested projections under binders.
// For example:
@@ -491,13 +496,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
// replace bound vars if the current type is a `Projection` and we need
// to make sure we don't forget to fold the substs regardless.
- match *ty.kind() {
+ match kind {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
- if !substs.has_escaping_bound_vars() =>
- {
+ ty::Opaque if !data.substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
@@ -513,8 +516,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
}
- let substs = substs.fold_with(self);
- let generic_ty = self.interner().type_of(def_id);
+ let substs = data.substs.fold_with(self);
+ let generic_ty = self.interner().type_of(data.def_id);
let concrete_ty = generic_ty.subst(self.interner(), substs);
self.depth += 1;
let folded_ty = self.fold_ty(concrete_ty);
@@ -523,8 +526,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
}
}
}
+ ty::Opaque => ty.super_fold_with(self),
- ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
+ ty::Projection if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't
// have escaping bound vars, we don't need to replace them with
// placeholders (see branch below). *Also*, we know that we can
@@ -563,7 +567,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
normalized_ty.ty().unwrap()
}
- ty::Alias(ty::Projection, data) => {
+ ty::Projection => {
// If there are escaping bound vars, we temporarily replace the
// bound vars with placeholders. Note though, that in the case
// that we still can't project for whatever reason (e.g. self
@@ -612,8 +616,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
-
- _ => ty.super_fold_with(self),
}
}
@@ -770,7 +772,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
}
ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
- let p = ty::PlaceholderRegion { universe, name: br.kind };
+ let p = ty::PlaceholderRegion { universe, bound: br };
self.mapped_regions.insert(p, br);
self.infcx.tcx.mk_re_placeholder(p)
}
@@ -788,7 +790,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
}
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
- let p = ty::PlaceholderType { universe, name: bound_ty.kind };
+ let p = ty::PlaceholderType { universe, bound: bound_ty };
self.mapped_types.insert(p, bound_ty);
self.infcx.tcx.mk_placeholder(p)
}
@@ -807,7 +809,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
}
ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
- let p = ty::PlaceholderConst { universe, name: bound_const };
+ let p = ty::PlaceholderConst { universe, bound: bound_const };
self.mapped_consts.insert(p, bound_const);
self.infcx.tcx.mk_const(p, ct.ty())
}
@@ -871,12 +873,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r1 = match *r0 {
- ty::ReVar(_) => self
+ ty::ReVar(vid) => self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
- .opportunistic_resolve_region(self.infcx.tcx, r0),
+ .opportunistic_resolve_var(self.infcx.tcx, vid),
_ => r0,
};
@@ -1296,7 +1298,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
) {
let tcx = selcx.tcx();
if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
- let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
let trait_def_id = tcx.parent(trait_fn_def_id);
let trait_substs =
@@ -2065,7 +2067,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
debug!(?cache_projection, ?obligation_projection);
- match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
+ match infcx.at(cause, param_env).eq(
+ DefineOpaqueTypes::No,
+ cache_projection,
+ obligation_projection,
+ ) {
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
@@ -2194,13 +2200,14 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
let tcx = selcx.tcx();
let mut obligations = data.nested;
- let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
Ok(assoc_ty) => assoc_ty,
Err(guar) => return Progress::error(tcx, guar),
};
// We don't support specialization for RPITITs anyways... yet.
- if !leaf_def.is_final() {
+ // Also don't try to project to an RPITIT that has no value
+ if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() {
return Progress { term: tcx.ty_error_misc().into(), obligations };
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index f183248f2..edbe2de81 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,9 +1,8 @@
+use rustc_infer::traits::{TraitEngine, TraitEngineExt};
use rustc_middle::ty;
-use rustc_session::config::TraitSolver;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt;
-use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
pub trait InferCtxtExt<'tcx> {
@@ -79,37 +78,30 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
_ => obligation.param_env.without_const(),
};
- if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+ if self.tcx.trait_solver_next() {
+ self.probe(|snapshot| {
+ let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
+ fulfill_cx.register_predicate_obligation(self, obligation.clone());
+ // True errors
+ // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
+ if !fulfill_cx.select_where_possible(self).is_empty() {
+ Ok(EvaluationResult::EvaluatedToErr)
+ } else if !fulfill_cx.select_all_or_error(self).is_empty() {
+ Ok(EvaluationResult::EvaluatedToAmbig)
+ } else if self.opaque_types_added_in_snapshot(snapshot) {
+ Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+ } else if self.region_constraints_added_in_snapshot(snapshot).is_some() {
+ Ok(EvaluationResult::EvaluatedToOkModuloRegions)
+ } else {
+ Ok(EvaluationResult::EvaluatedToOk)
+ }
+ })
+ } else {
let c_pred = self.canonicalize_query_keep_static(
param_env.and(obligation.predicate),
&mut _orig_values,
);
self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
- } else {
- self.probe(|snapshot| {
- if let Ok((_, certainty)) =
- self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate))
- {
- match certainty {
- Certainty::Yes => {
- if self.opaque_types_added_in_snapshot(snapshot) {
- Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
- } else if self.region_constraints_added_in_snapshot(snapshot).is_some()
- {
- Ok(EvaluationResult::EvaluatedToOkModuloRegions)
- } else {
- Ok(EvaluationResult::EvaluatedToOk)
- }
- }
- Certainty::Maybe(MaybeCause::Ambiguity) => {
- Ok(EvaluationResult::EvaluatedToAmbig)
- }
- Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical),
- }
- } else {
- Ok(EvaluationResult::EvaluatedToErr)
- }
- })
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index b0cec3ce7..a986a9b6a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -197,23 +197,30 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
return Ok(*ty);
}
+ let (kind, data) = match *ty.kind() {
+ ty::Alias(kind, data) => (kind, data),
+ _ => {
+ let res = ty.try_super_fold_with(self)?;
+ self.cache.insert(ty, res);
+ return Ok(res);
+ }
+ };
+
// See note in `rustc_trait_selection::traits::project` about why we
// wait to fold the substs.
// Wrap this in a closure so we don't accidentally return from the outer function
- let res = match *ty.kind() {
+ let res = match kind {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
- if !substs.has_escaping_bound_vars() =>
- {
+ ty::Opaque if !data.substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.try_super_fold_with(self)?,
Reveal::All => {
- let substs = substs.try_fold_with(self)?;
+ let substs = data.substs.try_fold_with(self)?;
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
// A closure or generator may have itself as in its upvars.
@@ -228,7 +235,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
return ty.try_super_fold_with(self);
}
- let generic_ty = self.interner().type_of(def_id);
+ let generic_ty = self.interner().type_of(data.def_id);
let concrete_ty = generic_ty.subst(self.interner(), substs);
self.anon_depth += 1;
if concrete_ty == ty {
@@ -248,62 +255,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
}
}
- ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
- // This branch is just an optimization: when we don't have escaping bound vars,
- // we don't need to replace them with placeholders (see branch below).
-
- let tcx = self.infcx.tcx;
- let data = data.try_fold_with(self)?;
-
- let mut orig_values = OriginalQueryValues::default();
- // HACK(matthewjasper) `'static` is special-cased in selection,
- // so we cannot canonicalize it.
- let c_data = self
- .infcx
- .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
- debug!("QueryNormalizer: c_data = {:#?}", c_data);
- debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- let result = tcx.normalize_projection_ty(c_data)?;
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- // Rustdoc normalizes possibly not well-formed types, so only
- // treat this as a bug if we're not in rustdoc.
- if !tcx.sess.opts.actually_rustdoc {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- format!("unexpected ambiguity: {:?} {:?}", c_data, result),
- );
- }
- return Err(NoSolution);
- }
- let InferOk { value: result, obligations } =
- self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- )?;
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
-
- let res = result.normalized_ty;
- // `tcx.normalize_projection_ty` may normalize to a type that still has
- // unevaluated consts, so keep normalizing here if that's the case.
- if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
- res.try_super_fold_with(self)?
- } else {
- res
- }
- }
+ ty::Opaque => ty.try_super_fold_with(self)?,
- ty::Alias(ty::Projection, data) => {
+ ty::Projection => {
// See note in `rustc_trait_selection::traits::project`
let tcx = self.infcx.tcx;
let infcx = self.infcx;
- let (data, mapped_regions, mapped_types, mapped_consts) =
- BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ // Just an optimization: When we don't have escaping bound vars,
+ // we don't need to replace them with placeholders.
+ let (data, maps) = if data.has_escaping_bound_vars() {
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ (data, Some((mapped_regions, mapped_types, mapped_consts)))
+ } else {
+ (data, None)
+ };
let data = data.try_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
@@ -337,14 +304,18 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- let res = PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- result.normalized_ty,
- );
+ let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ )
+ } else {
+ result.normalized_ty
+ };
// `tcx.normalize_projection_ty` may normalize to a type that still has
// unevaluated consts, so keep normalizing here if that's the case.
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
@@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
res
}
}
-
- _ => ty.try_super_fold_with(self)?,
};
self.cache.insert(ty, res);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 6bf3ed0d0..8f1b05c11 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,8 +1,8 @@
use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk};
-use crate::traits;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_span::source_map::DUMMY_SP;
@@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
);
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
- let errors = traits::fully_solve_obligations(infcx, obligations);
+ let ocx = ObligationCtxt::new(infcx);
+ ocx.register_obligations(obligations);
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
@@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
}
let region_obligations = infcx.take_registered_region_obligations();
-
let region_constraint_data = infcx.take_and_reset_region_constraints();
-
let region_constraints = query_response::make_query_region_constraints(
infcx.tcx,
region_obligations
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 e91057356..1f5bbc178 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -5,12 +5,14 @@
//! candidates. See the [rustc dev guide] for more details.
//!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
+
+use hir::def_id::DefId;
use hir::LangItem;
use rustc_hir as hir;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_target::spec::abi::Abi;
use crate::traits;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -95,7 +97,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} else if lang_items.tuple_trait() == Some(def_id) {
self.assemble_candidate_for_tuple(obligation, &mut candidates);
} else if lang_items.pointer_like() == Some(def_id) {
- self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
+ self.assemble_candidate_for_pointer_like(obligation, &mut candidates);
+ } else if lang_items.fn_ptr_trait() == Some(def_id) {
+ self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -290,6 +294,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
+ // Keep this function in sync with extract_tupled_inputs_and_output_from_callable
+ // until the old solver (and thus this function) is removed.
+
// Okay to skip binder because what we are inspecting doesn't involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
match *self_ty.kind() {
@@ -298,31 +305,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates.ambiguous = true; // Could wind up being a fn() type.
}
// Provide an impl, but only for suitable `fn` pointers.
- ty::FnPtr(_) => {
- if let ty::FnSig {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- c_variadic: false,
- ..
- } = self_ty.fn_sig(self.tcx()).skip_binder()
- {
+ ty::FnPtr(sig) => {
+ if sig.is_fn_trait_compatible() {
candidates.vec.push(FnPointerCandidate { is_const: false });
}
}
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
ty::FnDef(def_id, _) => {
- if let ty::FnSig {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- c_variadic: false,
- ..
- } = self_ty.fn_sig(self.tcx()).skip_binder()
+ if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+ && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
{
- if self.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 { is_const: self.tcx().is_const_fn(def_id) });
}
}
_ => {}
@@ -330,13 +325,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
/// Searches for impls that might apply to `obligation`.
+ #[instrument(level = "debug", skip(self, candidates))]
fn assemble_candidates_from_impls(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
- debug!(?obligation, "assemble_candidates_from_impls");
-
// Essentially any user-written impl will match with an error type,
// so creating `ImplCandidates` isn't useful. However, we might
// end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`)
@@ -350,6 +344,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
+ let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
+ let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs;
self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
@@ -358,7 +354,14 @@ 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 self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
+ if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) {
+ return;
+ }
+ if self.reject_fn_ptr_impls(
+ impl_def_id,
+ obligation,
+ impl_trait_ref.skip_binder().self_ty(),
+ ) {
return;
}
@@ -371,6 +374,99 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
}
+ /// The various `impl<T: FnPtr> Trait for T` in libcore are more like builtin impls for all function items
+ /// and function pointers and less like blanket impls. Rejecting them when they can't possibly apply (because
+ /// the obligation's self-type does not implement `FnPtr`) avoids reporting that the self type does not implement
+ /// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
+ #[instrument(level = "trace", skip(self), ret)]
+ fn reject_fn_ptr_impls(
+ &self,
+ impl_def_id: DefId,
+ obligation: &TraitObligation<'tcx>,
+ impl_self_ty: Ty<'tcx>,
+ ) -> bool {
+ // Let `impl<T: FnPtr> Trait for Vec<T>` go through the normal rejection path.
+ if !matches!(impl_self_ty.kind(), ty::Param(..)) {
+ return false;
+ }
+ let Some(fn_ptr_trait) = self.tcx().lang_items().fn_ptr_trait() else {
+ return false;
+ };
+
+ for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates {
+ let ty::PredicateKind::Clause(ty::Clause::Trait(pred))
+ = predicate.kind().skip_binder() else { continue };
+ if fn_ptr_trait != pred.trait_ref.def_id {
+ continue;
+ }
+ trace!(?pred);
+ // Not the bound we're looking for
+ if pred.self_ty() != impl_self_ty {
+ continue;
+ }
+
+ match obligation.self_ty().skip_binder().kind() {
+ // Fast path to avoid evaluating an obligation that trivially holds.
+ // There may be more bounds, but these are checked by the regular path.
+ ty::FnPtr(..) => return false,
+ // These may potentially implement `FnPtr`
+ ty::Placeholder(..)
+ | ty::Dynamic(_, _, _)
+ | ty::Alias(_, _)
+ | ty::Infer(_)
+ | ty::Param(..) => {}
+
+ ty::Bound(_, _) => span_bug!(
+ obligation.cause.span(),
+ "cannot have escaping bound var in self type of {obligation:#?}"
+ ),
+ // These can't possibly implement `FnPtr` as they are concrete types
+ // and not `FnPtr`
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(_, _)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(_, _)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(_, _, _)
+ | ty::Closure(_, _)
+ | ty::Generator(_, _, _)
+ | ty::GeneratorWitness(_)
+ | ty::GeneratorWitnessMIR(_, _)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Error(_) => return true,
+ // FIXME: Function definitions could actually implement `FnPtr` by
+ // casting the ZST function def to a function pointer.
+ ty::FnDef(_, _) => return true,
+ }
+
+ // Generic params can implement `FnPtr` if the predicate
+ // holds within its own environment.
+ let obligation = Obligation::new(
+ self.tcx(),
+ obligation.cause.clone(),
+ obligation.param_env,
+ self.tcx().mk_predicate(obligation.predicate.map_bound(|mut pred| {
+ pred.trait_ref =
+ self.tcx().mk_trait_ref(fn_ptr_trait, [pred.trait_ref.self_ty()]);
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred))
+ })),
+ );
+ if let Ok(r) = self.infcx.evaluate_obligation(&obligation) {
+ if !r.may_apply() {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
fn assemble_candidates_from_auto_impls(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -783,6 +879,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let relevant_impl = self.tcx().find_map_relevant_impl(
self.tcx().require_lang_item(LangItem::Drop, None),
obligation.predicate.skip_binder().trait_ref.self_ty(),
+ TreatProjections::ForLookup,
Some,
);
@@ -845,15 +942,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- fn assemble_candidate_for_ptr_sized(
+ fn assemble_candidate_for_pointer_like(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
// The regions of a type don't affect the size of the type
- let self_ty = self
- .tcx()
- .erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate.self_ty()));
+ let tcx = self.tcx();
+ let self_ty =
+ tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty()));
// But if there are inference variables, we have to wait until it's resolved.
if self_ty.has_non_region_infer() {
@@ -861,13 +958,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
- let usize_layout =
- self.tcx().layout_of(ty::ParamEnv::empty().and(self.tcx().types.usize)).unwrap().layout;
- if let Ok(layout) = self.tcx().layout_of(obligation.param_env.and(self_ty))
- && layout.layout.size() == usize_layout.size()
- && layout.layout.align().abi == usize_layout.align().abi
+ if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty))
+ && layout.layout.is_pointer_like(&tcx.data_layout)
{
candidates.vec.push(BuiltinCandidate { has_nested: false });
}
}
+
+ fn assemble_candidates_for_fn_ptr_trait(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+ match self_ty.skip_binder().kind() {
+ ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(..)
+ | ty::Foreign(..)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::Placeholder(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::GeneratorWitnessMIR(..)
+ | ty::Never
+ | ty::Tuple(..)
+ | ty::Alias(..)
+ | ty::Param(..)
+ | ty::Bound(..)
+ | ty::Error(_)
+ | ty::Infer(
+ ty::InferTy::IntVar(_)
+ | ty::InferTy::FloatVar(_)
+ | ty::InferTy::FreshIntTy(_)
+ | ty::InferTy::FreshFloatTy(_),
+ ) => {}
+ ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)) => {
+ candidates.ambiguous = true;
+ }
+ }
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 21c158fd0..88121f865 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -8,8 +8,8 @@
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::{
self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate,
TraitRef, Ty, TyCtxt, TypeVisitableExt,
@@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver;
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
-use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
+use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::vtable::{
count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
VtblSegment,
@@ -131,6 +131,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
};
+ // The obligations returned by confirmation are recursively evaluated
+ // so we need to make sure they have the correct depth.
+ for subobligation in impl_src.borrow_nested_obligations_mut() {
+ 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| {
@@ -177,7 +183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(placeholder_trait_predicate, candidate)
+ .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);
@@ -253,15 +259,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
let cause = obligation.derived_cause(BuiltinDerivedObligation);
- ensure_sufficient_stack(|| {
- self.collect_predicates_for_types(
- obligation.param_env,
- cause,
- obligation.recursion_depth + 1,
- trait_def,
- nested,
- )
- })
+ self.collect_predicates_for_types(
+ obligation.param_env,
+ cause,
+ obligation.recursion_depth + 1,
+ trait_def,
+ nested,
+ )
} else {
vec![]
};
@@ -462,7 +466,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(obligation_trait_ref, upcast_trait_ref)
+ .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);
@@ -601,10 +605,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, "confirm_fn_pointer_candidate");
let tcx = self.tcx();
- let self_ty = self
+
+ let Some(self_ty) = self
.infcx
- .shallow_resolve(obligation.self_ty().no_bound_vars())
- .expect("fn pointer should not capture bound vars from predicate");
+ .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
+ // them often.
+ return Err(SelectionError::Unimplemented);
+ };
+
let sig = self_ty.fn_sig(tcx);
let trait_ref = closure_trait_ref_and_return_type(
tcx,
@@ -819,11 +831,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
});
+ // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
self.infcx
.at(&obligation.cause, obligation.param_env)
- // needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
- .define_opaque_types(true)
- .sup(obligation_trait_ref, expected_trait_ref)
+ .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
.map(|InferOk { mut obligations, .. }| {
obligations.extend(nested);
obligations
@@ -888,7 +899,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(target, source_trait)
+ .sup(DefineOpaqueTypes::No, target, source_trait)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
@@ -987,7 +998,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(target, source_trait)
+ .sup(DefineOpaqueTypes::No, target, source_trait)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
@@ -1058,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(b, a)
+ .eq(DefineOpaqueTypes::No, b, a)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
}
@@ -1073,6 +1084,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tail_field = def
.non_enum_variant()
.fields
+ .raw
.last()
.expect("expected unsized ADT to have a tail field");
let tail_field_ty = tcx.type_of(tail_field.did);
@@ -1106,19 +1118,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(target, new_struct)
+ .eq(DefineOpaqueTypes::No, target, new_struct)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
// Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
- nested.push(predicate_for_trait_def(
+ let tail_unsize_obligation = obligation.with(
tcx,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.predicate.def_id(),
- obligation.recursion_depth + 1,
- [source_tail, target_tail],
- ));
+ tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]),
+ );
+ nested.push(tail_unsize_obligation);
}
// `(.., T)` -> `(.., U)`
@@ -1136,21 +1145,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(target, new_tuple)
+ .eq(DefineOpaqueTypes::No, target, new_tuple)
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
- // Construct the nested `T: Unsize<U>` predicate.
- nested.push(ensure_sufficient_stack(|| {
- predicate_for_trait_def(
- tcx,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.predicate.def_id(),
- obligation.recursion_depth + 1,
- [a_last, b_last],
- )
- }));
+ // Add a nested `T: Unsize<U>` predicate.
+ let last_unsize_obligation = obligation
+ .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last]));
+ nested.push(last_unsize_obligation);
}
_ => bug!("source: {source}, target: {target}"),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7f454fbb3..6bb53418b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2,12 +2,6 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
-// FIXME: The `map` field in ProvisionalEvaluationCache should be changed to
-// a `FxIndexMap` to avoid query instability, but right now it causes a perf regression. This would be
-// fixed or at least lightened by the addition of the `drain_filter` method to `FxIndexMap`
-// Relevant: https://github.com/rust-lang/rust/pull/103723 and https://github.com/bluss/indexmap/issues/242
-#![allow(rustc::potential_query_instability)]
-
use self::EvaluationResult::*;
use self::SelectionCandidate::*;
@@ -17,7 +11,7 @@ use super::project;
use super::project::normalize_with_depth_to;
use super::project::ProjectionTyObligation;
use super::util;
-use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
+use super::util::closure_trait_ref_and_return_type;
use super::wf;
use super::{
ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
@@ -32,25 +26,23 @@ use crate::traits::project::ProjectAndUnifyResult;
use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey;
use crate::traits::Unimplemented;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
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::DefineOpaqueTypes;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::TraitEngineExt;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_session::config::TraitSolver;
use rustc_span::symbol::sym;
use std::cell::{Cell, RefCell};
@@ -178,14 +170,14 @@ struct TraitObligationStack<'prev, 'tcx> {
}
struct SelectionCandidateSet<'tcx> {
- // A list of candidates that definitely apply to the current
- // obligation (meaning: types unify).
+ /// A list of candidates that definitely apply to the current
+ /// obligation (meaning: types unify).
vec: Vec<SelectionCandidate<'tcx>>,
- // If `true`, then there were candidates that might or might
- // not have applied, but we couldn't tell. This occurs when some
- // of the input types are type variables, in which case there are
- // various "builtin" rules that might or might not trigger.
+ /// If `true`, then there were candidates that might or might
+ /// not have applied, but we couldn't tell. This occurs when some
+ /// of the input types are type variables, in which case there are
+ /// various "builtin" rules that might or might not trigger.
ambiguous: bool,
}
@@ -211,7 +203,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
- freshener: infcx.freshener_keep_static(),
+ freshener: infcx.freshener(),
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
@@ -465,14 +457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if candidates.len() > 1 {
let mut i = 0;
while i < candidates.len() {
- let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
+ let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
self.candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
needs_infer,
- )
+ ) == DropVictim::Yes
});
- if is_dup {
+ if should_drop_i {
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
} else {
@@ -545,13 +537,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
self.evaluation_probe(|this| {
- if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+ if this.tcx().trait_solver_next() {
+ this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
+ } else {
this.evaluate_predicate_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
obligation.clone(),
)
- } else {
- this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
}
})
}
@@ -591,9 +583,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
where
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
{
- if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+ if self.tcx().trait_solver_next() {
+ self.evaluate_predicates_recursively_in_new_solver(predicates)
+ } else {
let mut result = EvaluatedToOk;
- for obligation in predicates {
+ for mut obligation in predicates {
+ obligation.set_depth_from_parent(stack.depth());
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
if let EvaluatedToErr = eval {
// fast-path - EvaluatedToErr is the top of the lattice,
@@ -604,8 +599,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
Ok(result)
- } else {
- self.evaluate_predicates_recursively_in_new_solver(predicates)
}
}
@@ -617,6 +610,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
fulfill_cx.register_predicate_obligations(self.infcx, predicates);
// True errors
+ // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
return Ok(EvaluatedToErr);
}
@@ -661,12 +655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p);
// Does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
- Ok(Ok(InferOk { mut obligations, .. })) => {
- self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
- self.evaluate_predicates_recursively(
- previous_stack,
- obligations.into_iter(),
- )
+ Ok(Ok(InferOk { obligations, .. })) => {
+ self.evaluate_predicates_recursively(previous_stack, obligations)
}
Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig),
@@ -677,12 +667,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p);
// Does this code ever run?
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
- Ok(Ok(InferOk { mut obligations, .. })) => {
- self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
- self.evaluate_predicates_recursively(
- previous_stack,
- obligations.into_iter(),
- )
+ Ok(Ok(InferOk { obligations, .. })) => {
+ self.evaluate_predicates_recursively(previous_stack, obligations)
}
Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig),
@@ -755,9 +741,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
arg,
obligation.cause.span,
) {
- Some(mut obligations) => {
- self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-
+ Some(obligations) => {
cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
let result =
self.evaluate_predicates_recursively(previous_stack, obligations);
@@ -778,14 +762,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
- // A global type with no late-bound regions can only
- // contain the "'static" lifetime (any other lifetime
- // would either be late-bound or local), so it is guaranteed
- // to outlive any other lifetime
- if pred.0.is_global() && !pred.0.has_late_bound_vars() {
- Ok(EvaluatedToOk)
- } else {
+ // 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_non_region_infer()
+ || pred.0.has_non_region_infer()
+ {
Ok(EvaluatedToOkModuloRegions)
+ } else {
+ Ok(EvaluatedToOk)
}
}
@@ -826,10 +812,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- self.add_depth(
- subobligations.iter_mut(),
- obligation.recursion_depth,
- );
+ // Need to explicitly set the depth of nested goals here as
+ // projection obligations can cycle by themselves and in
+ // `evaluate_predicates_recursively` we only add the depth
+ // for parent trait goals because only these get added to the
+ // `TraitObligationStackList`.
+ for subobligation in subobligations.iter_mut() {
+ subobligation.set_depth_from_parent(obligation.recursion_depth);
+ }
let res = self.evaluate_predicates_recursively(
previous_stack,
subobligations,
@@ -909,38 +899,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if a.def.did == b.def.did
&& tcx.def_kind(a.def.did) == DefKind::AssocConst =>
{
- if let Ok(new_obligations) = self
+ if let Ok(InferOk { obligations, value: () }) = self
.infcx
.at(&obligation.cause, obligation.param_env)
.trace(c1, c2)
- .eq(a.substs, b.substs)
+ .eq(DefineOpaqueTypes::No, a.substs, b.substs)
{
- let mut obligations = new_obligations.obligations;
- self.add_depth(
- obligations.iter_mut(),
- obligation.recursion_depth,
- );
return self.evaluate_predicates_recursively(
previous_stack,
- obligations.into_iter(),
+ obligations,
);
}
}
(_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => {
- if let Ok(new_obligations) = self
+ if let Ok(InferOk { obligations, value: () }) = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .eq(c1, c2)
+ .eq(DefineOpaqueTypes::No, c1, c2)
{
- let mut obligations = new_obligations.obligations;
- self.add_depth(
- obligations.iter_mut(),
- obligation.recursion_depth,
- );
return self.evaluate_predicates_recursively(
previous_stack,
- obligations.into_iter(),
+ obligations,
);
}
}
@@ -965,8 +945,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => {
- match self.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
- {
+ match self.infcx.at(&obligation.cause, obligation.param_env).eq(
+ DefineOpaqueTypes::No,
+ c1,
+ c2,
+ ) {
Ok(inf_ok) => self.evaluate_predicates_recursively(
previous_stack,
inf_ok.into_obligations(),
@@ -989,12 +972,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
- ty::PredicateKind::AliasEq(..) => {
- bug!("AliasEq is only used for new solver")
+ ty::PredicateKind::AliasRelate(..) => {
+ bug!("AliasRelate is only used for new solver")
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
- match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) {
+ match self.infcx.at(&obligation.cause, obligation.param_env).eq(
+ DefineOpaqueTypes::No,
+ ct.ty(),
+ ty,
+ ) {
Ok(inf_ok) => self.evaluate_predicates_recursively(
previous_stack,
inf_ok.into_obligations(),
@@ -1359,24 +1346,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
}
- /// For various reasons, it's possible for a subobligation
- /// to have a *lower* recursion_depth than the obligation used to create it.
- /// Projection sub-obligations may be returned from the projection cache,
- /// which results in obligations with an 'old' `recursion_depth`.
- /// Additionally, methods like `InferCtxt.subtype_predicate` produce
- /// subobligations without taking in a 'parent' depth, causing the
- /// generated subobligations to have a `recursion_depth` of `0`.
- ///
- /// To ensure that obligation_depth never decreases, we force all subobligations
- /// to have at least the depth of the original obligation.
- fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
- &self,
- it: I,
- min_depth: usize,
- ) {
- it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
- }
-
fn check_recursion_depth<T>(
&self,
depth: usize,
@@ -1752,7 +1721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
+ .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have
// inference variables and placeholders escape.
@@ -1814,7 +1783,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_match = self
.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(obligation.predicate, infer_projection)
+ .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -1842,16 +1811,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ProjectionMatchesProjection::No
}
}
+}
- ///////////////////////////////////////////////////////////////////////////
- // WINNOW
- //
- // Winnowing is the process of attempting to resolve ambiguity by
- // probing further. During the winnowing process, we unify all
- // type variables and then we also attempt to evaluate recursive
- // bounds to see if they are satisfied.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum DropVictim {
+ Yes,
+ No,
+}
+
+impl DropVictim {
+ fn drop_if(should_drop: bool) -> DropVictim {
+ if should_drop { DropVictim::Yes } else { DropVictim::No }
+ }
+}
- /// Returns `true` if `victim` should be dropped in favor of
+/// ## Winnowing
+///
+/// Winnowing is the process of attempting to resolve ambiguity by
+/// probing further. During the winnowing process, we unify all
+/// type variables and then we also attempt to evaluate recursive
+/// bounds to see if they are satisfied.
+impl<'tcx> SelectionContext<'_, 'tcx> {
+ /// Returns `DropVictim::Yes` if `victim` should be dropped in favor of
/// `other`. Generally speaking we will drop duplicate
/// candidates and prefer where-clause candidates.
///
@@ -1861,9 +1842,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>,
needs_infer: bool,
- ) -> bool {
+ ) -> DropVictim {
if victim.candidate == other.candidate {
- return true;
+ return DropVictim::Yes;
}
// Check if a bound would previously have been removed when normalizing
@@ -1887,11 +1868,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// FIXME(@jswrenn): this should probably be more sophisticated
- (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+ (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
// (*)
- (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true,
- (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false,
+ (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => {
+ DropVictim::Yes
+ }
+ (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
+ DropVictim::No
+ }
(ParamCandidate(other), ParamCandidate(victim)) => {
let same_except_bound_vars = other.skip_binder().trait_ref
@@ -1905,28 +1890,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// or the current one if tied (they should both evaluate to the same answer). This is
// 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.
- other.bound_vars().len() <= victim.bound_vars().len()
+ 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.
- true
+ DropVictim::Yes
} else {
- false
+ DropVictim::No
}
}
// Drop otherwise equivalent non-const fn pointer candidates
- (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
+ (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
- // Global bounds from the where clause should be ignored
- // here (see issue #50825). Otherwise, we have a where
- // clause so don't go around looking for impls.
- // Arbitrarily give param candidates priority
- // over projection and object candidates.
(
- ParamCandidate(ref cand),
+ ParamCandidate(ref other_cand),
ImplCandidate(..)
| ClosureCandidate { .. }
| GeneratorCandidate
@@ -1939,11 +1919,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate
| ObjectCandidate(_)
| ProjectionCandidate(..),
- ) => !is_global(cand),
- (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => {
+ ) => {
+ // We have a where clause so don't go around looking
+ // for impls. Arbitrarily give param candidates priority
+ // over projection and object candidates.
+ //
+ // Global bounds from the where clause should be ignored
+ // here (see issue #50825).
+ DropVictim::drop_if(!is_global(other_cand))
+ }
+ (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(cand)
+ if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
}
(
ImplCandidate(_)
@@ -1956,18 +1944,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate,
- ParamCandidate(ref cand),
+ ParamCandidate(ref victim_cand),
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(cand) && other.evaluation.must_apply_modulo_regions()
+ DropVictim::drop_if(
+ is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
+ )
}
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
- i < j && !needs_infer
+ DropVictim::drop_if(i < j && !needs_infer)
}
(ObjectCandidate(_), ProjectionCandidate(..))
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@@ -1987,7 +1977,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate,
- ) => true,
+ ) => DropVictim::Yes,
(
ImplCandidate(..)
@@ -2001,7 +1991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinCandidate { .. }
| TraitAliasCandidate,
ObjectCandidate(_) | ProjectionCandidate(..),
- ) => false,
+ ) => DropVictim::No,
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
// See if we can toss out `victim` based on specialization.
@@ -2014,59 +2004,69 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
if tcx.specializes((other_def, victim_def)) {
- return true;
+ return DropVictim::Yes;
}
}
- if other.evaluation.must_apply_considering_regions() {
- match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
- Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
- // Subtle: If the predicate we are evaluating has inference
- // variables, do *not* allow discarding candidates due to
- // marker trait impls.
- //
- // Without this restriction, we could end up accidentally
- // constraining inference variables based on an arbitrarily
- // chosen trait impl.
- //
- // Imagine we have the following code:
- //
- // ```rust
- // #[marker] trait MyTrait {}
- // impl MyTrait for u8 {}
- // impl MyTrait for bool {}
- // ```
- //
- // And we are evaluating the predicate `<_#0t as MyTrait>`.
- //
- // During selection, we will end up with one candidate for each
- // impl of `MyTrait`. If we were to discard one impl in favor
- // of the other, we would be left with one candidate, causing
- // us to "successfully" select the predicate, unifying
- // _#0t with (for example) `u8`.
- //
- // However, we have no reason to believe that this unification
- // is correct - we've essentially just picked an arbitrary
- // *possibility* for _#0t, and required that this be the *only*
- // possibility.
- //
- // Eventually, we will either:
- // 1) Unify all inference variables in the predicate through
- // some other means (e.g. type-checking of a function). We will
- // then be in a position to drop marker trait candidates
- // without constraining inference variables (since there are
- // none left to constrain)
- // 2) Be left with some unconstrained inference variables. We
- // will then correctly report an inference error, since the
- // existence of multiple marker trait impls tells us nothing
- // about which one should actually apply.
- !needs_infer
- }
- Some(_) => true,
- None => false,
+ match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+ // For #33140 the impl headers must be exactly equal, the trait must not have
+ // any associated items and there are no where-clauses.
+ //
+ // We can just arbitrarily drop one of the impls.
+ Some(ty::ImplOverlapKind::Issue33140) => {
+ assert_eq!(other.evaluation, victim.evaluation);
+ DropVictim::Yes
}
- } else {
- false
+ // For candidates which already reference errors it doesn't really
+ // matter what we do 🤷
+ Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
+ DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
+ }
+ Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+ // Subtle: If the predicate we are evaluating has inference
+ // variables, do *not* allow discarding candidates due to
+ // marker trait impls.
+ //
+ // Without this restriction, we could end up accidentally
+ // constraining inference variables based on an arbitrarily
+ // chosen trait impl.
+ //
+ // Imagine we have the following code:
+ //
+ // ```rust
+ // #[marker] trait MyTrait {}
+ // impl MyTrait for u8 {}
+ // impl MyTrait for bool {}
+ // ```
+ //
+ // And we are evaluating the predicate `<_#0t as MyTrait>`.
+ //
+ // During selection, we will end up with one candidate for each
+ // impl of `MyTrait`. If we were to discard one impl in favor
+ // of the other, we would be left with one candidate, causing
+ // us to "successfully" select the predicate, unifying
+ // _#0t with (for example) `u8`.
+ //
+ // However, we have no reason to believe that this unification
+ // is correct - we've essentially just picked an arbitrary
+ // *possibility* for _#0t, and required that this be the *only*
+ // possibility.
+ //
+ // Eventually, we will either:
+ // 1) Unify all inference variables in the predicate through
+ // some other means (e.g. type-checking of a function). We will
+ // then be in a position to drop marker trait candidates
+ // without constraining inference variables (since there are
+ // none left to constrain)
+ // 2) Be left with some unconstrained inference variables. We
+ // will then correctly report an inference error, since the
+ // existence of multiple marker trait impls tells us nothing
+ // about which one should actually apply.
+ DropVictim::drop_if(
+ !needs_infer && other.evaluation.must_apply_considering_regions(),
+ )
+ }
+ None => DropVictim::No,
}
}
@@ -2092,10 +2092,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate,
- ) => false,
+ ) => DropVictim::No,
}
}
+}
+impl<'tcx> SelectionContext<'_, 'tcx> {
fn sized_conditions(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -2149,7 +2151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,
ty::Infer(ty::TyVar(_)) => Ambiguous,
- // We can make this an ICE if/once we actually instantiate the trait obligation.
+ // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
ty::Bound(..) => None,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
@@ -2257,7 +2259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- ty::Adt(..) | ty::Alias(..) | ty::Param(..) => {
+ ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
// Fallback to whatever user-defined impls exist in this case.
None
}
@@ -2269,9 +2271,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ambiguous
}
- ty::Placeholder(..)
- | ty::Bound(..)
- | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
+ ty::Bound(..) => None,
+
+ ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
}
}
@@ -2405,15 +2408,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
placeholder_ty,
)
});
- let placeholder_obligation = predicate_for_trait_def(
+
+ let obligation = Obligation::new(
self.tcx(),
- param_env,
cause.clone(),
- trait_def_id,
- recursion_depth,
- [normalized_ty],
+ param_env,
+ self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
);
- obligations.push(placeholder_obligation);
+ obligations.push(obligation);
obligations
})
.collect()
@@ -2507,7 +2509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&cause, obligation.param_env)
- .eq(placeholder_obligation_trait_ref, impl_trait_ref)
+ .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
})?;
@@ -2523,19 +2525,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(Normalized { value: impl_substs, obligations: nested_obligations })
}
- fn fast_reject_trait_refs(
- &mut self,
- obligation: &TraitObligation<'tcx>,
- impl_trait_ref: &ty::TraitRef<'tcx>,
- ) -> bool {
- // We can avoid creating type variables and doing the full
- // substitution if we find that any of the input types, when
- // simplified, do not match.
- let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
- iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
- .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
- }
-
/// Normalize `where_clause_trait_ref` and try to match it against
/// `obligation`. If successful, return any predicates that
/// result from the normalization.
@@ -2557,7 +2546,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+ .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ())
}
@@ -2786,7 +2775,7 @@ struct ProvisionalEvaluationCache<'tcx> {
/// - then we determine that `E` is in error -- we will then clear
/// all cache values whose DFN is >= 4 -- in this case, that
/// means the cached value for `F`.
- map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
+ map: RefCell<FxIndexMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
/// The stack of args that we assume to be true because a `WF(arg)` predicate
/// is on the stack above (and because of wellformedness is coinductive).
@@ -2934,12 +2923,13 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
/// have a performance impact in practice.
fn on_completion(&self, dfn: usize) {
debug!(?dfn, "on_completion");
-
- for (fresh_trait_pred, eval) in
- self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
- {
- debug!(?fresh_trait_pred, ?eval, "on_completion");
- }
+ self.map.borrow_mut().retain(|fresh_trait_pred, eval| {
+ if eval.from_dfn >= dfn {
+ debug!(?fresh_trait_pred, ?eval, "on_completion");
+ return false;
+ }
+ true
+ });
}
}
@@ -3021,7 +3011,7 @@ fn bind_generator_hidden_types_above<'tcx>(
if let ty::ReErased = r.kind() {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter, None),
+ kind: ty::BrAnon(None),
};
counter += 1;
r = tcx.mk_re_late_bound(current_depth, br);
@@ -3037,7 +3027,7 @@ fn bind_generator_hidden_types_above<'tcx>(
debug_assert!(!hidden_types.has_erased_regions());
}
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain(
- (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
+ (num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))),
));
ty::Binder::bind_with_vars(hidden_types, bound_vars)
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index d1d6a7a90..8546bbe52 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -10,6 +10,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
pub mod specialization_graph;
+use rustc_infer::infer::DefineOpaqueTypes;
use specialization_graph::GraphExt;
use crate::errors::NegativePositiveConflict;
@@ -21,7 +22,7 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{error_code, DelayDm, Diagnostic};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
@@ -99,10 +100,10 @@ pub fn translate_substs<'tcx>(
}
fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
- |_| {
+ |()| {
bug!(
- "When translating substitutions for specialization, the expected \
- specialization failed to hold"
+ "When translating substitutions from {source_impl:?} to {target_impl:?}, \
+ the expected specialization failed to hold"
)
},
)
@@ -193,7 +194,7 @@ fn fulfill_implication<'tcx>(
// do the impls unify? If not, no specialization.
let Ok(InferOk { obligations: more_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait)
+ infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
else {
debug!(
"fulfill_implication: {:?} does not unify with {:?}",
@@ -349,6 +350,10 @@ fn report_conflicting_impls<'tcx>(
impl_span: Span,
err: &mut Diagnostic,
) {
+ if (overlap.trait_ref, overlap.self_ty).references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 61ed9ef2e..aa5c624f4 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -21,6 +21,7 @@ pub struct FutureCompatOverlapError<'tcx> {
}
/// The result of attempting to insert an impl into a group of children.
+#[derive(Debug)]
enum Inserted<'tcx> {
/// The impl was inserted as a new child in this group of children.
BecameNewSibling(Option<FutureCompatOverlapError<'tcx>>),
@@ -49,7 +50,8 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
/// Insert an impl into this set of children without comparing to any existing impls.
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
+ if let Some(st) =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
{
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
@@ -65,7 +67,8 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
let vec: &mut Vec<DefId>;
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
+ if let Some(st) =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
{
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap();
@@ -80,6 +83,7 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
/// Attempt to insert an impl into this set of children, while comparing for
/// specialization relationships.
+ #[instrument(level = "debug", skip(self, tcx), ret)]
fn insert(
&mut self,
tcx: TyCtxt<'tcx>,
@@ -90,18 +94,13 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
let mut last_lint = None;
let mut replace_children = Vec::new();
- debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,);
-
let possible_siblings = match simplified_self {
Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)),
None => PotentialSiblings::Unfiltered(iter_children(self)),
};
for possible_sibling in possible_siblings {
- debug!(
- "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}",
- impl_def_id, simplified_self, possible_sibling,
- );
+ debug!(?possible_sibling);
let create_overlap_error = |overlap: traits::coherence::OverlapResult<'tcx>| {
let trait_ref = overlap.impl_header.trait_ref.unwrap();
@@ -302,7 +301,8 @@ impl<'tcx> GraphExt<'tcx> for Graph {
let mut parent = trait_def_id;
let mut last_lint = None;
- let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer);
+ let simplified =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey);
// Descend the specialization tree, where `parent` is the current parent node.
loop {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index bcf63d5a6..20357d4d2 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,15 +1,14 @@
-use rustc_errors::Diagnostic;
-use rustc_span::Span;
-use smallvec::SmallVec;
-
+use super::NormalizeExt;
+use super::{ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferOk;
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, SubstsRef};
+use rustc_span::Span;
+use smallvec::SmallVec;
-use super::NormalizeExt;
-use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
-use rustc_infer::infer::InferOk;
pub use rustc_infer::traits::{self, util::*};
///////////////////////////////////////////////////////////////////////////
@@ -116,7 +115,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
}
// Get components of trait alias.
- let predicates = tcx.super_predicates_of(trait_ref.def_id());
+ let predicates = tcx.implied_predicates_of(trait_ref.def_id());
debug!(?predicates);
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
@@ -199,8 +198,9 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
impl_def_id: DefId,
impl_substs: SubstsRef<'tcx>,
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
- let subject = selcx.tcx().bound_impl_subject(impl_def_id);
+ let subject = selcx.tcx().impl_subject(impl_def_id);
let subject = subject.subst(selcx.tcx(), impl_substs);
+
let InferOk { value: subject, obligations: normalization_obligations1 } =
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);
@@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
(subject, impl_obligations)
}
-pub fn predicate_for_trait_ref<'tcx>(
- tcx: TyCtxt<'tcx>,
- cause: ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
- recursion_depth: usize,
-) -> PredicateObligation<'tcx> {
- Obligation {
- cause,
- param_env,
- recursion_depth,
- predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
- }
-}
-
-pub fn predicate_for_trait_def<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- trait_def_id: DefId,
- recursion_depth: usize,
- params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-) -> PredicateObligation<'tcx> {
- let trait_ref = tcx.mk_trait_ref(trait_def_id, params);
- predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
-}
-
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d498af359..3d026506a 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>(
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
- ty::PredicateKind::AliasEq(..) => {
- bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`")
+ ty::PredicateKind::AliasRelate(..) => {
+ bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`")
}
}
@@ -364,7 +364,7 @@ impl<'tcx> WfPredicates<'tcx> {
};
if let Elaborate::All = elaborate {
- let implied_obligations = traits::util::elaborate_obligations(tcx, obligations);
+ let implied_obligations = traits::util::elaborate(tcx, obligations);
let implied_obligations = implied_obligations.map(extend);
self.out.extend(implied_obligations);
} else {
@@ -920,10 +920,10 @@ pub(crate) fn required_region_bounds<'tcx>(
) -> Vec<ty::Region<'tcx>> {
assert!(!erased_self_ty.has_escaping_bound_vars());
- traits::elaborate_predicates(tcx, predicates)
- .filter_map(|obligation| {
- debug!(?obligation);
- match obligation.predicate.kind().skip_binder() {
+ traits::elaborate(tcx, predicates)
+ .filter_map(|pred| {
+ debug!(?pred);
+ match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
@@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>(
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
ref t,