reserve impl<T> From<!> for T
this is necessary for never-type stabilization
This commit is contained in:
parent
6ef275e6c3
commit
5d79e8c4c9
@ -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")]
|
||||
|
@ -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>,
|
||||
|
||||
@ -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>> {
|
||||
@ -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))
|
||||
}
|
||||
@ -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
|
||||
@ -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> {
|
||||
@ -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,
|
||||
|
@ -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()
|
||||
@ -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) {
|
||||
|
@ -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 => {
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
12
src/test/ui/never-impl-is-reserved.rs
Normal file
12
src/test/ui/never-impl-is-reserved.rs
Normal file
@ -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
src/test/ui/never-impl-is-reserved.stderr
Normal file
12
src/test/ui/never-impl-is-reserved.stderr
Normal file
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user