]> git.lizzy.rs Git - rust.git/commitdiff
introduce `predicates_defined_on` for traits
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 2 Jul 2018 14:35:30 +0000 (10:35 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 2 Jul 2018 15:33:24 +0000 (11:33 -0400)
This new query returns only the predicates *directly defined* on an
item (in contrast to the more common `predicates_of`, which returns
the predicates that must be proven to reference an item). These two
sets are almost always identical except for traits, where
`predicates_of` includes an artificial `Self: Trait<...>` predicate
(basically saying that you cannot use a trait item without proving
that the trait is implemented for the type parameters).

This new query is only used in chalk lowering, where this artificial
`Self: Trait` predicate is problematic. We encode it in metadata but
only where needed since it is kind of repetitive with existing
information.

Co-authored-by: Tyler Mandry <tmandry@gmail.com>
src/librustc/dep_graph/dep_node.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/plumbing.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_traits/lowering.rs
src/librustc_typeck/collect.rs
src/test/ui/chalkify/lower_env1.stderr

index 6cc61d748001a191f9bf4428080f1881dc2f285e..3c4472aef6bed3157d8013bb3d4b28696903724b 100644 (file)
@@ -504,6 +504,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [] GenericsOfItem(DefId),
     [] PredicatesOfItem(DefId),
     [] ExplicitPredicatesOfItem(DefId),
+    [] PredicatesDefinedOnItem(DefId),
     [] InferredOutlivesOf(DefId),
     [] InferredOutlivesCrate(CrateNum),
     [] SuperPredicatesOfItem(DefId),
index 77644cdf02b116d63e173a9d5c9f97916da3941c..9ad93b4d5e233117ade9d905014c6f4c490c65e6 100644 (file)
     [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
 
     /// Maps from the def-id of an item (trait/struct/enum/fn) to its
-    /// associated generics and predicates.
+    /// associated generics.
     [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,
+
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to the
+    /// predicates (where clauses) that must be proven true in order
+    /// to reference it. This is almost always the "predicates query"
+    /// that you want.
+    ///
+    /// `predicates_of` builds on `predicates_defined_on` -- in fact,
+    /// it is almost always the same as that query, except for the
+    /// case of traits. For traits, `predicates_of` contains
+    /// an additional `Self: Trait<...>` predicate that users don't
+    /// actually write. This reflects the fact that to invoke the
+    /// trait (e.g., via `Default::default`) you must supply types
+    /// that actually implement the trait. (However, this extra
+    /// predicate gets in the way of some checks, which are intended
+    /// to operate over only the actual where-clauses written by the
+    /// user.)
     [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to the
+    /// predicates (where clauses) directly defined on it. This is
+    /// equal to the `explicit_predicates_of` predicates plus the
+    /// `inferred_outlives_of` predicates.
+    [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// Returns the predicates written explicit by the user.
     [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
 
+    /// Returns the inferred outlives predicates (e.g., for `struct
+    /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
+    [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
+
     /// Maps from the def-id of a trait to the list of
     /// super-predicates. This is a subset of the full list of
     /// predicates. We store these in a separate map because we must
     /// (inferred) variance.
     [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
 
-    /// Maps from def-id of a type to its (inferred) outlives.
-    [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
-
     /// Maps from def-id of a type to its (inferred) outlives.
     [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
         -> Lrc<ty::CratePredicatesMap<'tcx>>,
index e17c6fba74c6ed2fc0c406e19287bef25ad5d891..874a62fb6a5cdc13f8444aaa003d5b3d37e2d224 100644 (file)
@@ -1074,6 +1074,7 @@ macro_rules! force {
         DepKind::TypeOfItem => { force!(type_of, def_id!()); }
         DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
         DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
+        DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); }
         DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); }
         DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
         DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); }
index d0e4e54e63d677f86f615ff5004b4620d3c5b644..14f63898a4fedaceafe2e7502cfc9c09b22b5409 100644 (file)
@@ -107,6 +107,7 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
         tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
     }
     predicates_of => { cdata.get_predicates(def_id.index, tcx) }
+    predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) }
     super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
     trait_def => {
         tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))
index 1985900b3e1170b05e03e4ae8bf48207997807a2..d604ac819b83b6af6a1b123075a01a4b1ac227a9 100644 (file)
@@ -563,6 +563,13 @@ pub fn get_predicates(&self,
         self.entry(item_id).predicates.unwrap().decode((self, tcx))
     }
 
+    pub fn get_predicates_defined_on(&self,
+                                   item_id: DefIndex,
+                                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                   -> ty::GenericPredicates<'tcx> {
+        self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx))
+    }
+
     pub fn get_super_predicates(&self,
                                 item_id: DefIndex,
                                 tcx: TyCtxt<'a, 'tcx, 'tcx>)
index d8a224d3badd8692390396d37d31e30bcc501e76..4c58eb8d5a05d36dc51f1ebd72405e8304417505 100644 (file)
@@ -627,6 +627,7 @@ fn encode_enum_variant_info(&mut self,
             },
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: self.encode_optimized_mir(def_id),
         }
