Skip to content

Commit

Permalink
implement fix for cross crate inferrence and fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu committed Jul 3, 2018
1 parent 1c571fd commit 3f616cb
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 119 deletions.
107 changes: 48 additions & 59 deletions src/librustc_typeck/outlives/explicit.rs
Expand Up @@ -8,77 +8,66 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir;
use rustc::hir::def_id::{CrateNum, DefId};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::{self, TyCtxt};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, OutlivesPredicate, TyCtxt};
use util::nodemap::FxHashMap;

use super::utils::*;

pub fn explicit_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
crate_num: CrateNum,
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
let mut predicates = FxHashMap::default();

// iterate over the entire crate
tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
tcx: tcx,
explicit_predicates: &mut predicates,
crate_num: crate_num,
});

predicates
#[derive(Debug)]
pub struct ExplicitPredicatesMap<'tcx> {
map: FxHashMap<DefId, RequiredPredicates<'tcx>>,
}

pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
explicit_predicates: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
crate_num: CrateNum,
}
impl<'tcx> ExplicitPredicatesMap<'tcx> {
pub fn new() -> ExplicitPredicatesMap<'tcx> {
ExplicitPredicatesMap {
map: FxHashMap::default(),
}
}

impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let def_id = DefId {
krate: self.crate_num,
index: item.hir_id.owner,
};
pub fn explicit_predicates_of(
&mut self,
tcx: TyCtxt<'_, 'tcx, 'tcx>,
def_id: DefId,
) -> &RequiredPredicates<'tcx> {
self.map.entry(def_id).or_insert_with(|| {
let predicates = if def_id.is_local() {
tcx.explicit_predicates_of(def_id).predicates
} else {
tcx.predicates_of(def_id).predicates
};
let mut required_predicates = RequiredPredicates::default();

let mut required_predicates = RequiredPredicates::default();
let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id).predicates;
// process predicates and convert to `RequiredPredicates` entry, see below
for pred in predicates.into_iter() {
match pred {
ty::Predicate::TypeOutlives(predicate) => {
let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
insert_outlives_predicate(tcx, (*ty).into(), reg, &mut required_predicates)
}

for pred in local_explicit_predicate.into_iter() {
match pred {
ty::Predicate::TypeOutlives(predicate) => {
let ty::OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
insert_outlives_predicate(self.tcx, (*ty).into(), reg, &mut required_predicates)
}
ty::Predicate::RegionOutlives(predicate) => {
let OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
insert_outlives_predicate(
tcx,
(*reg1).into(),
reg2,
&mut required_predicates,
)
}

ty::Predicate::RegionOutlives(predicate) => {
let ty::OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
insert_outlives_predicate(
self.tcx,
(*reg1).into(),
reg2,
&mut required_predicates,
)
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => (),
}

ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => (),
}
}

self.explicit_predicates.insert(def_id, required_predicates);
required_predicates
})
}

fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {}

fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {}
}
88 changes: 45 additions & 43 deletions src/librustc_typeck/outlives/implicit_infer.rs
Expand Up @@ -15,6 +15,7 @@ use rustc::ty::subst::{Kind, Subst, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;

use super::explicit::ExplicitPredicatesMap;
use super::utils::*;

/// Infer predicates for the items in the crate.
Expand All @@ -24,7 +25,7 @@ use super::utils::*;
/// now be filled with inferred predicates.
pub fn infer_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
debug!("infer_predicates");

Expand Down Expand Up @@ -55,7 +56,7 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
predicates_added: &'cx mut bool,
explicit_map: &'cx FxHashMap<DefId, RequiredPredicates<'tcx>>,
explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>,
}

impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
Expand Down Expand Up @@ -93,7 +94,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
field_ty,
self.global_inferred_outlives,
&mut item_required_predicates,
self.explicit_map,
&mut self.explicit_map,
);
}
}
Expand Down Expand Up @@ -129,7 +130,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
field_ty: Ty<'tcx>,
global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) {
for ty in field_ty.walk() {
match ty.sty {
Expand Down Expand Up @@ -257,53 +258,54 @@ pub fn check_explicit_predicates<'tcx>(
def_id: &DefId,
substs: &[Kind<'tcx>],
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
ignore_self_ty: bool,
) {
debug!("def_id = {:?}", &def_id);
debug!("substs = {:?}", &substs);
debug!("explicit_map = {:?}", explicit_map);
debug!("required_predicates = {:?}", required_predicates);
if let Some(explicit_predicates) = explicit_map.get(def_id) {
for outlives_predicate in explicit_predicates.iter() {
debug!("outlives_predicate = {:?}", &outlives_predicate);
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id);

// Careful: If we are inferring the effects of a `dyn Trait<..>`
// type, then when we look up the predicates for `Trait`,
// we may find some that reference `Self`. e.g., perhaps the
// definition of `Trait` was:
//
// ```
// trait Trait<'a, T> where Self: 'a { .. }
// ```
//
// we want to ignore such predicates here, because
// there is no type parameter for them to affect. Consider
// a struct containing `dyn Trait`:
//
// ```
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
// ```
//
// The `where Self: 'a` predicate refers to the *existential, hidden type*
// that is represented by the `dyn Trait`, not to the `X` type parameter
// (or any other generic parameter) declared on `MyStruct`.
//
// Note that we do this check for self **before** applying `substs`. In the
// case that `substs` come from a `dyn Trait` type, our caller will have
// included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were
// to apply the substs, and not filter this predicate, we might then falsely
// conclude that e.g. `X: 'x` was a reasonable inferred requirement.
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
if ty.is_self() && ignore_self_ty {
debug!("skipping self ty = {:?}", &ty);
continue;
}
}
for outlives_predicate in explicit_predicates.iter() {
debug!("outlives_predicate = {:?}", &outlives_predicate);

let predicate = outlives_predicate.subst(tcx, substs);
debug!("predicate = {:?}", &predicate);
insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
// Careful: If we are inferring the effects of a `dyn Trait<..>`
// type, then when we look up the predicates for `Trait`,
// we may find some that reference `Self`. e.g., perhaps the
// definition of `Trait` was:
//
// ```
// trait Trait<'a, T> where Self: 'a { .. }
// ```
//
// we want to ignore such predicates here, because
// there is no type parameter for them to affect. Consider
// a struct containing `dyn Trait`:
//
// ```
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
// ```
//
// The `where Self: 'a` predicate refers to the *existential, hidden type*
// that is represented by the `dyn Trait`, not to the `X` type parameter
// (or any other generic parameter) declared on `MyStruct`.
//
// Note that we do this check for self **before** applying `substs`. In the
// case that `substs` come from a `dyn Trait` type, our caller will have
// included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were
// to apply the substs, and not filter this predicate, we might then falsely
// conclude that e.g. `X: 'x` was a reasonable inferred requirement.
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
if ty.is_self() && ignore_self_ty {
debug!("skipping self ty = {:?}", &ty);
continue;
}
}

let predicate = outlives_predicate.subst(tcx, substs);
debug!("predicate = {:?}", &predicate);
insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
}
// }
}
7 changes: 5 additions & 2 deletions src/librustc_typeck/outlives/mod.rs
Expand Up @@ -84,6 +84,8 @@ fn inferred_outlives_crate<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
crate_num: CrateNum,
) -> Lrc<CratePredicatesMap<'tcx>> {
assert_eq!(crate_num, LOCAL_CRATE);

// Compute a map from each struct/enum/union S to the **explicit**
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Typically there won't be many of these, except in older code where
Expand All @@ -92,8 +94,9 @@ fn inferred_outlives_crate<'tcx>(
// for the type.

// Compute the inferred predicates
let exp = explicit::explicit_predicates(tcx, crate_num);
let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
let mut exp_map = explicit::ExplicitPredicatesMap::new();

let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map);

// Convert the inferred predicates into the "collected" form the
// global data structure expects.
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/rfc-2093-infer-outlives/cross-crate.rs
Expand Up @@ -11,9 +11,9 @@
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]

// #[rustc_outlives]
struct Foo<'a, T> {
bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309]
#[rustc_outlives]
struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
bar: std::slice::IterMut<'a, T>
}

fn main() {}
Expand Down
19 changes: 7 additions & 12 deletions src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr
@@ -1,17 +1,12 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/cross-crate.rs:16:5
error: rustc_outlives
--> $DIR/cross-crate.rs:15:1
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | bar: std::slice::IterMut<'a, T>
LL | | }
| |_^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> $DIR/cross-crate.rs:16:5
|
LL | bar: std::slice::IterMut<'a, T> //~ ERROR 16:5: 16:36: the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: T : 'a

error: aborting due to previous error

For more information about this error, try `rustc --explain E0309`.

0 comments on commit 3f616cb

Please sign in to comment.