Make rustc_onunimplemented export path agnostic

This makes it so that all the matchers that match against paths use the
definition path instead of the export path. This removes all duplication
around `std`/`alloc`/`core`.

This is not necessarily optimal because we now depend on internal
implementation details like `core::ops::control_flow::ControlFlow`,
which is not very nice and probably not acceptable for a stable
`on_unimplemented`.

An alternative would be to just string-replace normalize away
`alloc`/`core` to `std` as a special case, keeping the export paths but
making it so that we're still fully standard library flavor agnostic.
This commit is contained in:
Nilstrieb 2023-10-16 19:33:25 +02:00
parent 98c1e3d95b
commit 414135d522
7 changed files with 37 additions and 64 deletions

View file

@ -180,8 +180,9 @@ fn on_unimplemented_note(
flags.push((sym::cause, Some("MainFunctionType".to_string())));
}
// Add all types without trimmed paths.
ty::print::with_no_trimmed_paths!({
// Add all types without trimmed paths or visible paths, ensuring they end up with
// their "canonical" def path.
ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
@ -296,7 +297,7 @@ fn on_unimplemented_note(
{
flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
}
});
}));
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags)
@ -578,7 +579,9 @@ pub fn evaluate(
Some(tcx.features()),
&mut |cfg| {
let value = cfg.value.map(|v| {
OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
// `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map))
});
options.contains(&(cfg.name, value))

View file

@ -573,7 +573,7 @@ pub trait Into<T>: Sized {
#[rustc_diagnostic_item = "From"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(on(
all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")),
all(_Self = "&str", T = "alloc::string::String"),
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
))]
pub trait From<T>: Sized {

View file

@ -27,13 +27,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
on(
any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"),
_Self = "core::ops::range::RangeTo<Idx>",
label = "if you meant to iterate until a value, add a starting value",
note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
bounded `Range`: `0..end`"
),
on(
any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"),
_Self = "core::ops::range::RangeToInclusive<Idx>",
label = "if you meant to iterate until a value (including it), add a starting value",
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
to have a bounded `RangeInclusive`: `0..=end`"
@ -44,7 +44,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
),
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
on(
any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"),
_Self = "alloc::vec::Vec<T, A>",
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
),
on(
@ -52,7 +52,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
),
on(
any(_Self = "alloc::string::String", _Self = "std::string::String"),
_Self = "alloc::string::String",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
),
on(

View file

@ -573,59 +573,59 @@ impl<T: ?Sized> Copy for &T {}
#[lang = "sync"]
#[rustc_on_unimplemented(
on(
any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"),
_Self = "core::cell::once::OnceCell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
),
on(
any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"),
_Self = "core::cell::Cell<u8>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
),
on(
any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"),
_Self = "core::cell::Cell<u16>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
),
on(
any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"),
_Self = "core::cell::Cell<u32>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
),
on(
any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"),
_Self = "core::cell::Cell<u64>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
),
on(
any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"),
_Self = "core::cell::Cell<usize>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
),
on(
any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"),
_Self = "core::cell::Cell<i8>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
),
on(
any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"),
_Self = "core::cell::Cell<i16>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
),
on(
any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"),
_Self = "core::cell::Cell<i32>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
),
on(
any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"),
_Self = "core::cell::Cell<i64>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
),
on(
any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"),
_Self = "core::cell::Cell<isize>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
),
on(
any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"),
_Self = "core::cell::Cell<bool>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
),
on(
any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"),
_Self = "core::cell::Cell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
),
on(
any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"),
_Self = "core::cell::RefCell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
),
message = "`{Self}` cannot be shared between threads safely",

View file

@ -153,7 +153,7 @@ pub trait Index<Idx: ?Sized> {
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
),
on(
any(_Self = "alloc::string::String", _Self = "std::string::String"),
_Self = "alloc::string::String",
note = "you can use `.chars().nth()` or `.bytes().nth()`
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
),

View file

@ -226,14 +226,8 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::result::Result<T, E>",
_Self = "std::result::Result<T, E>",
),
any(
R = "core::option::Option<core::convert::Infallible>",
R = "std::option::Option<std::convert::Infallible>",
)
_Self = "core::result::Result<T, E>",
R = "core::option::Option<core::convert::Infallible>",
),
message = "the `?` operator can only be used on `Result`s, not `Option`s, \
in {ItemContext} that returns `Result`",
@ -243,10 +237,7 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::result::Result<T, E>",
_Self = "std::result::Result<T, E>",
)
_Self = "core::result::Result<T, E>",
),
// There's a special error message in the trait selection code for
// `From` in `?`, so this is not shown for result-in-result errors,
@ -259,14 +250,8 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::option::Option<T>",
_Self = "std::option::Option<T>",
),
any(
R = "core::result::Result<T, E>",
R = "std::result::Result<T, E>",
)
_Self = "core::option::Option<T>",
R = "core::result::Result<T, E>",
),
message = "the `?` operator can only be used on `Option`s, not `Result`s, \
in {ItemContext} that returns `Option`",
@ -276,10 +261,7 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::option::Option<T>",
_Self = "std::option::Option<T>",
)
_Self = "core::option::Option<T>",
),
// `Option`-in-`Option` always works, as there's only one possible
// residual, so this can also be phrased strongly.
@ -291,14 +273,8 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::ops::ControlFlow<B, C>",
_Self = "std::ops::ControlFlow<B, C>",
),
any(
R = "core::ops::ControlFlow<B, C>",
R = "std::ops::ControlFlow<B, C>",
)
_Self = "core::ops::control_flow::ControlFlow<B, C>",
R = "core::ops::control_flow::ControlFlow<B, C>",
),
message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
@ -309,10 +285,7 @@ pub trait Try: FromResidual {
on(
all(
from_desugaring = "QuestionMark",
any(
_Self = "core::ops::ControlFlow<B, C>",
_Self = "std::ops::ControlFlow<B, C>",
)
_Self = "core::ops::control_flow::ControlFlow<B, C>",
// `R` is not a `ControlFlow`, as that case was matched previously
),
message = "the `?` operator can only be used on `ControlFlow`s \

View file

@ -152,10 +152,7 @@ impl Sealed for ops::IndexRange {}
#[rustc_on_unimplemented(
on(T = "str", label = "string indices are ranges of `usize`",),
on(
all(
any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"),
_Self = "{integer}"
),
all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"),
note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
for more information, see chapter 8 in The Book: \
<https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"