summaryrefslogtreecommitdiff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs158
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs64
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs49
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs163
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs69
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs86
22 files changed, 569 insertions, 239 deletions
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index df7c4df1868..54e22cc3d7f 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
diag
}
}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_inherent_projection_normalization_overflow)]
+pub struct InherentProjectionNormalizationOverflow {
+ #[primary_span]
+ pub span: Span,
+ pub ty: String,
+}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index bacb0e32efc..25cc82f01d5 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::elaborate;
+use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::TypeFoldable;
@@ -87,7 +88,9 @@ pub(super) enum CandidateSource {
}
/// Methods used to assemble candidates for either trait or projection goals.
-pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
+pub(super) trait GoalKind<'tcx>:
+ TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
+{
fn self_ty(self) -> Ty<'tcx>;
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
@@ -96,6 +99,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
+ // Try equating an assumption predicate against a goal's predicate. If it
+ // holds, then execute the `then` callback, which should do any additional
+ // work, then produce a response (typically by executing
+ // [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
+ fn probe_and_match_goal_against_assumption(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ assumption: ty::Predicate<'tcx>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+ ) -> QueryResult<'tcx>;
+
// Consider a clause, which consists of a "assumption" and some "requirements",
// to satisfy a goal. If the requirements hold, then attempt to satisfy our
// goal by equating it with the assumption.
@@ -104,7 +118,26 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
- ) -> QueryResult<'tcx>;
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ ecx.add_goals(requirements);
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
+
+ /// Consider a bound originating from the item bounds of an alias. For this we
+ /// require that the well-formed requirements of the self type of the goal
+ /// are "satisfied from the param-env".
+ /// See [`EvalCtxt::validate_alias_bound_self_from_param_env`].
+ fn consider_alias_bound_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ assumption: ty::Predicate<'tcx>,
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ ecx.validate_alias_bound_self_from_param_env(goal)
+ })
+ }
// Consider a clause specifically for a `dyn Trait` self type. This requires
// additionally checking all of the supertraits and object bounds to hold,
@@ -113,7 +146,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- ) -> QueryResult<'tcx>;
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ let tcx = ecx.tcx();
+ let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
+ bug!("expected object type in `consider_object_bound_candidate`");
+ };
+ ecx.add_goals(
+ structural_traits::predicates_for_object_candidate(
+ &ecx,
+ goal.param_env,
+ goal.predicate.trait_ref(tcx),
+ bounds,
+ )
+ .into_iter()
+ .map(|pred| goal.with(tcx, pred)),
+ );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
@@ -463,7 +514,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
{
- match G::consider_implied_clause(self, goal, assumption, []) {
+ match G::consider_alias_bound_candidate(self, goal, assumption) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
}
@@ -472,6 +523,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ /// Check that we are allowed to use an alias bound originating from the self
+ /// type of this goal. This means something different depending on the self type's
+ /// alias kind.
+ ///
+ /// * Projection: Given a goal with a self type such as `<Ty as Trait>::Assoc`,
+ /// we require that the bound `Ty: Trait` can be proven using either a nested alias
+ /// bound candidate, or a param-env candidate.
+ ///
+ /// * Opaque: The param-env must be in `Reveal::UserFacing` mode. Otherwise,
+ /// the goal should be proven by using the hidden type instead.
+ #[instrument(level = "debug", skip(self), ret)]
+ pub(super) fn validate_alias_bound_self_from_param_env<G: GoalKind<'tcx>>(
+ &mut self,
+ goal: Goal<'tcx, G>,
+ ) -> QueryResult<'tcx> {
+ match *goal.predicate.self_ty().kind() {
+ ty::Alias(ty::Projection, projection_ty) => {
+ let mut param_env_candidates = vec![];
+ let self_trait_ref = projection_ty.trait_ref(self.tcx());
+
+ if self_trait_ref.self_ty().is_ty_var() {
+ return self
+ .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+ }
+
+ let trait_goal: Goal<'_, ty::TraitPredicate<'tcx>> = goal.with(
+ self.tcx(),
+ ty::TraitPredicate {
+ trait_ref: self_trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
+ },
+ );
+
+ self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates);
+ // FIXME: We probably need some sort of recursion depth check here.
+ // Can't come up with an example yet, though, and the worst case
+ // we can have is a compiler stack overflow...
+ self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates);
+
+ // FIXME: We must also consider alias-bound candidates for a peculiar
+ // class of built-in candidates that I'll call "defaulted" built-ins.
+ //
+ // For example, we always know that `T: Pointee` is implemented, but
+ // we do not always know what `<T as Pointee>::Metadata` actually is,
+ // similar to if we had a user-defined impl with a `default type ...`.
+ // For these traits, since we're not able to always normalize their
+ // associated types to a concrete type, we must consider their alias bounds
+ // instead, so we can prove bounds such as `<T as Pointee>::Metadata: Copy`.
+ self.assemble_alias_bound_candidates_for_builtin_impl_default_items(
+ trait_goal,
+ &mut param_env_candidates,
+ );
+
+ self.merge_candidates(param_env_candidates)
+ }
+ ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() {
+ Reveal::UserFacing => {
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ Reveal::All => return Err(NoSolution),
+ },
+ _ => bug!("only expected to be called on alias tys"),
+ }
+ }
+
+ /// Assemble a subset of builtin impl candidates for a class of candidates called
+ /// "defaulted" built-in traits.
+ ///
+ /// For example, we always know that `T: Pointee` is implemented, but we do not
+ /// always know what `<T as Pointee>::Metadata` actually is! See the comment in
+ /// [`EvalCtxt::validate_alias_bound_self_from_param_env`] for more detail.
+ #[instrument(level = "debug", skip_all)]
+ fn assemble_alias_bound_candidates_for_builtin_impl_default_items<G: GoalKind<'tcx>>(
+ &mut self,
+ goal: Goal<'tcx, G>,
+ candidates: &mut Vec<Candidate<'tcx>>,
+ ) {
+ let lang_items = self.tcx().lang_items();
+ let trait_def_id = goal.predicate.trait_def_id(self.tcx());
+
+ // You probably shouldn't add anything to this list unless you
+ // know what you're doing.
+ let result = if lang_items.pointee_trait() == Some(trait_def_id) {
+ G::consider_builtin_pointee_candidate(self, goal)
+ } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
+ G::consider_builtin_discriminant_kind_candidate(self, goal)
+ } else {
+ Err(NoSolution)
+ };
+
+ match result {
+ Ok(result) => {
+ candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
+ }
+ Err(NoSolution) => (),
+ }
+ }
+
#[instrument(level = "debug", skip_all)]
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
&mut self,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 996dc329dcb..0ede32c753c 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => {
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index e5d51064c8d..d3228074421 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -56,11 +56,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
self.trait_def_id(tcx)
}
- fn consider_implied_clause(
+ fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
@@ -75,49 +75,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
)?;
ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
.expect("expected goal term to be fully unconstrained");
- ecx.add_goals(requirements);
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- } else {
- Err(NoSolution)
- }
- }
-
- fn consider_object_bound_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- assumption: ty::Predicate<'tcx>,
- ) -> QueryResult<'tcx> {
- if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
- && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
- {
- ecx.probe(|ecx| {
- let tcx = ecx.tcx();
-
- let assumption_projection_pred =
- ecx.instantiate_binder_with_infer(poly_projection_pred);
- ecx.eq(
- goal.param_env,
- goal.predicate.projection_ty,
- assumption_projection_pred.projection_ty,
- )?;
-
- let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
- bug!("expected object type in `consider_object_bound_candidate`");
- };
- ecx.add_goals(
- structural_traits::predicates_for_object_candidate(
- &ecx,
- goal.param_env,
- goal.predicate.projection_ty.trait_ref(tcx),
- bounds,
- )
- .into_iter()
- .map(|pred| goal.with(tcx, pred)),
- );
- ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
- .expect("expected goal term to be fully unconstrained");
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ then(ecx)
})
} else {
Err(NoSolution)
@@ -166,10 +124,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
};
if !assoc_def.item.defaultness(tcx).has_value() {
- tcx.sess.delay_span_bug(
+ let guar = tcx.sess.delay_span_bug(
tcx.def_span(assoc_def.item.def_id),
"missing value for assoc item in impl",
);
+ let error_term = match assoc_def.item.kind {
+ ty::AssocKind::Const => tcx
+ .const_error(
+ tcx.type_of(goal.predicate.def_id())
+ .subst(tcx, goal.predicate.projection_ty.substs),
+ guar,
+ )
+ .into(),
+ ty::AssocKind::Type => tcx.ty_error(guar).into(),
+ ty::AssocKind::Fn => unreachable!(),
+ };
+ ecx.eq(goal.param_env, goal.predicate.term, error_term)
+ .expect("expected goal term to be fully unconstrained");
+ return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
// Getting the right substitutions here is complex, e.g. given:
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 6c98fadd148..dcfa33ae842 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -78,11 +78,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
})
}
- fn consider_implied_clause(
+ fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
&& poly_trait_pred.def_id() == goal.predicate.def_id()
@@ -97,48 +97,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
goal.predicate.trait_ref,
assumption_trait_pred.trait_ref,
)?;
- ecx.add_goals(requirements);
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- } else {
- Err(NoSolution)
- }
- }
-
- fn consider_object_bound_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- assumption: ty::Predicate<'tcx>,
- ) -> QueryResult<'tcx> {
- if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
- && poly_trait_pred.def_id() == goal.predicate.def_id()
- && poly_trait_pred.polarity() == goal.predicate.polarity
- {
- // FIXME: Constness and polarity
- ecx.probe(|ecx| {
- let assumption_trait_pred =
- ecx.instantiate_binder_with_infer(poly_trait_pred);
- ecx.eq(
- goal.param_env,
- goal.predicate.trait_ref,
- assumption_trait_pred.trait_ref,
- )?;
-
- let tcx = ecx.tcx();
- let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
- bug!("expected object type in `consider_object_bound_candidate`");
- };
- ecx.add_goals(
- structural_traits::predicates_for_object_candidate(
- &ecx,
- goal.param_env,
- goal.predicate.trait_ref,
- bounds,
- )
- .into_iter()
- .map(|pred| goal.with(tcx, pred)),
- );
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ then(ecx)
})
} else {
Err(NoSolution)
@@ -655,7 +614,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)),
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6b080a132f3..183c2401fc3 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -801,7 +801,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
span: tcx.def_span(unevaluated.def),
unevaluated: unevaluated,
});
- Err(ErrorHandled::Reported(reported))
+ Err(ErrorHandled::Reported(reported.into()))
}
Err(err) => Err(err),
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index b7690f79933..969e5fa64b0 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -322,7 +322,9 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
let selcx = &mut SelectionContext::new(&infcx);
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
let (subject2, obligations) =
- impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+ impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| {
+ ObligationCause::dummy()
+ });
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
}
@@ -673,7 +675,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
- | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
+ | ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
ty::Param(..) => self.found_param_ty(ty),
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 9d99d30d45c..bd1ea43a78e 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>(
"Missing value for constant, but no error reported?",
)))
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
@@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
Err(err)
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
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 afb64da8b61..f5f2fe54217 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -28,6 +28,7 @@ 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::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
@@ -796,9 +797,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_label(span, explanation);
}
- if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
- Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
- self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
+ if let ObligationCauseCode::Coercion { source, target } =
+ *obligation.cause.code().peel_derives()
+ {
+ if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ self.suggest_borrowing_for_object_cast(
+ &mut err,
+ &root_obligation,
+ source,
+ target,
+ );
+ }
}
let UnsatisfiedConst(unsatisfied_const) = self
@@ -1087,17 +1096,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- OutputTypeParameterMismatch(
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
found_trait_ref,
expected_trait_ref,
- terr @ TypeError::CyclicTy(_),
- ) => self.report_type_parameter_mismatch_cyclic_type_error(
+ terr: terr @ TypeError::CyclicTy(_),
+ }) => self.report_type_parameter_mismatch_cyclic_type_error(
&obligation,
found_trait_ref,
expected_trait_ref,
terr,
),
- OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
+ found_trait_ref,
+ expected_trait_ref,
+ terr: _,
+ }) => {
match self.report_type_parameter_mismatch_error(
&obligation,
span,
@@ -1505,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
- | ObligationCauseCode::ObjectCastObligation(..)
+ | ObligationCauseCode::Coercion { .. }
| ObligationCauseCode::OpaqueType
);
@@ -1687,13 +1700,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
ty::Alias(ty::Projection, ..) => Some(12),
- ty::Alias(ty::Opaque, ..) => Some(13),
- ty::Never => Some(14),
- ty::Adt(..) => Some(15),
- ty::Generator(..) => Some(16),
- ty::Foreign(..) => Some(17),
- ty::GeneratorWitness(..) => Some(18),
- ty::GeneratorWitnessMIR(..) => Some(19),
+ ty::Alias(ty::Inherent, ..) => Some(13),
+ ty::Alias(ty::Opaque, ..) => Some(14),
+ ty::Never => Some(15),
+ ty::Adt(..) => Some(16),
+ ty::Generator(..) => Some(17),
+ ty::Foreign(..) => Some(18),
+ ty::GeneratorWitness(..) => Some(19),
+ ty::GeneratorWitnessMIR(..) => Some(20),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 53bf38c0a34..ea17f23434b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1442,8 +1442,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
self_ty: Ty<'tcx>,
- object_ty: Ty<'tcx>,
+ target_ty: Ty<'tcx>,
) {
+ let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
@@ -1458,7 +1459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion(
obligation.cause.span.shrink_to_lo(),
format!(
- "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
+ "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"
),
"&",
Applicability::MaybeIncorrect,
@@ -2446,10 +2447,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& generator_did.is_local()
// Try to avoid cycles.
&& !generator_within_in_progress_typeck
+ && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
{
- let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
debug!(?generator_info);
-
'find_source: for (variant, source_info) in
generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
{
@@ -2851,30 +2851,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_note(tcx.def_span(item_def_id), descr);
}
}
- ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => {
- let (concrete_ty, concrete_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty));
- let (object_ty, object_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty));
+ ObligationCauseCode::Coercion { source, target } => {
+ let (source, source_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(source));
+ let (target, target_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(target));
err.note(with_forced_trimmed_paths!(format!(
- "required for the cast from `{concrete_ty}` to the object type `{object_ty}`",
+ "required for the cast from `{source}` to `{target}`",
)));
- if let Some(file) = concrete_file {
+ if let Some(file) = source_file {
err.note(format!(
- "the full name for the casted type has been written to '{}'",
+ "the full name for the source type has been written to '{}'",
file.display(),
));
}
- if let Some(file) = object_file {
+ if let Some(file) = target_file {
err.note(format!(
- "the full name for the object type has been written to '{}'",
+ "the full name for the target type has been written to '{}'",
file.display(),
));
}
}
- ObligationCauseCode::Coercion { source: _, target } => {
- err.note(format!("required by cast to type `{}`", self.ty_to_string(target)));
- }
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 43196d1e629..2f85c32b575 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -615,7 +615,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
(Err(ErrorHandled::Reported(reported)), _)
| (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
CodeSelectionError(SelectionError::NotConstEvaluatable(
- NotConstEvaluatable::Error(reported),
+ NotConstEvaluatable::Error(reported.into()),
)),
),
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d8e5725d3ca..223cdc48f0b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -26,6 +26,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorGuaranteed;
+use rustc_middle::query::Providers;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
@@ -49,12 +50,15 @@ pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
-pub use self::project::{normalize_projection_type, NormalizeExt};
+pub use self::project::NormalizeExt;
+pub use self::project::{normalize_inherent_projection, normalize_projection_type};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
-pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
+pub use self::specialize::{
+ specialization_graph, translate_substs, translate_substs_with_cause, OverlapError,
+};
pub use self::structural_match::{
search_for_adt_const_param_violation, search_for_structural_match_violation,
};
@@ -495,10 +499,10 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
false
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
object_safety::provide(providers);
vtable::provide(providers);
- *providers = ty::query::Providers {
+ *providers = Providers {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
subst_and_check_impossible_predicates,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 06d9c10386e..c81bf6ebc2e 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -16,6 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause};
use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
@@ -947,7 +948,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
})
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { object_safety_violations, check_is_object_safe, ..*providers };
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8c74860cdf3..8e684b7ac23 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -16,6 +16,7 @@ use super::{
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+use crate::errors::InherentProjectionNormalizationOverflow;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
@@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
reveal: Reveal,
) -> bool {
match reveal {
- Reveal::UserFacing => value
- .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
+ Reveal::UserFacing => value.has_type_flags(
+ ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
+ | ty::TypeFlags::HAS_CT_PROJECTION,
+ ),
Reveal::All => value.has_type_flags(
ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_TY_OPAQUE
| ty::TypeFlags::HAS_CT_PROJECTION,
),
@@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
+
+ ty::Inherent 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
+ // register an obligation to *later* project, since we know
+ // there won't be bound vars there.
+
+ let data = data.fold_with(self);
+
+ // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
+ // here like `ty::Projection`?
+ normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ }
+
+ ty::Inherent => {
+ let infcx = self.selcx.infcx;
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ let data = data.fold_with(self);
+ let ty = normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ );
+
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ ty,
+ )
+ }
}
}
@@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>(
Normalized { value: new_value, obligations: vec![trait_obligation] }
}
+/// Confirm and normalize the given inherent projection.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
+pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Ty<'tcx> {
+ let tcx = selcx.tcx();
+
+ if !tcx.recursion_limit().value_within_limit(depth) {
+ // Halt compilation because it is important that overflows never be masked.
+ tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
+ span: cause.span,
+ ty: alias_ty.to_string(),
+ });
+ }
+
+ let substs = compute_inherent_assoc_ty_substs(
+ selcx,
+ param_env,
+ alias_ty,
+ cause.clone(),
+ depth,
+ obligations,
+ );
+
+ // Register the obligations arising from the impl and from the associated type itself.
+ let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
+ for (predicate, span) in predicates {
+ let predicate = normalize_with_depth_to(
+ selcx,
+ param_env,
+ cause.clone(),
+ depth + 1,
+ predicate,
+ obligations,
+ );
+
+ let nested_cause = ObligationCause::new(
+ cause.span,
+ cause.body_id,
+ // FIXME(inherent_associated_types): Since we can't pass along the self type to the
+ // cause code, inherent projections will be printed with identity substitutions in
+ // diagnostics which is not ideal.
+ // Consider creating separate cause codes for this specific situation.
+ if span.is_dummy() {
+ super::ItemObligation(alias_ty.def_id)
+ } else {
+ super::BindingObligation(alias_ty.def_id, span)
+ },
+ );
+
+ obligations.push(Obligation::with_depth(
+ tcx,
+ nested_cause,
+ depth + 1,
+ param_env,
+ predicate,
+ ));
+ }
+
+ let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
+
+ let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
+ if ty.has_projections() {
+ ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
+ }
+
+ ty
+}
+
+pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> ty::SubstsRef<'tcx> {
+ let tcx = selcx.tcx();
+
+ let impl_def_id = tcx.parent(alias_ty.def_id);
+ let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
+
+ let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
+ let impl_ty =
+ normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
+
+ // Infer the generic parameters of the impl by unifying the
+ // impl type with the self type of the projection.
+ let self_ty = alias_ty.self_ty();
+ match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
+ Ok(mut ok) => obligations.append(&mut ok.obligations),
+ Err(_) => {
+ tcx.sess.delay_span_bug(
+ cause.span,
+ format!(
+ "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
+ ),
+ );
+ }
+ }
+
+ alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
+}
+
enum Projected<'tcx> {
Progress(Progress<'tcx>),
NoProgress(ty::Term<'tcx>),
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a986a9b6a71..8bf934cb78a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Opaque => ty.try_super_fold_with(self)?,
- ty::Projection => {
+ ty::Projection | ty::Inherent => {
// See note in `rustc_trait_selection::traits::project`
- let tcx = self.infcx.tcx;
let infcx = self.infcx;
+ let tcx = infcx.tcx;
// 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() {
@@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
// so we cannot canonicalize it.
- let c_data = self
- .infcx
+ let c_data = 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)?;
+ let result = match kind {
+ ty::Projection => tcx.normalize_projection_ty(c_data),
+ ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
+ _ => unreachable!(),
+ }?;
// We don't expect ambiguity.
if result.is_ambiguous() {
// Rustdoc normalizes possibly not well-formed types, so only
@@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
}
return Err(NoSolution);
}
- let InferOk { value: result, obligations } =
- self.infcx.instantiate_query_response_and_region_obligations(
+ let InferOk { value: result, obligations } = infcx
+ .instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
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 33f502f8182..a8fb55df2d3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// this trait and type.
}
ty::Param(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..) => {
// In these cases, we don't know what the actual
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 422285d9474..6a648294efd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::ty::{
self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate,
TraitRef, Ty, TyCtxt, TypeVisitableExt,
@@ -28,9 +29,9 @@ use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData,
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
- ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
- Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
- SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented,
+ ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation,
+ ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
+ TraitNotObjectSafe, TraitObligation, Unimplemented,
};
use super::BuiltinImplConditions;
@@ -811,7 +812,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_poly_trait_refs(
&mut self,
obligation: &TraitObligation<'tcx>,
- expected_trait_ref: ty::PolyTraitRef<'tcx>,
+ self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
// Normalize the obligation and expected trait refs together, because why not
@@ -822,7 +823,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- (obligation_trait_ref, expected_trait_ref),
+ (obligation_trait_ref, self_ty_trait_ref),
)
});
@@ -834,7 +835,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(nested);
obligations
})
- .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
+ .map_err(|terr| {
+ OutputTypeParameterMismatch(Box::new(SelectionOutputTypeParameterMismatch {
+ expected_trait_ref: obligation_trait_ref,
+ found_trait_ref: expected_trait_ref,
+ terr,
+ }))
+ })
}
fn confirm_trait_upcasting_unsize_candidate(
@@ -898,16 +905,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
- // Register one obligation for 'a: 'b.
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
- cause,
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
@@ -998,15 +999,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Register one obligation for 'a: 'b.
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
- cause,
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
@@ -1020,16 +1016,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(TraitNotObjectSafe(did));
}
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
-
let predicate_to_obligation = |predicate| {
Obligation::with_depth(
tcx,
- cause.clone(),
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate,
@@ -1049,7 +1039,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
// We can only make objects from sized types.
- let tr = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, cause.span, [source]);
+ let tr = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ obligation.cause.span,
+ [source],
+ );
nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
// If the type is `Foo + 'a`, ensure that the type
@@ -1268,7 +1263,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
- ty::Alias(ty::Projection, ..) => {
+ ty::Alias(ty::Projection | ty::Inherent, ..) => {
let predicate = normalize_with_depth_to(
self,
obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 246d3ea2ef2..b72ff5b78e4 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
@@ -2647,14 +2647,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let predicates = predicates.instantiate_own(tcx, substs);
let mut obligations = Vec::with_capacity(predicates.len());
for (index, (predicate, span)) in predicates.into_iter().enumerate() {
- let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
- ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
- derived,
- impl_or_alias_def_id: def_id,
- impl_def_predicate_index: Some(index),
- span,
- }))
- });
+ let cause =
+ if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() {
+ cause.clone()
+ } else {
+ cause.clone().derived_cause(parent_trait_pred, |derived| {
+ ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: def_id,
+ impl_def_predicate_index: Some(index),
+ span,
+ }))
+ })
+ };
let predicate = normalize_with_depth_to(
self,
param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 233d35aed38..9a4b72013b8 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -83,6 +83,30 @@ pub fn translate_substs<'tcx>(
source_substs: SubstsRef<'tcx>,
target_node: specialization_graph::Node,
) -> SubstsRef<'tcx> {
+ translate_substs_with_cause(
+ infcx,
+ param_env,
+ source_impl,
+ source_substs,
+ target_node,
+ |_, _| ObligationCause::dummy(),
+ )
+}
+
+/// Like [translate_substs], but obligations from the parent implementation
+/// are registered with the provided `ObligationCause`.
+///
+/// This is for reporting *region* errors from those bounds. Type errors should
+/// not happen because the specialization graph already checks for those, and
+/// will result in an ICE.
+pub fn translate_substs_with_cause<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ source_impl: DefId,
+ source_substs: SubstsRef<'tcx>,
+ target_node: specialization_graph::Node,
+ cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
+) -> SubstsRef<'tcx> {
debug!(
"translate_substs({:?}, {:?}, {:?}, {:?})",
param_env, source_impl, source_substs, target_node
@@ -99,14 +123,13 @@ pub fn translate_substs<'tcx>(
return source_substs;
}
- fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
- |()| {
+ fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
+ .unwrap_or_else(|()| {
bug!(
"When translating substitutions from {source_impl:?} to {target_impl:?}, \
the expected specialization failed to hold"
)
- },
- )
+ })
}
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
};
@@ -153,20 +176,12 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
// Create an infcx, taking the predicates of impl1 as assumptions:
let infcx = tcx.infer_ctxt().build();
- let impl1_trait_ref =
- match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
- Ok(impl1_trait_ref) => impl1_trait_ref,
- Err(_errors) => {
- tcx.sess.delay_span_bug(
- tcx.def_span(impl1_def_id),
- format!("failed to fully normalize {impl1_trait_ref}"),
- );
- impl1_trait_ref
- }
- };
// Attempt to prove that impl2 applies, given all of the above.
- fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
+ fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| {
+ ObligationCause::dummy()
+ })
+ .is_ok()
}
/// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -178,23 +193,41 @@ fn fulfill_implication<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
+ source_impl: DefId,
target_impl: DefId,
+ error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
) -> Result<SubstsRef<'tcx>, ()> {
debug!(
"fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
param_env, source_trait_ref, target_impl
);
+ let source_trait_ref = match traits::fully_normalize(
+ &infcx,
+ ObligationCause::dummy(),
+ param_env,
+ source_trait_ref,
+ ) {
+ Ok(source_trait_ref) => source_trait_ref,
+ Err(_errors) => {
+ infcx.tcx.sess.delay_span_bug(
+ infcx.tcx.def_span(source_impl),
+ format!("failed to fully normalize {source_trait_ref}"),
+ );
+ source_trait_ref
+ }
+ };
+
let source_trait = ImplSubject::Trait(source_trait_ref);
let selcx = &mut SelectionContext::new(&infcx);
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
let (target_trait, obligations) =
- util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs);
+ util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause);
// do the impls unify? If not, no specialization.
let Ok(InferOk { obligations: more_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
+ infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait)
else {
debug!(
"fulfill_implication: {:?} does not unify with {:?}",
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 7b7e297c64b..82f3df40198 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -197,6 +197,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
param_env: ty::ParamEnv<'tcx>,
impl_def_id: DefId,
impl_substs: SubstsRef<'tcx>,
+ cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
let subject = selcx.tcx().impl_subject(impl_def_id);
let subject = subject.subst(selcx.tcx(), impl_substs);
@@ -208,8 +209,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
let InferOk { value: predicates, obligations: normalization_obligations2 } =
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
- let impl_obligations =
- super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates);
+ let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
let impl_obligations = impl_obligations
.chain(normalization_obligations1.into_iter())
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index f7a3126b4aa..cc674ceee3d 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -4,6 +4,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::util::PredicateSet;
use rustc_infer::traits::ImplSource;
+use rustc_middle::query::Providers;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
@@ -379,8 +380,8 @@ pub(crate) fn count_own_vtable_entries<'tcx>(
tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
}
-pub(super) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub(super) fn provide(providers: &mut Providers) {
+ *providers = Providers {
own_existential_vtable_entries,
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 22710c7c059..086ab32b520 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -58,15 +58,8 @@ pub fn obligations<'tcx>(
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
};
- let mut wf = WfPredicates {
- tcx: infcx.tcx,
- param_env,
- body_id,
- span,
- out: vec![],
- recursion_depth,
- item: None,
- };
+ let mut wf =
+ WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
wf.compute(arg);
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
@@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>(
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id: CRATE_DEF_ID,
span: DUMMY_SP,
@@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>(
item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id,
span,
@@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>(
span: Span,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id,
span,
@@ -190,8 +183,8 @@ pub fn predicate_obligations<'tcx>(
wf.normalize(infcx)
}
-struct WfPredicates<'tcx> {
- tcx: TyCtxt<'tcx>,
+struct WfPredicates<'a, 'tcx> {
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId,
span: Span,
@@ -290,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
}
}
-impl<'tcx> WfPredicates<'tcx> {
+impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
+ self.infcx.tcx
}
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
@@ -325,7 +318,7 @@ impl<'tcx> WfPredicates<'tcx> {
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
- let tcx = self.tcx;
+ let tcx = self.tcx();
let trait_ref = &trait_pred.trait_ref;
// Negative trait predicates don't require supertraits to hold, just
@@ -369,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> {
self.out.extend(obligations);
}
- let tcx = self.tcx();
self.out.extend(
trait_ref
.substs
@@ -436,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> {
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
self.out.extend(obligations);
+ self.compute_projection_substs(data.substs);
+ }
+
+ fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
+ // An inherent projection is well-formed if
+ //
+ // (a) its predicates hold (*)
+ // (b) its substs are wf
+ //
+ // (*) The predicates of an inherent associated type include the
+ // predicates of the impl that it's contained in.
+
+ if !data.self_ty().has_escaping_bound_vars() {
+ // FIXME(inherent_associated_types): Should this happen inside of a snapshot?
+ // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
+ let substs = traits::project::compute_inherent_assoc_ty_substs(
+ &mut traits::SelectionContext::new(self.infcx),
+ self.param_env,
+ data,
+ self.cause(traits::WellFormed(None)),
+ self.recursion_depth,
+ &mut self.out,
+ );
+ // Inherent projection types do not require const predicates.
+ let obligations = self.nominal_obligations_without_const(data.def_id, substs);
+ self.out.extend(obligations);
+ }
+
+ self.compute_projection_substs(data.substs);
+ }
+
+ fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) {
let tcx = self.tcx();
let cause = self.cause(traits::WellFormed(None));
let param_env = self.param_env;
let depth = self.recursion_depth;
self.out.extend(
- data.substs
+ substs
.iter()
.filter(|arg| {
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
@@ -464,9 +488,9 @@ impl<'tcx> WfPredicates<'tcx> {
if !subty.has_escaping_bound_vars() {
let cause = self.cause(cause);
let trait_ref =
- ty::TraitRef::from_lang_item(self.tcx, LangItem::Sized, cause.span, [subty]);
+ ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
self.out.push(traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,
@@ -605,6 +629,10 @@ impl<'tcx> WfPredicates<'tcx> {
walker.skip_current_subtree(); // Subtree handled by compute_projection.
self.compute_projection(data);
}
+ ty::Alias(ty::Inherent, data) => {
+ walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection.
+ self.compute_inherent_projection(data);
+ }
ty::Adt(def, substs) => {
// WfNominalType
@@ -697,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> {
// All of the requirements on type parameters
// have already been checked for `impl Trait` in
// return position. We do need to check type-alias-impl-trait though.
- if self.tcx.is_type_alias_impl_trait(def_id) {
+ if self.tcx().is_type_alias_impl_trait(def_id) {
let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations);
}
@@ -767,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> {
substs: SubstsRef<'tcx>,
remap_constness: bool,
) -> Vec<traits::PredicateObligation<'tcx>> {
- let predicates = self.tcx.predicates_of(def_id);
+ let predicates = self.tcx().predicates_of(def_id);
let mut origins = vec![def_id; predicates.predicates.len()];
let mut head = predicates;
while let Some(parent) = head.parent {
- head = self.tcx.predicates_of(parent);
+ head = self.tcx().predicates_of(parent);
origins.extend(iter::repeat(parent).take(head.predicates.len()));
}
- let predicates = predicates.instantiate(self.tcx, substs);
+ let predicates = predicates.instantiate(self.tcx(), substs);
trace!("{:#?}", predicates);
debug_assert_eq!(predicates.predicates.len(), origins.len());
@@ -788,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> {
};
let cause = self.cause(code);
if remap_constness {
- pred = pred.without_const(self.tcx);
+ pred = pred.without_const(self.tcx());
}
traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,
@@ -856,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> {
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
// am looking forward to the future here.
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
- let implicit_bounds = object_region_bounds(self.tcx, data);
+ let implicit_bounds = object_region_bounds(self.tcx(), data);
let explicit_bound = region;
@@ -866,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> {
let outlives =
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
self.out.push(traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,