2025-02-28 01:28:32 +00:00
|
|
|
//! This module contains methods that assist in checking that impls are general
|
|
|
|
//! enough, i.e. that they always apply to every valid instantaiton of the ADT
|
|
|
|
//! they're implemented for.
|
|
|
|
//!
|
|
|
|
//! This is necessary for `Drop` and negative impls to be well-formed.
|
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
use rustc_errors::codes::*;
|
|
|
|
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
2024-07-01 21:43:00 +01:00
|
|
|
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
|
2025-02-28 01:28:32 +00:00
|
|
|
use rustc_middle::span_bug;
|
2023-04-25 07:36:58 +00:00
|
|
|
use rustc_middle::ty::util::CheckRegions;
|
2024-10-18 00:28:43 +02:00
|
|
|
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
|
2023-12-18 22:45:34 +00:00
|
|
|
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
2023-04-20 03:56:36 +00:00
|
|
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
2014-10-27 12:55:16 +01:00
|
|
|
|
2023-04-26 18:22:32 +00:00
|
|
|
use crate::errors;
|
|
|
|
use crate::hir::def_id::{DefId, LocalDefId};
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// This function confirms that the `Drop` implementation identified by
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
/// `drop_impl_did` is not any more specialized than the type it is
|
|
|
|
/// attached to (Issue #8142).
|
|
|
|
///
|
|
|
|
/// This means:
|
|
|
|
///
|
|
|
|
/// 1. The self type must be nominal (this is already checked during
|
|
|
|
/// coherence),
|
|
|
|
///
|
2019-02-08 14:53:55 +01:00
|
|
|
/// 2. The generic region/type parameters of the impl's self type must
|
2018-11-27 02:59:49 +00:00
|
|
|
/// all be parameters of the Drop impl itself (i.e., no
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
/// specialization like `impl Drop for Foo<i32>`), and,
|
|
|
|
///
|
|
|
|
/// 3. Any bounds on the generic parameters must be reflected in the
|
|
|
|
/// struct/enum definition for the nominal type itself (i.e.
|
|
|
|
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
2025-01-29 21:27:17 +11:00
|
|
|
pub(crate) fn check_drop_impl(
|
|
|
|
tcx: TyCtxt<'_>,
|
2025-03-27 14:11:44 +00:00
|
|
|
drop_impl_did: LocalDefId,
|
2025-01-29 21:27:17 +11:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-04-26 18:22:32 +00:00
|
|
|
match tcx.impl_polarity(drop_impl_did) {
|
|
|
|
ty::ImplPolarity::Positive => {}
|
|
|
|
ty::ImplPolarity::Negative => {
|
2023-12-18 22:21:37 +11:00
|
|
|
return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Negative {
|
2023-04-26 18:22:32 +00:00
|
|
|
span: tcx.def_span(drop_impl_did),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
ty::ImplPolarity::Reservation => {
|
2023-12-18 22:21:37 +11:00
|
|
|
return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Reservation {
|
2023-04-26 18:22:32 +00:00
|
|
|
span: tcx.def_span(drop_impl_did),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2025-02-28 01:28:32 +00:00
|
|
|
|
|
|
|
tcx.ensure_ok().orphan_check_impl(drop_impl_did)?;
|
|
|
|
|
2025-04-01 09:35:59 +00:00
|
|
|
let self_ty = tcx.type_of(drop_impl_did).instantiate_identity();
|
2025-02-28 01:28:32 +00:00
|
|
|
|
2025-04-01 09:35:59 +00:00
|
|
|
match self_ty.kind() {
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(adt_def, adt_to_impl_args) => {
|
2025-02-28 01:28:32 +00:00
|
|
|
ensure_impl_params_and_item_params_correspond(
|
2018-09-25 11:32:39 -04:00
|
|
|
tcx,
|
2025-02-28 01:28:32 +00:00
|
|
|
drop_impl_did,
|
2022-03-05 07:28:41 +11:00
|
|
|
adt_def.did(),
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args,
|
2018-09-25 11:32:39 -04:00
|
|
|
)?;
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
ensure_impl_predicates_are_implied_by_item_defn(
|
2018-09-25 11:32:39 -04:00
|
|
|
tcx,
|
2025-02-28 01:28:32 +00:00
|
|
|
drop_impl_did,
|
|
|
|
adt_def.did(),
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args,
|
2018-09-25 11:32:39 -04:00
|
|
|
)
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
_ => {
|
2025-02-28 01:28:32 +00:00
|
|
|
span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop");
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
pub(crate) fn check_negative_auto_trait_impl<'tcx>(
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2025-02-28 01:28:32 +00:00
|
|
|
impl_def_id: LocalDefId,
|
|
|
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
|
|
|
polarity: ty::ImplPolarity,
|
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
|
|
|
let ty::ImplPolarity::Negative = polarity else {
|
|
|
|
return Ok(());
|
|
|
|
};
|
|
|
|
|
|
|
|
if !tcx.trait_is_auto(impl_trait_ref.def_id) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
if tcx.defaultness(impl_def_id).is_default() {
|
|
|
|
tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative");
|
|
|
|
}
|
|
|
|
|
|
|
|
tcx.ensure_ok().orphan_check_impl(impl_def_id)?;
|
|
|
|
|
|
|
|
match impl_trait_ref.self_ty().kind() {
|
|
|
|
ty::Adt(adt_def, adt_to_impl_args) => {
|
|
|
|
ensure_impl_params_and_item_params_correspond(
|
|
|
|
tcx,
|
|
|
|
impl_def_id,
|
|
|
|
adt_def.did(),
|
|
|
|
adt_to_impl_args,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
ensure_impl_predicates_are_implied_by_item_defn(
|
|
|
|
tcx,
|
|
|
|
impl_def_id,
|
|
|
|
adt_def.did(),
|
|
|
|
adt_to_impl_args,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if tcx.features().auto_traits() {
|
|
|
|
// NOTE: We ignore the applicability check for negative auto impls
|
|
|
|
// defined in libcore. In the (almost impossible) future where we
|
|
|
|
// stabilize auto impls, then the proper applicability check MUST
|
|
|
|
// be implemented here to handle non-ADT rigid types.
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2025-03-07 17:09:36 +00:00
|
|
|
Err(tcx.dcx().span_delayed_bug(
|
|
|
|
tcx.def_span(impl_def_id),
|
|
|
|
"incoherent impl of negative auto trait",
|
|
|
|
))
|
2025-02-28 01:28:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ensure_impl_params_and_item_params_correspond<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
impl_def_id: LocalDefId,
|
|
|
|
adt_def_id: DefId,
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args: GenericArgsRef<'tcx>,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-11-14 13:13:27 +00:00
|
|
|
let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else {
|
2022-03-23 10:06:29 +01:00
|
|
|
return Ok(());
|
|
|
|
};
|
2016-03-25 05:22:44 +02:00
|
|
|
|
2025-02-28 02:43:12 +00:00
|
|
|
let impl_span = tcx.def_span(impl_def_id);
|
2025-02-28 01:28:32 +00:00
|
|
|
let item_span = tcx.def_span(adt_def_id);
|
|
|
|
let self_descr = tcx.def_descr(adt_def_id);
|
|
|
|
let polarity = match tcx.impl_polarity(impl_def_id) {
|
|
|
|
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
|
|
|
|
ty::ImplPolarity::Negative => "!",
|
|
|
|
};
|
|
|
|
let trait_name = tcx
|
|
|
|
.item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
|
2024-01-04 09:08:36 +11:00
|
|
|
let mut err = struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
2025-02-28 02:43:12 +00:00
|
|
|
impl_span,
|
2024-01-04 09:08:36 +11:00
|
|
|
E0366,
|
2025-02-28 01:28:32 +00:00
|
|
|
"`{polarity}{trait_name}` impls cannot be specialized",
|
2024-01-04 09:08:36 +11:00
|
|
|
);
|
2022-03-23 10:06:29 +01:00
|
|
|
match arg {
|
|
|
|
ty::util::NotUniqueParam::DuplicateParam(arg) => {
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.note(format!("`{arg}` is mentioned multiple times"))
|
2016-03-25 05:22:44 +02:00
|
|
|
}
|
2022-03-23 10:06:29 +01:00
|
|
|
ty::util::NotUniqueParam::NotParam(arg) => {
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.note(format!("`{arg}` is not a generic parameter"))
|
2016-03-25 05:22:44 +02:00
|
|
|
}
|
2022-03-23 10:06:29 +01:00
|
|
|
};
|
|
|
|
err.span_note(
|
|
|
|
item_span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!(
|
2022-03-29 07:29:59 +02:00
|
|
|
"use the same sequence of generic lifetime, type and const parameters \
|
2022-03-23 10:06:29 +01:00
|
|
|
as the {self_descr} definition",
|
|
|
|
),
|
|
|
|
);
|
|
|
|
Err(err.emit())
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
|
2024-07-01 21:43:00 +01:00
|
|
|
/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
|
|
|
|
/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
|
|
|
|
/// implied by the ADT being well formed.
|
2025-02-28 01:28:32 +00:00
|
|
|
fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2025-02-28 01:28:32 +00:00
|
|
|
impl_def_id: LocalDefId,
|
|
|
|
adt_def_id: DefId,
|
2023-07-11 22:35:29 +01:00
|
|
|
adt_to_impl_args: GenericArgsRef<'tcx>,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2024-10-18 00:28:43 +02:00
|
|
|
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
2024-06-01 14:51:31 -04:00
|
|
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
2023-04-20 03:56:36 +00:00
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
let impl_span = tcx.def_span(impl_def_id.to_def_id());
|
|
|
|
let trait_name = tcx
|
|
|
|
.item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
|
|
|
|
let polarity = match tcx.impl_polarity(impl_def_id) {
|
|
|
|
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
|
|
|
|
ty::ImplPolarity::Negative => "!",
|
|
|
|
};
|
2024-02-12 15:39:32 +09:00
|
|
|
// Take the param-env of the adt and instantiate the args that show up in
|
2023-04-20 03:56:36 +00:00
|
|
|
// the implementation's self type. This gives us the assumptions that the
|
|
|
|
// self ty of the implementation is allowed to know just from it being a
|
|
|
|
// well-formed adt, since that's all we're allowed to assume while proving
|
|
|
|
// the Drop implementation is not specialized.
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
//
|
2023-04-20 03:56:36 +00:00
|
|
|
// We don't need to normalize this param-env or anything, since we're only
|
2024-02-12 15:39:32 +09:00
|
|
|
// instantiating it with free params, so no additional param-env normalization
|
2023-04-20 03:56:36 +00:00
|
|
|
// can occur on top of what has been done in the param_env query itself.
|
2024-07-01 21:43:00 +01:00
|
|
|
//
|
|
|
|
// Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
|
|
|
|
// could instead use identity args for the adt. Unfortunately this would cause any errors to
|
|
|
|
// reference the params from the ADT instead of from the impl which is bad UX. To resolve
|
|
|
|
// this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
|
|
|
|
let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
|
|
|
|
let adt_env =
|
2023-07-27 15:50:42 +00:00
|
|
|
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
|
2023-04-20 03:56:36 +00:00
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id());
|
2024-07-01 21:43:00 +01:00
|
|
|
let fresh_adt_ty =
|
2025-02-28 01:28:32 +00:00
|
|
|
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
|
2024-07-01 21:43:00 +01:00
|
|
|
|
|
|
|
ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
|
2025-02-28 01:28:32 +00:00
|
|
|
.expect("equating fully generic trait ref should never fail");
|
2024-07-01 21:43:00 +01:00
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
for (clause, span) in tcx.predicates_of(impl_def_id).instantiate(tcx, fresh_impl_args) {
|
|
|
|
let normalize_cause = traits::ObligationCause::misc(span, impl_def_id);
|
2024-07-01 21:43:00 +01:00
|
|
|
let pred = ocx.normalize(&normalize_cause, adt_env, clause);
|
2025-02-28 01:28:32 +00:00
|
|
|
let cause = traits::ObligationCause::new(
|
|
|
|
span,
|
|
|
|
impl_def_id,
|
|
|
|
ObligationCauseCode::AlwaysApplicableImpl,
|
|
|
|
);
|
2024-07-01 21:43:00 +01:00
|
|
|
ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
|
2023-04-20 03:56:36 +00:00
|
|
|
}
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
// All of the custom error reporting logic is to preserve parity with the old
|
|
|
|
// error messages.
|
|
|
|
//
|
|
|
|
// They can probably get removed with better treatment of the new `DropImpl`
|
|
|
|
// obligation cause code, and perhaps some custom logic in `report_region_errors`.
|
|
|
|
|
|
|
|
let errors = ocx.select_all_or_error();
|
|
|
|
if !errors.is_empty() {
|
|
|
|
let mut guar = None;
|
|
|
|
let mut root_predicates = FxHashSet::default();
|
|
|
|
for error in errors {
|
|
|
|
let root_predicate = error.root_obligation.predicate;
|
|
|
|
if root_predicates.insert(root_predicate) {
|
|
|
|
let item_span = tcx.def_span(adt_def_id);
|
2025-02-28 01:28:32 +00:00
|
|
|
let self_descr = tcx.def_descr(adt_def_id);
|
2023-04-20 03:56:36 +00:00
|
|
|
guar = Some(
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2023-04-20 03:56:36 +00:00
|
|
|
error.root_obligation.cause.span,
|
|
|
|
E0367,
|
2025-02-28 01:28:32 +00:00
|
|
|
"`{polarity}{trait_name}` impl requires `{root_predicate}` \
|
2023-04-20 03:56:36 +00:00
|
|
|
but the {self_descr} it is implemented for does not",
|
|
|
|
)
|
2024-01-09 09:08:49 +11:00
|
|
|
.with_span_note(item_span, "the implementor must specify the same requirement")
|
2023-04-20 03:56:36 +00:00
|
|
|
.emit(),
|
|
|
|
);
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
2023-04-20 03:56:36 +00:00
|
|
|
return Err(guar.unwrap());
|
Reject specialized Drop impls.
See Issue 8142 for discussion.
This makes it illegal for a Drop impl to be more specialized than the
original item.
So for example, all of the following are now rejected (when they would
have been blindly accepted before):
```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type
struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region
struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement
struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```
Due to examples like the above, this is a [breaking-change].
(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)
----
This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.
Includes two new error codes for the new dropck check.
Update run-pass tests to accommodate new dropck pass.
Update tests and docs to reflect new destructor restriction.
----
Implementation notes:
We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.
More specifically:
1. Attempt unification of a skolemized instance of the struct/enum
with an instance of the Drop impl's type expression where all of
the impl's generics (i.e. the free variables of the type
expression) have been replaced with unification variables.
2. If unification fails, then reject Drop impl as specialized.
3. If unification succeeds, check if any of the skolemized
variables "leaked" into the constraint set for the inference
context; if so, then reject Drop impl as specialized.
4. Otherwise, unification succeeded without leaking skolemized
variables: accept the Drop impl.
We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
2015-03-21 13:12:08 +01:00
|
|
|
}
|
|
|
|
|
2025-02-28 01:28:32 +00:00
|
|
|
let errors = ocx.infcx.resolve_regions(impl_def_id, adt_env, []);
|
2023-04-20 03:56:36 +00:00
|
|
|
if !errors.is_empty() {
|
|
|
|
let mut guar = None;
|
|
|
|
for error in errors {
|
|
|
|
let item_span = tcx.def_span(adt_def_id);
|
2025-02-28 01:28:32 +00:00
|
|
|
let self_descr = tcx.def_descr(adt_def_id);
|
2023-04-20 03:56:36 +00:00
|
|
|
let outlives = match error {
|
|
|
|
RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
|
|
|
|
RegionResolutionError::GenericBoundFailure(_, generic, r) => {
|
|
|
|
format!("{generic}: {r}")
|
|
|
|
}
|
|
|
|
RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
|
|
|
|
RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
|
2023-05-29 17:54:53 +00:00
|
|
|
format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
|
2023-04-20 03:56:36 +00:00
|
|
|
}
|
2024-01-26 19:18:14 +00:00
|
|
|
RegionResolutionError::CannotNormalize(..) => unreachable!(),
|
2023-04-20 03:56:36 +00:00
|
|
|
};
|
|
|
|
guar = Some(
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2023-04-20 03:56:36 +00:00
|
|
|
error.origin().span(),
|
|
|
|
E0367,
|
2025-02-28 01:28:32 +00:00
|
|
|
"`{polarity}{trait_name}` impl requires `{outlives}` \
|
2023-04-20 03:56:36 +00:00
|
|
|
but the {self_descr} it is implemented for does not",
|
|
|
|
)
|
2024-01-09 09:08:49 +11:00
|
|
|
.with_span_note(item_span, "the implementor must specify the same requirement")
|
2023-04-20 03:56:36 +00:00
|
|
|
.emit(),
|
|
|
|
);
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
2023-04-20 03:56:36 +00:00
|
|
|
return Err(guar.unwrap());
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|
|
|
|
|
2023-04-20 03:56:36 +00:00
|
|
|
Ok(())
|
2019-12-16 11:27:28 -05:00
|
|
|
}
|