Skip to content

Commit 8d9686e

Browse files
authored
Rollup merge of #130098 - adetaylor:arbitrary-self-types-block-generics, r=wesleywiser
Reject generic self types. 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 #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 decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. 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 #44874 r? `@wesleywiser`
2 parents 298c746 + 86af0f9 commit 8d9686e

14 files changed

+549
-57
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
The `self` parameter in a method has an invalid generic "receiver type".
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0801
6+
struct Foo;
7+
8+
impl Foo {
9+
fn foo<R: std::ops::Deref<Target=Self>>(self: R) {}
10+
}
11+
```
12+
13+
or alternatively,
14+
15+
```compile_fail,E0801
16+
struct Foo;
17+
18+
impl Foo {
19+
fn foo(self: impl std::ops::Deref<Target=Self>) {}
20+
}
21+
```
22+
23+
Methods take a special first parameter, termed `self`. It's normal to
24+
use `self`, `&self` or `&mut self`, which are syntactic sugar for
25+
`self: Self`, `self: &Self`, and `self: &mut Self` respectively.
26+
But it's also possible to use more sophisticated types of `self`
27+
parameter, for instance `std::rc::Rc<Self>`. The set of allowable
28+
`Self` types is extensible using the nightly feature
29+
[Arbitrary self types][AST].
30+
This will extend the valid set of `Self` types to anything which implements
31+
`std::ops::Deref<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, or
32+
your own smart pointers that do the same.
33+
34+
However, even with that feature, the `self` type must be concrete.
35+
Generic `self` types are not permitted. Specifically, a `self` type will
36+
be rejected if it is a type parameter defined on the method.
37+
38+
These are OK:
39+
40+
```
41+
struct Foo;
42+
43+
impl Foo {
44+
fn foo(self) {}
45+
fn foo2(self: std::rc::Rc<Self>) {} // or some other similar
46+
// smart pointer if you enable arbitrary self types and
47+
// the pointer implements Deref<Target=Self>
48+
}
49+
```
50+
51+
[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html

compiler/rustc_error_codes/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ E0797: 0797,
540540
E0798: 0798,
541541
E0799: 0799,
542542
E0800: 0800,
543+
E0801: 0801,
543544
);
544545
)
545546
}

