Skip to content

Commit 98c173a

Browse files
committed
Auto merge of #65879 - ohadravid:stabilize-re-rebalance-coherence, r=nikomatsakis
Stabilize the `re_rebalance_coherence` feature This PR stabilizes [RFC 2451](https://rust-lang.github.io/rfcs/2451-re-rebalancing-coherence.html), re-rebalance coherence. Changes include removing the attribute from tests which tested both the old and new behavior, moving the feature to `accepted` and removing the old logic. I'll also open a [PR](rust-lang/reference#703) against the reference, updating it with the content of the RFC. Closes #63599 r? @nikomatsakis
2 parents 475c713 + 3e0759d commit 98c173a

File tree

229 files changed

+269
-1640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

229 files changed

+269
-1640
lines changed

src/doc/unstable-book/src/language-features/re-rebalance-coherence.md

-23
This file was deleted.

src/libcore/convert.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,12 @@ pub trait AsMut<T: ?Sized> {
205205
/// A value-to-value conversion that consumes the input value. The
206206
/// opposite of [`From`].
207207
///
208-
/// One should only implement [`Into`] if a conversion to a type outside the current crate is
209-
/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because
210-
/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to
211-
/// the blanket implementation in the standard library. [`From`] cannot do these type of
212-
/// conversions because of Rust's orphaning rules.
208+
/// One should avoid implementing [`Into`] and implement [`From`] instead.
209+
/// Implementing [`From`] automatically provides one with an implementation of [`Into`]
210+
/// thanks to the blanket implementation in the standard library.
211+
///
212+
/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function
213+
/// to ensure that types that only implement [`Into`] can be used as well.
213214
///
214215
/// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`].
215216
///
@@ -218,23 +219,22 @@ pub trait AsMut<T: ?Sized> {
218219
/// - [`From`]`<T> for U` implies `Into<U> for T`
219220
/// - [`Into`] is reflexive, which means that `Into<T> for T` is implemented
220221
///
221-
/// # Implementing [`Into`] for conversions to external types
222+
/// # Implementing [`Into`] for conversions to external types in old versions of Rust
222223
///
223-
/// If the destination type is not part of the current crate
224-
/// then you can't implement [`From`] directly.
224+
/// Prior to Rust 1.40, if the destination type was not part of the current crate
225+
/// then you couldn't implement [`From`] directly.
225226
/// For example, take this code:
226227
///
227-
/// ```compile_fail
228+
/// ```
228229
/// struct Wrapper<T>(Vec<T>);
229230
/// impl<T> From<Wrapper<T>> for Vec<T> {
230231
/// fn from(w: Wrapper<T>) -> Vec<T> {
231232
/// w.0
232233
/// }
233234
/// }
234235
/// ```
235-
/// This will fail to compile because we cannot implement a trait for a type
236-
/// if both the trait and the type are not defined by the current crate.
237-
/// This is due to Rust's orphaning rules. To bypass this, you can implement [`Into`] directly:
236+
/// This will fail to compile in older versions of the language because Rust's orphaning rules
237+
/// used to be a little bit more strict. To bypass this, you could implement [`Into`] directly:
238238
///
239239
/// ```
240240
/// struct Wrapper<T>(Vec<T>);
@@ -249,9 +249,6 @@ pub trait AsMut<T: ?Sized> {
249249
/// (as [`From`] does with [`Into`]). Therefore, you should always try to implement [`From`]
250250
/// and then fall back to [`Into`] if [`From`] can't be implemented.
251251
///
252-
/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function
253-
/// to ensure that types that only implement [`Into`] can be used as well.
254-
///
255252
/// # Examples
256253
///
257254
/// [`String`] implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>`:

src/librustc/traits/coherence.rs

+40-106
Original file line numberDiff line numberDiff line change
@@ -367,118 +367,52 @@ fn orphan_check_trait_ref<'tcx>(
367367
trait_ref);
368368
}
369369

370-
if tcx.features().re_rebalance_coherence {
371-
// Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
372-
// if at least one of the following is true:
373-
//
374-
// - Trait is a local trait
375-
// (already checked in orphan_check prior to calling this function)
376-
// - All of
377-
// - At least one of the types T0..=Tn must be a local type.
378-
// Let Ti be the first such type.
379-
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
380-
//
381-
fn uncover_fundamental_ty<'tcx>(
382-
tcx: TyCtxt<'tcx>,
383-
ty: Ty<'tcx>,
384-
in_crate: InCrate,
385-
) -> Vec<Ty<'tcx>> {
386-
if fundamental_ty(ty) && ty_is_non_local(tcx, ty, in_crate).is_some() {
387-
ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
388-
} else {
389-
vec![ty]
390-
}
370+
// Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
371+
// if at least one of the following is true:
372+
//
373+
// - Trait is a local trait
374+
// (already checked in orphan_check prior to calling this function)
375+
// - All of
376+
// - At least one of the types T0..=Tn must be a local type.
377+
// Let Ti be the first such type.
378+
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
379+
//
380+
fn uncover_fundamental_ty<'tcx>(
381+
tcx: TyCtxt<'tcx>,
382+
ty: Ty<'tcx>,
383+
in_crate: InCrate,
384+
) -> Vec<Ty<'tcx>> {
385+
if fundamental_ty(ty) && ty_is_non_local(tcx, ty, in_crate).is_some() {
386+
ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
387+
} else {
388+
vec![ty]
391389
}
390+
}
392391

393-
let mut non_local_spans = vec![];
394-
for (i, input_ty) in trait_ref
395-
.input_types()
396-
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
397-
.enumerate()
398-
{
399-
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
400-
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
401-
if non_local_tys.is_none() {
402-
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
403-
return Ok(());
404-
} else if let ty::Param(_) = input_ty.kind {
405-
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
406-
return Err(OrphanCheckErr::UncoveredTy(input_ty))
407-
}
408-
if let Some(non_local_tys) = non_local_tys {
409-
for input_ty in non_local_tys {
410-
non_local_spans.push((input_ty, i == 0));
411-
}
412-
}
392+
let mut non_local_spans = vec![];
393+
for (i, input_ty) in trait_ref
394+
.input_types()
395+
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
396+
.enumerate()
397+
{
398+
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
399+
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
400+
if non_local_tys.is_none() {
401+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
402+
return Ok(());
403+
} else if let ty::Param(_) = input_ty.kind {
404+
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
405+
return Err(OrphanCheckErr::UncoveredTy(input_ty))
413406
}
414-
// If we exit above loop, never found a local type.
415-
debug!("orphan_check_trait_ref: no local type");
416-
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
417-
} else {
418-
let mut non_local_spans = vec![];
419-
// First, create an ordered iterator over all the type
420-
// parameters to the trait, with the self type appearing
421-
// first. Find the first input type that either references a
422-
// type parameter OR some local type.
423-
for (i, input_ty) in trait_ref.input_types().enumerate() {
424-
let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
425-
if non_local_tys.is_none() {
426-
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
427-
428-
// First local input type. Check that there are no
429-
// uncovered type parameters.
430-
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
431-
for uncovered_ty in uncovered_tys {
432-
if let Some(param) = uncovered_ty.walk()
433-
.find(|t| is_possibly_remote_type(t, in_crate))
434-
{
435-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
436-
return Err(OrphanCheckErr::UncoveredTy(param));
437-
}
438-
}
439-
440-
// OK, found local type, all prior types upheld invariant.
441-
return Ok(());
442-
}
443-
444-
// Otherwise, enforce invariant that there are no type
445-
// parameters reachable.
446-
if let Some(param) = input_ty.walk()
447-
.find(|t| is_possibly_remote_type(t, in_crate))
448-
{
449-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
450-
return Err(OrphanCheckErr::UncoveredTy(param));
451-
}
452-
453-
if let Some(non_local_tys) = non_local_tys {
454-
for input_ty in non_local_tys {
455-
non_local_spans.push((input_ty, i == 0));
456-
}
407+
if let Some(non_local_tys) = non_local_tys {
408+
for input_ty in non_local_tys {
409+
non_local_spans.push((input_ty, i == 0));
457410
}
458411
}
459-
// If we exit above loop, never found a local type.
460-
debug!("orphan_check_trait_ref: no local type");
461-
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
462-
}
463-
}
464-
465-
fn uncovered_tys<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
466-
if ty_is_non_local_constructor(tcx, ty, in_crate).is_none() {
467-
vec![]
468-
} else if fundamental_ty(ty) {
469-
ty.walk_shallow()
470-
.flat_map(|t| uncovered_tys(tcx, t, in_crate))
471-
.collect()
472-
} else {
473-
vec![ty]
474-
}
475-
}
476-
477-
fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
478-
match ty.kind {
479-
ty::Projection(..) | ty::Param(..) => true,
480-
_ => false,
481412
}
413+
// If we exit above loop, never found a local type.
414+
debug!("orphan_check_trait_ref: no local type");
415+
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
482416
}
483417

484418
fn ty_is_non_local<'t>(tcx: TyCtxt<'t>, ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> {

src/libsyntax/feature_gate/accepted.rs

+3
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ declare_features! (
253253
(accepted, const_constructor, "1.40.0", Some(61456), None),
254254
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
255255
(accepted, cfg_doctest, "1.40.0", Some(62210), None),
256+
/// Allows relaxing the coherence rules such that
257+
/// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
258+
(accepted, re_rebalance_coherence, "1.41.0", Some(55437), None),
256259

257260
// -------------------------------------------------------------------------
258261
// feature-group-end: accepted features

src/libsyntax/feature_gate/active.rs

-4
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,6 @@ declare_features! (
466466
/// Allows exhaustive integer pattern matching on `usize` and `isize`.
467467
(active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
468468

469-
/// Allows relaxing the coherence rules such that
470-
/// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
471-
(active, re_rebalance_coherence, "1.32.0", Some(55437), None),
472-
473469
/// Allows using `#[ffi_returns_twice]` on foreign functions.
474470
(active, ffi_returns_twice, "1.34.0", Some(58314), None),
475471

src/test/ui/coherence/coherence-all-remote.re.stderr

-11
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
// aux-build:coherence_lib.rs
2-
// revisions: old re
3-
4-
#![cfg_attr(re, feature(re_rebalance_coherence))]
52

63
extern crate coherence_lib as lib;
74
use lib::Remote1;
85

96
impl<T> Remote1<T> for isize { }
10-
//[old]~^ ERROR E0210
11-
//[re]~^^ ERROR E0210
7+
//~^ ERROR E0210
128

139
fn main() { }

src/test/ui/coherence/coherence-all-remote.old.stderr src/test/ui/coherence/coherence-all-remote.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-all-remote.rs:9:6
2+
--> $DIR/coherence-all-remote.rs:6:6
33
|
44
LL | impl<T> Remote1<T> for isize { }
55
| ^ type parameter `T` must be used as the type parameter for some local type

src/test/ui/coherence/coherence-bigint-int.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// run-pass
22
// aux-build:coherence_lib.rs
3-
// revisions: old re
4-
5-
#![cfg_attr(re, feature(re_rebalance_coherence))]
63

74
// pretty-expanded FIXME #23616
85

src/test/ui/coherence/coherence-bigint-param.old.stderr

-11
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
// aux-build:coherence_lib.rs
2-
// revisions: old re
3-
4-
#![cfg_attr(re, feature(re_rebalance_coherence))]
52

63
extern crate coherence_lib as lib;
74
use lib::Remote1;
85

96
pub struct BigInt;
107

118
impl<T> Remote1<BigInt> for T { }
12-
//[old]~^ ERROR type parameter `T` must be used as the type parameter for some local type
13-
//[re]~^^ ERROR E0210
9+
//~^ ERROR E0210
1410

1511
fn main() { }

src/test/ui/coherence/coherence-bigint-param.re.stderr src/test/ui/coherence/coherence-bigint-param.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
2-
--> $DIR/coherence-bigint-param.rs:11:6
2+
--> $DIR/coherence-bigint-param.rs:8:6
33
|
44
LL | impl<T> Remote1<BigInt> for T { }
55
| ^ type parameter `T` must be used as the type parameter for some local type

src/test/ui/coherence/coherence-bigint-vecint.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// run-pass
22
// aux-build:coherence_lib.rs
3-
// revisions: old re
4-
5-
#![cfg_attr(re, feature(re_rebalance_coherence))]
63

74
// pretty-expanded FIXME #23616
85

src/test/ui/coherence/coherence-blanket-conflicts-with-blanket-implemented.re.stderr

-12
This file was deleted.

src/test/ui/coherence/coherence-blanket-conflicts-with-blanket-implemented.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
// revisions: old re
2-
3-
#![cfg_attr(re, feature(re_rebalance_coherence))]
4-
51
use std::fmt::Debug;
62
use std::default::Default;
73

@@ -26,8 +22,7 @@ impl<T:Even> MyTrait for T {
2622
}
2723

2824
impl<T:Odd> MyTrait for T {
29-
//[old]~^ ERROR E0119
30-
//[re]~^^ ERROR E0119
25+
//~^ ERROR E0119
3126

3227
fn get(&self) -> usize { 0 }
3328
}

src/test/ui/coherence/coherence-blanket-conflicts-with-blanket-implemented.old.stderr src/test/ui/coherence/coherence-blanket-conflicts-with-blanket-implemented.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0119]: conflicting implementations of trait `MyTrait`:
2-
--> $DIR/coherence-blanket-conflicts-with-blanket-implemented.rs:28:1
2+
--> $DIR/coherence-blanket-conflicts-with-blanket-implemented.rs:24:1
33
|
44
LL | impl<T:Even> MyTrait for T {
55
| -------------------------- first implementation here

0 commit comments

Comments
 (0)