Skip to content

Commit

Permalink
Rollup merge of rust-lang#62661 - arielb1:never-reserve, r=nikomatsakis
Browse files Browse the repository at this point in the history
reserve `impl<T> From<!> for T`

this is necessary for never-type stabilization.

cc rust-lang#57012 rust-lang#35121

I think we wanted a crater run for this @nikomatsakis?

r? @nikomatsakis
  • Loading branch information
Centril committed Sep 26, 2019
2 parents a5bc0f0 + e70724c commit 53d1fca
Show file tree
Hide file tree
Showing 22 changed files with 339 additions and 51 deletions.
12 changes: 12 additions & 0 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,18 @@ impl<T> From<T> for T {
fn from(t: T) -> T { t }
}

/// **Stability note:** This impl does not yet exist, but we are
/// "reserving space" to add it in the future. See
/// [rust-lang/rust#64715][#64715] for details.
///
/// [#64715]: https://github.com/rust-lang/rust/issues/64715
#[stable(feature = "convert_infallible", since = "1.34.0")]
#[cfg(not(bootstrap))]
#[rustc_reservation_impl="permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
impl<T> From<!> for T {
fn from(t: !) -> T { t }
}

// TryFrom implies TryInto
#[stable(feature = "try_from", since = "1.34.0")]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,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>> {}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
58 changes: 48 additions & 10 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use crate::hir;
use rustc_data_structures::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};
Expand Down Expand Up @@ -99,6 +101,9 @@ pub enum IntercrateAmbiguityCause {
trait_desc: String,
self_desc: Option<String>,
},
ReservationImpl {
message: String
},
}

impl IntercrateAmbiguityCause {
Expand Down Expand Up @@ -139,6 +144,11 @@ impl IntercrateAmbiguityCause {
trait_desc, self_desc
)
}
&IntercrateAmbiguityCause::ReservationImpl {
ref message
} => {
message.clone()
}
}
}
}
Expand Down Expand Up @@ -1326,17 +1336,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(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))
}
Expand Down Expand Up @@ -1453,7 +1484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// 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
Expand Down Expand Up @@ -1528,7 +1559,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

// 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> {
Expand Down Expand Up @@ -3728,6 +3759,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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,
Expand Down
51 changes: 40 additions & 11 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,19 @@ 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`
///
/// This is a "stability hack", not a real Rust feature.
/// See #64631 for details.
Reservation,
}

#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct AssocItem {
pub def_id: DefId,
Expand Down Expand Up @@ -2911,7 +2924,26 @@ impl<'tcx> TyCtxt<'tcx> {
return Some(ImplOverlapKind::Permitted);
}

let is_legit = if self.features().overlapping_marker_traits {
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) => {
// `impl AutoTrait for Type` + `impl !AutoTrait for Type`
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)
.map_or(false, |trait_ref| {
self.associated_item_def_ids(trait_ref.def_id).is_empty()
Expand All @@ -2920,22 +2952,19 @@ impl<'tcx> TyCtxt<'tcx> {
.map_or(false, |trait_ref| {
self.associated_item_def_ids(trait_ref.def_id).is_empty()
});
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
&& trait1_is_empty
&& trait2_is_empty
trait1_is_empty && trait2_is_empty
} else {
let is_marker_impl = |def_id: DefId| -> bool {
let trait_ref = self.impl_trait_ref(def_id);
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
};
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
&& is_marker_impl(def_id1)
&& is_marker_impl(def_id2)
is_marker_impl(def_id1) && is_marker_impl(def_id2)
};

if is_legit {
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)",
def_id1, def_id2);

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) {
Expand Down Expand Up @@ -3317,7 +3346,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.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,8 +1175,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| {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,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>,

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_traits/lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -295,7 +295,7 @@ 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) {
if let ty::ImplPolarity::Negative = tcx.impl_polarity(def_id) {
return List::empty();
}

Expand Down
38 changes: 24 additions & 14 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
}
}
}
Expand Down Expand Up @@ -398,16 +405,19 @@ fn check_impl<'tcx>(

match *ast_trait_ref {
Some(ref ast_trait_ref) => {
// `#[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).
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);
fcx.param_env,
fcx.body_id,
&trait_ref,
ast_trait_ref.path.span);
for obligation in obligations {
fcx.register_predicate(obligation);
}
Expand Down
26 changes: 23 additions & 3 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1889,10 +1889,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),
}
}
Expand Down
Loading

0 comments on commit 53d1fca

Please sign in to comment.