Skip to content

Commit 9ba1590

Browse files
Handle binder predicates in new trait solver
1 parent 9fd4a82 commit 9ba1590

File tree

9 files changed

+172
-12
lines changed

9 files changed

+172
-12
lines changed

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
8383
let binder_predicates = self.tcx().mk_clauses_from_iter(
8484
binder_predicates.into_iter().map(|(clause, _)| clause),
8585
);
86-
if !binder_predicates.is_empty() {
87-
println!("binder_predicates = {binder_predicates:#?}");
88-
}
8986

9087
// Keep the type around in a dummy predicate, in case of no bounds.
9188
// That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
@@ -636,8 +633,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
636633
ast_bounds.iter(),
637634
bounds,
638635
projection_ty.bound_vars(),
639-
// TODO: This is wrong, should take preds from binder
640-
ty::List::empty(),
636+
projection_ty.skip_binder_predicates(),
641637
only_self_bounds,
642638
);
643639
}

compiler/rustc_infer/src/infer/mod.rs

+65
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,71 @@ impl<'tcx> InferCtxt<'tcx> {
15281528
self.tcx.replace_bound_vars_uncached(value, delegate)
15291529
}
15301530

1531+
pub fn instantiate_binder_and_predicates_with_fresh_vars<T>(
1532+
&self,
1533+
span: Span,
1534+
lbrct: BoundRegionConversionTime,
1535+
value: ty::Binder<'tcx, T>,
1536+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>)
1537+
where
1538+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
1539+
{
1540+
if let Some(inner) = value.no_bound_vars() {
1541+
return (inner, ty::List::empty());
1542+
}
1543+
1544+
struct ToFreshVars<'a, 'tcx> {
1545+
infcx: &'a InferCtxt<'tcx>,
1546+
span: Span,
1547+
lbrct: BoundRegionConversionTime,
1548+
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
1549+
}
1550+
1551+
impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'_, 'tcx> {
1552+
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
1553+
self.map
1554+
.entry(br.var)
1555+
.or_insert_with(|| {
1556+
self.infcx
1557+
.next_region_var(BoundRegion(self.span, br.kind, self.lbrct))
1558+
.into()
1559+
})
1560+
.expect_region()
1561+
}
1562+
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
1563+
self.map
1564+
.entry(bt.var)
1565+
.or_insert_with(|| {
1566+
self.infcx
1567+
.next_ty_var(TypeVariableOrigin {
1568+
kind: TypeVariableOriginKind::MiscVariable,
1569+
span: self.span,
1570+
})
1571+
.into()
1572+
})
1573+
.expect_ty()
1574+
}
1575+
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
1576+
self.map
1577+
.entry(bv)
1578+
.or_insert_with(|| {
1579+
self.infcx
1580+
.next_const_var(
1581+
ty,
1582+
ConstVariableOrigin {
1583+
kind: ConstVariableOriginKind::MiscVariable,
1584+
span: self.span,
1585+
},
1586+
)
1587+
.into()
1588+
})
1589+
.expect_const()
1590+
}
1591+
}
1592+
let delegate = ToFreshVars { infcx: self, span, lbrct, map: Default::default() };
1593+
self.tcx.replace_bound_vars_and_predicates_uncached(value, delegate)
1594+
}
1595+
15311596
/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
15321597
pub fn verify_generic_bound(
15331598
&self,

compiler/rustc_infer/src/infer/relate/higher_ranked.rs

+49
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,55 @@ impl<'tcx> InferCtxt<'tcx> {
108108
self.tcx.replace_bound_vars_uncached(binder, delegate)
109109
}
110110

111+
/// Replaces all bound variables (lifetimes, types, and constants) bound by
112+
/// `binder` with placeholder variables in a new universe. This means that the
113+
/// new placeholders can only be named by inference variables created after
114+
/// this method has been called.
115+
///
116+
/// This is the first step of checking subtyping when higher-ranked things are involved.
117+
/// For more details visit the relevant sections of the [rustc dev guide].
118+
///
119+
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
120+
#[instrument(level = "debug", skip(self), ret)]
121+
pub fn instantiate_binder_and_assumptions_with_placeholders<T>(
122+
&self,
123+
binder: ty::Binder<'tcx, T>,
124+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>)
125+
where
126+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
127+
{
128+
if let Some(inner) = binder.no_bound_vars() {
129+
return (inner, ty::List::empty());
130+
}
131+
132+
let next_universe = self.create_next_universe();
133+
134+
let delegate = FnMutDelegate {
135+
regions: &mut |br: ty::BoundRegion| {
136+
ty::Region::new_placeholder(
137+
self.tcx,
138+
ty::PlaceholderRegion { universe: next_universe, bound: br },
139+
)
140+
},
141+
types: &mut |bound_ty: ty::BoundTy| {
142+
Ty::new_placeholder(
143+
self.tcx,
144+
ty::PlaceholderType { universe: next_universe, bound: bound_ty },
145+
)
146+
},
147+
consts: &mut |bound_var: ty::BoundVar, ty| {
148+
ty::Const::new_placeholder(
149+
self.tcx,
150+
ty::PlaceholderConst { universe: next_universe, bound: bound_var },
151+
ty,
152+
)
153+
},
154+
};
155+
156+
debug!(?next_universe);
157+
self.tcx.replace_bound_vars_and_predicates_uncached(binder, delegate)
158+
}
159+
111160
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
112161
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
113162
/// universe.

compiler/rustc_middle/src/ty/fold.rs

+9
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,15 @@ impl<'tcx> TyCtxt<'tcx> {
315315
self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
316316
}
317317

318+
pub fn replace_bound_vars_and_predicates_uncached<T: TypeFoldable<TyCtxt<'tcx>>>(
319+
self,
320+
value: Binder<'tcx, T>,
321+
delegate: impl BoundVarReplacerDelegate<'tcx>,
322+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
323+
let preds = value.skip_binder_predicates();
324+
self.replace_escaping_bound_vars_uncached((value.skip_binder(), preds), delegate)
325+
}
326+
318327
/// Replaces any late-bound regions bound in `value` with
319328
/// free variants attached to `all_outlive_scope`.
320329
pub fn liberate_late_bound_regions<T>(

compiler/rustc_middle/src/ty/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,17 @@ impl<'tcx> ParamEnv<'tcx> {
17171717
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
17181718
}
17191719

1720+
pub fn augment(
1721+
tcx: TyCtxt<'tcx>,
1722+
param_env: ty::ParamEnv<'tcx>,
1723+
more_caller_bounds: &'tcx List<Clause<'tcx>>,
1724+
) -> Self {
1725+
ty::ParamEnv::new(
1726+
tcx.mk_clauses_from_iter(param_env.caller_bounds().iter().chain(more_caller_bounds)),
1727+
param_env.reveal(),
1728+
)
1729+
}
1730+
17201731
pub fn with_user_facing(mut self) -> Self {
17211732
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
17221733
self

compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ where
10341034
}
10351035

10361036
impl<'tcx, T> Binder<'tcx, T> {
1037-
pub fn skip_binder_predicates(self) -> &'tcx List<ty::Clause<'tcx>> {
1037+
pub fn skip_binder_predicates(&self) -> &'tcx List<ty::Clause<'tcx>> {
10381038
self.bound_predicates
10391039
}
10401040

compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
437437
}
438438
}
439439
} else {
440-
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
441-
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
440+
let (kind, additional_assumptions) =
441+
self.instantiate_binder_and_assumptions_with_placeholders(kind);
442+
let goal = Goal::new(
443+
self.tcx(),
444+
ty::ParamEnv::augment(self.tcx(), goal.param_env, additional_assumptions),
445+
ty::Binder::dummy(kind),
446+
);
442447
self.add_goal(goal);
443448
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
444449
}
@@ -752,13 +757,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
752757
)
753758
}
754759

