about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-06 16:01:25 +0000
committerbors <bors@rust-lang.org>2018-07-06 16:01:25 +0000
commit062a416dd4f12cf99b37d078a3da8dd81a1c008e (patch)
tree628c1f3af52ed2cb499d149534259f2f74e93882
parent50302821c4f63f487783762c1b45b412c2574334 (diff)
parent3f616cb8c1831948a40beca8fb117e920df5a7a8 (diff)
downloadrust-062a416dd4f12cf99b37d078a3da8dd81a1c008e.tar.gz
rust-062a416dd4f12cf99b37d078a3da8dd81a1c008e.zip
Auto merge of #52010 - toidiu:ak-crossCrateOutlives, r=nikomatsakis
Fix: infer outlives requirements across crates

Fixes https://github.com/rust-lang/rust/issues/51858
-rw-r--r--src/librustc_typeck/outlives/explicit.rs107
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs88
-rw-r--r--src/librustc_typeck/outlives/mod.rs7
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/cross-crate.rs20
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr12
5 files changed, 130 insertions, 104 deletions
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
index bbe47ecee79..a7ecfc269f3 100644
--- a/src/librustc_typeck/outlives/explicit.rs
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -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) {}
 }
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index c966db98c8e..a015122d62e 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -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.
@@ -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");
 
@@ -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> {
@@ -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,
                     );
                 }
             }
@@ -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 {
@@ -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);
     }
+    // }
 }
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index c6c7e8f931f..9c483924992 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -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
@@ -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.
diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs
new file mode 100644
index 00000000000..01673997883
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+#![feature(infer_outlives_requirements)]
+
+#[rustc_outlives]
+struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
+    bar: std::slice::IterMut<'a, T>
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr
new file mode 100644
index 00000000000..a90643ae891
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr
@@ -0,0 +1,12 @@
+error: rustc_outlives
+  --> $DIR/cross-crate.rs:15:1
+   |
+LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
+LL | |     bar: std::slice::IterMut<'a, T>
+LL | | }
+   | |_^
+   |
+   = note: T : 'a
+
+error: aborting due to previous error
+