-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Add a way to get shorter spans until char
for pointing at defs
#41214
Conversation
It's missing tests. |
Can we avoid manually tweaking spans like this? Historically this always have been a source of weird bugs. |
@nagisa from what I gather, there are a few ways of accomplishing the end goal of smaller diagnostic spans, all with problems:
@nikomatsakis, I just checked what happens with macros with this change and there's no detrimental difference: Before: $ rustc file2.rs
error[E0072]: recursive type `Foo` has infinite size
--> file2.rs:3:9
|
3 | struct $n {
| _________^ starting here...
4 | | field: $n
5 | | }
| |_________^ ...ending here: recursive type has infinite size
...
9 | mk_struct!(Foo);
| ---------------- in this macro invocation After: $ ./stage1/bin/rustc file2.rs
error[E0072]: recursive type `Foo` has infinite size
--> file2.rs:3:9
|
3 | struct $n {
| ^^^^^^^^^ recursive type has infinite size
...
9 | mk_struct!(Foo);
| ---------------- in this macro invocation I'm also thinking that if, for example, a Instead of: error[E0072]: recursive type `A` has infinite size
--> file2.rs:1:1
|
1 | struct
| _^ starting here...
2 | | A
| |_^ ...ending here: recursive type has infinite size given that you're already displaying a multiline span, just go with the current output: error[E0072]: recursive type `A` has infinite size
--> file2.rs:1:1
|
1 | struct
| _^ starting here...
2 | | A
3 | | {
4 | | a: A,
5 | | }
| |_^ ...ending here: recursive type has infinite size |
60631ed
to
033332b
Compare
```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | ^^^^^^^^ recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ``` vs ```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | _^ starting here... 11 | | x: X, 12 | | } | |_^ ...ending here: recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ```
033332b
to
439ff69
Compare
Maybe there should be a way to run the LALR parser on spans and match on the concrete syntax tree? |
I'll rather have one of the parser guys look at this. |
Personally, I think we should have a "short span" for each item that probably consists of only the ident, and e.g. store it in metadata. I'm not afraid of performance - we don't have that much items. |
I'm inclined to agree with this, though I've not looked over this PR, which seems like a potentially cute approach to the problem. (At least, having a "short span" for each item was the way I expected us to address this problem.) |
Still, this PR seems to work -- I'd love to reduce our reliance on fancy ASCII art :) -- so I'd be happy to accept it, if we feel that it's sufficiently robust around macros etc (which I admit isn't entirely clear to me). |
Fair enough, but that will be a much larger PR that I won't be tackling
I'd like to measure memory usage before and after that change before categorically saying it has negligible impact on projects the size of
I started doing that while on the road, and after severals hours of treading water I tried this approach which got me a huge bang for the buck (literally two
I'd be happy to add more test cases to make sure this behaves correctly, but I feel confident about this not breaking things as it needs to be added on each diagnostic creation/call explicitly and I haven't come up with any part of the grammar that would use |
@estebank
Here are some stats from adding spans to path segments. The number of items is order of magnitude smaller than number of path segments, so new spans for items shouldn't be a problem. This PR is a hack and the heuristics are imperfect, e.g. multiline diagnostics for
are still bad. I also don't know how exactly spans interact with macros, @jseyfried is the specialist here. However, multiline spans are horrible and turn something that is supposed to be useful - error messages, into something harmful - long and unreadable ascii soup, especially if there are many of them, and this PR mostly fixes the problem. So I'm ready to r+ this if the proper solution is going to be implemented in the future. |
[meta] I actually have similar sentiment with regards to new helps and notes that continue to be actively added to the compiler. |
Fair enough, @petrochenkov.
What would appropriate output for It used to be error[E0072]: recursive type `ListNode` has infinite size
--> file2.rs:1:1
|
1 | struct
| ^ recursive type has infinite size Which I feel lacked all and any context, now it is error[E0072]: recursive type `ListNode` has infinite size
--> file2.rs:1:1
|
1 | struct
| _^ starting here...
2 | | ListNode
3 | | {
... |
9 | | }
| |_^ ...ending here: recursive type has infinite size which is admittedly verbose. And after cleaning up #41245 it should look like this: error[E0072]: recursive type `ListNode` has infinite size
--> file2.rs:1:1
|
1 | / struct
2 | | ListNode
3 | | {
... |
9 | | }
| |_^ recursive type has infinite size or error[E0072]: recursive type `ListNode` has infinite size
--> file2.rs:1:1
|
1 | / struct
2 | | ListNode
| |________^ recursive type has infinite size
I agree that multiline spans are overused at the moment, mainly because I added a way to display them before adding better spans for the errors. Multiline spans should be sparsely seen under normal circumstances. This is an attempt to go in that direction. I particularly find the lifetime errors quite galling (from #41343): error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____^ starting here...
12 | | vec.get(0)
13 | | }
| |_____^ ...ending here
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 11:60...
--> <anon>:11:61
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____________________________________________________________^ starting here...
12 | | vec.get(0)
13 | | }
| |_____^ ...ending here
note: ...so that method type is compatible with trait (expected fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>, found fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>)
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____^ starting here...
12 | | vec.get(0)
13 | | }
| |_____^ ...ending here
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 11:60...
--> <anon>:11:61
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____________________________________________________________^ starting here...
12 | | vec.get(0)
13 | | }
| |_____^ ...ending here
note: ...so that method type is compatible with trait (expected fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>, found fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>)
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____^ starting here...
12 | | vec.get(0)
13 | | }
| |_____^ ...ending here
error: aborting due to previous error If the couple of PRs I'm working on land, it would look like this instead: error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 11:60...
--> <anon>:11:61
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____________________________________________________________^
12 | | vec.get(0)
13 | | }
| |_____^
note: ...so that method type is compatible with trait (expected fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>, found fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>)
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 11:60...
--> <anon>:11:61
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| _____________________________________________________________^
12 | | vec.get(0)
13 | | }
| |_____^
note: ...so that method type is compatible with trait (expected fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>, found fn(&Foo, &std::vec::Vec<u32>) -> std::option::Option<&u32>)
--> <anon>:11:5
|
11 | fn bar<'a>(&self, vec: &'a Vec<u32>) -> Option<&'a u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error Which I feel is a slight improvement. (This diagnostic is still opaque for other reasons.)
Throwing too much text at the user is definitely a problem, but there are many cases where the error without the help information would be too vague to be of much use. Should we open a ticket, internals thread or rust-lang RFC to track the task of trimming the output of different errors that show too much text unnecessarily? By the way, multiline spans are visible now more often: they show up always on diagnostics regardless of length, showing the first 4 lines and the last 2 instead of showing only if the span is shorter than 9 lines. This could also be shortened to maybe the first 2 lines and last 2 instead. |
My take so far is that @estebank is correct -- we should land this, and open a FIXME or something to thread "short spans" the 'right' way. I think cases like (Mainly, I'd like to see improvement, and this seems like a pretty simple approach to get eliminate the worst cases.) |
📌 Commit 439ff69 has been approved by |
@petrochenkov would the scope of the ticket be covered by one of #33961, #35965 or #38246? |
⌛ Testing commit 439ff69 with merge bf38a4b... |
@bors retry - prioritizing rollup |
…nkov Add a way to get shorter spans until `char` for pointing at defs ```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | ^^^^^^^^ recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ``` vs ```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | _^ starting here... 11 | | x: X, 12 | | } | |_^ ...ending here: recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ``` Re: rust-lang#35965, rust-lang#38246. Follow up to rust-lang#38328. r? @jonathandturner
vs
Re: #35965, #38246. Follow up to #38328.
r? @jonathandturner