Skip to content

Commit 3cd8baa

Browse files
trait_goals: Assemble alias and object candidates
1 parent a11eb4f commit 3cd8baa

File tree

3 files changed

+127
-2
lines changed

3 files changed

+127
-2
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
4444
goal: Goal<'tcx, Self>,
4545
impl_def_id: DefId,
4646
);
47+
48+
fn consider_alias_bound_candidates(
49+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
50+
goal: Goal<'tcx, Self>,
51+
alias_ty: ty::AliasTy<'tcx>,
52+
);
53+
54+
fn consider_object_bound_candidates(
55+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
56+
goal: Goal<'tcx, Self>,
57+
object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
58+
);
4759
}
4860

4961
/// An abstraction which correctly deals with the canonical results for candidates.
@@ -69,6 +81,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
6981

7082
acx.assemble_impl_candidates(goal);
7183

84+
acx.assemble_bound_candidates(goal);
85+
7286
acx.candidates
7387
}
7488

@@ -147,4 +161,14 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
147161
|impl_def_id| G::consider_impl_candidate(self, goal, impl_def_id),
148162
);
149163
}
164+
165+
fn assemble_bound_candidates(&mut self, goal: Goal<'tcx, G>) {
166+
match *goal.predicate.self_ty().kind() {
167+
ty::Alias(_, alias_ty) => G::consider_alias_bound_candidates(self, goal, alias_ty),
168+
ty::Dynamic(predicates, _, _) => {
169+
G::consider_object_bound_candidates(self, goal, predicates)
170+
}
171+
_ => {}
172+
}
173+
}
150174
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
211211
acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty);
212212
})
213213
}
214+
215+
fn consider_alias_bound_candidates(
216+
_acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
217+
_goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
218+
_alias_ty: ty::AliasTy<'tcx>,
219+
) {
220+
todo!()
221+
}
222+
223+
fn consider_object_bound_candidates(
224+
_acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
225+
_goal: Goal<'tcx, Self>,
226+
_object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
227+
) {
228+
todo!()
229+
}
214230
}
215231

216232
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.

compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ use std::iter;
55
use super::assembly::{self, AssemblyCtxt};
66
use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult};
77
use rustc_hir::def_id::DefId;
8-
use rustc_infer::infer::InferOk;
8+
use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
99
use rustc_infer::traits::query::NoSolution;
10+
use rustc_infer::traits::util::supertraits;
1011
use rustc_infer::traits::ObligationCause;
1112
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
1213
use rustc_middle::ty::TraitPredicate;
@@ -36,6 +37,8 @@ pub(super) enum CandidateSource {
3637
/// We know that `<Whatever as Trait>::Assoc: OtherTrait` holds by looking at
3738
/// the bounds on `Trait::Assoc`.
3839
AliasBound(usize),
40+
/// Implementation of `Trait` or its supertraits for a `dyn Trait + Send + Sync`.
41+
ObjectBound(usize),
3942
/// A builtin implementation for some specific traits, used in cases
4043
/// where we cannot rely an ordinary library implementations.
4144
///
@@ -68,7 +71,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
6871

6972
fn consider_impl_candidate(
7073
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
71-
goal: Goal<'tcx, TraitPredicate<'tcx>>,
74+
goal: Goal<'tcx, Self>,
7275
impl_def_id: DefId,
7376
) {
7477
let tcx = acx.cx.tcx;
@@ -108,6 +111,87 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
108111
acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty);
109112
})
110113
}
114+
115+
fn consider_alias_bound_candidates(
116+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
117+
goal: Goal<'tcx, Self>,
118+
alias_ty: ty::AliasTy<'tcx>,
119+
) {
120+
for (idx, (predicate, _)) in acx
121+
.cx
122+
.tcx
123+
.bound_explicit_item_bounds(alias_ty.def_id)
124+
.subst_iter_copied(acx.cx.tcx, alias_ty.substs)
125+
.enumerate()
126+
{
127+
let Some(poly_trait_pred) = predicate.to_opt_poly_trait_pred() else { continue };
128+
if poly_trait_pred.skip_binder().def_id() != goal.predicate.def_id() {
129+
continue;
130+
};
131+
// FIXME: constness? polarity?
132+
let poly_trait_ref = poly_trait_pred.map_bound(|trait_pred| trait_pred.trait_ref);
133+
// FIXME: Faster to do a filter first with a rejection context?
134+
match_poly_trait_ref_against_goal(
135+
acx,
136+
goal,
137+
poly_trait_ref,
138+
CandidateSource::AliasBound(idx),
139+
);
140+
}
141+
}
142+
143+
fn consider_object_bound_candidates(
144+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
145+
goal: Goal<'tcx, Self>,
146+
object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
147+
) {
148+
if let Some(principal_trait_ref) = object_bounds.principal() {
149+
let principal_trait_ref =
150+
principal_trait_ref.with_self_ty(acx.cx.tcx, goal.predicate.self_ty());
151+
152+
for (idx, poly_trait_ref) in supertraits(acx.cx.tcx, principal_trait_ref).enumerate() {
153+
if poly_trait_ref.skip_binder().def_id != goal.predicate.def_id() {
154+
continue;
155+
};
156+
match_poly_trait_ref_against_goal(
157+
acx,
158+
goal,
159+
poly_trait_ref,
160+
CandidateSource::ObjectBound(idx),
161+
);
162+
}
163+
}
164+
}
165+
}
166+
167+
fn match_poly_trait_ref_against_goal<'tcx>(
168+
acx: &mut AssemblyCtxt<'_, 'tcx, TraitPredicate<'tcx>>,
169+
goal: Goal<'tcx, TraitPredicate<'tcx>>,
170+
trait_ref: ty::PolyTraitRef<'tcx>,
171+
candidate: impl FnOnce() -> CandidateSource,
172+
) {
173+
acx.infcx.probe(|_| {
174+
let trait_ref = acx.infcx.replace_bound_vars_with_fresh_vars(
175+
DUMMY_SP,
176+
LateBoundRegionConversionTime::HigherRankedType,
177+
trait_ref,
178+
);
179+
180+
let Ok(InferOk { obligations, .. }) = acx
181+
.infcx
182+
.at(&ObligationCause::dummy(), goal.param_env)
183+
.define_opaque_types(false)
184+
.sup(goal.predicate.trait_ref, trait_ref)
185+
.map_err(|e| debug!("failed to equate trait refs: {e:?}"))
186+
else {
187+
return
188+
};
189+
190+
let nested_goals = obligations.into_iter().map(|o| o.into()).collect();
191+
192+
let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
193+
acx.try_insert_candidate(candidate(), certainty);
194+
})
111195
}
112196

113197
impl<'tcx> EvalCtxt<'tcx> {
@@ -169,6 +253,7 @@ impl<'tcx> EvalCtxt<'tcx> {
169253
(CandidateSource::Impl(_), _)
170254
| (CandidateSource::ParamEnv(_), _)
171255
| (CandidateSource::AliasBound(_), _)
256+
| (CandidateSource::ObjectBound(_), _)
172257
| (CandidateSource::Builtin, _)
173258
| (CandidateSource::AutoImpl, _) => unimplemented!(),
174259
}

0 commit comments

Comments
 (0)