Skip to content

Commit

Permalink
Auto merge of #129073 - compiler-errors:receiver-variance, r=lcnr
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Sep 17, 2024
2 parents 46b0f8b + 05483d5 commit e9e13a6
Show file tree
Hide file tree
Showing 17 changed files with 141 additions and 56 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,10 +1388,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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 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,
self_ty,
impl_ty,
self_ty,
) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
Expand Down
26 changes: 22 additions & 4 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
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

Expand Down Expand Up @@ -1443,7 +1453,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, impl_ty, impl_args);
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(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
Expand Down Expand Up @@ -1514,7 +1525,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
{
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(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
Expand Down Expand Up @@ -1560,7 +1577,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
(xform_self_ty, xform_ret_ty) =
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);
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(()) => {}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
Expand Down Expand Up @@ -1603,7 +1621,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}

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(()) => {}
Err(_) => {
result = ProbeResult::BadReturnType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ impl Fail<i32> {

fn main() {
Fail::<()>::C
//~^ ERROR no associated item named `C` found for struct `Fail<()>` in the current scope
}
Original file line number Diff line number Diff line change
Expand Up @@ -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: 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>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0392`.
Some errors have detailed explanations: E0392, E0599.
For more information about an error, try `rustc --explain E0392`.
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ impl Fail<i32, i32> {
fn main() {
Fail::<i32, u32>::C
//~^ ERROR: type mismatch
//~| ERROR no associated item named `C` found for struct `Fail<i32, u32>` in the current scope
}
Original file line number Diff line number Diff line change
@@ -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`
--> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5
|
Expand All @@ -15,6 +27,7 @@ note: required by a bound in `Fail`
LL | struct Fail<T: Proj<Assoc = U>, U>(T);
| ^^^^^^^^^ 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`.
11 changes: 0 additions & 11 deletions tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr

This file was deleted.

8 changes: 4 additions & 4 deletions tests/ui/coercion/coerce-issue-49593-box-never.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ revisions: nofallback fallback
//@check-fail
//@[fallback] check-pass

#![feature(never_type)]
#![cfg_attr(fallback, feature(never_type_fallback))]
Expand All @@ -13,10 +13,10 @@ fn raw_ptr_box<T>(t: T) -> *mut T {
}

fn foo(x: !) -> Box<dyn Error> {
// Subtyping during method resolution will generate new inference vars and
// subtype them. Thus fallback will not fall back to `!`, but `()` instead.
// Method resolution will generate new inference vars and relate them.
// Thus fallback will not fall back to `!`, but `()` instead.
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 {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/generic_arg_infer/issue-91614.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
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<_, _>`
Expand All @@ -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
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
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/impl-trait/issues/issue-62742.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::marker::PhantomData;

fn a() {
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() {
Expand Down
52 changes: 42 additions & 10 deletions tests/ui/impl-trait/issues/issue-62742.stderr
Original file line number Diff line number Diff line change
@@ -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
|
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
--> $DIR/issue-62742.rs:9:22
--> $DIR/issue-62742.rs:10:22
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
Expand All @@ -17,33 +49,33 @@ 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:34:20
--> $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:18:1
--> $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:9:5
--> $DIR/issue-62742.rs:10:5
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
|
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()`
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)>);
| ^^^^^^ 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.
For more information about an error, try `rustc --explain E0275`.
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/type-alias-indirect.rs:14:5
|
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

Expand Down
6 changes: 3 additions & 3 deletions tests/ui/inference/need_type_info/type-alias.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ error[E0282]: type annotations needed
--> $DIR/type-alias.rs:12:5
|
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
--> $DIR/type-alias.rs:18:5
|
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
--> $DIR/type-alias.rs:32:5
|
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

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/methods/receiver-equality.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions tests/ui/methods/receiver-equality.stderr
Original file line number Diff line number Diff line change
@@ -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`.
1 change: 0 additions & 1 deletion tests/ui/suggestions/mut-borrow-needed-by-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ fn main() {
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

writeln!(fp, "hello world").unwrap(); //~ ERROR the method
}
16 changes: 3 additions & 13 deletions tests/ui/suggestions/mut-borrow-needed-by-trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,6 @@ LL | let fp = BufWriter::new(fp);
note: required by a bound in `BufWriter::<W>::new`
--> $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
--> $DIR/mut-borrow-needed-by-trait.rs:17:14
|
Expand All @@ -31,21 +21,21 @@ note: required by a bound in `BufWriter`
--> $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
--> $DIR/mut-borrow-needed-by-trait.rs:22:14
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
|
LL | writeln!(fp, "hello world").unwrap();
| ---------^^---------------- 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
--> $DIR/mut-borrow-needed-by-trait.rs:22:14
--> $DIR/mut-borrow-needed-by-trait.rs:21:14
|
LL | writeln!(fp, "hello world").unwrap();
| ^^
= note: the following trait bounds were not satisfied:
`&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.
For more information about an error, try `rustc --explain E0277`.

0 comments on commit e9e13a6

Please sign in to comment.