1
Fork 0

When checking whether an impl applies, constrain hidden types of opaque types.

We already handle this case this way on the coherence side, and it matches the new solver's behaviour. While there is some breakage around type-alias-impl-trait (see new "type annotations needed" in tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs), no stable code breaks, and no new stable code is accepted.
This commit is contained in:
Oli Scherer 2024-04-17 09:29:13 +00:00
parent dc8d1bc373
commit 29a630eb72
23 changed files with 126 additions and 115 deletions

View file

@ -2539,7 +2539,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&cause, obligation.param_env) .at(&cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref) .eq(DefineOpaqueTypes::Yes, placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| { .map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
})?; })?;

View file

@ -22,7 +22,7 @@ fn sum_to(n: u32) -> impl Foo {
0 0
} else { } else {
n + sum_to(n - 1) n + sum_to(n - 1)
//~^ ERROR cannot add `impl Foo` to `u32` //~^ ERROR cannot satisfy `<u32 as Add<impl Foo>>::Output == i32`
} }
} }
@ -32,12 +32,15 @@ trait Leak: Sized {
} }
impl<T> Leak for T { impl<T> Leak for T {
default type T = (); default type T = ();
default fn leak(self) -> Self::T { panic!() } default fn leak(self) -> Self::T {
panic!()
}
} }
impl Leak for i32 { impl Leak for i32 {
type T = i32; type T = i32;
fn leak(self) -> i32 { self } fn leak(self) -> i32 {
self
}
} }
fn main() { fn main() {}
}

View file

@ -22,20 +22,13 @@ help: change the type of the numeric literal from `u32` to `i32`
LL | 0_i32 LL | 0_i32
| ~~~ | ~~~
error[E0277]: cannot add `impl Foo` to `u32` error[E0284]: type annotations needed: cannot satisfy `<u32 as Add<impl Foo>>::Output == i32`
--> $DIR/equality.rs:24:11 --> $DIR/equality.rs:24:11
| |
LL | n + sum_to(n - 1) LL | n + sum_to(n - 1)
| ^ no implementation for `u32 + impl Foo` | ^ cannot satisfy `<u32 as Add<impl Foo>>::Output == i32`
|
= help: the trait `Add<impl Foo>` is not implemented for `u32`
= help: the following other types implement trait `Add<Rhs>`:
<&'a u32 as Add<u32>>
<&u32 as Add<&u32>>
<u32 as Add<&u32>>
<u32 as Add>
error: aborting due to 2 previous errors; 1 warning emitted error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0308. Some errors have detailed explanations: E0284, E0308.
For more information about an error, try `rustc --explain E0277`. For more information about an error, try `rustc --explain E0284`.

View file

@ -46,19 +46,23 @@ error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfie
--> $DIR/nested_impl_trait.rs:6:46 --> $DIR/nested_impl_trait.rs:6:46
| |
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>` | ^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `impl Into<u32>`
| |
= help: the trait `Into<U>` is implemented for `T` help: consider further restricting this bound
= note: required for `impl Into<u32>` to implement `Into<impl Debug>` |
LL | fn bad_in_ret_position(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
| +++++++++++++++++
error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
--> $DIR/nested_impl_trait.rs:19:34 --> $DIR/nested_impl_trait.rs:19:34
| |
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Into<u32>`, which is required by `impl Into<u32>: Into<impl Debug>` | ^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `impl Into<u32>`
| |
= help: the trait `Into<U>` is implemented for `T` help: consider further restricting this bound
= note: required for `impl Into<u32>` to implement `Into<impl Debug>` |
LL | fn bad(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
| +++++++++++++++++
error: aborting due to 7 previous errors error: aborting due to 7 previous errors

View file

@ -11,7 +11,7 @@ impl PartialEq<(Bar, i32)> for Bar {
} }
fn foo() -> Foo { fn foo() -> Foo {
//~^ ERROR can't compare `Bar` with `(Foo, i32)` //~^ ERROR overflow evaluating the requirement `Bar: PartialEq<(Foo, i32)>`
Bar Bar
} }

