-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Added byte position range for proc_macro::Span
#109002
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @petrochenkov (or someone else) soon. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
Sorry, I did not check any of the |
@michaelvanstraten I think the failing CI job just runs |
Thanks, got the same error locally. |
Some changes occurred in src/tools/rust-analyzer cc @rust-lang/wg-rls-2 |
Personally I think the API itself is a good addition, but for other things I wonder about different design:
|
I get where you are coming from with the name, I had an issue with that as well. I cast the u32 to an usize to be consistent with LineColumn, but that will probably be only temporary. |
I follow the stability of various features on the proc-macro crate for a wile now and I don't really understand why many of the things related to the |
How is the returned value supposed to be used? |
If the byte range is from the "root" |
It has some meaning in the context of the proc-macro crate in the sense that you get a relative token stream. If you take any token from that stream, get its byte range, and then subtract the lower byte index of the first token in the stream, you get a relative position. Making the position relative is first of all tedious to implementation and second of all you lose the ability to get a absolute positive of the token. |
Let me give some context, I am working on a crate which parses the source text of a token stream using some grammar rules. The parser produces tokens with a relative offset byte offset to the start of the input string slice. If want to translate these tokens span back to the original i need to know relative byte offset of each input span. Why would I like to translate back to the original spans? The first reason is the issue of error reporting, which, if you have worked with proc-macro, is terrible if you don't have the original tokens to work of. And the second reason is because I what some of the original token from the input stream in the output stream. I know that my problem is mainly caused by the lack of custom error reporting available in the proc-macro crate but the issue that addresses this has not been updated for many years and this pull request offers a simple solution. Also, nothing prevents anybody to use the Debug implementation to parse this information programmatically even though it should be interpreted by a human. |
Except it being entirely undocumented and unstable, and being able to change at any moment. |
I still don't understand the use case from #109002 (comment).
What is the "source text" of a token stream? Having an example would be much more clear. |
let mut input_stream_iter = input.into_iter()
let input_span = match (input_stream_iter.next(), input_stream_iter.last()) {
(Some(first_token), Some(last_token)) => first_token
.span()
.join(last_token.span())
.expect("the two spans are from the same file"),
(Some(first_token), None) => first_token.span(),
_ => return Ok(...),
};
let Some(source_text) = input_span.source_text() else {
return Err(...);
}; I extract the source text from a given token stream, which then gets parsed using some sort of grammar. The parsed grammar then gets validated and in case of an error I want to attribute that error back to a Span in the input token stream. |
Could you give an example? |
With relative byte range, I mean that the lowest byte of the first span in a token stream passed to a proc-macro would be zero and every other span would have a relative byte range to the first. |
I am sorry I did not know that, that really makes the absolute value meaningless. |
I don't know 🤷 |
Okay, still if the byte span values are meaningless in the file they still give relative information. Could we merge this with a notice that the values are from the start of the |
I think this would be translatable using the |
The Is this now mergeable @petrochenkov? |
Should be fine as an unstable method, but I wouldn't want to stabilize neither this method nor Span difference and length (#109002 (comment)) are better stabilized instead to address your use case. @bors r+ |
☀️ Test successful - checks-actions |
Finished benchmarking commit (1151ea6): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
|
…nkov Added byte position range for `proc_macro::Span` Currently, the [`Debug`](https://doc.rust-lang.org/beta/proc_macro/struct.Span.html#impl-Debug-for-Span) implementation for [`proc_macro::Span`](https://doc.rust-lang.org/beta/proc_macro/struct.Span.html#) calls the debug function implemented in the trait implementation of `server::Span` for the type `Rustc` in the `rustc-expand` crate. The current implementation, of the referenced function, looks something like this: ```rust fn debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { format!("{:?}", span) } else { format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) } } ``` It returns the byte position of the [`Span`](https://doc.rust-lang.org/beta/proc_macro/struct.Span.html#) as an interpolated string. Because this is currently the only way to get a spans position in the file, I might lead someone, who is interested in this information, to parsing this interpolated string back into a range of bytes, which I think is a very non-rusty way. The proposed `position()`, method implemented in this PR, gives the ability to directly get this info. It returns a [`std::ops::Range`](https://doc.rust-lang.org/std/ops/struct.Range.html#) wrapping the lowest and highest byte of the [`Span`](https://doc.rust-lang.org/beta/proc_macro/struct.Span.html#). I put it behind the `proc_macro_span` feature flag because many of the other functions that have a similar footprint also are annotated with it, I don't actually know if this is right. It would be great if somebody could take a look at this, thank you very much in advanced.
Add span to group. This appears to fix #14959, but I've never contributed to rust-analyzer before and there were some things that confused me: - I had to add the `fn byte_range` method to get it to build. This was added to rust in [April](rust-lang/rust#109002), so I don't understand why it wasn't needed until now - When testing, I ran into the fact that rust recently updated its `METADATA_VERSION`, so I had to test this with nightly-2023-05-20. But then I noticed that rust has its own copy of `rust-analyzer`, and the metadata version bump has already been [handled there](rust-lang/rust@60e95e7). So I guess I don't really understand the relationship between the code there and the code here.
Add span to group. This appears to fix #14959, but I've never contributed to rust-analyzer before and there were some things that confused me: - I had to add the `fn byte_range` method to get it to build. This was added to rust in [April](rust-lang/rust#109002), so I don't understand why it wasn't needed until now - When testing, I ran into the fact that rust recently updated its `METADATA_VERSION`, so I had to test this with nightly-2023-05-20. But then I noticed that rust has its own copy of `rust-analyzer`, and the metadata version bump has already been [handled there](rust-lang/rust@60e95e7). So I guess I don't really understand the relationship between the code there and the code here.
Add span to group. This appears to fix #14959, but I've never contributed to rust-analyzer before and there were some things that confused me: - I had to add the `fn byte_range` method to get it to build. This was added to rust in [April](rust-lang/rust#109002), so I don't understand why it wasn't needed until now - When testing, I ran into the fact that rust recently updated its `METADATA_VERSION`, so I had to test this with nightly-2023-05-20. But then I noticed that rust has its own copy of `rust-analyzer`, and the metadata version bump has already been [handled there](rust-lang/rust@60e95e7). So I guess I don't really understand the relationship between the code there and the code here.
Add span to group. This appears to fix #14959, but I've never contributed to rust-analyzer before and there were some things that confused me: - I had to add the `fn byte_range` method to get it to build. This was added to rust in [April](rust-lang/rust#109002), so I don't understand why it wasn't needed until now - When testing, I ran into the fact that rust recently updated its `METADATA_VERSION`, so I had to test this with nightly-2023-05-20. But then I noticed that rust has its own copy of `rust-analyzer`, and the metadata version bump has already been [handled there](rust-lang/rust@60e95e7). So I guess I don't really understand the relationship between the code there and the code here.
Add span to group. This appears to fix #14959, but I've never contributed to rust-analyzer before and there were some things that confused me: - I had to add the `fn byte_range` method to get it to build. This was added to rust in [April](rust-lang/rust#109002), so I don't understand why it wasn't needed until now - When testing, I ran into the fact that rust recently updated its `METADATA_VERSION`, so I had to test this with nightly-2023-05-20. But then I noticed that rust has its own copy of `rust-analyzer`, and the metadata version bump has already been [handled there](rust-lang/rust@60e95e7). So I guess I don't really understand the relationship between the code there and the code here.
Currently, the
Debug
implementation forproc_macro::Span
calls the debug function implemented in the trait implementation ofserver::Span
for the typeRustc
in therustc-expand
crate.The current implementation, of the referenced function, looks something like this:
It returns the byte position of the
Span
as an interpolated string.Because this is currently the only way to get a spans position in the file, I might lead someone, who is interested in this information, to parsing this interpolated string back into a range of bytes, which I think is a very non-rusty way.
The proposed
position()
, method implemented in this PR, gives the ability to directly get this info.It returns a
std::ops::Range
wrapping the lowest and highest byte of theSpan
.I put it behind the
proc_macro_span
feature flag because many of the other functions that have a similar footprint also are annotated with it, I don't actually know if this is right.It would be great if somebody could take a look at this, thank you very much in advanced.