-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
32 changed files
with
600 additions
and
798 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use proc_macro2::Span; | ||
use syn::visit_mut::VisitMut; | ||
|
||
pub(crate) fn make_self_hygienic_in_signature(mut target: syn::Signature) -> syn::Signature { | ||
let mut visitor = Visitor; | ||
visitor.visit_signature_mut(&mut target); | ||
target | ||
} | ||
|
||
/// Replaces `self` to avoid issues around macro hygienicity. | ||
/// | ||
/// `thin_delegate` transfers definition of a trait and a struct/enum to | ||
/// `#[thin_delegate::derive_delegate]` by using declarative macro. | ||
/// `#[thin_delegate::internal_derive_delegate]` processes a token stream in the macro context. | ||
/// If we use `self` in this token stream as is, an error like the following arise: | ||
/// | ||
/// ```ignore | ||
/// error[E0424]: expected value, found module `self` | ||
/// --> src/main.rs:24:1 | ||
/// | | ||
/// 3 | fn hello(&self) -> String; | ||
/// | -- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters | ||
/// ... | ||
/// 24 | #[thin_delegate::derive_delegate] | ||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` value is a keyword only available in methods with a `self` parameter | ||
/// | | ||
/// = 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) | ||
/// For more information about this error, try `rustc --explain E0424`. | ||
/// ``` | ||
/// | ||
/// Rust's macro hygienicity forbids use of `self` in declarative macros. | ||
/// We can resolve it by replacing `self` in the token stream by `self` generated in a proc macro, | ||
/// which this `Visitor` does. | ||
struct Visitor; | ||
|
||
impl VisitMut for Visitor { | ||
// We only replaces `self` in receiver position, as we need it for `syn::Signature`. | ||
fn visit_receiver_mut(&mut self, node: &mut syn::Receiver) { | ||
node.self_token = syn::Token![self](Span::call_site()); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
16 changes: 0 additions & 16 deletions
16
tests/ui.old/fail_parameter_cant_substituted_to_argument.rs
This file was deleted.
Oops, something went wrong.
7 changes: 0 additions & 7 deletions
7
tests/ui.old/fail_parameter_cant_substituted_to_argument.stderr
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// TODO: Support external crates. | ||
#[thin_delegate::register] | ||
pub trait AsRef<T: ?Sized> { | ||
/// Converts this type into a shared reference of the (usually inferred) input type. | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
fn as_ref(&self) -> &T; | ||
} | ||
|
||
#[thin_delegate::register] | ||
struct Hoge(Box<dyn Fn(usize) -> usize>); | ||
|
||
#[thin_delegate::derive_delegate] | ||
impl AsRef<(dyn Fn(usize) -> usize + 'static)> for Hoge {} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// TODO: Support external crates. | ||
#[thin_delegate::register] | ||
pub trait ToString { | ||
/// Converts the given value to a `String`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// let i = 5; | ||
/// let five = String::from("5"); | ||
/// | ||
/// assert_eq!(five, i.to_string()); | ||
/// ``` | ||
#[rustc_conversion_suggestion] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] | ||
fn to_string(&self) -> String; | ||
} | ||
|
||
#[thin_delegate::register] | ||
pub trait Hello: ToString { | ||
fn hello(&self) -> String; | ||
} | ||
|
||
impl Hello for String { | ||
fn hello(&self) -> String { | ||
format!("hello, {}", &self.to_string()) | ||
} | ||
} | ||
|
||
impl Hello for char { | ||
fn hello(&self) -> String { | ||
format!("hello, {}", &self.to_string()) | ||
} | ||
} | ||
|
||
#[thin_delegate::register] | ||
enum Hoge { | ||
A(String), | ||
B(char), | ||
} | ||
|
||
#[thin_delegate::derive_delegate] | ||
impl ToString for Hoge {} | ||
|
||
#[thin_delegate::derive_delegate] | ||
impl Hello for Hoge {} | ||
|
||
fn main() { | ||
let hoge = Hoge::A("a".to_string()); | ||
assert_eq!(hoge.hello(), "hello, a"); | ||
|
||
let hoge = Hoge::B('b'); | ||
assert_eq!(hoge.hello(), "hello, b"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#[thin_delegate::register] | ||
struct Hoge(String); | ||
|
||
#[thin_delegate::derive_delegate] | ||
impl Hoge {} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
error: expected `impl <Trait> for <Type>` | ||
--> tests/ui/fail_derive_delegate_for_impl_without_trait.rs:5:1 | ||
| | ||
5 | impl Hoge {} | ||
| ^^^^^^^^^^^^ |
Oops, something went wrong.