Skip to content

Commit be8a496

Browse files
Rollup merge of rust-lang#56145 - weiznich:re_rebalance_coherence, r=nikomatsakis
Implement the Re-rebalance coherence RFC This is the first time I touch anything in the compiler so just tell me if I got something wrong. Big thanks to @sgrif for the pointers where to look for those things. cc rust-lang#55437
2 parents 677eef5 + 32118a9 commit be8a496

File tree

174 files changed

+1612
-263
lines changed

Some content is hidden

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

174 files changed

+1612
-263
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# `re_rebalance_coherence`
2+
3+
The tracking issue for this feature is: [#55437]
4+
5+
[#55437]: https://github.com/rust-lang/rust/issues/55437
6+
7+
------------------------
8+
9+
The `re_rebalance_coherence` feature tweaks the rules regarding which trait
10+
impls are allowed in crates.
11+
The following rule is used:
12+
13+
Given `impl<P1..=Pn> Trait<T1..=Tn> for T0`, an impl is valid only if at
14+
least one of the following is true:
15+
- `Trait` is a local trait
16+
- All of
17+
- At least one of the types `T0..=Tn` must be a local type. Let `Ti` be the
18+
first such type.
19+
- No uncovered type parameters `P1..=Pn` may appear in `T0..Ti` (excluding
20+
`Ti`)
21+
22+
23+
See the [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2451-re-rebalancing-coherence.md) for details.

src/librustc/traits/coherence.rs

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -344,43 +344,68 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt<'_, '_, '_>,
344344
trait_ref);
345345
}
346346