@@ -664,6 +665,7 @@ fn encode_info_for_mod(&mut self,
             variances: LazySeq::empty(),
             generics: None,
             predicates: None,
+            predicates_defined_on: None,
 
             mir: None
         }
@@ -704,6 +706,7 @@ fn encode_field(&mut self,
             variances: LazySeq::empty(),
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: None,
         }
@@ -761,6 +764,7 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
             },
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: self.encode_optimized_mir(def_id),
         }
@@ -778,6 +782,12 @@ fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tc
         self.lazy(&tcx.predicates_of(def_id))
     }
 
+    fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+        debug!("IsolatedEncoder::encode_predicates_defined_on({:?})", def_id);
+        let tcx = self.tcx;
+        self.lazy(&tcx.predicates_defined_on(def_id))
+    }
+
     fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
         debug!("IsolatedEncoder::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
@@ -867,6 +877,7 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
             },
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: self.encode_optimized_mir(def_id),
         }
@@ -963,6 +974,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
             },
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: if mir { self.encode_optimized_mir(def_id) } else { None },
         }
@@ -1226,6 +1238,16 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
                 _ => None,
             },
 
+            // The only time that `predicates_defined_on` is used (on
+            // an external item) is for traits, during chalk lowering,
+            // so only encode it in that case as an efficiency
+            // hack. (No reason not to expand it in the future if
+            // necessary.)
+            predicates_defined_on: match item.node {
+                hir::ItemTrait(..) => Some(self.encode_predicates_defined_on(def_id)),
+                _ => None, // not *wrong* for other kinds of items, but not needed
+            },
+
             mir: match item.node {
                 hir::ItemStatic(..) => {
                     self.encode_optimized_mir(def_id)
@@ -1276,6 +1298,7 @@ fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx
             variances: LazySeq::empty(),
             generics: None,
             predicates: None,
+            predicates_defined_on: None,
             mir: None,
         }
     }
@@ -1303,6 +1326,7 @@ fn encode_info_for_ty_param(&mut self,
             variances: LazySeq::empty(),
             generics: None,
             predicates: None,
+            predicates_defined_on: None,
 
             mir: None,
         }
@@ -1347,6 +1371,7 @@ fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
             variances: LazySeq::empty(),
             generics: Some(self.encode_generics(def_id)),
             predicates: None,
+            predicates_defined_on: None,
 
             mir: self.encode_optimized_mir(def_id),
         }
@@ -1374,6 +1399,7 @@ fn encode_info_for_anon_const(&mut self, def_id: DefId) -> Entry<'tcx> {
             variances: LazySeq::empty(),
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: self.encode_optimized_mir(def_id),
         }
@@ -1575,6 +1601,7 @@ fn encode_info_for_foreign_item(&mut self,
             },
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
+            predicates_defined_on: None,
 
             mir: None,
         }
index 21d6d15457aa0252a4ac51f14e6f61af78e3b913..a0b21e63ac560278af6995c962e70f777287bbc5 100644 (file)
@@ -273,6 +273,7 @@ pub struct Entry<'tcx> {
     pub variances: LazySeq<ty::Variance>,
     pub generics: Option<Lazy<ty::Generics>>,
     pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
+    pub predicates_defined_on: Option<Lazy<ty::GenericPredicates<'tcx>>>,
 
     pub mir: Option<Lazy<mir::Mir<'tcx>>>,
 }
