about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2019-07-14 00:09:46 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2019-09-24 21:11:50 +0300
commit1ec7ae14fa5b4b29f56d7085f632dd6301ad4815 (patch)
treecf6cf1ebb1b4001ebeef9f88e07a698be9bd2fcb
parent9a94ecde04306986dac1b7ca88b4b327b67ea499 (diff)
downloadrust-1ec7ae14fa5b4b29f56d7085f632dd6301ad4815.tar.gz
rust-1ec7ae14fa5b4b29f56d7085f632dd6301ad4815.zip
resolve the rustc_reservation_impl attribute in 1 place
-rw-r--r--src/librustc/query/mod.rs2
-rw-r--r--src/librustc/traits/auto_trait.rs2
-rw-r--r--src/librustc/traits/select.rs24
-rw-r--r--src/librustc/ty/mod.rs46
-rw-r--r--src/librustc_metadata/decoder.rs2
-rw-r--r--src/librustc_metadata/encoder.rs3
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_traits/lowering/mod.rs5
-rw-r--r--src/librustc_typeck/check/wfcheck.rs53
-rw-r--r--src/librustc_typeck/collect.rs26
-rw-r--r--src/librustdoc/clean/mod.rs13
11 files changed, 112 insertions, 66 deletions
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index c7260945295..b937d1a3040 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -286,7 +286,7 @@ rustc_queries! {
         query associated_item(_: DefId) -> ty::AssocItem {}
 
         query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
-        query impl_polarity(_: DefId) -> hir::ImplPolarity {}
+        query impl_polarity(_: DefId) -> ty::ImplPolarity {}
 
         query issue33140_self_ty(_: DefId) -> Option<ty::Ty<'tcx>> {}
     }
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index d89cf8eb3e8..c481943e25e 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -321,7 +321,7 @@ impl AutoTraitFinder<'tcx> {
                     match vtable {
                         Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => {
                             // Blame tidy for the weird bracket placement
-                            if infcx.tcx.impl_polarity(*impl_def_id) == hir::ImplPolarity::Negative
+                            if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative
                             {
                                 debug!("evaluate_nested_obligations: Found explicit negative impl\
                                         {:?}, bailing out", impl_def_id);
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index debd946d716..61bb53dd334 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -50,8 +50,6 @@ use std::iter;
 use std::rc::Rc;
 use crate::util::nodemap::{FxHashMap, FxHashSet};
 
-use syntax::symbol::sym;
-
 pub struct SelectionContext<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
 
@@ -1334,15 +1332,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidate: SelectionCandidate<'tcx>,
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
         if let ImplCandidate(def_id) = candidate {
-            if !self.allow_negative_impls
-                && self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative
-            {
-                return Err(Unimplemented);
-            }
-
-            if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) {
-                return Ok(None);
-            }
+            match self.tcx().impl_polarity(def_id) {
+                ty::ImplPolarity::Negative if !self.allow_negative_impls => {
+                    return Err(Unimplemented);
+                }
+                ty::ImplPolarity::Reservation => {
+                    return Ok(None);
+                }
+                _ => {}
+            };
         }
         Ok(Some(candidate))
     }
@@ -3734,8 +3732,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Err(());
         }
 