347-
// First, create an ordered iterator over all the type parameters to the trait, with the self
348-
// type appearing first.
349-
// Find the first input type that either references a type parameter OR
350-
// some local type.
351-
for input_ty in trait_ref.input_types() {
352-
if ty_is_local(tcx, input_ty, in_crate) {
353-
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
354-
355-
// First local input type. Check that there are no
356-
// uncovered type parameters.
357-
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
358-
for uncovered_ty in uncovered_tys {
359-
if let Some(param) = uncovered_ty.walk()
360-
.find(|t| is_possibly_remote_type(t, in_crate))
361-
{
362-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
363-
return Err(OrphanCheckErr::UncoveredTy(param));
364-
}
347+
if tcx.features().re_rebalance_coherence {
348+
// Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
349+
// if at least one of the following is true:
350+
//
351+
// - Trait is a local trait
352+
// (already checked in orphan_check prior to calling this function)
353+
// - All of
354+
// - At least one of the types T0..=Tn must be a local type.
355+
// Let Ti be the first such type.
356+
// - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
357+
//
358+
for input_ty in trait_ref.input_types() {
359+
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
360+
if ty_is_local(tcx, input_ty, in_crate) {
361+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
362+
return Ok(());
363+
} else if let ty::Param(_) = input_ty.sty {
364+
debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
365+
return Err(OrphanCheckErr::UncoveredTy(input_ty))
365366
}
366-
367-
// OK, found local type, all prior types upheld invariant.
368-
return Ok(());
369367
}
368+
// If we exit above loop, never found a local type.
369+
debug!("orphan_check_trait_ref: no local type");
370+
Err(OrphanCheckErr::NoLocalInputType)
371+
} else {
372+
// First, create an ordered iterator over all the type
373+
// parameters to the trait, with the self type appearing
374+
// first. Find the first input type that either references a
375+
// type parameter OR some local type.
376+
for input_ty in trait_ref.input_types() {
377+
if ty_is_local(tcx, input_ty, in_crate) {
378+
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
379+
380+
// First local input type. Check that there are no
381+
// uncovered type parameters.
382+
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
383+
for uncovered_ty in uncovered_tys {
384+
if let Some(param) = uncovered_ty.walk()
385+
.find(|t| is_possibly_remote_type(t, in_crate))
386+
{
387+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
388+
return Err(OrphanCheckErr::UncoveredTy(param));
389+
}
390+
}
370391

371-
// Otherwise, enforce invariant that there are no type
372-
// parameters reachable.
373-
if let Some(param) = input_ty.walk()
374-
.find(|t| is_possibly_remote_type(t, in_crate))
375-
{
376-
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
377-
return Err(OrphanCheckErr::UncoveredTy(param));
392+
// OK, found local type, all prior types upheld invariant.
393+
return Ok(());
394+
}
395+
396+
// Otherwise, enforce invariant that there are no type
397+
// parameters reachable.
398+
if let Some(param) = input_ty.walk()
399+
.find(|t| is_possibly_remote_type(t, in_crate))
400+
{
401+
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
402+
return Err(OrphanCheckErr::UncoveredTy(param));
403+
}
378404
}
405+
// If we exit above loop, never found a local type.
406+
debug!("orphan_check_trait_ref: no local type");
407+
Err(OrphanCheckErr::NoLocalInputType)
379408
}
380-
381-
// If we exit above loop, never found a local type.
382-
debug!("orphan_check_trait_ref: no local type");
383-
return Err(OrphanCheckErr::NoLocalInputType);
384409
}
385410

386411
fn uncovered_tys<'tcx>(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>, in_crate: InCrate)

src/libsyntax/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ declare_features! (
479479

480480
// Allows paths to enum variants on type aliases.
481481
(active, type_alias_enum_variants, "1.31.0", Some(49683), None),
482+
483+
// Re-Rebalance coherence
484+
(active, re_rebalance_coherence, "1.32.0", Some(55437), None),
482485
);
483486

484487
declare_features! (
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
pub trait Backend{}
3+
pub trait SupportsDefaultKeyword {}
4+
5+
impl SupportsDefaultKeyword for Postgres {}
6+
7+
pub struct Postgres;
8+
9+
impl Backend for Postgres {}
10+
11+
pub struct AstPass<DB>(::std::marker::PhantomData<DB>);
12+
13+
pub trait QueryFragment<DB: Backend> {}
14+
15+
16+
#[derive(Debug, Clone, Copy)]
17+
pub struct BatchInsert<'a, T: 'a, Tab> {
18+
_marker: ::std::marker::PhantomData<(&'a T, Tab)>,
19+
}
20+
21+
impl<'a, T:'a, Tab, DB> QueryFragment<DB> for BatchInsert<'a, T, Tab>
22+
where DB: SupportsDefaultKeyword + Backend,
23+
{}

src/test/run-pass/coherence/coherence-bigint-int.rs

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

47
// pretty-expanded FIXME #23616
58

src/test/run-pass/coherence/coherence-bigint-vecint.rs

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

47
// pretty-expanded FIXME #23616
58

src/test/run-pass/coherence/coherence-blanket.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// run-pass
22
#![allow(unused_imports)]
33
// aux-build:coherence_lib.rs
4+
// revisions: old re
5+
6+
#![cfg_attr(re, feature(re_rebalance_coherence))]
47

58
// pretty-expanded FIXME #23616
69

src/test/run-pass/coherence/coherence-covered-type-parameter.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// run-pass
22
#![allow(dead_code)]
33
// aux-build:coherence_lib.rs
4+
// revisions: old re
5+
6+
#![cfg_attr(re, feature(re_rebalance_coherence))]
47

58
// pretty-expanded FIXME #23616
69

src/test/run-pass/coherence/coherence-impl-in-fn.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(dead_code)]
36
#![allow(non_camel_case_types)]
47

src/test/run-pass/coherence/coherence-iterator-vec-any-elem.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(dead_code)]
36
// aux-build:coherence_lib.rs
47

src/test/run-pass/coherence/coherence-iterator-vec.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(dead_code)]
36
// aux-build:coherence_lib.rs
47

src/test/run-pass/coherence/coherence-multidispatch-tuple.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(unused_imports)]
36
// pretty-expanded FIXME #23616
47

src/test/run-pass/coherence/coherence-negative-impls-safe.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(dead_code)]
36
// pretty-expanded FIXME #23616
47

