Skip to content

Commit ae7cda5

Browse files
dtolnaydanielhenrymantilla
authored andcommitted
eddyb autoref trick written by dtolnay and tweaked by danielhenrymantilla
Fix stability annotations `autoref!` cleanup: improve comments, and move it under `core::ops`
1 parent 0265a3e commit ae7cda5

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

library/core/src/macros/mod.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,15 @@ macro_rules! r#try {
515515
#[macro_export]
516516
#[stable(feature = "rust1", since = "1.0.0")]
517517
#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")]
518+
#[allow_internal_unstable(autoref)]
518519
macro_rules! write {
519520
($dst:expr, $($arg:tt)*) => {
520-
$dst.write_fmt($crate::format_args!($($arg)*))
521+
match $crate::ops::autoref::autoref_mut!($dst) {
522+
mut _dst => {
523+
let result = _dst.write_fmt($crate::format_args!($($arg)*));
524+
result
525+
}
526+
}
521527
};
522528
}
523529

@@ -549,13 +555,18 @@ macro_rules! write {
549555
#[macro_export]
550556
#[stable(feature = "rust1", since = "1.0.0")]
551557
#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")]
552-
#[allow_internal_unstable(format_args_nl)]
558+
#[allow_internal_unstable(autoref, format_args_nl)]
553559
macro_rules! writeln {
554560
($dst:expr $(,)?) => {
555561
$crate::write!($dst, "\n")
556562
};
557563
($dst:expr, $($arg:tt)*) => {
558-
$dst.write_fmt($crate::format_args_nl!($($arg)*))
564+
match $crate::ops::autoref::autoref_mut!($dst) {
565+
mut _dst => {
566+
let result = _dst.write_fmt($crate::format_args_nl!($($arg)*));
567+
result
568+
}
569+
}
559570
};
560571
}
561572

library/core/src/ops/autoref.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![allow(missing_docs, missing_debug_implementations)]
2+
// Poor man's `k#autoref` operator.
3+
//
4+
// See https://github.com/rust-lang/rust/issues/99684
5+
// and https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Desired.20behavior.20of.20.60write!.60.20is.20unimplementable
6+
// for some more context about this idea.
7+
//
8+
// Right now we polyfill this idea, by reducing support to `&mut`-autoref-only
9+
// (effectively "just" preventing an unnecessary `&mut` level of indirection
10+
// from being applied for a thing already behind a `&mut …`), which happens to
11+
// work for `&mut`-based `.write_fmt()` methods, and some cases of `&`-based
12+
// `.write_fmt()` —the whole duck-typed design / API of `write!` is asking for
13+
// trouble—, but won't work for a `self`-based `.write_fmt()`, as pointed out
14+
// here: https://github.com/rust-lang/rust/pull/100202#pullrequestreview-1064499226
15+
//
16+
// Finally, in order to reduce the chances of name conflicts as much as
17+
// possible, the method name is a bit mangled, and to prevent usage of this
18+
// method in stable-rust, an unstable const generic parameter that needs to be
19+
// turbofished is added to it as well.
20+
21+
/// The unstable const generic parameter achieving the "unstable seal" effect.
22+
#[unstable(feature = "autoref", issue = "none")]
23+
#[derive(Eq, PartialEq)]
24+
pub struct UnstableMethodSeal;
25+
26+
#[unstable(feature = "autoref", issue = "none")]
27+
pub trait AutoRef {
28+
#[unstable(feature = "autoref", issue = "none")]
29+
#[inline(always)]
30+
fn __rustc_unstable_auto_ref_mut_helper<const _SEAL: UnstableMethodSeal>(
31+
&mut self,
32+
) -> &mut Self {
33+
self
34+
}
35+
}
36+
37+
#[unstable(feature = "autoref", issue = "none")]
38+
impl<T: ?Sized> AutoRef for T {}
39+
40+
#[unstable(feature = "autoref", issue = "none")]
41+
#[allow_internal_unstable(autoref)]
42+
#[rustc_macro_transparency = "semitransparent"]
43+
pub macro autoref_mut($x:expr) {{
44+
use $crate::ops::autoref::AutoRef as _;
45+
$x.__rustc_unstable_auto_ref_mut_helper::<{ $crate::ops::autoref::UnstableMethodSeal }>()
46+
}}

library/core/src/ops/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@
139139
#![stable(feature = "rust1", since = "1.0.0")]
140140

141141
mod arith;
142+
#[doc(hidden)]
143+
#[unstable(feature = "autoref", issue = "none")]
144+
pub mod autoref;
142145
mod bit;
143146
mod control_flow;
144147
mod deref;

0 commit comments

Comments
 (0)