gate rustc_on_unimplemented under rustc_attrs
This commit is contained in:
parent
e4931eaaa3
commit
1c7595fd0f
17 changed files with 34 additions and 190 deletions
|
@ -1,154 +0,0 @@
|
|||
# `on_unimplemented`
|
||||
|
||||
The tracking issue for this feature is: [#29628]
|
||||
|
||||
[#29628]: https://github.com/rust-lang/rust/issues/29628
|
||||
|
||||
------------------------
|
||||
|
||||
The `on_unimplemented` feature provides the `#[rustc_on_unimplemented]`
|
||||
attribute, which allows trait definitions to add specialized notes to error
|
||||
messages when an implementation was expected but not found. You can refer
|
||||
to the trait's generic arguments by name and to the resolved type using
|
||||
`Self`.
|
||||
|
||||
For example:
|
||||
|
||||
```rust,compile_fail
|
||||
#![feature(on_unimplemented)]
|
||||
|
||||
#[rustc_on_unimplemented="an iterator over elements of type `{A}` \
|
||||
cannot be built from a collection of type `{Self}`"]
|
||||
trait MyIterator<A> {
|
||||
fn next(&mut self) -> A;
|
||||
}
|
||||
|
||||
fn iterate_chars<I: MyIterator<char>>(i: I) {
|
||||
// ...
|
||||
}
|
||||
|
||||
fn main() {
|
||||
iterate_chars(&[1, 2, 3][..]);
|
||||
}
|
||||
```
|
||||
|
||||
When the user compiles this, they will see the following;
|
||||
|
||||
```txt
|
||||
error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
|
||||
--> <anon>:14:5
|
||||
|
|
||||
14 | iterate_chars(&[1, 2, 3][..]);
|
||||
| ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
|
||||
|
|
||||
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
||||
= note: required by `iterate_chars`
|
||||
```
|
||||
|
||||
`on_unimplemented` also supports advanced filtering for better targeting
|
||||
of messages, as well as modifying specific parts of the error message. You
|
||||
target the text of:
|
||||
|
||||
- the main error message (`message`)
|
||||
- the label (`label`)
|
||||
- an extra note (`note`)
|
||||
|
||||
For example, the following attribute
|
||||
|
||||
```rust,compile_fail
|
||||
#[rustc_on_unimplemented(
|
||||
message="message",
|
||||
label="label",
|
||||
note="note"
|
||||
)]
|
||||
trait MyIterator<A> {
|
||||
fn next(&mut self) -> A;
|
||||
}
|
||||
```
|
||||
|
||||
Would generate the following output:
|
||||
|
||||
```text
|
||||
error[E0277]: message
|
||||
--> <anon>:14:5
|
||||
|
|
||||
14 | iterate_chars(&[1, 2, 3][..]);
|
||||
| ^^^^^^^^^^^^^ label
|
||||
|
|
||||
= note: note
|
||||
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
||||
= note: required by `iterate_chars`
|
||||
```
|
||||
|
||||
To allow more targeted error messages, it is possible to filter the
|
||||
application of these fields based on a variety of attributes when using
|
||||
`on`:
|
||||
|
||||
- `crate_local`: whether the code causing the trait bound to not be
|
||||
fulfilled is part of the user's crate. This is used to avoid suggesting
|
||||
code changes that would require modifying a dependency.
|
||||
- Any of the generic arguments that can be substituted in the text can be
|
||||
referred by name as well for filtering, like `Rhs="i32"`, except for
|
||||
`Self`.
|
||||
- `_Self`: to filter only on a particular calculated trait resolution, like
|
||||
`Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
|
||||
keyword which cannot appear in attributes.
|
||||
- `direct`: user-specified rather than derived obligation.
|
||||
- `from_method`: usable both as boolean (whether the flag is present, like
|
||||
`crate_local`) or matching against a particular method. Currently used
|
||||
for `try`.
|
||||
- `from_desugaring`: usable both as boolean (whether the flag is present)
|
||||
or matching against a particular desugaring. The desugaring is identified
|
||||
with its variant name in the `DesugaringKind` enum.
|
||||
|
||||
For example, the `Iterator` trait can be annotated in the following way:
|
||||
|
||||
```rust,compile_fail
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
_Self="&str",
|
||||
note="call `.chars()` or `.as_bytes()` on `{Self}"
|
||||
),
|
||||
message="`{Self}` is not an iterator",
|
||||
label="`{Self}` is not an iterator",
|
||||
note="maybe try calling `.iter()` or a similar method"
|
||||
)]
|
||||
pub trait Iterator {}
|
||||
```
|
||||
|
||||
Which would produce the following outputs:
|
||||
|
||||
```text
|
||||
error[E0277]: `Foo` is not an iterator
|
||||
--> src/main.rs:4:16
|
||||
|
|
||||
4 | for foo in Foo {}
|
||||
| ^^^ `Foo` is not an iterator
|
||||
|
|
||||
= note: maybe try calling `.iter()` or a similar method
|
||||
= help: the trait `std::iter::Iterator` is not implemented for `Foo`
|
||||
= note: required by `std::iter::IntoIterator::into_iter`
|
||||
|
||||
error[E0277]: `&str` is not an iterator
|
||||
--> src/main.rs:5:16
|
||||
|
|
||||
5 | for foo in "" {}
|
||||
| ^^ `&str` is not an iterator
|
||||
|
|
||||
= note: call `.chars()` or `.bytes() on `&str`
|
||||
= help: the trait `std::iter::Iterator` is not implemented for `&str`
|
||||
= note: required by `std::iter::IntoIterator::into_iter`
|
||||
```
|
||||
|
||||
If you need to filter on multiple attributes, you can use `all`, `any` or
|
||||
`not` in the following way:
|
||||
|
||||
```rust,compile_fail
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
all(_Self="&str", T="std::string::String"),
|
||||
note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
|
||||
)
|
||||
)]
|
||||
pub trait From<T>: Sized { /* ... */ }
|
||||
```
|
|
@ -116,7 +116,7 @@
|
|||
#![feature(unsize)]
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
#![feature(nll)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(no_core)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
|
|
@ -607,7 +607,7 @@ position that needs that trait. For example, when the following code is
|
|||
compiled:
|
||||
|
||||
```compile_fail
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
|
@ -639,7 +639,7 @@ position that needs that trait. For example, when the following code is
|
|||
compiled:
|
||||
|
||||
```compile_fail
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
|
@ -669,7 +669,7 @@ position that needs that trait. For example, when the following code is
|
|||
compiled:
|
||||
|
||||
```compile_fail
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
|
|
|
@ -284,7 +284,7 @@
|
|||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![cfg_attr(bootstrap, feature(non_exhaustive))]
|
||||
#![feature(on_unimplemented)]
|
||||
#![cfg_attr(bootstrap, feature(on_unimplemented))]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(panic_internals)]
|
||||
|
|
|
@ -134,9 +134,6 @@ declare_features! (
|
|||
/// Allows using `rustc_*` attributes (RFC 572).
|
||||
(active, rustc_attrs, "1.0.0", Some(29642), None),
|
||||
|
||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||
(active, on_unimplemented, "1.0.0", Some(29628), None),
|
||||
|
||||
/// Allows using the `box $expr` syntax.
|
||||
(active, box_syntax, "1.0.0", Some(49733), None),
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ macro_rules! experimental {
|
|||
}
|
||||
|
||||
const IMPL_DETAIL: &str = "internal implementation detail";
|
||||
const INTERAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
||||
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
||||
|
||||
pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
|
||||
|
||||
|
@ -418,14 +418,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
|
||||
"the `linkage` attribute is experimental and not portable across platforms",
|
||||
),
|
||||
rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE),
|
||||
rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERNAL_UNSTABLE),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Macro related:
|
||||
// ==========================================================================
|
||||
|
||||
rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERAL_UNSTABLE),
|
||||
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
|
||||
rustc_attr!(
|
||||
rustc_macro_transparency, Whitelisted,
|
||||
template!(NameValueStr: "transparent|semitransparent|opaque"),
|
||||
|
@ -436,17 +436,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// Internal attributes, Diagnostics related:
|
||||
// ==========================================================================
|
||||
|
||||
gated!(
|
||||
rustc_attr!(
|
||||
rustc_on_unimplemented, Whitelisted,
|
||||
template!(
|
||||
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
|
||||
NameValueStr: "message"
|
||||
),
|
||||
on_unimplemented,
|
||||
experimental!(rustc_on_unimplemented),
|
||||
INTERNAL_UNSTABLE
|
||||
),
|
||||
// Whitelists "identity-like" conversion methods to suggest on type mismatch.
|
||||
rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE),
|
||||
rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERNAL_UNSTABLE),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Const related:
|
||||
|
@ -454,7 +453,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||
rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL),
|
||||
rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE),
|
||||
rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERNAL_UNSTABLE),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Layout related:
|
||||
|
|
|
@ -99,6 +99,9 @@ declare_features! (
|
|||
/// + `__register_diagnostic`
|
||||
/// +`__build_diagnostic_array`
|
||||
(removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
|
||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||
/// (Moved to `rustc_attrs`.)
|
||||
(removed, on_unimplemented, "1.40.0", None, None, None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: removed features
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// revisions: cfail1 cfail2
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![deny(unused_attributes)]
|
||||
|
||||
#[rustc_on_unimplemented = "invalid"]
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
// Test that `#[rustc_on_unimplemented]` is gated by `on_unimplemented` feature
|
||||
// gate.
|
||||
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||
//~^ ERROR the `#[rustc_on_unimplemented]` attribute is an experimental feature
|
||||
trait Foo<Bar>
|
||||
{}
|
||||
|
||||
fn main() {}
|
|
@ -1,6 +1,6 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// access to the variable, whether that mutable access be used
|
||||
// for direct assignment or for taking mutable ref. Issue #6801.
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_on_unimplemented(
|
||||
message="the message"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
|
||||
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||
//~^ ERROR this is an internal attribute that will never be stable
|
||||
trait Foo<Bar>
|
||||
{}
|
||||
|
||||
fn main() {}
|
|
@ -1,11 +1,11 @@
|
|||
error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-on-unimplemented.rs:4:1
|
||||
error[E0658]: this is an internal attribute that will never be stable
|
||||
--> $DIR/feature-gate-on-unimplemented.rs:3:1
|
||||
|
|
||||
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/29628
|
||||
= help: add `#![feature(on_unimplemented)]` to the crate attributes to enable
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/29642
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Test if the on_unimplemented message override works
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
||||
struct Foo<T>(T);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Test if the on_unimplemented message override works
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
||||
#[rustc_on_unimplemented = "invalid"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub mod Bar {
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{Foo}`"]
|
||||
|
|
Loading…
Add table
Reference in a new issue