Skip to content

Commit 1dc00a3

Browse files
Handle binder predicates in new trait solver
1 parent 93b8719 commit 1dc00a3

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`
@@ -710,8 +707,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
710707
ast_bounds.iter(),
711708
bounds,
712709
projection_ty.bound_vars(),
713-
// TODO: This is wrong, should take preds from binder
714-
ty::List::empty(),
710+
projection_ty.skip_binder_predicates(),
715711
only_self_bounds,
716712
);
717713
}

compiler/rustc_infer/src/infer/higher_ranked/mod.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_infer/src/infer/mod.rs

+65
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,71 @@ impl<'tcx> InferCtxt<'tcx> {
15041504
self.tcx.replace_bound_vars_uncached(value, delegate)
15051505
}
15061506

1507+
pub fn instantiate_binder_and_predicates_with_fresh_vars<T>(
1508+
&self,
1509+
span: Span,
1510+
lbrct: LateBoundRegionConversionTime,
1511+
value: ty::Binder<'tcx, T>,
1512+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>)
1513+
where
1514+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
1515+
{
1516+
if let Some(inner) = value.no_bound_vars() {
1517+
return (inner, ty::List::empty());
1518+
}
1519+
1520+
struct ToFreshVars<'a, 'tcx> {
1521+
infcx: &'a InferCtxt<'tcx>,
1522+
span: Span,
1523+
lbrct: LateBoundRegionConversionTime,
1524+
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
1525+
}
1526+
1527+
impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'_, 'tcx> {
1528+
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
1529+
self.map
1530+
.entry(br.var)
1531+
.or_insert_with(|| {
1532+
self.infcx
1533+
.next_region_var(LateBoundRegion(self.span, br.kind, self.lbrct))
1534+
.into()
1535+
})
1536+
.expect_region()
1537+
}
1538+
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
1539+
self.map
1540+
.entry(bt.var)
1541+
.or_insert_with(|| {
1542+
self.infcx
1543+
.next_ty_var(TypeVariableOrigin {
1544+
kind: TypeVariableOriginKind::MiscVariable,
1545+
span: self.span,
1546+
})
1547+
.into()
1548+
})
1549+
.expect_ty()
1550+
}
1551+
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
1552+
self.map
1553+
.entry(bv)
1554+
.or_insert_with(|| {
1555+
self.infcx
1556+
.next_const_var(
1557+
ty,
1558+
ConstVariableOrigin {
1559+
kind: ConstVariableOriginKind::MiscVariable,
1560+
span: self.span,
1561+
},
1562+
)
1563+
.into()
1564+
})
1565+
.expect_const()
1566+
}
1567+
}
1568+
let delegate = ToFreshVars { infcx: self, span, lbrct, map: Default::default() };
1569+
self.tcx.replace_bound_vars_and_predicates_uncached(value, delegate)
1570+
}
1571+
15071572
/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
15081573
pub fn verify_generic_bound(
15091574
&self,

compiler/rustc_middle/src/ty/fold.rs

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

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

compiler/rustc_middle/src/ty/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,17 @@ impl<'tcx> ParamEnv<'tcx> {
17241724
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
17251725
}
17261726

1727+
pub fn augment(
1728+
tcx: TyCtxt<'tcx>,
1729+
param_env: ty::ParamEnv<'tcx>,
1730+
more_caller_bounds: &'tcx List<Clause<'tcx>>,
1731+
) -> Self {
1732+
ty::ParamEnv::new(
1733+
tcx.mk_clauses_from_iter(param_env.caller_bounds().iter().chain(more_caller_bounds)),
1734+
param_env.reveal(),
1735+
)
1736+
}
1737+
17271738
pub fn with_user_facing(mut self) -> Self {
17281739
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
17291740
self

compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ where
10431043
}
10441044

10451045
impl<'tcx, T> Binder<'tcx, T> {
1046-
pub fn skip_binder_predicates(self) -> &'tcx List<ty::Clause<'tcx>> {
1046+
pub fn skip_binder_predicates(&self) -> &'tcx List<ty::Clause<'tcx>> {
10471047
self.bound_predicates
10481048
}
10491049

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

+29-2
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
500500
}
501501
}
502502
} else {
503-
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
504-
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
503+
let (kind, additional_assumptions) =
504+
self.instantiate_binder_and_assumptions_with_placeholders(kind);
505+
let goal = Goal::new(
506+
self.tcx(),
507+
ty::ParamEnv::augment(self.tcx(), goal.param_env, additional_assumptions),
508+
ty::Binder::dummy(kind),
509+
);
505510
self.add_goal(goal);
506511
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
507512
}
@@ -799,13 +804,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
799804
)
800805
}
801806

807+
pub(super) fn instantiate_binder_and_predicates_with_infer<
808+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
809+
>(
810+
&self,
811+
value: ty::Binder<'tcx, T>,
812+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
813+
self.infcx.instantiate_binder_and_predicates_with_fresh_vars(
814+
DUMMY_SP,
815+
LateBoundRegionConversionTime::HigherRankedType,
816+
value,
817+
)
818+
}
819+
802820
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
803821
&self,
804822
value: ty::Binder<'tcx, T>,
805823
) -> T {
806824
self.infcx.instantiate_binder_with_placeholders(value)
807825
}
808826

827+
pub(super) fn instantiate_binder_and_assumptions_with_placeholders<
828+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
829+
>(
830+
&self,
831+
value: ty::Binder<'tcx, T>,
832+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
833+
self.infcx.instantiate_binder_and_assumptions_with_placeholders(value)
834+
}
835+
809836
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
810837
where
811838
T: TypeFoldable<TyCtxt<'tcx>>,

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
119119
if projection_pred.projection_def_id() == goal.predicate.def_id() {
120120
let tcx = ecx.tcx();
121121
ecx.probe_misc_candidate("assumption").enter(|ecx| {
122-
let assumption_projection_pred =
123-
ecx.instantiate_binder_with_infer(projection_pred);
122+
let (assumption_projection_pred, additional_goals) =
123+
ecx.instantiate_binder_and_predicates_with_infer(projection_pred);
124124
ecx.eq(
125125
goal.param_env,
126126
goal.predicate.projection_ty,
@@ -135,7 +135,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
135135
.instantiate_own(tcx, goal.predicate.projection_ty.args)
136136
.map(|(pred, _)| goal.with(tcx, pred)),
137137
);
138-
138+
ecx.add_goals(additional_goals.iter().map(|pred| goal.with(tcx, pred)));
139139
then(ecx)
140140
})
141141
} 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)