src/test/run-pass/coherence/coherence-rfc447-constrained.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
// check that trait matching can handle impls whose types are only
36
// constrained by a projection.
47

src/test/run-pass/coherence/coherence-subtyping.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
// Test that two distinct impls which match subtypes of one another
36
// yield coherence errors (or not) depending on the variance.
47

src/test/run-pass/coherence/coherence-where-clause.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
5+
26
use std::fmt::Debug;
37
use std::default::Default;
48

src/test/run-pass/coherence/coherence_copy_like.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// run-pass
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25
#![allow(dead_code)]
36
// Test that we are able to introduce a negative constraint that
47
// `MyType: !MyTrait` along with other "fundamental" wrappers.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![allow(dead_code)]
2+
#![feature(re_rebalance_coherence)]
3+
4+
// run-pass
5+
// aux-build:re_rebalance_coherence_lib.rs
6+
7+
extern crate re_rebalance_coherence_lib as lib;
8+
use lib::*;
9+
10+
struct Oracle;
11+
impl Backend for Oracle {}
12+
impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
13+
14+
fn main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
pub trait Backend{}
3+
pub trait SupportsDefaultKeyword {}
4+
5+
impl SupportsDefaultKeyword for Postgres {}
6+
7+
pub struct Postgres;
8+
9+
impl Backend for Postgres {}
10+
11+
pub struct AstPass<DB>(::std::marker::PhantomData<DB>);
12+
13+
pub trait QueryFragment<DB: Backend> {}
14+
15+
16+
#[derive(Debug, Clone, Copy)]
17+
pub struct BatchInsert<'a, T: 'a, Tab> {
18+
_marker: ::std::marker::PhantomData<(&'a T, Tab)>,
19+
}
20+
21+
impl<'a, T:'a, Tab, DB> QueryFragment<DB> for BatchInsert<'a, T, Tab>
22+
where DB: SupportsDefaultKeyword + Backend,
23+
{}

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

Lines changed: 1 addition & 1 deletion
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:6:1
2+
--> $DIR/coherence-all-remote.rs:9:1
33
|
44
LL | impl<T> Remote1<T> for isize { }
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
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:1
3+
|
4+
LL | impl<T> Remote1<T> for isize { }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
6+
|
7+
= note: only traits defined in the current crate can be implemented for a type parameter
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
// aux-build:coherence_lib.rs
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25

36
extern crate coherence_lib as lib;
47
use lib::Remote1;
58

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

913
fn main() { }

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

Lines changed: 1 addition & 1 deletion
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:8:1
2+
--> $DIR/coherence-bigint-param.rs:11:1
33
|
44
LL | impl<T> Remote1<BigInt> for T { }
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
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:1
3+
|
4+
LL | impl<T> Remote1<BigInt> for T { }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
6+
|
7+
= note: only traits defined in the current crate can be implemented for a type parameter
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// aux-build:coherence_lib.rs
2+
// revisions: old re
3+
4+
#![cfg_attr(re, feature(re_rebalance_coherence))]
25

36
extern crate coherence_lib as lib;
47
use lib::Remote1;
58

69
pub struct BigInt;
710

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

1115
fn main() { }

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0119]: conflicting implementations of trait `MyTrait`:
2-
--> $DIR/coherence-blanket-conflicts-with-blanket-implemented.rs:24:1
2+
--> $DIR/coherence-blanket-conflicts-with-blanket-implemented.rs:28:1
33
|
44
LL | impl<T:Even> MyTrait for T {
55
| -------------------------- first implementation here
66
...
7-
LL | impl<T:Odd> MyTrait for T { //~ ERROR E0119
7+
LL | impl<T:Odd> MyTrait for T {
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
99

1010
error: aborting due to previous error

0 commit comments

Comments
 (0)