Skip to content

Commit 30da22b

Browse files
committed
Make the WF check a bit more friendly to binders
Skip the binder in less places during WF check. I thought this might help fix #50781, but I couldn't actually observe any effect for this changes. Maybe it's still a worthwhile refactoring since skipping binders is generally a bad thing. There is a (manageble) conflict with #50183.
1 parent 448cc57 commit 30da22b

File tree

2 files changed

+69
-23
lines changed

2 files changed

+69
-23
lines changed

src/librustc/ty/sty.rs

+28
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,34 @@ impl<T> Binder<T> {
797797
let (u, v) = f(self.0);
798798
(Binder(u), Binder(v))
799799
}
800+
801+
pub fn unfold<U,F>(self, f: F) -> impl Iterator<Item = Binder<U>>
802+
where F: FnOnce(T) -> Vec<U>
803+
{
804+
f(self.0).into_iter().map(|u| Binder(u))
805+
}
806+
}
807+
808+
impl<'tcx> Binder<ty::Predicate<'tcx>> {
809+
pub fn flatten<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ty::Predicate<'tcx> {
810+
// We will rebind inside the predicate.
811+
match self.0 {
812+
ty::Predicate::Trait(b) =>
813+
ty::Predicate::Trait(tcx.flatten_late_bound_regions(&Binder::bind(b))),
814+
ty::Predicate::Subtype(b) =>
815+
ty::Predicate::Subtype(tcx.flatten_late_bound_regions(&Binder::bind(b))),
816+
ty::Predicate::RegionOutlives(b) =>
817+
ty::Predicate::RegionOutlives(tcx.flatten_late_bound_regions(&Binder::bind(b))),
818+
ty::Predicate::TypeOutlives(b) =>
819+
ty::Predicate::TypeOutlives(tcx.flatten_late_bound_regions(&Binder::bind(b))),
820+
ty::Predicate::Projection(b) =>
821+
ty::Predicate::Projection(tcx.flatten_late_bound_regions(&Binder::bind(b))),
822+
ty::Predicate::WellFormed(_) |
823+
ty::Predicate::ObjectSafe(_) |
824+
ty::Predicate::ClosureKind(_, _, _) |
825+
ty::Predicate::ConstEvaluatable(_, _) => self.no_late_bound_regions().unwrap()
826+
}
827+
}
800828
}
801829

802830
/// Represents the projection of an associated type. In explicit UFCS

src/librustc/ty/wf.rs

+41-23
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use middle::const_val::ConstVal;
1313
use infer::InferCtxt;
1414
use ty::subst::Substs;
1515
use traits;
16-
use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
16+
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
1717
use std::iter::once;
1818
use syntax::ast;
1919
use syntax_pos::Span;
@@ -59,7 +59,7 @@ pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
5959
-> Vec<traits::PredicateObligation<'tcx>>
6060
{
6161
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
62-
wf.compute_trait_ref(trait_ref, Elaborate::All);
62+
wf.compute_trait_ref(&trait_ref.to_poly_trait_ref(), Elaborate::All);
6363
wf.normalize()
6464
}
6565

@@ -73,19 +73,18 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
7373
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
7474

