Skip to content

Commit a0236b7

Browse files
committed
Auto merge of #62661 - arielb1:never-reserve, r=<try>
reserve `impl<T> From<!> for T` this is necessary for never-type stabilization. cc #57012 #35121 I think we wanted a crater run for this @nikomatsakis? r? @nikomatsakis
2 parents 11a5148 + 4e437d6 commit a0236b7

24 files changed

+287
-177
lines changed

src/libcore/convert.rs

+14-112
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040
4141
#![stable(feature = "rust1", since = "1.0.0")]
4242

43-
use crate::fmt;
44-
4543
/// An identity function.
4644
///
4745
/// Two things are important to note about this function:
@@ -426,9 +424,7 @@ pub trait TryInto<T>: Sized {
426424
/// - `TryFrom<T> for U` implies [`TryInto`]`<U> for T`
427425
/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
428426
/// is implemented and cannot fail -- the associated `Error` type for
429-
/// calling `T::try_from()` on a value of type `T` is [`Infallible`].
430-
/// When the [`!`] type is stabilized [`Infallible`] and [`!`] will be
431-
/// equivalent.
427+
/// calling `T::try_from()` on a value of type `T` is [`!`].
432428
///
433429
/// `TryFrom<T>` can be implemented as follows:
434430
///
@@ -477,7 +473,6 @@ pub trait TryInto<T>: Sized {
477473
/// [`TryInto`]: trait.TryInto.html
478474
/// [`i32::MAX`]: ../../std/i32/constant.MAX.html
479475
/// [`!`]: ../../std/primitive.never.html
480-
/// [`Infallible`]: enum.Infallible.html
481476
#[stable(feature = "try_from", since = "1.34.0")]
482477
pub trait TryFrom<T>: Sized {
483478
/// The type returned in the event of a conversion error.
@@ -551,6 +546,17 @@ impl<T> From<T> for T {
551546
fn from(t: T) -> T { t }
552547
}
553548

549+
#[stable(feature = "convert_infallible", since = "1.34.0")]
550+
#[cfg(not(bootstrap))]
551+
#[rustc_reservation_impl="a future version of Rust might implement `From<!>` for \
552+
all types. \
553+
However, it is OK to implement `From<!>` for types you own - \
554+
when the blanket impl will be added, coherence will be changed \
555+
to make these impls not be an error."
556+
]
557+
impl<T> From<!> for T {
558+
fn from(t: !) -> T { t }
559+
}
554560

555561
// TryFrom implies TryInto
556562
#[stable(feature = "try_from", since = "1.34.0")]
@@ -604,110 +610,6 @@ impl AsRef<str> for str {
604610
// THE NO-ERROR ERROR TYPE
605611
////////////////////////////////////////////////////////////////////////////////
606612

607-
/// The error type for errors that can never happen.
608-
///
609-
/// Since this enum has no variant, a value of this type can never actually exist.
610-
/// This can be useful for generic APIs that use [`Result`] and parameterize the error type,
611-
/// to indicate that the result is always [`Ok`].
612-
///
613-
/// For example, the [`TryFrom`] trait (conversion that returns a [`Result`])
614-
/// has a blanket implementation for all types where a reverse [`Into`] implementation exists.
615-
///
616-
/// ```ignore (illustrates std code, duplicating the impl in a doctest would be an error)
617-
/// impl<T, U> TryFrom<U> for T where U: Into<T> {
618-
/// type Error = Infallible;
619-
///
620-
/// fn try_from(value: U) -> Result<Self, Infallible> {
621-
/// Ok(U::into(value)) // Never returns `Err`
622-
/// }
623-
/// }
624-
/// ```
625-
///
626-
/// # Future compatibility
627-
///
628-
/// This enum has the same role as [the `!` “never” type][never],
629-
/// which is unstable in this version of Rust.
630-
/// When `!` is stabilized, we plan to make `Infallible` a type alias to it:
631-
///
632-
/// ```ignore (illustrates future std change)
633-
/// pub type Infallible = !;
634-
/// ```
635-
///
636-
/// … and eventually deprecate `Infallible`.
637-
///
638-
///
639-
/// However there is one case where `!` syntax can be used
640-
/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
641-
/// Specifically, it is possible implementations for two different function pointer types:
642-
///
643-
/// ```
644-
/// trait MyTrait {}
645-
/// impl MyTrait for fn() -> ! {}
646-
/// impl MyTrait for fn() -> std::convert::Infallible {}
647-
/// ```
648-
///
649-
/// With `Infallible` being an enum, this code is valid.
650-
/// However when `Infallible` becomes an alias for the never type,
651-
/// the two `impl`s will start to overlap
652-
/// and therefore will be disallowed by the language’s trait coherence rules.
653-
///
654-
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
655-
/// [`Result`]: ../result/enum.Result.html
656-
/// [`TryFrom`]: trait.TryFrom.html
657-
/// [`Into`]: trait.Into.html
658-
/// [never]: ../../std/primitive.never.html
659-
#[stable(feature = "convert_infallible", since = "1.34.0")]
660-
#[derive(Copy)]
661-
pub enum Infallible {}
662-
663-
#[stable(feature = "convert_infallible", since = "1.34.0")]
664-
impl Clone for Infallible {
665-
fn clone(&self) -> Infallible {
666-
match *self {}
667-
}
668-
}
669-
670-
#[stable(feature = "convert_infallible", since = "1.34.0")]
671-
impl fmt::Debug for Infallible {
672-
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
673-
match *self {}
674-
}
675-
}
676-
613+
/// Blah Blah Blah
677614
#[stable(feature = "convert_infallible", since = "1.34.0")]
678-
impl fmt::Display for Infallible {
679-
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
680-
match *self {}
681-
}
682-
}
683-
684-
#[stable(feature = "convert_infallible", since = "1.34.0")]
685-
impl PartialEq for Infallible {
686-
fn eq(&self, _: &Infallible) -> bool {
687-
match *self {}
688-
}
689-
}
690-
691-
#[stable(feature = "convert_infallible", since = "1.34.0")]
692-
impl Eq for Infallible {}
693-
694-
#[stable(feature = "convert_infallible", since = "1.34.0")]
695-
impl PartialOrd for Infallible {
696-
fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> {
697-
match *self {}
698-
}
699-
}
700-
701-
#[stable(feature = "convert_infallible", since = "1.34.0")]
702-
impl Ord for Infallible {
703-
fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
704-
match *self {}
705-
}
706-
}
707-
708-
#[stable(feature = "convert_infallible", since = "1.34.0")]
709-
impl From<!> for Infallible {
710-
fn from(x: !) -> Self {
711-
x
712-
}
713-
}
615+
pub type Infallible = !;