View file

@ -1,15 +1,9 @@
error[E0277]: can't compare `Bar` with `(Foo, i32)` error[E0275]: overflow evaluating the requirement `Bar: PartialEq<(Foo, i32)>`
--> $DIR/recursive-type-alias-impl-trait-declaration.rs:13:13 --> $DIR/recursive-type-alias-impl-trait-declaration.rs:13:13
| |
LL | fn foo() -> Foo { LL | fn foo() -> Foo {
| ^^^ no implementation for `Bar == (Foo, i32)` | ^^^
LL |
LL | Bar
| --- return type was inferred to be `Bar` here
|
= help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar`
= help: the trait `PartialEq<(Bar, i32)>` is implemented for `Bar`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0275`.

View file

@ -1,11 +0,0 @@
error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied
--> $DIR/constrain_in_projection.rs:24:14
|
LL | let x = <Foo as Trait<Bar>>::Assoc::default();
| ^^^ the trait `Trait<Bar>` is not implemented for `Foo`
|
= help: the trait `Trait<()>` is implemented for `Foo`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -4,7 +4,7 @@
//@ revisions: current next //@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions) //@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver //@[next] compile-flags: -Znext-solver
//@[next]check-pass //@check-pass
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
@ -22,7 +22,6 @@ impl Trait<()> for Foo {
fn bop(_: Bar) { fn bop(_: Bar) {
let x = <Foo as Trait<Bar>>::Assoc::default(); let x = <Foo as Trait<Bar>>::Assoc::default();
//[current]~^ `Foo: Trait<Bar>` is not satisfied
} }
fn main() {} fn main() {}

View file

@ -1,13 +1,19 @@
error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied error[E0283]: type annotations needed: cannot satisfy `Foo: Trait<Bar>`
--> $DIR/constrain_in_projection2.rs:27:14 --> $DIR/constrain_in_projection2.rs:27:14
| |
LL | let x = <Foo as Trait<Bar>>::Assoc::default(); LL | let x = <Foo as Trait<Bar>>::Assoc::default();
| ^^^ the trait `Trait<Bar>` is not implemented for `Foo` | ^^^ help: use the fully qualified path to an implementation: `<Type as Trait>::Assoc`
| |
= help: the following other types implement trait `Trait<T>`: note: multiple `impl`s satisfying `Foo: Trait<Bar>` found
<Foo as Trait<()>> --> $DIR/constrain_in_projection2.rs:18:1
<Foo as Trait<u32>> |
LL | impl Trait<()> for Foo {
| ^^^^^^^^^^^^^^^^^^^^^^
...
LL | impl Trait<u32> for Foo {
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0283`.

View file

@ -25,8 +25,7 @@ impl Trait<u32> for Foo {
fn bop(_: Bar) { fn bop(_: Bar) {
let x = <Foo as Trait<Bar>>::Assoc::default(); let x = <Foo as Trait<Bar>>::Assoc::default();
//[next]~^ ERROR: cannot satisfy `Foo: Trait<Bar>` //~^ ERROR: cannot satisfy `Foo: Trait<Bar>`
//[current]~^^ ERROR: `Foo: Trait<Bar>` is not satisfied
} }
fn main() {} fn main() {}

View file

@ -1,5 +1,5 @@
error[E0119]: conflicting implementations of trait `Trait<Bar, _>` error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
--> $DIR/issue-84660-unsoundness.rs:23:1 --> $DIR/issue-84660-unsoundness.rs:28:1
| |
LL | impl<In, Out> Trait<Bar, In> for Out { LL | impl<In, Out> Trait<Bar, In> for Out {
| ------------------------------------ first implementation here | ------------------------------------ first implementation here

View file

@ -0,0 +1,23 @@
error[E0284]: type annotations needed: cannot satisfy `<Out as Trait<Bar, In>>::Out == ()`
--> $DIR/issue-84660-unsoundness.rs:22:37
|
LL | fn convert(_i: In) -> Self::Out {
| _____________________________________^
LL | |
LL | | unreachable!();
LL | | }
| |_____^ cannot satisfy `<Out as Trait<Bar, In>>::Out == ()`
error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
--> $DIR/issue-84660-unsoundness.rs:28:1
|
LL | impl<In, Out> Trait<Bar, In> for Out {
| ------------------------------------ first implementation here
...
LL | impl<In, Out> Trait<(), In> for Out {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0119, E0284.
For more information about an error, try `rustc --explain E0119`.

View file

@ -1,6 +1,10 @@
// Another example from issue #84660, this time weaponized as a safe transmute: an opaque type in an // Another example from issue #84660, this time weaponized as a safe transmute: an opaque type in an
// impl header being accepted was used to create unsoundness. // impl header being accepted was used to create unsoundness.
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
trait Foo {} trait Foo {}
@ -16,11 +20,13 @@ trait Trait<T, In> {
impl<In, Out> Trait<Bar, In> for Out { impl<In, Out> Trait<Bar, In> for Out {
type Out = Out; type Out = Out;
fn convert(_i: In) -> Self::Out { fn convert(_i: In) -> Self::Out {
//[next]~^ ERROR: type annotations needed
unreachable!(); unreachable!();
} }
} }
impl<In, Out> Trait<(), In> for Out { //~ ERROR conflicting implementations of trait `Trait<Bar, _>` impl<In, Out> Trait<(), In> for Out {
//~^ ERROR conflicting implementations of trait `Trait<Bar, _>`
type Out = In; type Out = In;
fn convert(i: In) -> Self::Out { fn convert(i: In) -> Self::Out {
i i

View file

@ -1,18 +1,21 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(dead_code)] #![allow(dead_code)]
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@check-pass
use std::fmt::Debug; use std::fmt::Debug;
type FooX = impl Debug; type FooX = impl Debug;
trait Foo<A> { } trait Foo<A> {}
impl Foo<()> for () { } impl Foo<()> for () {}
fn foo() -> impl Foo<FooX> { fn foo() -> impl Foo<FooX> {
//~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
// FIXME(type-alias-impl-trait): We could probably make this work.
() ()
} }
fn main() { } fn main() {}

View file

@ -0,0 +1,17 @@
error[E0283]: type annotations needed: cannot satisfy `(): Foo<FooX>`
--> $DIR/nested-tait-inference2.rs:17:13
|
LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^
|
note: multiple `impl`s satisfying `(): Foo<FooX>` found
--> $DIR/nested-tait-inference2.rs:14:1
|
LL | impl Foo<()> for () {}
| ^^^^^^^^^^^^^^^^^^^
LL | impl Foo<u32> for () {}
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`.

View file

@ -0,0 +1,9 @@
error[E0284]: type annotations needed: cannot satisfy `impl Foo<FooX> == ()`
--> $DIR/nested-tait-inference2.rs:19:5
|
LL | ()
| ^^ cannot satisfy `impl Foo<FooX> == ()`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`.

View file

@ -1,6 +1,10 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(dead_code)] #![allow(dead_code)]
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
use std::fmt::Debug; use std::fmt::Debug;
type FooX = impl Debug; type FooX = impl Debug;
@ -11,8 +15,9 @@ impl Foo<()> for () {}
impl Foo<u32> for () {} impl Foo<u32> for () {}
fn foo() -> impl Foo<FooX> { fn foo() -> impl Foo<FooX> {
//~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied //[current]~^ ERROR: cannot satisfy `(): Foo<FooX>`
() ()
//[next]~^ ERROR: cannot satisfy `impl Foo<FooX> == ()`
} }
fn main() {} fn main() {}

View file

@ -1,16 +0,0 @@
error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
--> $DIR/nested-tait-inference2.rs:13:13
|
LL | fn foo() -> impl Foo<FooX> {
| ^^^^^^^^^^^^^^ the trait `Foo<FooX>` is not implemented for `()`
LL |
LL | ()
| -- return type was inferred to be `()` here
|
= help: the following other types implement trait `Foo<A>`:
<() as Foo<()>>
<() as Foo<u32>>
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -22,21 +22,17 @@ note: previous use here
LL | fn define_1() -> Opaque { dyn_hoops::<_>(0) } LL | fn define_1() -> Opaque { dyn_hoops::<_>(0) }
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types error: concrete type differs from previous defining opaque type use
--> $DIR/normalize-hidden-types.rs:43:25 --> $DIR/normalize-hidden-types.rs:43:25
| |
LL | type Opaque = impl Sized;
| ---------- the expected opaque type
...
LL | let _: Opaque = dyn_hoops::<u8>(0); LL | let _: Opaque = dyn_hoops::<u8>(0);
| ------ ^^^^^^^^^^^^^^^^^^ expected opaque type, found `*const dyn FnOnce(())` | ^^^^^^^^^^^^^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(<u8 as Trait>::Gat<'a>)`
| |
| expected due to this
| |
= note: expected opaque type `typeck::Opaque` note: previous use here
found raw pointer `*const (dyn FnOnce(()) + 'static)` --> $DIR/normalize-hidden-types.rs:44:9
= help: consider constraining the associated type `<u8 as Trait>::Gat<'_>` to `()` or calling a method that returns `<u8 as Trait>::Gat<'_>` |
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html LL | None
| ^^^^
error: concrete type differs from previous defining opaque type use error: concrete type differs from previous defining opaque type use
--> $DIR/normalize-hidden-types.rs:52:25 --> $DIR/normalize-hidden-types.rs:52:25
@ -52,4 +48,3 @@ LL | None
error: aborting due to 4 previous errors error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,14 +0,0 @@
error[E0277]: can't compare `i32` with `Foo`
--> $DIR/self-referential-2.rs:10:13
|
LL | fn bar() -> Bar {
| ^^^ no implementation for `i32 == Foo`
LL | 42_i32
| ------ return type was inferred to be `i32` here
|
= help: the trait `PartialEq<Foo>` is not implemented for `i32`
= help: the trait `PartialEq` is implemented for `i32`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,14 +1,14 @@
//@ revisions: current next //@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions) //@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver //@[next] compile-flags: -Znext-solver
//@[next] check-pass //@ check-pass
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
type Foo = impl std::fmt::Debug; type Foo = impl std::fmt::Debug;
type Bar = impl PartialEq<Foo>; type Bar = impl PartialEq<Foo>;
fn bar() -> Bar { fn bar() -> Bar {
42_i32 //[current]~^ ERROR can't compare `i32` with `Foo` 42_i32
} }
fn main() {} fn main() {}

View file

@ -5,7 +5,7 @@
type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug; type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug;
fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
//~^ ERROR can't compare `&i32` with `Bar<'a, 'b>` //~^ ERROR overflow normalizing the type alias `Bar<'a, 'b>`
i i
} }

View file

@ -1,15 +1,11 @@
error[E0277]: can't compare `&i32` with `Bar<'a, 'b>` error[E0275]: overflow normalizing the type alias `Bar<'a, 'b>`
--> $DIR/self-referential-3.rs:7:31 --> $DIR/self-referential-3.rs:7:31
| |
LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
| ^^^^^^^^^^^ no implementation for `&i32 == Bar<'a, 'b>` | ^^^^^^^^^^^
LL |
LL | i
| - return type was inferred to be `&i32` here
| |
= help: the trait `PartialEq<Bar<'a, 'b>>` is not implemented for `&i32` = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
= help: the trait `PartialEq` is implemented for `i32`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0275`.