Skip to content

Commit

Permalink
Reject generic self types using impl defid: do not merge.
Browse files Browse the repository at this point in the history
The RFC for arbitrary self types v2 declares that we should reject
"generic" self types. This commit does so.

The definition of "generic" was unclear in the RFC, but has been
explored in
rust-lang#129147
and the conclusion is that "generic" means any `self` type which
is a type parameter defined on the method itself, or references
to such a type.

This approach was chosen because other definitions of "generic"
don't work. Specifically,
* we can't filter out generic type _arguments_, because that would
  filter out Rc<Self> and all the other types of smart pointer
  we want to support;
* we can't filter out all type params, because Self itself is a
  type param, and because existing Rust code depends on other
  type params declared on the type (as opposed to the method).

This PR is a second attempt at achieving this, based on producing a new
well-formedness checking context which is only aware of the type params
of the impl block, not of the method itself.

It doesn't currently work because it turns out we do need some method
params under some circumstances, but raising it for completeness.

This PR adds lots of extra tests to arbitrary-self-from-method-substs.
Most of these are ways to trigger a "type mismatch" error which
https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519
hopes can be minimized by filtering out generics in this way.
We remove a FIXME from confirm.rs suggesting that we make this change.
It's still possible to cause type mismatch errors, and a subsequent
PR may be able to improve diagnostics in this area, but it's harder
to cause these errors without contrived uses of the turbofish.

This is a part of the arbitrary self types v2 project,
rust-lang/rfcs#3519
rust-lang#44874

r? @wesleywiser
  • Loading branch information
adetaylor committed Sep 8, 2024
1 parent 7f4b270 commit 58fcf8a
Show file tree
Hide file tree
Showing 10 changed files with 486 additions and 100 deletions.
109 changes: 57 additions & 52 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,6 @@ fn check_impl_item<'tcx>(
hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
_ => (None, impl_item.span),
};

check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig)
}

Expand Down Expand Up @@ -1699,62 +1698,68 @@ fn check_method_receiver<'tcx>(
None
};

if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
return Err(match arbitrary_self_types_level {
// Wherever possible, emit a message advising folks that the features
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
// have helped.
None if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::Basic),
) =>
{
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
None | Some(ArbitrarySelfTypesLevel::Basic)
if receiver_is_valid(
let impl_block_def_id =
tcx.impl_of_method(method.def_id).unwrap_or(method.def_id).expect_local();

let receiver_validity = enter_wf_checking_ctxt(tcx, span, impl_block_def_id, |wfcx| {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
return Err(match arbitrary_self_types_level {
// Wherever possible, emit a message advising folks that the features
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
// have helped.
None if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::WithPointers),
Some(ArbitrarySelfTypesLevel::Basic),
) =>
{
// Report error; would have worked with `arbitrary_self_types_pointers`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types_pointers,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types_pointers` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
_ =>
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
{
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
}
});
}
Ok(())
{
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
None | Some(ArbitrarySelfTypesLevel::Basic)
if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::WithPointers),
) =>
{
// Report error; would have worked with `arbitrary_self_types_pointers`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types_pointers,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types_pointers` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
_ =>
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
{
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
}
});
}
Ok(())
});
receiver_validity
}

/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,9 +516,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.register_predicates(obligations);
}
Err(terr) => {
// FIXME(arbitrary_self_types): We probably should limit the
// situations where this can occur by adding additional restrictions
// to the feature, like the self type can't reference method args.
if self.tcx.features().arbitrary_self_types {
self.err_ctxt()
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
Expand Down
1 change: 0 additions & 1 deletion src/tools/tidy/src/issues.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4122,7 +4122,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs
ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs
ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs
ui/type-alias-impl-trait/issue-57611-trait-alias.rs
ui/type-alias-impl-trait/issue-57700.rs
ui/type-alias-impl-trait/issue-57807-associated-type.rs
ui/type-alias-impl-trait/issue-57961.rs
ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/self/arbitrary-self-from-method-substs-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::ops::Deref;
struct Foo(u32);
impl Foo {
const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
//~^ ERROR: `R` cannot be used as the type of `self`
//~^ ERROR invalid generic `self` parameter type
//~| ERROR destructor of `R` cannot be evaluated at compile-time
self.0
//~^ ERROR cannot borrow here, since the borrowed element may contain interior mutability
Expand Down
10 changes: 4 additions & 6 deletions tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,16 @@ LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
LL | }
| - value is dropped here

error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
error[E0799]: invalid generic `self` parameter type: `R`
--> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
|
LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
| ^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0015, E0493, E0658.
Some errors have detailed explanations: E0015, E0493, E0658, E0799.
For more information about an error, try `rustc --explain E0015`.
162 changes: 158 additions & 4 deletions tests/ui/self/arbitrary-self-from-method-substs.default.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,168 @@
error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
--> $DIR/arbitrary-self-from-method-substs.rs:8:43
error[E0799]: invalid generic `self` parameter type: `R`
--> $DIR/arbitrary-self-from-method-substs.rs:9:43
|
LL | fn get<R: Deref<Target = Self>>(self: R) -> u32 {
| ^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0799]: invalid generic `self` parameter type: `&R`
--> $DIR/arbitrary-self-from-method-substs.rs:13:44
|
LL | fn get1<R: Deref<Target = Self>>(self: &R) -> u32 {
| ^^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0799]: invalid generic `self` parameter type: `&mut R`
--> $DIR/arbitrary-self-from-method-substs.rs:17:44
|
LL | fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 {
| ^^^^^^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0799]: invalid generic `self` parameter type: `Rc<R>`
--> $DIR/arbitrary-self-from-method-substs.rs:21:44
|
LL | fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 {
| ^^^^^^^^^^^^^^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0799]: invalid generic `self` parameter type: `&Rc<R>`
--> $DIR/arbitrary-self-from-method-substs.rs:25:44
|
LL | fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 {
| ^^^^^^^^^^^^^^^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0799]: invalid generic `self` parameter type: `Rc<&R>`
--> $DIR/arbitrary-self-from-method-substs.rs:29:44
|
LL | fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 {
| ^^^^^^^^^^^^^^^
|
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0658]: `<FR as FindReceiver>::Receiver` cannot be used as the type of `self` without the `arbitrary_self_types` feature
--> $DIR/arbitrary-self-from-method-substs.rs:33:37
|
LL | fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
| ^^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error: aborting due to 1 previous error
error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
--> $DIR/arbitrary-self-from-method-substs.rs:61:18
|
LL | fn get(self: R) {}
| ^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:92:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
|
note: expected this to be `Rc<Foo>`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected struct `Rc<Foo>`
found struct `Foo`

error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:96:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
|
note: expected this to be `Rc<Foo>`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected struct `Rc<Foo>`
found reference `&Foo`

error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:100:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
note: the trait `Deref` must be implemented
--> $SRC_DIR/core/src/ops/deref.rs:LL:COL
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `get`, perhaps you need to implement it:
candidate #1: `SliceIndex`

error[E0599]: the method `get` exists for reference `&Rc<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:108:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>`
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
note: the trait `Deref` must be implemented
--> $SRC_DIR/core/src/ops/deref.rs:LL:COL
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `get`, perhaps you need to implement it:
candidate #1: `SliceIndex`

error: aborting due to 12 previous errors

For more information about this error, try `rustc --explain E0658`.
Some errors have detailed explanations: E0271, E0599, E0658, E0799.
For more information about an error, try `rustc --explain E0271`.
Loading

0 comments on commit 58fcf8a

Please sign in to comment.