Auto merge of #129073 - compiler-errors:receiver-variance, r=lcnr

Relate receiver invariantly in method probe for `Mode::Path`

Effectively reverts part of #126128
Fixes #126227

This PR changes method probing to use equality for fully path-based method lookup, and subtyping for receiver `.` method lookup.

r? lcnr
This commit is contained in:
bors 2024-09-17 12:44:08 +00:00
commit e9e13a68d7
17 changed files with 141 additions and 56 deletions

View File

@ -1388,10 +1388,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This also occurs for an enum variant on a type alias. // This also occurs for an enum variant on a type alias.
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
let self_ty = self.normalize(span, self_ty); let self_ty = self.normalize(span, self_ty);
match self.at(&self.misc(span), self.param_env).sub( match self.at(&self.misc(span), self.param_env).eq(
DefineOpaqueTypes::Yes, DefineOpaqueTypes::Yes,
self_ty,
impl_ty, impl_ty,
self_ty,
) { ) {
Ok(ok) => self.register_infer_ok_obligations(ok), Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => { Err(_) => {

View File

@ -621,6 +621,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.unsatisfied_predicates.borrow_mut().clear(); self.unsatisfied_predicates.borrow_mut().clear();
} }
/// When we're looking up a method by path (UFCS), we relate the receiver
/// types invariantly. When we are looking up a method by the `.` operator,
/// we relate them covariantly.
fn variance(&self) -> ty::Variance {
match self.mode {
Mode::MethodCall => ty::Covariant,
Mode::Path => ty::Invariant,
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// CANDIDATE ASSEMBLY // CANDIDATE ASSEMBLY
@ -1443,7 +1453,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) = (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, impl_ty, impl_args); self.xform_self_ty(probe.item, impl_ty, impl_args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty)
{
Ok(()) => {} Ok(()) => {}
Err(err) => { Err(err) => {
debug!("--> cannot relate self-types {:?}", err); debug!("--> cannot relate self-types {:?}", err);
@ -1514,7 +1525,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
{ {
return ProbeResult::NoMatch; return ProbeResult::NoMatch;
} }
_ => match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { _ => match ocx.relate(
cause,
self.param_env,
self.variance(),
self_ty,
xform_self_ty,
) {
Ok(()) => {} Ok(()) => {}
Err(err) => { Err(err) => {
debug!("--> cannot relate self-types {:?}", err); debug!("--> cannot relate self-types {:?}", err);
@ -1560,7 +1577,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) = (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty)
{
Ok(()) => {} Ok(()) => {}
Err(err) => { Err(err) => {
debug!("--> cannot relate self-types {:?}", err); debug!("--> cannot relate self-types {:?}", err);
@ -1603,7 +1621,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty); debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty);
match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) { match ocx.relate(cause, self.param_env, self.variance(), xform_ret_ty, return_ty) {
Ok(()) => {} Ok(()) => {}
Err(_) => { Err(_) => {
result = ProbeResult::BadReturnType; result = ProbeResult::BadReturnType;

View File

@ -7,4 +7,5 @@ impl Fail<i32> {
fn main() { fn main() {
Fail::<()>::C Fail::<()>::C
//~^ ERROR no associated item named `C` found for struct `Fail<()>` in the current scope
} }

View File

@ -7,6 +7,19 @@ LL | struct Fail<T>;
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error: aborting due to 1 previous error error[E0599]: no associated item named `C` found for struct `Fail<()>` in the current scope
--> $DIR/wrong-projection-self-ty-invalid-bivariant-arg.rs:9:17
|
LL | struct Fail<T>;
| -------------- associated item `C` not found for this struct
...
LL | Fail::<()>::C
| ^ associated item not found in `Fail<()>`
|
= note: the associated item was found for
- `Fail<i32>`
For more information about this error, try `rustc --explain E0392`. error: aborting due to 2 previous errors
Some errors have detailed explanations: E0392, E0599.
For more information about an error, try `rustc --explain E0392`.

View File

@ -14,4 +14,5 @@ impl Fail<i32, i32> {
fn main() { fn main() {
Fail::<i32, u32>::C Fail::<i32, u32>::C
//~^ ERROR: type mismatch //~^ ERROR: type mismatch
//~| ERROR no associated item named `C` found for struct `Fail<i32, u32>` in the current scope
} }

View File

@ -1,3 +1,15 @@
error[E0599]: no associated item named `C` found for struct `Fail<i32, u32>` in the current scope
--> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:23
|
LL | struct Fail<T: Proj<Assoc = U>, U>(T);
| ---------------------------------- associated item `C` not found for this struct
...
LL | Fail::<i32, u32>::C
| ^ associated item not found in `Fail<i32, u32>`
|
= note: the associated item was found for
- `Fail<i32, i32>`
error[E0271]: type mismatch resolving `<i32 as Proj>::Assoc == u32` error[E0271]: type mismatch resolving `<i32 as Proj>::Assoc == u32`
--> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5 --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5
| |
@ -15,6 +27,7 @@ note: required by a bound in `Fail`
LL | struct Fail<T: Proj<Assoc = U>, U>(T); LL | struct Fail<T: Proj<Assoc = U>, U>(T);
| ^^^^^^^^^ required by this bound in `Fail` | ^^^^^^^^^ required by this bound in `Fail`
error: aborting due to 1 previous error error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`. Some errors have detailed explanations: E0271, E0599.
For more information about an error, try `rustc --explain E0271`.

View File

@ -1,11 +0,0 @@
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:18:5
|
LL | Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,5 +1,5 @@
//@ revisions: nofallback fallback //@ revisions: nofallback fallback
//@check-fail //@[fallback] check-pass
#![feature(never_type)] #![feature(never_type)]
#![cfg_attr(fallback, feature(never_type_fallback))] #![cfg_attr(fallback, feature(never_type_fallback))]
@ -13,10 +13,10 @@ fn raw_ptr_box<T>(t: T) -> *mut T {
} }
fn foo(x: !) -> Box<dyn Error> { fn foo(x: !) -> Box<dyn Error> {
// Subtyping during method resolution will generate new inference vars and // Method resolution will generate new inference vars and relate them.
// subtype them. Thus fallback will not fall back to `!`, but `()` instead. // Thus fallback will not fall back to `!`, but `()` instead.
Box::<_ /* ! */>::new(x) Box::<_ /* ! */>::new(x)
//~^ ERROR trait bound `(): std::error::Error` is not satisfied //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
} }
fn foo_raw_ptr(x: !) -> *mut dyn Error { fn foo_raw_ptr(x: !) -> *mut dyn Error {

View File

@ -8,7 +8,7 @@ note: required by a const generic parameter in `Mask::<T, N>::splat`
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
| |
LL | let y: Mask<T, N> = Mask::<_, _>::splat(false); LL | let y: Mask<_, N> = Mask::<_, _>::splat(false);
| ++++++++++++ | ++++++++++++
error[E0284]: type annotations needed for `Mask<_, _>` error[E0284]: type annotations needed for `Mask<_, _>`
@ -21,7 +21,7 @@ note: required by a const generic parameter in `Mask`
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
| |
LL | let y: Mask<T, N> = Mask::<_, _>::splat(false); LL | let y: Mask<_, N> = Mask::<_, _>::splat(false);
| ++++++++++++ | ++++++++++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -2,7 +2,8 @@ use std::marker::PhantomData;
fn a() { fn a() {
WrongImpl::foo(0i32); WrongImpl::foo(0i32);
//~^ ERROR overflow assigning `_` to `[_]` //~^ ERROR the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
} }
fn b() { fn b() {

View File

@ -1,11 +1,43 @@
error[E0275]: overflow assigning `_` to `[_]` error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied
--> $DIR/issue-62742.rs:4:16 --> $DIR/issue-62742.rs:4:16
| |
LL | WrongImpl::foo(0i32); LL | WrongImpl::foo(0i32);
| ^^^ | ^^^ function or associated item cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds
...
LL | pub struct RawImpl<T>(PhantomData<T>);
| --------------------- doesn't satisfy `RawImpl<_>: Raw<_>`
...
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ----------------------------------------- function or associated item `foo` not found for this struct
|
note: trait bound `RawImpl<_>: Raw<_>` was not satisfied
--> $DIR/issue-62742.rs:35:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ --------------
| |
| unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:19:1
|
LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:33:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
--> $DIR/issue-62742.rs:9:22 --> $DIR/issue-62742.rs:10:22
| |
LL | WrongImpl::<()>::foo(0i32); LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
@ -17,20 +49,20 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ----------------------------------------- function or associated item `foo` not found for this struct | ----------------------------------------- function or associated item `foo` not found for this struct
| |
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
--> $DIR/issue-62742.rs:34:20 --> $DIR/issue-62742.rs:35:20
| |
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> { LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ -------------- | ^^^^^^ --------------
| | | |
| unsatisfied trait bound introduced here | unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:18:1 --> $DIR/issue-62742.rs:19:1
| |
LL | pub trait Raw<T: ?Sized> { LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
--> $DIR/issue-62742.rs:9:5 --> $DIR/issue-62742.rs:10:5
| |
LL | WrongImpl::<()>::foo(0i32); LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
@ -38,12 +70,12 @@ LL | WrongImpl::<()>::foo(0i32);
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>` = help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()` = help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl` note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:32:35 --> $DIR/issue-62742.rs:33:35
| |
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl` | ^^^^^^ required by this bound in `SafeImpl`
error: aborting due to 3 previous errors error: aborting due to 4 previous errors
Some errors have detailed explanations: E0275, E0277, E0599. Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0275`. For more information about an error, try `rustc --explain E0277`.

View File

@ -2,7 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/type-alias-indirect.rs:14:5 --> $DIR/type-alias-indirect.rs:14:5
| |
LL | IndirectAlias::new(); LL | IndirectAlias::new();
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -2,19 +2,19 @@ error[E0282]: type annotations needed
--> $DIR/type-alias.rs:12:5 --> $DIR/type-alias.rs:12:5
| |
LL | DirectAlias::new() LL | DirectAlias::new()
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectAlias` | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/type-alias.rs:18:5 --> $DIR/type-alias.rs:18:5
| |
LL | IndirectAlias::new(); LL | IndirectAlias::new();
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias`
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/type-alias.rs:32:5 --> $DIR/type-alias.rs:32:5
| |
LL | DirectButWithDefaultAlias::new(); LL | DirectButWithDefaultAlias::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectButWithDefaultAlias` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View File

@ -0,0 +1,16 @@
// Tests that we probe receivers invariantly when using path-based method lookup.
struct B<T>(T);
impl B<fn(&'static ())> {
fn method(self) {
println!("hey");
}
}
fn foo(y: B<fn(&'static ())>) {
B::<for<'a> fn(&'a ())>::method(y);
//~^ ERROR no function or associated item named `method` found
}
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0599]: no function or associated item named `method` found for struct `B<for<'a> fn(&'a ())>` in the current scope
--> $DIR/receiver-equality.rs:12:30
|
LL | struct B<T>(T);
| ----------- function or associated item `method` not found for this struct
...
LL | B::<for<'a> fn(&'a ())>::method(y);
| ^^^^^^ function or associated item not found in `B<fn(&())>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View File

@ -17,7 +17,6 @@ fn main() {
let fp = BufWriter::new(fp); let fp = BufWriter::new(fp);
//~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
//~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
//~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
writeln!(fp, "hello world").unwrap(); //~ ERROR the method writeln!(fp, "hello world").unwrap(); //~ ERROR the method
} }

View File

@ -10,16 +10,6 @@ LL | let fp = BufWriter::new(fp);
note: required by a bound in `BufWriter::<W>::new` note: required by a bound in `BufWriter::<W>::new`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:17:14
|
LL | let fp = BufWriter::new(fp);
| ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
|
= note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
note: required by a bound in `BufWriter`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:17:14 --> $DIR/mut-borrow-needed-by-trait.rs:17:14
| |
@ -31,13 +21,13 @@ note: required by a bound in `BufWriter`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:22:14 --> $DIR/mut-borrow-needed-by-trait.rs:21:14
| |
LL | writeln!(fp, "hello world").unwrap(); LL | writeln!(fp, "hello world").unwrap();
| ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
| |
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
--> $DIR/mut-borrow-needed-by-trait.rs:22:14 --> $DIR/mut-borrow-needed-by-trait.rs:21:14
| |
LL | writeln!(fp, "hello world").unwrap(); LL | writeln!(fp, "hello world").unwrap();
| ^^ | ^^
@ -45,7 +35,7 @@ LL | writeln!(fp, "hello world").unwrap();
`&dyn std::io::Write: std::io::Write` `&dyn std::io::Write: std::io::Write`
which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
error: aborting due to 4 previous errors error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0599. Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`. For more information about an error, try `rustc --explain E0277`.