Skip to content

Commit b1b8677

Browse files
Handle binder predicates in new trait solver
1 parent 9463863 commit b1b8677

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`
@@ -707,8 +704,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
707704
ast_bounds.iter(),
708705
bounds,
709706
projection_ty.bound_vars(),
710-
// TODO: This is wrong, should take preds from binder
711-
ty::List::empty(),
707+
projection_ty.skip_binder_predicates(),
712708
only_self_bounds,
713709
);
714710
}

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
@@ -1459,6 +1459,71 @@ impl<'tcx> InferCtxt<'tcx> {
14591459
self.tcx.replace_bound_vars_uncached(value, delegate)
14601460
}
14611461

1462+
pub fn instantiate_binder_and_predicates_with_fresh_vars<T>(
1463+
&self,
1464+
span: Span,
1465+
lbrct: LateBoundRegionConversionTime,
1466+
value: ty::Binder<'tcx, T>,
1467+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>)
1468+
where
1469+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
1470+
{
1471+
if let Some(inner) = value.no_bound_vars() {
1472+
return (inner, ty::List::empty());
1473+
}
1474+
1475+
struct ToFreshVars<'a, 'tcx> {
1476+
infcx: &'a InferCtxt<'tcx>,
1477+
span: Span,
1478+
lbrct: LateBoundRegionConversionTime,
1479+
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
1480+
}
1481+
1482+
impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'_, 'tcx> {
1483+
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
1484+
self.map
1485+
.entry(br.var)
1486+
.or_insert_with(|| {
1487+
self.infcx
1488+
.next_region_var(LateBoundRegion(self.span, br.kind, self.lbrct))
1489+
.into()
1490+
})
1491+
.expect_region()
1492+
}
1493+
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
1494+
self.map
1495+
.entry(bt.var)
1496+
.or_insert_with(|| {
1497+
self.infcx
1498+
.next_ty_var(TypeVariableOrigin {
1499+
kind: TypeVariableOriginKind::MiscVariable,
1500+
span: self.span,
1501+
})
1502+
.into()
1503+
})
1504+
.expect_ty()
1505+
}
1506+
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
1507+
self.map
1508+
.entry(bv)
1509+
.or_insert_with(|| {
1510+
self.infcx
1511+
.next_const_var(
1512+
ty,
1513+
ConstVariableOrigin {
1514+
kind: ConstVariableOriginKind::MiscVariable,
1515+
span: self.span,
1516+
},
1517+
)
1518+
.into()
1519+
})
1520+
.expect_const()
1521+
}
1522+
}
1523+
let delegate = ToFreshVars { infcx: self, span, lbrct, map: Default::default() };
1524+
self.tcx.replace_bound_vars_and_predicates_uncached(value, delegate)
1525+
}
1526+
14621527
/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
14631528
pub fn verify_generic_bound(
14641529
&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
@@ -1737,6 +1737,17 @@ impl<'tcx> ParamEnv<'tcx> {
17371737
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
17381738
}
17391739

1740+
pub fn augment(
1741+
tcx: TyCtxt<'tcx>,
1742+
param_env: ty::ParamEnv<'tcx>,
1743+
more_caller_bounds: &'tcx List<Clause<'tcx>>,
1744+
) -> Self {
1745+
ty::ParamEnv::new(
1746+
tcx.mk_clauses_from_iter(param_env.caller_bounds().iter().chain(more_caller_bounds)),
1747+
param_env.reveal(),
1748+
)
1749+
}
1750+
17401751
pub fn with_user_facing(mut self) -> Self {
17411752
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
17421753
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.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
492492
}
493493
}
494494
} else {
495-
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
496-
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
495+
let (kind, additional_assumptions) =
496+
self.instantiate_binder_and_assumptions_with_placeholders(kind);
497+
let goal = Goal::new(
498+
self.tcx(),
499+
ty::ParamEnv::augment(self.tcx(), goal.param_env, additional_assumptions),
500+
ty::Binder::dummy(kind),
501+
);
497502
self.add_goal(goal);
498503
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
499504
}
@@ -787,13 +792,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
787792
)
788793
}
789794

795+
pub(super) fn instantiate_binder_and_predicates_with_infer<
796+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
797+
>(
798+
&self,
799+
value: ty::Binder<'tcx, T>,
800+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
801+
self.infcx.instantiate_binder_and_predicates_with_fresh_vars(
802+
DUMMY_SP,
803+
LateBoundRegionConversionTime::HigherRankedType,
804+
value,
805+
)
806+
}
807+
790808
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
791809
&self,
792810
value: ty::Binder<'tcx, T>,
793811
) -> T {
794812
self.infcx.instantiate_binder_with_placeholders(value)
795813
}
796814

815+
pub(super) fn instantiate_binder_and_assumptions_with_placeholders<
816+
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
817+
>(
818+
&self,
819+
value: ty::Binder<'tcx, T>,
820+
) -> (T, &'tcx ty::List<ty::Clause<'tcx>>) {
821+
self.infcx.instantiate_binder_and_assumptions_with_placeholders(value)
822+
}
823+
797824
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
798825
where
799826
T: TypeFoldable<TyCtxt<'tcx>>,

compiler/rustc_trait_selection/src/solve/project_goals.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
114114
if projection_pred.projection_def_id() == goal.predicate.def_id() {
115115
let tcx = ecx.tcx();
116116
ecx.probe_candidate("assumption").enter(|ecx| {
117-
let assumption_projection_pred =
118-
ecx.instantiate_binder_with_infer(projection_pred);
117+
let (assumption_projection_pred, additional_goals) =
118+
ecx.instantiate_binder_and_predicates_with_infer(projection_pred);
119119
ecx.eq(
120120
goal.param_env,
121121
goal.predicate.projection_ty,
@@ -130,7 +130,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
130130
.instantiate_own(tcx, goal.predicate.projection_ty.args)
131131
.map(|(pred, _)| goal.with(tcx, pred)),
132132
);
133-
133+
ecx.add_goals(additional_goals.iter().map(|pred| goal.with(tcx, pred)));
134134
then(ecx)
135135
})
136136
} 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_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)