compiler/rustc_hir_analysis/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
234234
.help = consider moving this inherent impl into the crate defining the type if possible
235235
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
236236
237+
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
238+
.note = type of `self` must not be a method generic parameter type
239+
240+
hir_analysis_invalid_generic_receiver_ty_help =
241+
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`)
242+
237243
hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
238244
.note = type of `self` must be `Self` or a type that dereferences to it
239245

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+52-9
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,6 @@ fn check_impl_item<'tcx>(
904904
hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
905905
_ => (None, impl_item.span),
906906
};
907-
908907
check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig)
909908
}
910909

@@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>(
17251724
} else {
17261725
None
17271726
};
1727+
let generics = tcx.generics_of(method.def_id);
17281728

1729-
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
1729+
let receiver_validity =
1730+
receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics);
1731+
if let Err(receiver_validity_err) = receiver_validity {
17301732
return Err(match arbitrary_self_types_level {
17311733
// Wherever possible, emit a message advising folks that the features
17321734
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
@@ -1737,7 +1739,9 @@ fn check_method_receiver<'tcx>(
17371739
receiver_ty,
17381740
self_ty,
17391741
Some(ArbitrarySelfTypesLevel::Basic),
1740-
) =>
1742+
generics,
1743+
)
1744+
.is_ok() =>
17411745
{
17421746
// Report error; would have worked with `arbitrary_self_types`.
17431747
feature_err(
@@ -1759,7 +1763,9 @@ fn check_method_receiver<'tcx>(
17591763
receiver_ty,
17601764
self_ty,
17611765
Some(ArbitrarySelfTypesLevel::WithPointers),
1762-
) =>
1766+
generics,
1767+
)
1768+
.is_ok() =>
17631769
{
17641770
// Report error; would have worked with `arbitrary_self_types_pointers`.
17651771
feature_err(
@@ -1777,13 +1783,45 @@ fn check_method_receiver<'tcx>(
17771783
_ =>
17781784
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
17791785
{
1780-
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
1786+
match receiver_validity_err {
1787+
ReceiverValidityError::DoesNotDeref => {
1788+
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
1789+
}
1790+
ReceiverValidityError::MethodGenericParamUsed => {
1791+
tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty })
1792+
}
1793+
}
17811794
}
17821795
});
17831796
}
17841797
Ok(())
17851798
}
17861799

1800+
/// Error cases which may be returned from `receiver_is_valid`. These error
1801+
/// cases are generated in this function as they may be unearthed as we explore
1802+
/// the `autoderef` chain, but they're converted to diagnostics in the caller.
1803+
enum ReceiverValidityError {
1804+
/// The self type does not get to the receiver type by following the
1805+
/// autoderef chain.
1806+
DoesNotDeref,
1807+
/// A type was found which is a method type parameter, and that's not allowed.
1808+
MethodGenericParamUsed,
1809+
}
1810+
1811+
/// Confirms that a type is not a type parameter referring to one of the
1812+
/// method's type params.
1813+
fn confirm_type_is_not_a_method_generic_param(
1814+
ty: Ty<'_>,
1815+
method_generics: &ty::Generics,
1816+
) -> Result<(), ReceiverValidityError> {
1817+
if let ty::Param(param) = ty.kind() {
1818+
if (param.index as usize) >= method_generics.parent_count {
1819+
return Err(ReceiverValidityError::MethodGenericParamUsed);
1820+
}
1821+
}
1822+
Ok(())
1823+
}
1824+
17871825
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
17881826
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
17891827
/// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled.
@@ -1799,7 +1837,8 @@ fn receiver_is_valid<'tcx>(
17991837
receiver_ty: Ty<'tcx>,
18001838
self_ty: Ty<'tcx>,
18011839
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
1802-
) -> bool {
1840+
method_generics: &ty::Generics,
1841+
) -> Result<(), ReceiverValidityError> {
18031842
let infcx = wfcx.infcx;
18041843
let tcx = wfcx.tcx();
18051844
let cause =
@@ -1811,9 +1850,11 @@ fn receiver_is_valid<'tcx>(
18111850
ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
18121851
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
18131852
}) {
1814-
return true;
1853+
return Ok(());
18151854
}
18161855

1856+
confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?;
1857+
18171858
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
18181859

18191860
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
@@ -1830,6 +1871,8 @@ fn receiver_is_valid<'tcx>(
18301871
potential_self_ty, self_ty
18311872
);
18321873

1874+
confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?;
1875+
18331876
// Check if the self type unifies. If it does, then commit the result
18341877
// since it may have region side-effects.
18351878
if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
@@ -1838,7 +1881,7 @@ fn receiver_is_valid<'tcx>(
18381881
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
18391882
}) {
18401883
wfcx.register_obligations(autoderef.into_obligations());
1841-
return true;
1884+
return Ok(());
18421885
}
18431886

18441887
// Without `feature(arbitrary_self_types)`, we require that each step in the
@@ -1865,7 +1908,7 @@ fn receiver_is_valid<'tcx>(
18651908
}
18661909

18671910
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
1868-
false
1911+
Err(ReceiverValidityError::DoesNotDeref)
18691912
}
18701913

18711914
fn receiver_is_implemented<'tcx>(

compiler/rustc_hir_analysis/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,16 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
16231623
pub receiver_ty: Ty<'tcx>,
16241624
}
16251625

1626+
#[derive(Diagnostic)]
1627+
#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)]
1628+
#[note]
1629+
#[help(hir_analysis_invalid_generic_receiver_ty_help)]
1630+
pub(crate) struct InvalidGenericReceiverTy<'tcx> {
1631+
#[primary_span]
1632+
pub span: Span,
1633+
pub receiver_ty: Ty<'tcx>,
1634+
}
1635+
16261636
#[derive(Diagnostic)]
16271637
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
16281638
#[note]

compiler/rustc_hir_typeck/src/method/confirm.rs

-3
Original file line numberDiff line numberDiff line change
@@ -533,9 +533,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
533533
self.register_predicates(obligations);
534534
}
535535
Err(terr) => {
536-
// FIXME(arbitrary_self_types): We probably should limit the
537-
// situations where this can occur by adding additional restrictions
538-
// to the feature, like the self type can't reference method args.
539536
if self.tcx.features().arbitrary_self_types() {
540537
self.err_ctxt()
541538
.report_mismatched_types(

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -4102,7 +4102,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs
41024102
ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs
41034103
ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs
41044104
ui/type-alias-impl-trait/issue-57611-trait-alias.rs
4105-
ui/type-alias-impl-trait/issue-57700.rs
41064105
ui/type-alias-impl-trait/issue-57807-associated-type.rs
41074106
ui/type-alias-impl-trait/issue-57961.rs
41084107
ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs

tests/ui/self/arbitrary-self-from-method-substs-ice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::ops::Deref;
88
struct Foo(u32);
99
impl Foo {
1010
const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
11-
//~^ ERROR: `R` cannot be used as the type of `self`
11+
//~^ ERROR invalid generic `self` parameter type
1212
//~| ERROR destructor of `R` cannot be evaluated at compile-time
1313
self.0
1414
//~^ ERROR cannot call non-const fn `<R as Deref>::deref` in constant function

tests/ui/self/arbitrary-self-from-method-substs-ice.stderr

+4-6
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,16 @@ LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
1515
LL | }
1616
| - value is dropped here
1717

18-
error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
18+
error[E0801]: invalid generic `self` parameter type: `R`
1919
--> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
2020
|
2121
LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
2222
| ^
2323
|
24-
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
25-
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
26-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
27-
= 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`)
24+
= note: type of `self` must not be a method generic parameter type
25+
= 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`)
2826

2927
error: aborting due to 3 previous errors
3028

31-
Some errors have detailed explanations: E0015, E0493, E0658.
29+
Some errors have detailed explanations: E0015, E0493, E0801.
3230
For more information about an error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)