-        if self.intercrate.is_none() &&
-            self.tcx().has_attr(impl_def_id, sym::rustc_reservation_impl)
+        if self.intercrate.is_none()
+            && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
             debug!("match_impl: reservation impls only apply in intercrate mode");
             return Err(());
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c5cbe0d0dab..b546a245346 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -167,6 +167,16 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+pub enum ImplPolarity {
+    /// `impl Trait for Type`
+    Positive,
+    /// `impl !Trait for Type`
+    Negative,
+    /// `#[rustc_reservation_impl] impl Trait for Type`
+    Reservation,
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
 pub struct AssocItem {
     pub def_id: DefId,
@@ -2911,11 +2921,24 @@ impl<'tcx> TyCtxt<'tcx> {
             return Some(ImplOverlapKind::Permitted);
         }
 
-        if self.impl_polarity(def_id1) != self.impl_polarity(def_id2) {
-            debug!("impls_are_allowed_to_overlap({:?}, {:?}) - different polarities, None",
-                   def_id1, def_id2);
-            return None;
-        }
+        match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) {
+            (ImplPolarity::Reservation, _) |
+            (_, ImplPolarity::Reservation) => {
+                // `#[rustc_reservation_impl]` impls don't overlap with anything
+                debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)",
+                       def_id1, def_id2);
+                return Some(ImplOverlapKind::Permitted);
+            }
+            (ImplPolarity::Positive, ImplPolarity::Negative) |
+            (ImplPolarity::Negative, ImplPolarity::Positive) => {
+                // FIXME: when can this happen?
+                debug!("impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)",
+                       def_id1, def_id2);
+                return None;
+            }
+            (ImplPolarity::Positive, ImplPolarity::Positive) |
+            (ImplPolarity::Negative, ImplPolarity::Negative) => {}
+        };
 
         let is_marker_overlap = if self.features().overlapping_marker_traits {
             let trait1_is_empty = self.impl_trait_ref(def_id1)
@@ -2935,15 +2958,10 @@ impl<'tcx> TyCtxt<'tcx> {
             is_marker_impl(def_id1) && is_marker_impl(def_id2)
         };
 
-        // `#[rustc_reservation_impl]` impls don't overlap with anything
-        let is_reserve_overlap = {
-            self.has_attr(def_id1, sym::rustc_reservation_impl) ||
-            self.has_attr(def_id2, sym::rustc_reservation_impl)
-        };
 
-        if is_marker_overlap || is_reserve_overlap {
-            debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) ({:?}/{:?})",
-                  def_id1, def_id2, is_marker_overlap, is_reserve_overlap);
+        if is_marker_overlap {
+            debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)",
+                   def_id1, def_id2);
             Some(ImplOverlapKind::Permitted)
         } else {
             if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {
@@ -3325,7 +3343,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
     debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
 
     let is_marker_like =
-        tcx.impl_polarity(def_id) == hir::ImplPolarity::Positive &&
+        tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive &&
         tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
 
     // Check whether these impls would be ok for a marker trait.
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 34c84b1d79d..9785b69eaf0 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -722,7 +722,7 @@ impl<'a, 'tcx> CrateMetadata {
         self.get_impl_data(id).parent_impl
     }
 
-    pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity {
+    pub fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
         self.get_impl_data(id).polarity
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index f430f01542e..9bf0eefd9fe 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1172,8 +1172,9 @@ impl EncodeContext<'tcx> {
                     ctor_sig: None,
                 }), repr_options)
             }
