Skip to content

Commit

Permalink
Auto merge of #132361 - jieyouxu:rollup-zburkwr, r=jieyouxu
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #130098 (Reject generic self types.)
 - #131096 (rustdoc: Remove usage of `allow(unused)` attribute on `no_run` merged doctests)
 - #132315 (compiletest: improve robustness of LLVM version handling)
 - #132346 (Some graphviz tweaks)
 - #132359 (Fix AIX libc call char type from i8 to u8)
 - #132360 (Un-vacation myself)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Oct 30, 2024
2 parents 298c746 + 5209757 commit 759e07f
Show file tree
Hide file tree
Showing 29 changed files with 836 additions and 186 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ dependencies = [
"miropt-test-tools",
"regex",
"rustfix",
"semver",
"serde",
"serde_json",
"tracing",
Expand Down
51 changes: 51 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0801.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
The `self` parameter in a method has an invalid generic "receiver type".

Erroneous code example:

```compile_fail,E0801
struct Foo;
impl Foo {
fn foo<R: std::ops::Deref<Target=Self>>(self: R) {}
}
```

or alternatively,

```compile_fail,E0801
struct Foo;
impl Foo {
fn foo(self: impl std::ops::Deref<Target=Self>) {}
}
```

Methods take a special first parameter, termed `self`. It's normal to
use `self`, `&self` or `&mut self`, which are syntactic sugar for
`self: Self`, `self: &Self`, and `self: &mut Self` respectively.
But it's also possible to use more sophisticated types of `self`
parameter, for instance `std::rc::Rc<Self>`. The set of allowable
`Self` types is extensible using the nightly feature
[Arbitrary self types][AST].
This will extend the valid set of `Self` types to anything which implements
`std::ops::Deref<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, or
your own smart pointers that do the same.

However, even with that feature, the `self` type must be concrete.
Generic `self` types are not permitted. Specifically, a `self` type will
be rejected if it is a type parameter defined on the method.

These are OK:

```
struct Foo;
impl Foo {
fn foo(self) {}
fn foo2(self: std::rc::Rc<Self>) {} // or some other similar
// smart pointer if you enable arbitrary self types and
// the pointer implements Deref<Target=Self>
}
```

[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ E0797: 0797,
E0798: 0798,
E0799: 0799,
E0800: 0800,
E0801: 0801,
);
)
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
.help = consider moving this inherent impl into the crate defining the type if possible
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
.note = type of `self` must not be a method generic parameter type
hir_analysis_invalid_generic_receiver_ty_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`)
hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
.note = type of `self` must be `Self` or a type that dereferences to it
Expand Down
61 changes: 52 additions & 9 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,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 @@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>(
} else {
None
};
let generics = tcx.generics_of(method.def_id);

if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
let receiver_validity =
receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics);
if let Err(receiver_validity_err) = receiver_validity {
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
Expand All @@ -1737,7 +1739,9 @@ fn check_method_receiver<'tcx>(
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::Basic),
) =>
generics,
)
.is_ok() =>
{
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
Expand All @@ -1759,7 +1763,9 @@ fn check_method_receiver<'tcx>(
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::WithPointers),
) =>
generics,
)
.is_ok() =>
{
// Report error; would have worked with `arbitrary_self_types_pointers`.
feature_err(
Expand All @@ -1777,13 +1783,45 @@ fn check_method_receiver<'tcx>(
_ =>
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
{
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
match receiver_validity_err {
ReceiverValidityError::DoesNotDeref => {
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
}
ReceiverValidityError::MethodGenericParamUsed => {
tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty })
}
}
}
});
}
Ok(())
}

/// Error cases which may be returned from `receiver_is_valid`. These error
/// cases are generated in this function as they may be unearthed as we explore
/// the `autoderef` chain, but they're converted to diagnostics in the caller.
enum ReceiverValidityError {
/// The self type does not get to the receiver type by following the
/// autoderef chain.
DoesNotDeref,
/// A type was found which is a method type parameter, and that's not allowed.
MethodGenericParamUsed,
}

/// Confirms that a type is not a type parameter referring to one of the
/// method's type params.
fn confirm_type_is_not_a_method_generic_param(
ty: Ty<'_>,
method_generics: &ty::Generics,
) -> Result<(), ReceiverValidityError> {
if let ty::Param(param) = ty.kind() {
if (param.index as usize) >= method_generics.parent_count {
return Err(ReceiverValidityError::MethodGenericParamUsed);
}
}
Ok(())
}

/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
/// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled.
Expand All @@ -1799,7 +1837,8 @@ fn receiver_is_valid<'tcx>(
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
) -> bool {
method_generics: &ty::Generics,
) -> Result<(), ReceiverValidityError> {
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
let cause =
Expand All @@ -1811,9 +1850,11 @@ fn receiver_is_valid<'tcx>(
ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
}) {
return true;
return Ok(());
}

confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?;

let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);

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

confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?;

// Check if the self type unifies. If it does, then commit the result
// since it may have region side-effects.
if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
Expand All @@ -1838,7 +1881,7 @@ fn receiver_is_valid<'tcx>(
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
}) {
wfcx.register_obligations(autoderef.into_obligations());
return true;
return Ok(());
}

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

debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
false
Err(ReceiverValidityError::DoesNotDeref)
}

fn receiver_is_implemented<'tcx>(
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,16 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
pub receiver_ty: Ty<'tcx>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)]
#[note]
#[help(hir_analysis_invalid_generic_receiver_ty_help)]
pub(crate) struct InvalidGenericReceiverTy<'tcx> {
#[primary_span]
pub span: Span,
pub receiver_ty: Ty<'tcx>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
#[note]
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 @@ -533,9 +533,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(
Expand Down
Loading

0 comments on commit 759e07f

Please sign in to comment.