summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/solve/project_goals
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_trait_selection/src/solve/project_goals
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve/project_goals')
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs50
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/mod.rs680
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs85
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs34
4 files changed, 0 insertions, 849 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
deleted file mode 100644
index 28fe59b7f..000000000
--- a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-//! Computes a normalizes-to (projection) goal for inherent associated types,
-//! `#![feature(inherent_associated_type)]`. Since astconv already determines
-//! which impl the IAT is being projected from, we just:
-//! 1. instantiate substs,
-//! 2. equate the self type, and
-//! 3. instantiate and register where clauses.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
-use rustc_middle::ty;
-
-use super::EvalCtxt;
-
-impl<'tcx> EvalCtxt<'_, 'tcx> {
- pub(super) fn normalize_inherent_associated_type(
- &mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
- ) -> QueryResult<'tcx> {
- let tcx = self.tcx();
- let inherent = goal.predicate.projection_ty;
- let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");
-
- let impl_def_id = tcx.parent(inherent.def_id);
- let impl_substs = self.fresh_args_for_item(impl_def_id);
-
- // Equate impl header and add impl where clauses
- self.eq(
- goal.param_env,
- inherent.self_ty(),
- tcx.type_of(impl_def_id).instantiate(tcx, impl_substs),
- )?;
-
- // Equate IAT with the RHS of the project goal
- let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx);
- self.eq(
- goal.param_env,
- expected,
- tcx.type_of(inherent.def_id).instantiate(tcx, inherent_substs),
- )
- .expect("expected goal term to be fully unconstrained");
-
- // Check both where clauses on the impl and IAT
- self.add_goals(
- tcx.predicates_of(inherent.def_id)
- .instantiate(tcx, inherent_substs)
- .into_iter()
- .map(|(pred, _)| goal.with(tcx, pred)),
- );
-
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
deleted file mode 100644
index 240141065..000000000
--- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
+++ /dev/null
@@ -1,680 +0,0 @@
-use crate::traits::{check_args_compatible, specialization_graph};
-
-use super::assembly::{self, structural_traits};
-use super::EvalCtxt;
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_hir::LangItem;
-use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::specialization_graph::LeafDef;
-use rustc_infer::traits::Reveal;
-use rustc_middle::traits::solve::{
- CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
-};
-use rustc_middle::traits::BuiltinImplSource;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::ProjectionPredicate;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
-use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
-
-mod inherent_projection;
-mod opaques;
-mod weak_types;
-
-impl<'tcx> EvalCtxt<'_, 'tcx> {
- #[instrument(level = "debug", skip(self), ret)]
- pub(super) fn compute_projection_goal(
- &mut self,
- goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
- ) -> QueryResult<'tcx> {
- let def_id = goal.predicate.def_id();
- match self.tcx().def_kind(def_id) {
- DefKind::AssocTy | DefKind::AssocConst => {
- // To only compute normalization once for each projection we only
- // assemble normalization candidates if the expected term is an
- // unconstrained inference variable.
- //
- // Why: For better cache hits, since if we have an unconstrained RHS then
- // there are only as many cache keys as there are (canonicalized) alias
- // types in each normalizes-to goal. This also weakens inference in a
- // forwards-compatible way so we don't use the value of the RHS term to
- // affect candidate assembly for projections.
- //
- // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
- // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
- // `U` and equate it with `u32`. This means that we don't need a separate
- // projection cache in the solver, since we're piggybacking off of regular
- // goal caching.
- if self.term_is_fully_unconstrained(goal) {
- match self.tcx().associated_item(def_id).container {
- ty::AssocItemContainer::TraitContainer => {
- let candidates = self.assemble_and_evaluate_candidates(goal);
- self.merge_candidates(candidates)
- }
- ty::AssocItemContainer::ImplContainer => {
- self.normalize_inherent_associated_type(goal)
- }
- }
- } else {
- self.set_normalizes_to_hack_goal(goal);
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- }
- }
- DefKind::AnonConst => self.normalize_anon_const(goal),
- DefKind::OpaqueTy => self.normalize_opaque_type(goal),
- DefKind::TyAlias => self.normalize_weak_type(goal),
- kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
- }
- }
-
- #[instrument(level = "debug", skip(self), ret)]
- fn normalize_anon_const(
- &mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
- ) -> QueryResult<'tcx> {
- if let Some(normalized_const) = self.try_const_eval_resolve(
- goal.param_env,
- ty::UnevaluatedConst::new(
- goal.predicate.projection_ty.def_id,
- goal.predicate.projection_ty.args,
- ),
- self.tcx()
- .type_of(goal.predicate.projection_ty.def_id)
- .no_bound_vars()
- .expect("const ty should not rely on other generics"),
- ) {
- self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- } else {
- self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
- }
- }
-}
-
-impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
- fn self_ty(self) -> Ty<'tcx> {
- self.self_ty()
- }
-
- fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
- self.projection_ty.trait_ref(tcx)
- }
-
- fn polarity(self) -> ty::ImplPolarity {
- ty::ImplPolarity::Positive
- }
-
- fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
- self.with_self_ty(tcx, self_ty)
- }
-
- fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
- self.trait_def_id(tcx)
- }
-
- fn probe_and_match_goal_against_assumption(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- assumption: ty::Clause<'tcx>,
- then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
- ) -> QueryResult<'tcx> {
- if let Some(projection_pred) = assumption.as_projection_clause() {
- if projection_pred.projection_def_id() == goal.predicate.def_id() {
- let tcx = ecx.tcx();
- ecx.probe_misc_candidate("assumption").enter(|ecx| {
- let assumption_projection_pred =
- ecx.instantiate_binder_with_infer(projection_pred);
- ecx.eq(
- goal.param_env,
- goal.predicate.projection_ty,
- assumption_projection_pred.projection_ty,
- )?;
- ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
- .expect("expected goal term to be fully unconstrained");
-
- // Add GAT where clauses from the trait's definition
- ecx.add_goals(
- tcx.predicates_of(goal.predicate.def_id())
- .instantiate_own(tcx, goal.predicate.projection_ty.args)
- .map(|(pred, _)| goal.with(tcx, pred)),
- );
-
- then(ecx)
- })
- } else {
- Err(NoSolution)
- }
- } else {
- Err(NoSolution)
- }
- }
-
- fn consider_impl_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
- impl_def_id: DefId,
- ) -> QueryResult<'tcx> {
- let tcx = ecx.tcx();
-
- let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
- if !drcx.args_refs_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args) {
- return Err(NoSolution);
- }
-
- ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
- let impl_args = ecx.fresh_args_for_item(impl_def_id);
- let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
-
- ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
-
- let where_clause_bounds = tcx
- .predicates_of(impl_def_id)
- .instantiate(tcx, impl_args)
- .predicates
- .into_iter()
- .map(|pred| goal.with(tcx, pred));
- ecx.add_goals(where_clause_bounds);
-
- // Add GAT where clauses from the trait's definition
- ecx.add_goals(
- tcx.predicates_of(goal.predicate.def_id())
- .instantiate_own(tcx, goal.predicate.projection_ty.args)
- .map(|(pred, _)| goal.with(tcx, pred)),
- );
-
- // In case the associated item is hidden due to specialization, we have to
- // return ambiguity this would otherwise be incomplete, resulting in
- // unsoundness during coherence (#105782).
- let Some(assoc_def) = fetch_eligible_assoc_item_def(
- ecx,
- goal.param_env,
- goal_trait_ref,
- goal.predicate.def_id(),
- impl_def_id,
- )?
- else {
- return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
- };
-
- let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| {
- let guar = tcx.sess.delay_span_bug(tcx.def_span(assoc_def.item.def_id), reason);
- let error_term = match assoc_def.item.kind {
- ty::AssocKind::Const => ty::Const::new_error(
- tcx,
- guar,
- tcx.type_of(goal.predicate.def_id())
- .instantiate(tcx, goal.predicate.projection_ty.args),
- )
- .into(),
- ty::AssocKind::Type => Ty::new_error(tcx, guar).into(),
- ty::AssocKind::Fn => unreachable!(),
- };
- ecx.eq(goal.param_env, goal.predicate.term, error_term)
- .expect("expected goal term to be fully unconstrained");
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- };
-
- if !assoc_def.item.defaultness(tcx).has_value() {
- return error_response(ecx, "missing value for assoc item in impl");
- }
-
- // Getting the right args here is complex, e.g. given:
- // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>`
- // - the applicable impl `impl<T> Trait<i32> for Vec<T>`
- // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>`
- //
- // We first rebase the goal args onto the impl, going from `[Vec<u32>, i32, u64]`
- // to `[u32, u64]`.
- //
- // And then map these args to the args of the defining impl of `Assoc`, going
- // from `[u32, u64]` to `[u32, i32, u64]`.
- let impl_args_with_gat = goal.predicate.projection_ty.args.rebase_onto(
- tcx,
- goal_trait_ref.def_id,
- impl_args,
- );
- let args = ecx.translate_args(
- goal.param_env,
- impl_def_id,
- impl_args_with_gat,
- assoc_def.defining_node,
- );
-
- if !check_args_compatible(tcx, assoc_def.item, args) {
- return error_response(
- ecx,
- "associated item has mismatched generic item arguments",
- );
- }
-
- // Finally we construct the actual value of the associated type.
- let term = match assoc_def.item.kind {
- ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()),
- ty::AssocKind::Const => {
- if tcx.features().associated_const_equality {
- bug!("associated const projection is not supported yet")
- } else {
- ty::EarlyBinder::bind(
- ty::Const::new_error_with_message(
- tcx,
- tcx.type_of(assoc_def.item.def_id).instantiate_identity(),
- DUMMY_SP,
- "associated const projection is not supported yet",
- )
- .into(),
- )
- }
- }
- ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
- };
-
- ecx.eq(goal.param_env, goal.predicate.term, term.instantiate(tcx, args))
- .expect("expected goal term to be fully unconstrained");
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
-
- /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
- /// and succeed. Can experiment with this to figure out what results in better error messages.
- fn consider_error_guaranteed_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- _guar: ErrorGuaranteed,
- ) -> QueryResult<'tcx> {
- Err(NoSolution)
- }
-
- fn consider_auto_trait_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- ecx.tcx().sess.delay_span_bug(
- ecx.tcx().def_span(goal.predicate.def_id()),
- "associated types not allowed on auto traits",
- );
- Err(NoSolution)
- }
-
- fn consider_trait_alias_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("trait aliases do not have associated types: {:?}", goal);
- }
-
- fn consider_builtin_sized_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`Sized` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_copy_clone_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_pointer_like_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`PointerLike` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_fn_ptr_trait_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`FnPtr` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_fn_trait_candidates(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- goal_kind: ty::ClosureKind,
- ) -> QueryResult<'tcx> {
- let tcx = ecx.tcx();
- let tupled_inputs_and_output =
- match structural_traits::extract_tupled_inputs_and_output_from_callable(
- tcx,
- goal.predicate.self_ty(),
- goal_kind,
- )? {
- Some(tupled_inputs_and_output) => tupled_inputs_and_output,
- None => {
- return ecx
- .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
- }
- };
- let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
- ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
- });
-
- let pred = tupled_inputs_and_output
- .map_bound(|(inputs, output)| ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(
- tcx,
- goal.predicate.def_id(),
- [goal.predicate.self_ty(), inputs],
- ),
- term: output.into(),
- })
- .to_predicate(tcx);
-
- // A built-in `Fn` impl only holds if the output is sized.
- // (FIXME: technically we only need to check this if the type is a fn ptr...)
- Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
- }
-
- fn consider_builtin_tuple_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`Tuple` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_pointee_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- let tcx = ecx.tcx();
- ecx.probe_misc_candidate("builtin pointee").enter(|ecx| {
- let metadata_ty = match goal.predicate.self_ty().kind() {
- ty::Bool
- | ty::Char
- | ty::Int(..)
- | ty::Uint(..)
- | ty::Float(..)
- | ty::Array(..)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(..)
- | ty::Closure(..)
- | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
- | ty::Coroutine(..)
- | ty::CoroutineWitness(..)
- | ty::Never
- | ty::Foreign(..) => tcx.types.unit,
-
- ty::Error(e) => Ty::new_error(tcx, *e),
-
- ty::Str | ty::Slice(_) => tcx.types.usize,
-
- ty::Dynamic(_, _, _) => {
- let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
- tcx.type_of(dyn_metadata)
- .instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
- }
-
- ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
- // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
- let sized_predicate = ty::TraitRef::from_lang_item(
- tcx,
- LangItem::Sized,
- DUMMY_SP,
- [ty::GenericArg::from(goal.predicate.self_ty())],
- );
- ecx.add_goal(goal.with(tcx, sized_predicate));
- tcx.types.unit
- }
-
- ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
- None => tcx.types.unit,
- Some(field_def) => {
- let self_ty = field_def.ty(tcx, args);
- ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
- return ecx
- .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
- }
- },
- ty::Adt(_, _) => tcx.types.unit,
-
- ty::Tuple(elements) => match elements.last() {
- None => tcx.types.unit,
- Some(&self_ty) => {
- ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
- return ecx
- .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
- }
- },
-
- ty::Infer(
- ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
- )
- | ty::Bound(..) => bug!(
- "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
- goal.predicate.self_ty()
- ),
- };
-
- ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
- .expect("expected goal term to be fully unconstrained");
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
-
- fn consider_builtin_future_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- let self_ty = goal.predicate.self_ty();
- let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
- return Err(NoSolution);
- };
-
- // Coroutines are not futures unless they come from `async` desugaring
- let tcx = ecx.tcx();
- if !tcx.coroutine_is_async(def_id) {
- return Err(NoSolution);
- }
-
- let term = args.as_coroutine().return_ty().into();
-
- Self::consider_implied_clause(
- ecx,
- goal,
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
- term,
- }
- .to_predicate(tcx),
- // Technically, we need to check that the future type is Sized,
- // but that's already proven by the coroutine being WF.
- [],
- )
- }
-
- fn consider_builtin_iterator_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- let self_ty = goal.predicate.self_ty();
- let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
- return Err(NoSolution);
- };
-
- // Coroutines are not Iterators unless they come from `gen` desugaring
- let tcx = ecx.tcx();
- if !tcx.coroutine_is_gen(def_id) {
- return Err(NoSolution);
- }
-
- let term = args.as_coroutine().yield_ty().into();
-
- Self::consider_implied_clause(
- ecx,
- goal,
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
- term,
- }
- .to_predicate(tcx),
- // Technically, we need to check that the iterator type is Sized,
- // but that's already proven by the generator being WF.
- [],
- )
- }
-
- fn consider_builtin_coroutine_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- let self_ty = goal.predicate.self_ty();
- let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
- return Err(NoSolution);
- };
-
- // `async`-desugared coroutines do not implement the coroutine trait
- let tcx = ecx.tcx();
- if !tcx.is_general_coroutine(def_id) {
- return Err(NoSolution);
- }
-
- let coroutine = args.as_coroutine();
-
- let name = tcx.associated_item(goal.predicate.def_id()).name;
- let term = if name == sym::Return {
- coroutine.return_ty().into()
- } else if name == sym::Yield {
- coroutine.yield_ty().into()
- } else {
- bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
- };
-
- Self::consider_implied_clause(
- ecx,
- goal,
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(
- ecx.tcx(),
- goal.predicate.def_id(),
- [self_ty, coroutine.resume_ty()],
- ),
- term,
- }
- .to_predicate(tcx),
- // Technically, we need to check that the coroutine type is Sized,
- // but that's already proven by the coroutine being WF.
- [],
- )
- }
-
- fn consider_unsize_to_dyn_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`Unsize` does not have an associated type: {:?}", goal)
- }
-
- fn consider_structural_builtin_unsize_candidates(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
- bug!("`Unsize` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_discriminant_kind_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- let self_ty = goal.predicate.self_ty();
- let discriminant_ty = match *self_ty.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(..)
- | ty::Uint(..)
- | ty::Float(..)
- | ty::Array(..)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(..)
- | ty::Closure(..)
- | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
- | ty::Coroutine(..)
- | ty::CoroutineWitness(..)
- | ty::Never
- | ty::Foreign(..)
- | ty::Adt(_, _)
- | ty::Str
- | ty::Slice(_)
- | ty::Dynamic(_, _, _)
- | ty::Tuple(_)
- | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()),
-
- // We do not call `Ty::discriminant_ty` on alias, param, or placeholder
- // types, which return `<self_ty as DiscriminantKind>::Discriminant`
- // (or ICE in the case of placeholders). Projecting a type to itself
- // is never really productive.
- ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
- return Err(NoSolution);
- }
-
- ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
- | ty::Bound(..) => bug!(
- "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
- goal.predicate.self_ty()
- ),
- };
-
- ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| {
- ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())
- .expect("expected goal term to be fully unconstrained");
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
-
- fn consider_builtin_destruct_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`Destruct` does not have an associated type: {:?}", goal);
- }
-
- fn consider_builtin_transmute_candidate(
- _ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
- bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
- }
-}
-
-/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
-///
-/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
-/// diverge.
-#[instrument(level = "debug", skip(ecx, param_env), ret)]
-fn fetch_eligible_assoc_item_def<'tcx>(
- ecx: &EvalCtxt<'_, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- goal_trait_ref: ty::TraitRef<'tcx>,
- trait_assoc_def_id: DefId,
- impl_def_id: DefId,
-) -> Result<Option<LeafDef>, NoSolution> {
- let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
- .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
-
- let eligible = if node_item.is_final() {
- // Non-specializable items are always projectable.
- true
- } else {
- // Only reveal a specializable default if we're past type-checking
- // and the obligation is monomorphic, otherwise passes such as
- // transmute checking and polymorphic MIR optimizations could
- // get a result which isn't correct for all monomorphizations.
- if param_env.reveal() == Reveal::All {
- let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
- !poly_trait_ref.still_further_specializable()
- } else {
- debug!(?node_item.item.def_id, "not eligible due to default");
- false
- }
- };
-
- if eligible { Ok(Some(node_item)) } else { Ok(None) }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
deleted file mode 100644
index ebd129f32..000000000
--- a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-//! Computes a normalizes-to (projection) goal for opaque types. This goal
-//! behaves differently depending on the param-env's reveal mode and whether
-//! the opaque is in a defining scope.
-use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
-use rustc_middle::traits::Reveal;
-use rustc_middle::ty;
-use rustc_middle::ty::util::NotUniqueParam;
-
-use crate::solve::{EvalCtxt, SolverMode};
-
-impl<'tcx> EvalCtxt<'_, 'tcx> {
- pub(super) fn normalize_opaque_type(
- &mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
- ) -> QueryResult<'tcx> {
- let tcx = self.tcx();
- let opaque_ty = goal.predicate.projection_ty;
- let expected = goal.predicate.term.ty().expect("no such thing as an opaque const");
-
- match (goal.param_env.reveal(), self.solver_mode()) {
- (Reveal::UserFacing, SolverMode::Normal) => {
- let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else {
- return Err(NoSolution);
- };
- // FIXME: at some point we should call queries without defining
- // new opaque types but having the existing opaque type definitions.
- // This will require moving this below "Prefer opaques registered already".
- if !self.can_define_opaque_ty(opaque_ty_def_id) {
- return Err(NoSolution);
- }
- // FIXME: This may have issues when the args contain aliases...
- match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
- Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
- return self.evaluate_added_goals_and_make_canonical_response(
- Certainty::AMBIGUOUS,
- );
- }
- Err(_) => {
- return Err(NoSolution);
- }
- Ok(()) => {}
- }
- // Prefer opaques registered already.
- let opaque_type_key =
- ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args };
- let matches =
- self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected);
- if !matches.is_empty() {
- if let Some(response) = self.try_merge_responses(&matches) {
- return Ok(response);
- } else {
- return self.flounder(&matches);
- }
- }
- // Otherwise, define a new opaque type
- self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
- self.add_item_bounds_for_hidden_type(
- opaque_ty.def_id,
- opaque_ty.args,
- goal.param_env,
- expected,
- );
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- }
- (Reveal::UserFacing, SolverMode::Coherence) => {
- // An impossible opaque type bound is the only way this goal will fail
- // e.g. assigning `impl Copy := NotCopy`
- self.add_item_bounds_for_hidden_type(
- opaque_ty.def_id,
- opaque_ty.args,
- goal.param_env,
- expected,
- );
- self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
- }
- (Reveal::All, _) => {
- // FIXME: Add an assertion that opaque type storage is empty.
- let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args);
- self.eq(goal.param_env, expected, actual)?;
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- }
- }
- }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
deleted file mode 100644
index 54de32cf6..000000000
--- a/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! Computes a normalizes-to (projection) goal for inherent associated types,
-//! `#![feature(lazy_type_alias)]` and `#![feature(type_alias_impl_trait)]`.
-//!
-//! Since a weak alias is not ambiguous, this just computes the `type_of` of
-//! the alias and registers the where-clauses of the type alias.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
-use rustc_middle::ty;
-
-use super::EvalCtxt;
-
-impl<'tcx> EvalCtxt<'_, 'tcx> {
- pub(super) fn normalize_weak_type(
- &mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
- ) -> QueryResult<'tcx> {
- let tcx = self.tcx();
- let weak_ty = goal.predicate.projection_ty;
- let expected = goal.predicate.term.ty().expect("no such thing as a const alias");
-
- let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
- self.eq(goal.param_env, expected, actual)?;
-
- // Check where clauses
- self.add_goals(
- tcx.predicates_of(weak_ty.def_id)
- .instantiate(tcx, weak_ty.args)
- .predicates
- .into_iter()
- .map(|pred| goal.with(tcx, pred)),
- );
-
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- }
-}