Skip to content

Commit

Permalink
Auto merge of #73503 - lcnr:forall-predicate-what-and-why-2, r=nikoma…
Browse files Browse the repository at this point in the history
…tsakis

convert higher ranked `Predicate`s to `PredicateKind::ForAll`

implements step 2 of rust-lang/compiler-team#285
r? @nikomatsakis
  • Loading branch information
bors committed Jul 27, 2020
2 parents efc02b0 + 602ef6b commit 76e8333
Show file tree
Hide file tree
Showing 61 changed files with 1,268 additions and 1,150 deletions.
45 changes: 20 additions & 25 deletions src/librustc_infer/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,28 +525,25 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
result_subst: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
unsubstituted_region_constraints.iter().map(move |constraint| {
let constraint = substitute_value(self.tcx, result_subst, constraint);
let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
let ty::OutlivesPredicate(k1, r2) =
substitute_value(self.tcx, result_subst, constraint).skip_binder();

Obligation::new(
cause.clone(),
param_env,
match k1.unpack() {
GenericArgKind::Lifetime(r1) => ty::PredicateKind::RegionOutlives(
ty::Binder::bind(ty::OutlivesPredicate(r1, r2)),
)
.to_predicate(self.tcx),
GenericArgKind::Type(t1) => ty::PredicateKind::TypeOutlives(ty::Binder::bind(
ty::OutlivesPredicate(t1, r2),
))
.to_predicate(self.tcx),
GenericArgKind::Const(..) => {
// Consts cannot outlive one another, so we don't expect to
// ecounter this branch.
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
}
},
)
let predicate = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2))
}
GenericArgKind::Type(t1) => {
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t1, r2))
}
GenericArgKind::Const(..) => {
// Consts cannot outlive one another, so we don't expect to
// encounter this branch.
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
}
}
.potentially_quantified(self.tcx, ty::PredicateKind::ForAll);

Obligation::new(cause.clone(), param_env, predicate)
})
}

Expand Down Expand Up @@ -666,10 +663,8 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
predicate: ty::PredicateKind::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
sup, sub,
)))
.to_predicate(self.infcx.tcx),
predicate: ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(sup, sub))
.to_predicate(self.infcx.tcx),
recursion_depth: 0,
});
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_infer/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
self.param_env,
ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
ty::PredicateAtom::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
));
}

Expand Down Expand Up @@ -400,9 +400,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
b: &'tcx ty::Const<'tcx>,
) {
let predicate = if a_is_expected {
ty::PredicateKind::ConstEquate(a, b)
ty::PredicateAtom::ConstEquate(a, b)
} else {
ty::PredicateKind::ConstEquate(b, a)
ty::PredicateAtom::ConstEquate(b, a)
};
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
Expand Down
34 changes: 20 additions & 14 deletions src/librustc_infer/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,29 @@ pub mod verify;

use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
use rustc_middle::ty::fold::TypeFoldable;

pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
debug!("explicit_outlives_bounds()");
param_env.caller_bounds().into_iter().filter_map(move |predicate| match predicate.kind() {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => None,
ty::PredicateKind::RegionOutlives(ref data) => data
.no_bound_vars()
.map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
})
param_env
.caller_bounds()
.into_iter()
.map(ty::Predicate::skip_binders)
.filter(|atom| !atom.has_escaping_bound_vars())
.filter_map(move |atom| match atom {
ty::PredicateAtom::Projection(..)
| ty::PredicateAtom::Trait(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::WellFormed(..)
| ty::PredicateAtom::ObjectSafe(..)
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::TypeOutlives(..)
| ty::PredicateAtom::ConstEvaluatable(..)
| ty::PredicateAtom::ConstEquate(..) => None,
ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
}
})
}
4 changes: 2 additions & 2 deletions src/librustc_infer/infer/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
self.fields.obligations.push(Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,
ty::PredicateKind::Subtype(ty::Binder::dummy(ty::SubtypePredicate {
ty::PredicateAtom::Subtype(ty::SubtypePredicate {
a_is_expected: self.a_is_expected,
a,
b,
}))
})
.to_predicate(self.tcx()),
));

Expand Down
88 changes: 28 additions & 60 deletions src/librustc_infer/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,20 @@ use smallvec::smallvec;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, TyCtxt, WithConstness};
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
use rustc_span::Span;

pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
pred: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
let kind = pred.kind();
let new = match kind {
&ty::PredicateKind::Trait(ref data, constness) => {
ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness)
match pred.kind() {
ty::PredicateKind::ForAll(binder) => {
let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
tcx.reuse_or_mk_predicate(pred, new)
}

ty::PredicateKind::RegionOutlives(data) => {
ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data))
}

ty::PredicateKind::TypeOutlives(data) => {
ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data))
}

ty::PredicateKind::Projection(data) => {
ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data))
}

&ty::PredicateKind::WellFormed(data) => ty::PredicateKind::WellFormed(data),

&ty::PredicateKind::ObjectSafe(data) => ty::PredicateKind::ObjectSafe(data),

&ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
}

ty::PredicateKind::Subtype(data) => {
ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data))
}

&ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
ty::PredicateKind::ConstEvaluatable(def_id, substs)
}

ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2),
};

if new != *kind { new.to_predicate(tcx) } else { pred }
ty::PredicateKind::Atom(_) => pred,
}
}

struct PredicateSet<'tcx> {
Expand Down Expand Up @@ -158,15 +127,16 @@ impl Elaborator<'tcx> {

fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
let tcx = self.visited.tcx;
match obligation.predicate.kind() {
ty::PredicateKind::Trait(ref data, _) => {

match obligation.predicate.skip_binders() {
ty::PredicateAtom::Trait(data, _) => {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());

let obligations = predicates.predicates.iter().map(|(pred, span)| {
let obligations = predicates.predicates.iter().map(|&(pred, span)| {
predicate_obligation(
pred.subst_supertrait(tcx, &data.to_poly_trait_ref()),
Some(*span),
pred.subst_supertrait(tcx, &ty::Binder::bind(data.trait_ref)),
Some(span),
)
});
debug!("super_predicates: data={:?}", data);
Expand All @@ -180,36 +150,36 @@ impl Elaborator<'tcx> {

self.stack.extend(obligations);
}
ty::PredicateKind::WellFormed(..) => {
ty::PredicateAtom::WellFormed(..) => {
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
ty::PredicateKind::ObjectSafe(..) => {
ty::PredicateAtom::ObjectSafe(..) => {
// Currently, we do not elaborate object-safe
// predicates.
}
ty::PredicateKind::Subtype(..) => {
ty::PredicateAtom::Subtype(..) => {
// Currently, we do not "elaborate" predicates like `X <: Y`,
// though conceivably we might.
}
ty::PredicateKind::Projection(..) => {
ty::PredicateAtom::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
ty::PredicateKind::ClosureKind(..) => {
ty::PredicateAtom::ClosureKind(..) => {
// Nothing to elaborate when waiting for a closure's kind to be inferred.
}
ty::PredicateKind::ConstEvaluatable(..) => {
ty::PredicateAtom::ConstEvaluatable(..) => {
// Currently, we do not elaborate const-evaluatable
// predicates.
}
ty::PredicateKind::ConstEquate(..) => {
ty::PredicateAtom::ConstEquate(..) => {
// Currently, we do not elaborate const-equate
// predicates.
}
ty::PredicateKind::RegionOutlives(..) => {
ty::PredicateAtom::RegionOutlives(..) => {
// Nothing to elaborate from `'a: 'b`.
}
ty::PredicateKind::TypeOutlives(ref data) => {
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
// We know that `T: 'a` for some type `T`. We can
// often elaborate this. For example, if we know that
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
Expand All @@ -224,8 +194,6 @@ impl Elaborator<'tcx> {
// consider this as evidence that `T: 'static`, but
// I'm a bit wary of such constructions and so for now
// I want to be conservative. --nmatsakis
let ty_max = data.skip_binder().0;
let r_min = data.skip_binder().1;
if r_min.is_late_bound() {
return;
}
Expand All @@ -241,16 +209,16 @@ impl Elaborator<'tcx> {
if r.is_late_bound() {
None
} else {
Some(ty::PredicateKind::RegionOutlives(ty::Binder::dummy(
ty::OutlivesPredicate(r, r_min),
Some(ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
r, r_min,
)))
}
}

Component::Param(p) => {
let ty = tcx.mk_ty_param(p.index, p.name);
Some(ty::PredicateKind::TypeOutlives(ty::Binder::dummy(
ty::OutlivesPredicate(ty, r_min),
Some(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(
ty, r_min,
)))
}

Expand Down Expand Up @@ -331,8 +299,8 @@ impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToT

fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
while let Some(obligation) = self.base_iterator.next() {
if let ty::PredicateKind::Trait(data, _) = obligation.predicate.kind() {
return Some(data.to_poly_trait_ref());
if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
return Some(data);
}
}
None
Expand Down
24 changes: 10 additions & 14 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1202,13 +1202,13 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PredicateKind::*;
use rustc_middle::ty::PredicateAtom::*;

if cx.tcx.features().trivial_bounds {
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
let predicates = cx.tcx.predicates_of(def_id);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind() {
let predicate_kind_name = match predicate.skip_binders() {
Trait(..) => "Trait",
TypeOutlives(..) |
RegionOutlives(..) => "Lifetime",
Expand Down Expand Up @@ -1497,14 +1497,11 @@ impl ExplicitOutlivesRequirements {
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
.filter_map(|(pred, _)| match pred.kind() {
ty::PredicateKind::RegionOutlives(outlives) => {
let outlives = outlives.skip_binder();
match outlives.0 {
ty::ReEarlyBound(ebr) if ebr.index == index => Some(outlives.1),
_ => None,
}
}
.filter_map(|(pred, _)| match pred.skip_binders() {
ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
_ => None,
},
_ => None,
})
.collect()
Expand All @@ -1516,10 +1513,9 @@ impl ExplicitOutlivesRequirements {
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
.filter_map(|(pred, _)| match pred.kind() {
ty::PredicateKind::TypeOutlives(outlives) => {
let outlives = outlives.skip_binder();
outlives.0.is_param(index).then_some(outlives.1)
.filter_map(|(pred, _)| match pred.skip_binders() {
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
a.is_param(index).then_some(b)
}
_ => None,
})
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
ty::Opaque(def, _) => {
let mut has_emitted = false;
for (predicate, _) in cx.tcx.predicates_of(def).predicates {
if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) =
predicate.kind()
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
predicate.skip_binders()
{
let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
let def_id = trait_ref.def_id;
let def_id = poly_trait_predicate.trait_ref.def_id;
let descr_pre =
&format!("{}implementer{} of ", descr_pre, plural_suffix,);
if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
Expand Down
Loading

0 comments on commit 76e8333

Please sign in to comment.