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:
commit
e9e13a68d7
@ -1388,10 +1388,10 @@ fn inferred_kind(
|
||||
// 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(_) => {
|
||||
|
@ -621,6 +621,16 @@ fn reset(&mut self) {
|
||||
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
|
||||
|
||||
@ -1443,7 +1453,8 @@ fn consider_probe(
|
||||
(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);
|
||||
@ -1514,7 +1525,13 @@ fn consider_probe(
|
||||
{
|
||||
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);
|
||||
@ -1560,7 +1577,8 @@ fn consider_probe(
|
||||
(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);
|
||||
@ -1603,7 +1621,7 @@ fn consider_probe(
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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>`
|
||||
|
||||
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`.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
@ -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`.
|
||||
|
@ -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`.
|
@ -1,5 +1,5 @@
|
||||
//@ revisions: nofallback fallback
|
||||
//@check-fail
|
||||
//@[fallback] check-pass
|
||||
|
||||
#![feature(never_type)]
|
||||
#![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> {
|
||||
// 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 {
|
||||
|
@ -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<_, _>`
|
||||
@ -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
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
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() {
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
|
||||
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<()>`
|
||||
@ -38,12 +70,12 @@ LL | WrongImpl::<()>::foo(0i32);
|
||||
= 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`.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
16
tests/ui/methods/receiver-equality.rs
Normal file
16
tests/ui/methods/receiver-equality.rs
Normal 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() {}
|
12
tests/ui/methods/receiver-equality.stderr
Normal file
12
tests/ui/methods/receiver-equality.stderr
Normal 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`.
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
@ -31,13 +21,13 @@ 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();
|
||||
| ^^
|
||||
@ -45,7 +35,7 @@ LL | writeln!(fp, "hello world").unwrap();
|
||||
`&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`.
|
||||
|
Loading…
Reference in New Issue
Block a user