Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTokenStream::parse does not resolve with Span::call_site() #50050
Comments
This comment has been minimized.
This comment has been minimized.
|
Looking at the symptoms, likely to be the same bug as #50061 |
This comment has been minimized.
This comment has been minimized.
|
This still happens on the latest nightly ( |
This comment has been minimized.
This comment has been minimized.
alexcrichton
changed the title
Only the presence of futures-await regresses error-chain-derive
TokenStream::parse does not resolve with Span::call_site()
May 1, 2018
This comment has been minimized.
This comment has been minimized.
|
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? |
kennytm
added
A-macros-2.0
C-bug
labels
May 1, 2018
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton |
petrochenkov
self-assigned this
May 1, 2018
This comment has been minimized.
This comment has been minimized.
|
Sure yeah, I will test out that hypothesis tomorrow morning! |
This comment has been minimized.
This comment has been minimized.
|
Ah unfortunately this diff on 5a662bf produced the same error:
|
aturon
referenced this issue
May 7, 2018
Closed
Tracking issue for RFC 1566: Procedural macros #38356
alexcrichton
referenced this issue
May 7, 2018
Closed
proc_macro! expansion can refer to items defined in the root w/o importing them #50504
This comment has been minimized.
This comment has been minimized.
jan-hudec
commented
May 9, 2018
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 |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
jan-hudec
commented
May 9, 2018
|
Except if |
This comment has been minimized.
This comment has been minimized.
|
@jan-hudec oh it was always the intention that stringifcation loses all hygiene information. The upcoming |
This comment has been minimized.
This comment has been minimized.
|
I'm running into this on multiple projects: it's a show-stopper. I believe some form of this may also be causing SergioBenitez/Rocket#635. One possible band-aid could be to add a |
SergioBenitez
referenced this issue
May 16, 2018
Closed
Hygiene break in macros involving string containing single quote #50061
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
@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 SergioBenitez/Rocket#635 reports that their particular issue is resolved by falling back to |
This comment has been minimized.
This comment has been minimized.
|
Ok, that's good. |
This comment has been minimized.
This comment has been minimized.
|
I did some more testing. I'm using |
This comment has been minimized.
This comment has been minimized.
Arnavion
commented
May 16, 2018
•
|
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). |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
If I won't be able to implement |
This comment has been minimized.
This comment has been minimized.
|
Ok awesome, thanks @petrochenkov! |
alexcrichton
added
the
A-macros-1.2
label
May 22, 2018
petrochenkov
referenced this issue
May 26, 2018
Open
Implement PartialEq for Ident, PartialEq for TokenStream #51074
This comment has been minimized.
This comment has been minimized.
|
Status update: I started working on |
Manishearth
referenced this issue
May 30, 2018
Closed
"path starts with module" lint fails with rustfix when triggered in macro #51205
This was referenced Jun 18, 2018
This comment has been minimized.
This comment has been minimized.
|
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. |
petrochenkov
referenced this issue
Jun 24, 2018
Merged
hygiene: Implement transparent marks and use them for call-site hygiene in proc-macros #51762
This comment has been minimized.
This comment has been minimized.
|
#51762 is submitted. |
bors
added a commit
that referenced
this issue
Jun 24, 2018
bors
added a commit
that referenced
this issue
Jun 24, 2018
bors
added a commit
that referenced
this issue
Jun 25, 2018
Mark-Simulacrum
added a commit
to Mark-Simulacrum/rust
that referenced
this issue
Jun 30, 2018
bors
added a commit
that referenced
this issue
Jun 30, 2018
bors
added a commit
that referenced
this issue
Jun 30, 2018
bors
closed this
in
#51762
Jun 30, 2018
This comment has been minimized.
This comment has been minimized.
|
Is this fully fixed? We're still seeing issues on SergioBenitez/Rocket#635, and I can also externally confirm that I'm seeing similar issues with other proc-macro/macro interactions. |
This comment has been minimized.
This comment has been minimized.
|
@SergioBenitez |
golddranks commentedApr 18, 2018
•
edited by alexcrichton
Updated description
The following procedural macro:
fails when invoked as:
with the error message:
Original description
Linking the
futures-awaitcrate and a crate that useserror-chain-derivetogether breaks the build. Here's a simple example: https://github.com/golddranks/test_futures_await_error_chain_derive Either of the two dependencies (futures-awaitanddotenv, 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-deriveis 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 scopeIt seems like just the presence of
futures-awaitsomehow affects how the Derive macros 1.1 hygiene works; however, the derive macros are stable, so this is an undesirable thing.