src/libcore/num/mod.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
#![stable(feature = "rust1", since = "1.0.0")]
66

7-
use crate::convert::{TryFrom, Infallible};
7+
use crate::convert::{TryFrom};
88
use crate::fmt;
99
use crate::intrinsics;
1010
use crate::mem;
@@ -4674,13 +4674,6 @@ impl fmt::Display for TryFromIntError {
46744674
}
46754675
}
46764676

4677-
#[stable(feature = "try_from", since = "1.34.0")]
4678-
impl From<Infallible> for TryFromIntError {
4679-
fn from(x: Infallible) -> TryFromIntError {
4680-
match x {}
4681-
}
4682-
}
4683-
46844677
#[unstable(feature = "never_type", issue = "35121")]
46854678
impl From<!> for TryFromIntError {
46864679
fn from(never: !) -> TryFromIntError {

src/librustc/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ rustc_queries! {
273273
query associated_item(_: DefId) -> ty::AssocItem {}
274274

275275
query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
276-
query impl_polarity(_: DefId) -> hir::ImplPolarity {}
276+
query impl_polarity(_: DefId) -> ty::ImplPolarity {}
277277

278278
query issue33140_self_ty(_: DefId) -> Option<ty::Ty<'tcx>> {}
279279
}

src/librustc/traits/auto_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ impl AutoTraitFinder<'tcx> {
321321
match vtable {
322322
Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => {
323323
// Blame tidy for the weird bracket placement
324-
if infcx.tcx.impl_polarity(*impl_def_id) == hir::ImplPolarity::Negative
324+
if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative
325325
{
326326
debug!("evaluate_nested_obligations: Found explicit negative impl\
327327
{:?}, bailing out", impl_def_id);

src/librustc/traits/select.rs

+48-10
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use crate::hir;
4343
use rustc_data_structures::bit_set::GrowableBitSet;
4444
use rustc_data_structures::sync::Lock;
4545
use rustc_target::spec::abi::Abi;
46+
use syntax::attr;
47+
use syntax::symbol::sym;
4648
use std::cell::{Cell, RefCell};
4749
use std::cmp;
4850
use std::fmt::{self, Display};
@@ -99,6 +101,9 @@ pub enum IntercrateAmbiguityCause {
99101
trait_desc: String,
100102
self_desc: Option<String>,
101103
},
104+
ReservationImpl {
105+
message: String
106+
},
102107
}
103108

104109
impl IntercrateAmbiguityCause {
@@ -139,6 +144,11 @@ impl IntercrateAmbiguityCause {
139144
trait_desc, self_desc
140145
)
141146
}
147+
&IntercrateAmbiguityCause::ReservationImpl {
148+
ref message
149+
} => {
150+
message.clone()
151+
}
142152
}
143153
}
144154
}
@@ -1325,17 +1335,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13251335
(result, dep_node)
13261336
}
13271337

1328-
// Treat negative impls as unimplemented
1329-
fn filter_negative_impls(
1330-
&self,
1338+
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
1339+
fn filter_negative_and_reservation_impls(
1340+
&mut self,
13311341
candidate: SelectionCandidate<'tcx>,
13321342
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
13331343
if let ImplCandidate(def_id) = candidate {
1334-
if !self.allow_negative_impls
1335-
&& self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative
1336-
{
1337-
return Err(Unimplemented);
1338-
}
1344+
let tcx = self.tcx();
1345+
match tcx.impl_polarity(def_id) {
1346+
ty::ImplPolarity::Negative if !self.allow_negative_impls => {
1347+
return Err(Unimplemented);
1348+
}
1349+
ty::ImplPolarity::Reservation => {
1350+
if let Some(intercrate_ambiguity_clauses)
1351+
= &mut self.intercrate_ambiguity_causes
1352+
{
1353+
let attrs = tcx.get_attrs(def_id);
1354+
let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
1355+
let value = attr.and_then(|a| a.value_str());
1356+
if let Some(value) = value {
1357+
debug!("filter_negative_and_reservation_impls: \
1358+
reservation impl ambiguity on {:?}", def_id);
1359+
intercrate_ambiguity_clauses.push(
1360+
IntercrateAmbiguityCause::ReservationImpl {
1361+
message: value.to_string()
1362+
}
1363+
);
1364+
}
1365+
}
1366+
return Ok(None);
1367+
}
1368+
_ => {}
1369+
};
13391370
}
13401371
Ok(Some(candidate))
13411372
}
@@ -1452,7 +1483,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14521483
// Instead, we select the right impl now but report `Bar does
14531484
// not implement Clone`.
14541485
if candidates.len() == 1 {
1455-
return self.filter_negative_impls(candidates.pop().unwrap());
1486+
return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
14561487
}
14571488

14581489
// Winnow, but record the exact outcome of evaluation, which
@@ -1527,7 +1558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15271558
}
15281559

15291560
// Just one candidate left.
1530-
self.filter_negative_impls(candidates.pop().unwrap().candidate)
1561+
self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
15311562
}
15321563

15331564
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
@@ -3727,6 +3758,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
37273758
return Err(());
37283759
}
37293760

3761+
if self.intercrate.is_none()
3762+
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
3763+
{
3764+
debug!("match_impl: reservation impls only apply in intercrate mode");
3765+
return Err(());
3766+
}
3767+
37303768
debug!("match_impl: success impl_substs={:?}", impl_substs);
37313769
Ok(Normalized {
37323770
value: impl_substs,

src/librustc/traits/specialize/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ pub(super) fn specialization_graph_provider(
310310
};
311311

312312
if let Some(overlap) = overlap {
313+
debug!("found conflicting implementations {:?}", overlap);
314+
313315
let msg = format!("conflicting implementations of trait `{}`{}:{}",
314316
overlap.trait_desc,
315317
overlap.self_desc.clone().map_or(

0 commit comments

Comments
 (0)