@@ -290,6 +291,7 @@ pub struct Entry<'tcx> {
     variances,
     generics,
     predicates,
+    predicates_defined_on,
     mir
 });
 
index 5eb8c93b510aedd6ebfb5634201046109e7e2ed5..27daebbf8c12d4b9cf90720b8f9f3f13f9cca298 100644 (file)
@@ -252,10 +252,8 @@ fn program_clauses_for_trait<'a, 'tcx>(
     // ```
 
     // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
-    // FIXME: Remove the [1..] slice; this is a hack because the query
-    // predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
-    let where_clauses = &tcx.predicates_of(def_id).predicates;
-    let implied_bound_clauses = where_clauses[1..]
+    let where_clauses = &tcx.predicates_defined_on(def_id).predicates;
+    let implied_bound_clauses = where_clauses
         .into_iter()
         .map(|wc| wc.lower())
 
index 3c956d8b4306cba3296fbf42fee63ce2ce6f8eef..4e645c5433b44caea622cc757428bd36282a0cbc 100644 (file)
@@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) {
         type_of,
         generics_of,
         predicates_of,
+        predicates_defined_on,
         explicit_predicates_of,
         super_predicates_of,
         type_param_predicates,
@@ -1309,10 +1310,10 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
     })
 }
 
-fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           def_id: DefId)
-                           -> ty::GenericPredicates<'tcx> {
-    let explicit = explicit_predicates_of(tcx, def_id);
+fn predicates_defined_on<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   def_id: DefId)
+                                   -> ty::GenericPredicates<'tcx> {
+    let explicit = tcx.explicit_predicates_of(def_id);
     let predicates = if tcx.sess.features_untracked().infer_outlives_requirements {
         [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
     } else { explicit.predicates };
@@ -1323,9 +1324,35 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            def_id: DefId)
                            -> ty::GenericPredicates<'tcx> {
+    let ty::GenericPredicates { parent, mut predicates } =
+        tcx.predicates_defined_on(def_id);
+
+    if tcx.is_trait(def_id) {
+        // For traits, add `Self: Trait` predicate. This is
+        // not part of the predicates that a user writes, but it
+        // is something that one must prove in order to invoke a
+        // method or project an associated type.
+        //
+        // In the chalk setup, this predicate is not part of the
+        // "predicates" for a trait item. But it is useful in
+        // rustc because if you directly (e.g.) invoke a trait
+        // method like `Trait::method(...)`, you must naturally
+        // prove that the trait applies to the types that were
+        // used, and adding the predicate into this list ensures
+        // that this is done.
+        predicates.push(ty::TraitRef::identity(tcx, def_id).to_predicate());
+    }
+
+    ty::GenericPredicates { parent, predicates }
+}
+
+fn explicit_predicates_of<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+) -> ty::GenericPredicates<'tcx> {
     use rustc::hir::map::*;
     use rustc::hir::*;
 
@@ -1340,7 +1367,10 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let icx = ItemCtxt::new(tcx, def_id);
     let no_generics = hir::Generics::empty();
     let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
+        NodeTraitItem(item) => {
+            &item.generics
+        }
+
         NodeImplItem(item) => &item.generics,
 
         NodeItem(item) => {
@@ -1405,12 +1435,8 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // and the explicit where-clauses, but to get the full set of predicates
     // on a trait we need to add in the supertrait bounds and bounds found on
     // associated types.
-    if let Some((trait_ref, _)) = is_trait {
+    if let Some((_trait_ref, _)) = is_trait {
         predicates = tcx.super_predicates_of(def_id).predicates;
-
-        // Add in a predicate that `Self:Trait` (where `Trait` is the
-        // current trait).  This is needed for builtin bounds.
-        predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
     }
 
     // In default impls, we can assume that the self type implements
index 3a280f85e76949e0e862df6135838f7a74e1ecf4..812418a3053e99554784b49da3b316ff6b29efa9 100644 (file)
@@ -4,7 +4,7 @@ error: program clause dump
 LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+   = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
    = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
    = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
 
@@ -14,7 +14,7 @@ error: program clause dump
 LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+   = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
    = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
    = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
    = note: Implemented(Self: Foo) :- FromEnv(Self: Foo).