Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Span pointing to its own construction site like Location::caller #359

Open
ia0 opened this issue Nov 15, 2022 · 1 comment
Open

Span pointing to its own construction site like Location::caller #359

ia0 opened this issue Nov 15, 2022 · 1 comment

Comments

@ia0
Copy link

ia0 commented Nov 15, 2022

I couldn't easily figure by myself reading the code and documentation of proc-macro and proc-macro2, so asking here. Is it possible to generate a Span that points to its own span? Or maybe asked differently, is it possible to create a Span from (or similarly to) a core::panic::Location (or 2 to make it an actual span, but a point in code is enough for me)?

Here's the motivation (which I would understand if it's not something proc-macro is trying to address):

  • I would like to use proc-macro to generate code from some data-structure describing the code to be generated (see below for why this data-structure cannot be a token stream).
  • This data-structure would be built within the proc-macro crate itself (or eventually from a dependency crate).
  • When building this data-structure, I would like to "capture" the Span of constructor calls.
  • I would then use quote_spanned!() to generate the proc-macro output based on those Spans.
  • (I hope rust-analyzer would then be able to point me back to the correct place in the proc-macro crate when looking for definitions generated by the proc-macro.)

Here's a sketch of a concret example:

enum Input { ... }  // data-structure to generate code from

#[proc_macro]
pub fn generate(_: TokenStream) -> TokenStream {
    // We don't need the proc-macro input. We use the `Input` data-structure.
    let input = Input::generate();  // The input is actually constant, but built dynamically.
    input.into_token_stream().into()
}

impl Input {
    fn generate() -> Input {
        ...
        let span = Span::caller();  // This behaves like Location::caller();
        let sub_input = SubInput::Foo { span, ... };
        ...
        let span = Span::caller();  // All those calls could be split in multiple modules and possibly crates.
        Input::Bar { span, sub_input, ... }
    }
}

impl ToTokens for Input {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        ...
        tokens.extend(quote_spanned!(sub_input.span => ...));
        ...
    }
}

The reason to not use the input token stream is that it doesn't support going through modules recursively. I would like my data-structure (or equivalently the proc-macro input) to be hierarchically structured through multiple files like the module hierarchy in a crate does. In other words, the following alternatives would also work for me:

  • It is possible within a proc-macro to read the content of a file (relative to the initial macro invocation) as a token stream.
  • It is possible for a proc-macro to take a full crate as input, where modules are flattened as if it was a single file. (But this assumes the proc-macro input is valid Rust, which adds a usage constraint.)
@ia0
Copy link
Author

ia0 commented Dec 20, 2022

Actually found out about rust-lang/rust#92565, rust-lang/rfcs#3200, and in particular rust-lang/rust#55904, which may be solving my problem in a different way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant