-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
TokenStream::parse does not resolve with Span::call_site() #50050
Comments
Looking at the symptoms, likely to be the same bug as #50061 |
This still happens on the latest nightly ( |
I've updated the OP and issue title to reflect the underlying issue, minimized at https://gist.github.com/alexcrichton/6b4c56549c6732e697eb0aa9986bf398. The tl;dr; is that a @petrochenkov or @nrc, do y'all know where this might be occurring? |
@alexcrichton |
Sure yeah, I will test out that hypothesis tomorrow morning! |
Ah unfortunately this diff on 5a662bf produced the same error:
|
I am probably missing something, but to me it sounds about right. I would expect manually parsed code to be its own context. That's the hygiene. Similar to literal code in template macros, except proc macros don't have definition site, so the context is simply fresh. To refer to the symbol from the call site, you can replace it with the |
@jan-hudec I think you're right yeah, but the problem is that we've been advocating Macros 1.1 and 1.2 as "hygiene comes later, we're just copy/pasting code". That seems to not be the case and there's actual hygiene involved, which is unintended currently |
Except if |
@jan-hudec oh it was always the intention that stringifcation loses all hygiene information. The upcoming |
I'm running into this on multiple projects: it's a show-stopper. I believe some form of this may also be causing rwf2/Rocket#635. One possible band-aid could be to add a |
The following let code: &str = /* some Rust code with an identifier */;
let stream: proc_macro::TokenStream = code.parse().unwrap();
let stream: proc_macro::TokenStream = stream.into_iter()
.map(|mut tree| { tree.set_span(Span::call_site()); tree })
.collect(); Thus, the In particular, the issue I have is that name resolution information is lost when a In #![feature(proc_macro)]
extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;
#[macro_use] extern crate quote;
use syn::Ident;
use proc_macro::{Span, TokenStream};
use quote::Tokens;
fn create(ident: &Ident) -> Tokens {
// // This works.
// quote!(do_f!(#ident))
// // This does as well.
// let new_ident = Ident::from(ident.to_string());
// quote!(do_f!(#new_ident))
// // So does this.
// quote!(do_f!(x))
// // This does not.
// let source = format!("do_f!({})", ident);
// let expr: syn::Expr = syn::parse_str(&source).unwrap();
// quote!(#expr)
// // Neither does this.
// let source = format!("do_f!({})", ident);
// let stream: proc_macro2::TokenStream = source.parse().unwrap();
// quote!(#stream)
// Nor this.
let source = format!("do_f!({})", ident);
let stream: proc_macro2::TokenStream = source.parse().unwrap();
quote_spanned!(Span::call_site() => #stream)
}
#[proc_macro_attribute]
pub fn demo(_args: TokenStream, _input: TokenStream) -> TokenStream {
let ident = Ident::from("x");
let expr = create(&ident);
let tokens: Tokens = quote! {
macro_rules! do_f {
($id:ident) => ($id + 1)
}
fn f(#ident: usize) -> usize {
#expr
}
};
tokens.into()
} In #![feature(proc_macro)]
extern crate codegen;
use codegen::demo;
#[demo] struct X;
fn main() { } Results in: error[E0425]: cannot find value `x` in this scope
--> src/main.rs:7:1
|
7 | #[demo]
| ^^^^^^^ not found in this scope |
FWIW, interaction between "modern" macros ( I haven't looked into it yet and I suspect that right now only @jseyfried knows how it works in detail, and relying on work of one person that's not sanity checked by anyone else, and that never went through RFC or any other discussion (and in addition to that the person in question is not around anymore) is and almost guaranteed way to shoot the language in the foot. |
@petrochenkov This appears to be unrelated to whether #[proc_macro_attribute]
pub fn demo(_args: TokenStream, _input: TokenStream) -> TokenStream {
let ident = Ident::from("x");
let expr = create(&ident);
let tokens: Tokens = quote! {
macro do_f($id:ident) {
$id + 1
}
fn f(#ident: usize) -> usize {
#expr
}
};
tokens.into()
} Furthermore, this issue was introduced in a recent nightly, somewhere in the last few months. For instance, the author of rwf2/Rocket#635 reports that their particular issue is resolved by falling back to |
Ok, that's good. |
I did some more testing. I'm using |
Yes, because pm2 without the nightly feature stringifies the input and parses that. Only with the nightly feature does it use pm types directly. Edit: Also note that even if rocket doesn't enable the feature, something else in the deps tree might. That's what's going on in the OP (futures-await enables the feature and breaks derive-error-chain). |
OK, here's a fix for the "Updated description" in the original comment: The problem is that the pre-fix behavior was intended - tokens parsed from strings have different context from This means that produced local variables are hygienic, but everything else is not. Moreover, each string is a different Tokens parsed from strings had My commit above makes tokens parsed from strings (Implementation section) A solution giving both |
Thanks for the investigation @petrochenkov! Do you want to open a PR with your fix? I'd agree as well yeah that name resolution comes before backtraces/clippy |
If I won't be able to implement |
Ok awesome, thanks @petrochenkov! |
Status update: I started working on |
Some status update: I have an implementation for macro_rules! m {
() => {
let_x_transparent!();
let y = x;
}
}
m!(); generates an "unresolved So far it looks like I need to really dig into the core hygiene/resolution algorithms to fix this properly, perhaps by refactoring hygiene data in some way in which these opaque/transparent/semi-transparent interactions can be expressed more naturally than the current "syntax context transplantation" technique (see the large comment in In the meantime I'll probably just sumbit a PR with the buggy version this weekend. |
#51762 is submitted. |
hygiene: Implement transparent marks and use them for call-site hygiene in proc-macros Fixes #50050
hygiene: Implement transparent marks and use them for call-site hygiene in proc-macros Fixes rust-lang#50050
hygiene: Implement transparent marks and use them for call-site hygiene in proc-macros Fixes #50050
Is this fully fixed? We're still seeing issues on rwf2/Rocket#635, and I can also externally confirm that I'm seeing similar issues with other proc-macro/macro interactions. |
@SergioBenitez |
Updated description
The following procedural macro:
fails when invoked as:
with the error message:
Original description
Linking the
futures-await
crate and a crate that useserror-chain-derive
together breaks the build. Here's a simple example: https://github.com/golddranks/test_futures_await_error_chain_derive Either of the two dependencies (futures-await
anddotenv
, which useserror-chain-derive
) builds on its own (using the latest nightly), but together they refuse to build.This seems to have something to do with the defsite hygiene:
error-chain-derive
is using derive macros 1.1, and the syntax for using it is as follows: (from https://github.com/purpliminal/rust-dotenv/blob/master/src/errors.rs )|l| write!(f, "Error parsing line: '{}'", l)
breaks, because it can't findf
:cannot find value f in this scope
It seems like just the presence of
futures-await
somehow affects how the Derive macros 1.1 hygiene works; however, the derive macros are stable, so this is an undesirable thing.The text was updated successfully, but these errors were encountered: