-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Stabilize proc_macro Span::source_text #101991
Comments
Nominating to consider for partial stabilization. I remember we had a lot of conversation about some of the proc_macro APIs in the past. I don't remember this one in particular being of concern. Does anyone on @rust-lang/libs-api know of any blockers for stabilizing this? |
Most of the discussion was related to either user-defined diagnostics or the line/column information being exposed. I see no reason this can't be stabilized. |
@rfcbot merge |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
@matklad Do you have thoughts here? |
It would be nice to have an example in the docs for this API, if possible. One other thing that pops out at me is the return type of |
Yeah, I think getting the text of what's passed into a macro shouldn't be problematic. What could problematic is the macro somehow getting a span which "escapes" the macro (so, eg, the span for the whole file containing the macro) and querying the source of that, but I assume that's not possible. There's also a question of line-endings. Does the returned text preserve original line-endings, or is it allowed to normalize to |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
@rfcbot concern a question of line-endings |
Not the whole file, but it can certainly escape a single macro call, and can include totally unrelated items. It sounds similarly problematic as getting a span for the whole file. # Cargo.toml
[package]
name = "repro"
version = "0.0.0"
edition = "2021"
[lib]
proc-macro = true // src/lib.rs
#![feature(proc_macro_span)]
use proc_macro::TokenStream;
#[proc_macro]
pub fn source_text(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
let begin = iter.next().unwrap().span();
let end = iter.next().unwrap().span().resolved_at(begin);
let joined = begin.join(end).unwrap();
let source_text = joined.source_text().unwrap();
format!("{source_text:?}").parse().unwrap()
} // src/main.rs
macro_rules! source_text {
($end:ident) => {
repro::source_text!(start $end)
};
}
// huh
fn sick_fn_bro() {}
fn main() {
println!("{}", source_text!(end));
} $ cargo run
start $end)
};
}
// huh
fn sick_fn_bro() {}
fn main() {
println!("{}", source_text!(end @rfcbot concern span which escapes the macro Is |
I would personally expect that to fail at the source_text call (good find), unless we want to make more stringent guarantees about external spans being impossible to construct. (Personally my expectations of Span::join are that failures are about spans impossible to represent (from incompatible sources), not ones we choose not to let the user do things with) |
I wonder whether one should do
fn main() {
let s = python!(
print("hi")
);
println!("{}", s);
} For a macro: #[proc_macro]
pub fn python(_input: TokenStream) -> TokenStream {
let source_text = proc_macro::Span::call_site().source_text().unwrap();
format!("{source_text:?}").parse().unwrap()
} Then it currently outputs: python!(
print("hi")
) Which isn't that nice. It's not just not what shows up in the code, as the python!(
print("hi")
) I wonder if there is some way of processing that we could arrive at something like: python!(
print("hi")
) |
(FTR, @dtolnay 's example above is using |
I think modifying whitespace outside of newline normalization is a bad idea. I'm not sure what usecase the API would be useful for if that were the case. Even for diagnostics/errors, changing the code formatting is detrimental? Or well, I guess for indoc-style it is consistent across the contents of the macro so it's maybe fine? I would be worried about how it'd effect mapping spans to the contents of source_text (such as pointing to specific tokens in an error) |
I don't think we should do any modification to the source text, even newline normalization. I think we should just return the source text verbatim. If a user wants to normalize it, they can do so (or use any number of crates to do so); however, a user can't un-normalize it if we've normalized it. |
To clarify why normalizing might be a good idea: What line endings are used is already somewhat ill-defined. The source code of the same git project checked out on Linux and on Windows would typically have different line-endings. If we don't normalize line-endings and expose them to proc-macros, that opens another avenue why, eg, I don't think that in practice there will be a lot of these sorts of problems, but if we are committed to reproducible builds in principle, it seems worthwhile to not add fundamental non-determinism, if we can help it. |
I think that differing newlines will already cause issues with reproducible builds since all of the spans will have different offsets, the debuginfo will be different, etc. I think it's reasonable to require configuring git to preserve line endings if you want reproducible builds. |
... and I now recall that we actually do normalize newlines already? rust/compiler/rustc_span/src/lib.rs Lines 1763 to 1844 in e1d7dec
|
I don't feel that either of these warrants blocking the stabilization of @rfcbot resolve a question of line-endings For line endings, either normalizing or not is okay with me. For spans that cross boundaries of a macro invocation, I'd probably prefer if |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
@dtolnay how would you deal with join being already exposed on stable, without an Option like interface? I've pointed that out above in the thread, linking to a comment that links to a join primitive in your syn crate. Given that the API is already stable and doesn't return an Option, it should IMO be |
That hack doesn't result in a joined |
@m-ou-se good point. I've tried building a similar primitive that joins spans in a similar fashion, but it doesn't work: fn join_spans(sp1: Span, sp2: Span) -> Span {
let begin = TokenTree::Ident(Ident::new("A", sp1));
let end = TokenTree::Ident(Ident::new("B", sp2));
let group = Group::new(Delimiter::None, [begin, end].into_iter().collect());
group.span()
} If you try that on the example from dtolnay given above, you get as output:
It's I think because the group wholly ignores the spans of its children and instead assumes the span of the macro invocation that created it. I guess this combination trick can only be used to issue compilation errors. So things work differently than I thought they would work. I'm sorry for having brought this up. Case rested :). |
Stabilization PR: #103197 |
…text, r=petrochenkov Stabilize proc_macro::Span::source_text Splits `proc_macro::Span::source_text` into a new feature gate and stabilizes it. The [FCP is complete](rust-lang#101991 (comment)). ```Rust impl Span { pub fn source_text(&self) -> Option<String>; } ``` Closes rust-lang#101991
…etrochenkov Stabilize proc_macro::Span::source_text Splits `proc_macro::Span::source_text` into a new feature gate and stabilizes it. The [FCP is complete](rust-lang/rust#101991 (comment)). ```Rust impl Span { pub fn source_text(&self) -> Option<String>; } ``` Closes #101991
In the interest of improving error/diagnostic quality for macros I'd like to try and get some of the
proc_macro_span
feature stabilized.While some of these APIs don't seem to have consensus on their effect on IDE/language server support, the
source_text
API seems both well-tested and to have consensus that its result only being invalidated by edits to the contents of the macro makes it a non-issue for IDE support (as noted by niko in #54725).API
@rustbot label +T-libs-api +A-macros +A-proc-macros
The text was updated successfully, but these errors were encountered: