Rollup merge of #121047 - compiler-errors:default-impls, r=lcnr
Do not assemble candidates for default impls There is no reason (as far as I can tell?) that we should assemble an impl candidate for a default impl. This candidate itself does not prove that the impl holds, and any time that it *does* hold, there will be a more specializing non-default impl that also is assembled. This is because `default impl<T> Foo for T {}` actually expands to `impl<T> Foo for T where T: Foo {}`. The only way to satisfy that where clause (without coinduction) is via *another* implementation that does hold -- precisely an impl that specializes it. This should fix the specialization related regressions for #116494. That should lead to one root crate regression that doesn't have to do with specialization, which I think we can regress. r? lcnr cc ``@rust-lang/types`` cc #31844
This commit is contained in:
commit
ab1fa19d08
9 changed files with 59 additions and 40 deletions
|
@ -337,6 +337,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
let mut consider_impls_for_simplified_type = |simp| {
|
let mut consider_impls_for_simplified_type = |simp| {
|
||||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||||
for &impl_def_id in impls_for_type {
|
for &impl_def_id in impls_for_type {
|
||||||
|
// For every `default impl`, there's always a non-default `impl`
|
||||||
|
// that will *also* apply. There's no reason to register a candidate
|
||||||
|
// for this impl, since it is *not* proof that the trait goal holds.
|
||||||
|
if tcx.defaultness(impl_def_id).is_default() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||||
Ok(candidate) => candidates.push(candidate),
|
Ok(candidate) => candidates.push(candidate),
|
||||||
Err(NoSolution) => (),
|
Err(NoSolution) => (),
|
||||||
|
@ -440,6 +447,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||||
for &impl_def_id in trait_impls.blanket_impls() {
|
for &impl_def_id in trait_impls.blanket_impls() {
|
||||||
|
// For every `default impl`, there's always a non-default `impl`
|
||||||
|
// that will *also* apply. There's no reason to register a candidate
|
||||||
|
// for this impl, since it is *not* proof that the trait goal holds.
|
||||||
|
if tcx.defaultness(impl_def_id).is_default() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||||
Ok(candidate) => candidates.push(candidate),
|
Ok(candidate) => candidates.push(candidate),
|
||||||
Err(NoSolution) => (),
|
Err(NoSolution) => (),
|
||||||
|
|
|
@ -566,6 +566,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For every `default impl`, there's always a non-default `impl`
|
||||||
|
// that will *also* apply. There's no reason to register a candidate
|
||||||
|
// for this impl, since it is *not* proof that the trait goal holds.
|
||||||
|
if self.tcx().defaultness(impl_def_id).is_default() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if self.reject_fn_ptr_impls(
|
if self.reject_fn_ptr_impls(
|
||||||
impl_def_id,
|
impl_def_id,
|
||||||
obligation,
|
obligation,
|
||||||
|
|
|
@ -20,5 +20,5 @@ default impl<T> Foo for T {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{}", MyStruct.foo_one());
|
println!("{}", MyStruct.foo_one());
|
||||||
//~^ ERROR the method
|
//~^ ERROR no method named `foo_one` found for struct `MyStruct` in the current scope
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,27 +8,15 @@ LL | #![feature(specialization)]
|
||||||
= help: consider using `min_specialization` instead, which is more stable and complete
|
= help: consider using `min_specialization` instead, which is more stable and complete
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait bounds were not satisfied
|
error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
|
||||||
--> $DIR/specialization-trait-not-implemented.rs:22:29
|
--> $DIR/specialization-trait-not-implemented.rs:22:29
|
||||||
|
|
|
|
||||||
LL | struct MyStruct;
|
LL | struct MyStruct;
|
||||||
| --------------- method `foo_one` not found for this struct because it doesn't satisfy `MyStruct: Foo`
|
| --------------- method `foo_one` not found for this struct
|
||||||
...
|
...
|
||||||
LL | println!("{}", MyStruct.foo_one());
|
LL | println!("{}", MyStruct.foo_one());
|
||||||
| ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds
|
| ^^^^^^^ method not found in `MyStruct`
|
||||||
|
|
|
|
||||||
note: trait bound `MyStruct: Foo` was not satisfied
|
|
||||||
--> $DIR/specialization-trait-not-implemented.rs:14:1
|
|
||||||
|
|
|
||||||
LL | default impl<T> Foo for T {
|
|
||||||
| ^^^^^^^^^^^^^^^^---^^^^^-
|
|
||||||
| |
|
|
||||||
| unsatisfied trait bound introduced here
|
|
||||||
note: the trait `Foo` must be implemented
|
|
||||||
--> $DIR/specialization-trait-not-implemented.rs:7:1
|
|
||||||
|
|
|
||||||
LL | trait Foo {
|
|
||||||
| ^^^^^^^^^
|
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
note: `Foo` defines an item `foo_one`, perhaps you need to implement it
|
note: `Foo` defines an item `foo_one`, perhaps you need to implement it
|
||||||
--> $DIR/specialization-trait-not-implemented.rs:7:1
|
--> $DIR/specialization-trait-not-implemented.rs:7:1
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct Z;
|
||||||
default impl S {} //~ ERROR inherent impls cannot be `default`
|
default impl S {} //~ ERROR inherent impls cannot be `default`
|
||||||
|
|
||||||
default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default
|
default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default
|
||||||
|
//~^ ERROR `S` cannot be sent between threads safely
|
||||||
default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default
|
default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default
|
||||||
//~^ ERROR negative impls cannot be default impls
|
//~^ ERROR negative impls cannot be default impls
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,19 @@ LL | default unsafe impl Send for S {}
|
||||||
| |
|
| |
|
||||||
| default because of this
|
| default because of this
|
||||||
|
|
||||||
|
error[E0277]: `S` cannot be sent between threads safely
|
||||||
|
--> $DIR/validation.rs:9:1
|
||||||
|
|
|
||||||
|
LL | default unsafe impl Send for S {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `S` cannot be sent between threads safely
|
||||||
|
|
|
||||||
|
= help: the trait `Send` is not implemented for `S`
|
||||||
|
= help: the trait `Send` is implemented for `S`
|
||||||
|
= help: see issue #48214
|
||||||
|
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: impls of auto traits cannot be default
|
error: impls of auto traits cannot be default
|
||||||
--> $DIR/validation.rs:10:15
|
--> $DIR/validation.rs:11:15
|
||||||
|
|
|
|
||||||
LL | default impl !Send for Z {}
|
LL | default impl !Send for Z {}
|
||||||
| ------- ^^^^ auto trait
|
| ------- ^^^^ auto trait
|
||||||
|
@ -35,17 +46,18 @@ LL | default impl !Send for Z {}
|
||||||
| default because of this
|
| default because of this
|
||||||
|
|
||||||
error[E0750]: negative impls cannot be default impls
|
error[E0750]: negative impls cannot be default impls
|
||||||
--> $DIR/validation.rs:10:1
|
--> $DIR/validation.rs:11:1
|
||||||
|
|
|
|
||||||
LL | default impl !Send for Z {}
|
LL | default impl !Send for Z {}
|
||||||
| ^^^^^^^ ^
|
| ^^^^^^^ ^
|
||||||
|
|
||||||
error[E0750]: negative impls cannot be default impls
|
error[E0750]: negative impls cannot be default impls
|
||||||
--> $DIR/validation.rs:14:1
|
--> $DIR/validation.rs:15:1
|
||||||
|
|
|
|
||||||
LL | default impl !Tr for S {}
|
LL | default impl !Tr for S {}
|
||||||
| ^^^^^^^ ^
|
| ^^^^^^^ ^
|
||||||
|
|
||||||
error: aborting due to 5 previous errors; 1 warning emitted
|
error: aborting due to 6 previous errors; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0750`.
|
Some errors have detailed explanations: E0277, E0750.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
error[E0275]: overflow evaluating the requirement `T: Trait<_>`
|
error[E0119]: conflicting implementations of trait `Trait<_>`
|
||||||
|
|
--> $DIR/issue-45814.rs:10:1
|
||||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
|
|
||||||
note: required for `T` to implement `Trait<_>`
|
|
||||||
--> $DIR/issue-45814.rs:9:20
|
|
||||||
|
|
|
|
||||||
LL | default impl<T, U> Trait<T> for U {}
|
LL | default impl<T, U> Trait<T> for U {}
|
||||||
| ^^^^^^^^ ^
|
| --------------------------------- first implementation here
|
||||||
= note: 128 redundant requirements hidden
|
LL |
|
||||||
= note: required for `T` to implement `Trait<_>`
|
LL | impl<T> Trait<<T as Iterator>::Item> for T {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0275`.
|
For more information about this error, try `rustc --explain E0119`.
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
error[E0275]: overflow evaluating the requirement `T: Trait<_>`
|
error[E0119]: conflicting implementations of trait `Trait<_>`
|
||||||
|
|
--> $DIR/issue-45814.rs:10:1
|
||||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
|
|
||||||
note: required for `T` to implement `Trait<_>`
|
|
||||||
--> $DIR/issue-45814.rs:9:20
|
|
||||||
|
|
|
|
||||||
LL | default impl<T, U> Trait<T> for U {}
|
LL | default impl<T, U> Trait<T> for U {}
|
||||||
| ^^^^^^^^ ^
|
| --------------------------------- first implementation here
|
||||||
= note: 128 redundant requirements hidden
|
LL |
|
||||||
= note: required for `T` to implement `Trait<_>`
|
LL | impl<T> Trait<<T as Iterator>::Item> for T {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0275`.
|
For more information about this error, try `rustc --explain E0119`.
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//~ ERROR overflow evaluating the requirement `T: Trait<_>`
|
|
||||||
// revisions: current negative
|
// revisions: current negative
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
#![cfg_attr(negative, feature(with_negative_coherence))]
|
#![cfg_attr(negative, feature(with_negative_coherence))]
|
||||||
|
@ -9,5 +8,6 @@ pub trait Trait<T> {}
|
||||||
default impl<T, U> Trait<T> for U {}
|
default impl<T, U> Trait<T> for U {}
|
||||||
|
|
||||||
impl<T> Trait<<T as Iterator>::Item> for T {}
|
impl<T> Trait<<T as Iterator>::Item> for T {}
|
||||||
|
//~^ ERROR conflicting implementations of trait `Trait<_>`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue