Skip to content

Commit 17f0e8e

Browse files
committed
rewrite: Change association method
Before this patch, `thin_delegate` used a global variable in proc macro to transfer definitions of traits and structs/enums to where it generates impl of a trait. This method is problematic. For example, it's not ensured that the same process is used to invoke proc macros, even if it's in the same compilation unit (crate). E.g. incremental builds like rust-analyzer. See e.g. [1], [2], and [3] for more details. We resolve this problem by using declarative macros to transfer the data. This CL updates fundamental structures of this crate and updates tests as much as possible. Remaining tests will be updated in the next patches. [1] rust-lang/rust#44034 [2] https://users.rust-lang.org/t/simple-state-in-procedural-macro/68204 [3] https://stackoverflow.com/questions/52910783/is-it-possible-to-store-state-within-rusts-procedural-macros
1 parent a382b8c commit 17f0e8e

32 files changed

+600
-798
lines changed

src/lib.rs

Lines changed: 344 additions & 479 deletions
Large diffs are not rendered by default.

src/punctuated_parser.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/self_replacer.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use proc_macro2::Span;
2+
use syn::visit_mut::VisitMut;
3+
4+
pub(crate) fn make_self_hygienic_in_signature(mut target: syn::Signature) -> syn::Signature {
5+
let mut visitor = Visitor;
6+
visitor.visit_signature_mut(&mut target);
7+
target
8+
}
9+
10+
/// Replaces `self` to avoid issues around macro hygienicity.
11+
///
12+
/// `thin_delegate` transfers definition of a trait and a struct/enum to
13+
/// `#[thin_delegate::derive_delegate]` by using declarative macro.
14+
/// `#[thin_delegate::internal_derive_delegate]` processes a token stream in the macro context.
15+
/// If we use `self` in this token stream as is, an error like the following arise:
16+
///
17+
/// ```ignore
18+
/// error[E0424]: expected value, found module `self`
19+
/// --> src/main.rs:24:1
20+
/// |
21+
/// 3 | fn hello(&self) -> String;
22+
/// | -- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
23+
/// ...
24+
/// 24 | #[thin_delegate::derive_delegate]
25+
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` value is a keyword only available in methods with a `self` parameter
26+
/// |
27+
/// = note: this error originates in the attribute macro `::thin_delegate::internal_derive_delegate` which comes from the expansion of the attribute macro `thin_delegate::derive_delegate` (in Nightly builds, run with -Z macro-backtrace for more info)
28+
/// For more information about this error, try `rustc --explain E0424`.
29+
/// ```
30+
///
31+
/// Rust's macro hygienicity forbids use of `self` in declarative macros.
32+
/// We can resolve it by replacing `self` in the token stream by `self` generated in a proc macro,
33+
/// which this `Visitor` does.
34+
struct Visitor;
35+
36+
impl VisitMut for Visitor {
37+
// We only replaces `self` in receiver position, as we need it for `syn::Signature`.
38+
fn visit_receiver_mut(&mut self, node: &mut syn::Receiver) {
39+
node.self_token = syn::Token![self](Span::call_site());
40+
}
41+
}

src/storage.rs

Lines changed: 0 additions & 99 deletions
This file was deleted.

tests/ui.old/fail_num_of_generic_parameters_differ.stderr

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/ui.old/fail_parameter_cant_substituted_to_argument.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/ui.old/fail_parameter_cant_substituted_to_argument.stderr

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/ui.old/fail_register_conflicted.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.

tests/ui.old/fail_register_conflicted.stderr

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/ui.old/fail_register_missing.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/ui.old/fail_register_missing.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/ui.old/pass_generics_specialize_complex.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/ui.old/pass_multiple_derive.rs

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// TODO: Support external crates.
2+
#[thin_delegate::register]
3+
pub trait AsRef<T: ?Sized> {
4+
/// Converts this type into a shared reference of the (usually inferred) input type.
5+
#[stable(feature = "rust1", since = "1.0.0")]
6+
fn as_ref(&self) -> &T;
7+
}
8+
9+
#[thin_delegate::register]
10+
struct Hoge(Box<dyn Fn(usize) -> usize>);
11+
12+
#[thin_delegate::derive_delegate]
13+
impl AsRef<(dyn Fn(usize) -> usize + 'static)> for Hoge {}
14+
15+
fn main() {}

tests/ui/_pass_multiple_derive.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// TODO: Support external crates.
2+
#[thin_delegate::register]
3+
pub trait ToString {
4+
/// Converts the given value to a `String`.
5+
///
6+
/// # Examples
7+
///
8+
/// ```
9+
/// let i = 5;
10+
/// let five = String::from("5");
11+
///
12+
/// assert_eq!(five, i.to_string());
13+
/// ```
14+
#[rustc_conversion_suggestion]
15+
#[stable(feature = "rust1", since = "1.0.0")]
16+
#[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")]
17+
fn to_string(&self) -> String;
18+
}
19+
20+
#[thin_delegate::register]
21+
pub trait Hello: ToString {
22+
fn hello(&self) -> String;
23+
}
24+
25+
impl Hello for String {
26+
fn hello(&self) -> String {
27+
format!("hello, {}", &self.to_string())
28+
}
29+
}
30+
31+
impl Hello for char {
32+
fn hello(&self) -> String {
33+
format!("hello, {}", &self.to_string())
34+
}
35+
}
36+
37+
#[thin_delegate::register]
38+
enum Hoge {
39+
A(String),
40+
B(char),
41+
}
42+
43+
#[thin_delegate::derive_delegate]
44+
impl ToString for Hoge {}
45+
46+
#[thin_delegate::derive_delegate]
47+
impl Hello for Hoge {}
48+
49+
fn main() {
50+
let hoge = Hoge::A("a".to_string());
51+
assert_eq!(hoge.hello(), "hello, a");
52+
53+
let hoge = Hoge::B('b');
54+
assert_eq!(hoge.hello(), "hello, b");
55+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[thin_delegate::register]
2+
struct Hoge(String);
3+
4+
#[thin_delegate::derive_delegate]
5+
impl Hoge {}
6+
7+
fn main() {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: expected `impl <Trait> for <Type>`
2+
--> tests/ui/fail_derive_delegate_for_impl_without_trait.rs:5:1
3+
|
4+
5 | impl Hoge {}
5+
| ^^^^^^^^^^^^

0 commit comments

Comments
 (0)