760+
pub(super) fn instantiate_binder_and_predicates_with_infer<
761+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
762+
>(
763+
&self,
764+
value: ty::Binder<'tcx, T>,
765+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
766+
self.infcx.instantiate_binder_and_predicates_with_fresh_vars(
767+
DUMMY_SP,
768+
BoundRegionConversionTime::HigherRankedType,
769+
value,
770+
)
771+
}
772+
755773
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
756774
&self,
757775
value: ty::Binder<'tcx, T>,
758776
) -> T {
759777
self.infcx.instantiate_binder_with_placeholders(value)
760778
}
761779

780+
pub(super) fn instantiate_binder_and_assumptions_with_placeholders<
781+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
782+
>(
783+
&self,
784+
value: ty::Binder<'tcx, T>,
785+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
786+
self.infcx.instantiate_binder_and_assumptions_with_placeholders(value)
787+
}
788+
762789
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
763790
where
764791
T: TypeFoldable<TyCtxt<'tcx>>,

compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
116116
if projection_pred.projection_def_id() == goal.predicate.def_id() {
117117
let tcx = ecx.tcx();
118118
ecx.probe_misc_candidate("assumption").enter(|ecx| {
119-
let assumption_projection_pred =
120-
ecx.instantiate_binder_with_infer(projection_pred);
119+
let (assumption_projection_pred, additional_goals) =
120+
ecx.instantiate_binder_and_predicates_with_infer(projection_pred);
121121
ecx.eq(
122122
goal.param_env,
123123
goal.predicate.alias,
@@ -132,7 +132,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
132132
.instantiate_own(tcx, goal.predicate.alias.args)
133133
.map(|(pred, _)| goal.with(tcx, pred)),
134134
);
135-
135+
ecx.add_goals(additional_goals.iter().map(|pred| goal.with(tcx, pred)));
136136
then(ecx)
137137
})
138138
} else {

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
9797
{
9898
// FIXME: Constness
9999
ecx.probe_misc_candidate("assumption").enter(|ecx| {
100-
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
100+
let (assumption_trait_pred, additional_goals) =
101+
ecx.instantiate_binder_and_predicates_with_infer(trait_clause);
101102
ecx.eq(
102103
goal.param_env,
103104
goal.predicate.trait_ref,
104105
assumption_trait_pred.trait_ref,
105106
)?;
107+
let tcx = ecx.tcx();
108+
ecx.add_goals(additional_goals.iter().map(|pred| goal.with(tcx, pred)));
106109
then(ecx)
107110
})
108111
} else {

0 commit comments

Comments
 (0)