]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/traits/select.rs
Rollup merge of #65073 - ecstatic-morse:issue-65071, r=petrochenkov
[rust.git] / src / librustc / traits / select.rs
index 87191a4b4558d763c86ab77e6036933257c64a64..1fae2a2fe8dbffc783595f05aacbf58e5f2541a7 100644 (file)
 use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use crate::hir;
-use rustc_data_structures::bit_set::GrowableBitSet;
+use rustc_index::bit_set::GrowableBitSet;
 use rustc_data_structures::sync::Lock;
 use rustc_target::spec::abi::Abi;
+use syntax::attr;
+use syntax::symbol::sym;
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::fmt::{self, Display};
@@ -99,6 +101,9 @@ pub enum IntercrateAmbiguityCause {
         trait_desc: String,
         self_desc: Option<String>,
     },
+    ReservationImpl {
+        message: String
+    },
 }
 
 impl IntercrateAmbiguityCause {
@@ -139,6 +144,11 @@ pub fn intercrate_ambiguity_hint(&self) -> String {
                     trait_desc, self_desc
                 )
             }
+            &IntercrateAmbiguityCause::ReservationImpl {
+                ref message
+            } => {
+                message.clone()
+            }
         }
     }
 }
@@ -1326,17 +1336,38 @@ fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
         (result, dep_node)
     }
 
-    // Treat negative impls as unimplemented
-    fn filter_negative_impls(
-        &self,
+    // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+    fn filter_negative_and_reservation_impls(
+        &mut self,
         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);
-            }
+            let tcx = self.tcx();
+            match tcx.impl_polarity(def_id) {
+                ty::ImplPolarity::Negative if !self.allow_negative_impls => {
+                    return Err(Unimplemented);
+                }
+                ty::ImplPolarity::Reservation => {
+                    if let Some(intercrate_ambiguity_clauses)
+                        = &mut self.intercrate_ambiguity_causes
+                    {
+                        let attrs = tcx.get_attrs(def_id);
+                        let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
+                        let value = attr.and_then(|a| a.value_str());
+                        if let Some(value) = value {
+                            debug!("filter_negative_and_reservation_impls: \
+                                    reservation impl ambiguity on {:?}", def_id);
+                            intercrate_ambiguity_clauses.push(
+                                IntercrateAmbiguityCause::ReservationImpl {
+                                    message: value.to_string()
+                                }
+                            );
+                        }
+                    }
+                    return Ok(None);
+                }
+                _ => {}
+            };
         }
         Ok(Some(candidate))
     }
@@ -1453,7 +1484,7 @@ fn candidate_from_obligation_no_cache<'o>(
         // Instead, we select the right impl now but report `Bar does
         // not implement Clone`.
         if candidates.len() == 1 {
-            return self.filter_negative_impls(candidates.pop().unwrap());
+            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
         }
 
         // Winnow, but record the exact outcome of evaluation, which
@@ -1528,7 +1559,7 @@ fn candidate_from_obligation_no_cache<'o>(
         }
 
         // Just one candidate left.
-        self.filter_negative_impls(candidates.pop().unwrap().candidate)
+        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
     }
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
@@ -2020,7 +2051,10 @@ fn assemble_closure_candidates(
                     "assemble_unboxed_candidates: kind={:?} obligation={:?}",
                     kind, obligation
                 );
-                match self.infcx.closure_kind(closure_def_id, closure_substs) {
+                match self.infcx.closure_kind(
+                    closure_def_id,
+                    closure_substs
+                ) {
                     Some(closure_kind) => {
                         debug!(
                             "assemble_unboxed_candidates: closure_kind = {:?}",
@@ -2460,7 +2494,7 @@ fn candidate_should_be_dropped_in_favor_of(
                 if other.evaluation.must_apply_modulo_regions() {
                     match victim.candidate {
                         ImplCandidate(victim_def) => {
-                            let tcx = self.tcx().global_tcx();
+                            let tcx = self.tcx();
                             return tcx.specializes((other_def, victim_def))
                                 || tcx.impls_are_allowed_to_overlap(
                                     other_def, victim_def).is_some();
@@ -2638,7 +2672,7 @@ fn copy_clone_conditions(
             ty::Closure(def_id, substs) => {
                 // (*) binder moved here
                 Where(ty::Binder::bind(
-                    substs.upvar_tys(def_id, self.tcx()).collect(),
+                    substs.as_closure().upvar_tys(def_id, self.tcx()).collect(),
                 ))
             }
 
@@ -2722,7 +2756,9 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
                 tys.iter().map(|k| k.expect_ty()).collect()
             }
 
-            ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, self.tcx()).collect(),
+            ty::Closure(def_id, ref substs) => substs.as_closure()
+                .upvar_tys(def_id, self.tcx())
+                .collect(),
 
             ty::Generator(def_id, ref substs, _) => {
                 let witness = substs.witness(def_id, self.tcx());
@@ -3339,17 +3375,22 @@ fn confirm_closure_candidate(
         )?);
 
         // FIXME: chalk
+
         if !self.tcx().sess.opts.debugging_opts.chalk {
             obligations.push(Obligation::new(
                 obligation.cause.clone(),
                 obligation.param_env,
-                ty::Predicate::ClosureKind(closure_def_id, substs, kind),
+                ty::Predicate::ClosureKind(
+                    closure_def_id,
+                    substs,
+                    kind
+                ),
             ));
         }
 
         Ok(VtableClosureData {
             closure_def_id,
-            substs: substs.clone(),
+            substs: substs,
             nested: obligations,
         })
     }
@@ -3728,6 +3769,13 @@ fn match_impl(
             return Err(());
         }
 
+        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(());
+        }
+
         debug!("match_impl: success impl_substs={:?}", impl_substs);
         Ok(Normalized {
             value: impl_substs,
@@ -3831,7 +3879,7 @@ fn closure_trait_ref_unnormalized(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         closure_def_id: DefId,
-        substs: ty::ClosureSubsts<'tcx>,
+        substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
         debug!(
             "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})",