-            hir::ItemKind::Impl(_, polarity, defaultness, ..) => {
+            hir::ItemKind::Impl(_, _, defaultness, ..) => {
                 let trait_ref = tcx.impl_trait_ref(def_id);
+                let polarity = tcx.impl_polarity(def_id);
                 let parent = if let Some(trait_ref) = trait_ref {
                     let trait_def = tcx.trait_def(trait_ref.def_id);
                     trait_def.ancestors(tcx, def_id).nth(1).and_then(|node| {
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 1a5f0e17ba7..90967c79333 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -327,7 +327,7 @@ pub struct TraitAliasData<'tcx> {
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ImplData<'tcx> {
-    pub polarity: hir::ImplPolarity,
+    pub polarity: ty::ImplPolarity,
     pub defaultness: hir::Defaultness,
     pub parent_impl: Option<DefId>,
 
diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs
index 1558ce1bced..51d49f0d59a 100644
--- a/src/librustc_traits/lowering/mod.rs
+++ b/src/librustc_traits/lowering/mod.rs
@@ -4,7 +4,7 @@ use rustc::hir::def::DefKind;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::definitions::DefPathData;
-use rustc::hir::{self, ImplPolarity};
+use rustc::hir;
 use rustc::traits::{
     Clause,
     Clauses,
@@ -295,7 +295,8 @@ fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
 }
 
 fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> {
-    if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
+    // FIXME: implement reservation impls.
+    if let ty::ImplPolarity::Negative = tcx.impl_polarity(def_id) {
         return List::empty();
     }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 87c34d62bde..e0e878ffdcc 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -94,20 +94,27 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) {
         //
         // won't be allowed unless there's an *explicit* implementation of `Send`
         // for `T`
-        hir::ItemKind::Impl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
+        hir::ItemKind::Impl(_, _, defaultness, _, ref trait_ref, ref self_ty, _) => {
             let is_auto = tcx.impl_trait_ref(tcx.hir().local_def_id(item.hir_id))
-                                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+            let polarity = tcx.impl_polarity(def_id);
             if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
                 tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
             }
-            if polarity == hir::ImplPolarity::Positive {
-                check_impl(tcx, item, self_ty, trait_ref);
-            } else {
-                // FIXME(#27579): what amount of WF checking do we need for neg impls?
-                if trait_ref.is_some() && !is_auto {
-                    span_err!(tcx.sess, item.span, E0192,
-                              "negative impls are only allowed for \
-                               auto traits (e.g., `Send` and `Sync`)")
+            match polarity {
+                ty::ImplPolarity::Positive => {
+                    check_impl(tcx, item, self_ty, trait_ref);
+                }
+                ty::ImplPolarity::Negative => {
+                    // FIXME(#27579): what amount of WF checking do we need for neg impls?
+                    if trait_ref.is_some() && !is_auto {
+                        span_err!(tcx.sess, item.span, E0192,
+                                  "negative impls are only allowed for \
+                                   auto traits (e.g., `Send` and `Sync`)")
+                    }
+                }
+                ty::ImplPolarity::Reservation => {
+                    // FIXME: what amount of WF checking do we need for reservation impls?
                 }
             }
         }
@@ -401,20 +408,18 @@ fn check_impl<'tcx>(
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                if !fcx.tcx.has_attr(item_def_id, sym::rustc_reservation_impl) {
-                    let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
-                    let trait_ref =
-                        fcx.normalize_associated_types_in(
-                            ast_trait_ref.path.span, &trait_ref);
-                    let obligations =
-                        ty::wf::trait_obligations(fcx,
-                                                  fcx.param_env,
-                                                  fcx.body_id,
-                                                  &trait_ref,
-                                                  ast_trait_ref.path.span);
-                    for obligation in obligations {
-                        fcx.register_predicate(obligation);
-                    }
+                let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
+                let trait_ref =
+                    fcx.normalize_associated_types_in(
+                        ast_trait_ref.path.span, &trait_ref);
+                let obligations =
+                    ty::wf::trait_obligations(fcx,
+                                              fcx.param_env,
+                                              fcx.body_id,
+                                              &trait_ref,
+                                              ast_trait_ref.path.span);
+                for obligation in obligations {
+                    fcx.register_predicate(obligation);
                 }
             }
             None => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d2e9203779c..4503bb264a5 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1866,10 +1866,30 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     }
 }
 
-fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> hir::ImplPolarity {
+fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
     let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    match tcx.hir().expect_item(hir_id).node {
-        hir::ItemKind::Impl(_, polarity, ..) => polarity,
+    let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
+    let item = tcx.hir().expect_item(hir_id);
+    match &item.node {
+        hir::ItemKind::Impl(_, hir::ImplPolarity::Negative, ..) => {
+            if is_rustc_reservation {
+                tcx.sess.span_err(item.span, "reservation impls can't be negative");
+            }
+            ty::ImplPolarity::Negative
+        }
+        hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, None, _, _) => {
+            if is_rustc_reservation {
+                tcx.sess.span_err(item.span, "reservation impls can't be inherent");
+            }
+            ty::ImplPolarity::Positive
+        }
+        hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, Some(_tr), _, _) => {
+            if is_rustc_reservation {
+                ty::ImplPolarity::Reservation
+            } else {
+                ty::ImplPolarity::Positive
+            }
+        }
         ref item => bug!("impl_polarity: {:?} not an impl", item),
     }
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ae70fdc530b..15ada0952c8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3864,11 +3864,13 @@ pub enum ImplPolarity {
     Negative,
 }
 
-impl Clean<ImplPolarity> for hir::ImplPolarity {
+impl Clean<ImplPolarity> for ty::ImplPolarity {
     fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
         match self {
-            &hir::ImplPolarity::Positive => ImplPolarity::Positive,
-            &hir::ImplPolarity::Negative => ImplPolarity::Negative,
+            &ty::ImplPolarity::Positive |
+            // FIXME: do we want to do something else here?
+            &ty::ImplPolarity::Reservation => ImplPolarity::Positive,
+            &ty::ImplPolarity::Negative => ImplPolarity::Negative,
         }
     }
 }
@@ -3900,6 +3902,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
         let mut ret = Vec::new();
         let trait_ = self.trait_.clean(cx);
         let items = self.items.iter().map(|ii| ii.clean(cx)).collect::<Vec<_>>();
+        let def_id = cx.tcx.hir().local_def_id(self.id);
 
         // If this impl block is an implementation of the Deref trait, then we
         // need to try inlining the target's inherent impl blocks as well.
@@ -3918,7 +3921,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: cx.tcx.hir().local_def_id(self.id),
+            def_id,
             visibility: self.vis.clean(cx),
             stability: cx.stability(self.id).clean(cx),
             deprecation: cx.deprecation(self.id).clean(cx),
@@ -3929,7 +3932,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
                 trait_,
                 for_: self.for_.clean(cx),
                 items,
-                polarity: Some(self.polarity.clean(cx)),
+                polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
                 synthetic: false,
                 blanket_impl: None,
             })