7575
// (*) ok to skip binders, because wf code is prepared for it
76-
match *predicate {
77-
ty::Predicate::Trait(ref t) => {
78-
wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
76+
match predicate {
77+
ty::Predicate::Trait(t) => {
78+
wf.compute_trait_ref(&t.to_poly_trait_ref(), Elaborate::None);
7979
}
8080
ty::Predicate::RegionOutlives(..) => {
8181
}
82-
ty::Predicate::TypeOutlives(ref t) => {
82+
ty::Predicate::TypeOutlives(t) => {
8383
wf.compute(t.skip_binder().0);
8484
}
85-
ty::Predicate::Projection(ref t) => {
86-
let t = t.skip_binder(); // (*)
87-
wf.compute_projection(t.projection_ty);
88-
wf.compute(t.ty);
85+
ty::Predicate::Projection(t) => {
86+
wf.compute_projection(t.map_bound(|t| t.projection_ty));
87+
wf.compute(t.skip_binder().ty); // (*)
8988
}
9089
ty::Predicate::WellFormed(t) => {
9190
wf.compute(t);
@@ -94,12 +93,12 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
9493
}
9594
ty::Predicate::ClosureKind(..) => {
9695
}
97-
ty::Predicate::Subtype(ref data) => {
96+
ty::Predicate::Subtype(data) => {
9897
wf.compute(data.skip_binder().a); // (*)
9998
wf.compute(data.skip_binder().b); // (*)
10099
}
101100
ty::Predicate::ConstEvaluatable(def_id, substs) => {
102-
let obligations = wf.nominal_obligations(def_id, substs);
101+
let obligations = wf.nominal_obligations(*def_id, substs);
103102
wf.out.extend(obligations);
104103

105104
for ty in substs.types() {
@@ -169,8 +168,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
169168

170169
/// Pushes the obligations required for `trait_ref` to be WF into
171170
/// `self.out`.
172-
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
173-
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
171+
fn compute_trait_ref(&mut self, poly_trait_ref: &ty::PolyTraitRef<'tcx>, elaborate: Elaborate) {
172+
let obligations = self.nominal_trait_ref_obligations(poly_trait_ref);
174173

175174
let cause = self.cause(traits::MiscObligation);
176175
let param_env = self.param_env;
@@ -189,7 +188,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
189188
self.out.extend(obligations);
190189

191190
self.out.extend(
192-
trait_ref.substs.types()
191+
poly_trait_ref.skip_binder().substs.types()
193192
.filter(|ty| !ty.has_escaping_regions())
194193
.map(|ty| traits::Obligation::new(cause.clone(),
195194
param_env,
@@ -198,16 +197,18 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
198197

199198
/// Pushes the obligations required for `trait_ref::Item` to be WF
200199
/// into `self.out`.
201-
fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
200+
fn compute_projection(&mut self, poly_proj: ty::Binder<ty::ProjectionTy<'tcx>>) {
202201
// A projection is well-formed if (a) the trait ref itself is
203202
// WF and (b) the trait-ref holds. (It may also be
204203
// normalizable and be WF that way.)
205-
let trait_ref = data.trait_ref(self.infcx.tcx);
206-
self.compute_trait_ref(&trait_ref, Elaborate::None);
207-
208-
if !data.has_escaping_regions() {
209-
let predicate = trait_ref.to_predicate();
210-
let cause = self.cause(traits::ProjectionWf(data));
204+
let poly_trait_ref = poly_proj.map_bound(|proj| proj.trait_ref(self.infcx.tcx));
205+
self.compute_trait_ref(&poly_trait_ref, Elaborate::None);
206+
207+
// FIXME(leodasvacas): Should be straightforward to remove
208+
// this condition and use the `poly_proj` directly.
209+
if let Some(proj) = poly_proj.no_late_bound_regions() {
210+
let predicate = poly_trait_ref.to_predicate();
211+
let cause = self.cause(traits::ProjectionWf(proj));
211212
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
212213
}
213214
}
@@ -289,7 +290,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
289290

290291
ty::TyProjection(data) => {
291292
subtys.skip_current_subtree(); // subtree handled by compute_projection
292-
self.compute_projection(data);
293+
self.compute_projection(ty::Binder::bind(data));
293294
}
294295

295296
ty::TyAdt(def, substs) => {
@@ -431,6 +432,23 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
431432
return true;
432433
}
433434

435+
fn nominal_trait_ref_obligations(&mut self,
436+
poly_trait_ref: &ty::PolyTraitRef<'tcx>)
437+
-> Vec<traits::PredicateObligation<'tcx>> {
438+
let cause = self.cause(traits::ItemObligation(poly_trait_ref.def_id()));
439+
poly_trait_ref
440+
.unfold(|trait_ref| {
441+
self.infcx
442+
.tcx
443+
.predicates_of(trait_ref.def_id)
444+
.instantiate(self.infcx.tcx, trait_ref.substs)
445+
.predicates
446+
})
447+
.map(|poly_pred| poly_pred.flatten(self.infcx.tcx))
448+
.map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred))
449+
.collect()
450+
}
451+
434452
fn nominal_obligations(&mut self,
435453
def_id: DefId,
436454
substs: &Substs<'tcx>)

0 commit comments

Comments
 (0)