Skip to content

Commit

Permalink
reserve impl<T> From<!> for T
Browse files Browse the repository at this point in the history
this is necessary for never-type stabilization
  • Loading branch information
arielb1 committed Sep 24, 2019
1 parent 6ef275e commit 5d79e8c
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 26 deletions.
6 changes: 6 additions & 0 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,12 @@ impl<T> From<T> for T {
fn from(t: T) -> T { t }
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
#[cfg(not(boostrap_stdarch_ignore_this))]
#[rustc_reservation_impl]
impl<T> From<!> for T {
fn from(t: !) -> T { t }
}

// TryFrom implies TryInto
#[stable(feature = "try_from", since = "1.34.0")]
Expand Down
21 changes: 17 additions & 4 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ 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>,

Expand Down Expand Up @@ -1326,8 +1328,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(result, dep_node)
}

// Treat negative impls as unimplemented
fn filter_negative_impls(
// Treat negative impls as unimplemented, and reservation impls as Ok(None)
fn filter_negative_and_reservation_impls(
&self,
candidate: SelectionCandidate<'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
Expand All @@ -1337,6 +1339,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
{
return Err(Unimplemented);
}

if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) {
return Ok(None);
}
}
Ok(Some(candidate))
}
Expand Down Expand Up @@ -1453,7 +1459,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 +1534,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 +3734,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(());
}

if self.intercrate.is_none() &&
self.tcx().has_attr(impl_def_id, sym::rustc_reservation_impl)
{
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
28 changes: 18 additions & 10 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2911,7 +2911,13 @@ impl<'tcx> TyCtxt<'tcx> {
return Some(ImplOverlapKind::Permitted);
}

let is_legit = if self.features().overlapping_marker_traits {
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;
}

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 +2926,24 @@ 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);
// `#[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);
Some(ImplOverlapKind::Permitted)
} else {
if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {
Expand Down
29 changes: 17 additions & 12 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,18 +398,23 @@ fn check_impl<'tcx>(

match *ast_trait_ref {
Some(ref ast_trait_ref) => {
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);
// `#[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);
}
}
}
None => {
Expand Down
4 changes: 4 additions & 0 deletions src/libsyntax/feature_gate/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable",
),
rustc_attr!(rustc_reservation_impl, Normal, template!(Word),
"the `#[rustc_reservation_impl]` attribute is internally used \
for reserving for `for<T> From<!> for T` impl"
),
rustc_attr!(
rustc_test_marker, Normal, template!(Word),
"the `#[rustc_test_marker]` attribute is used internally to track tests",
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ symbols! {
rustc_std_internal_symbol,
rustc_symbol_name,
rustc_synthetic,
rustc_reservation_impl,
rustc_test_marker,
rustc_then_this_would_need,
rustc_variance,
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/never-impl-is-reserved.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// check that the `for<T> T: From<!>` impl is reserved

#![feature(never_type)]

pub struct MyFoo;
pub trait MyTrait {}

impl MyTrait for MyFoo {}
// This will conflict with the first impl if we impl `for<T> T: From<!>`.
impl<T> MyTrait for T where T: From<!> {} //~ ERROR conflicting implementation

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/never-impl-is-reserved.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`:
--> $DIR/never-impl-is-reserved.rs:10:1
|
LL | impl MyTrait for MyFoo {}
| ---------------------- first implementation here
LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
LL | impl<T> MyTrait for T where T: From<!> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.

0 comments on commit 5d79e8c

Please sign in to comment.