No completions after `.` in second argument of `dbg!`
pub struct Point {
id1: i32,
id2: i32,
id3: i32,
}
impl Point {
pub fn add_next_state(&mut self) {
dbg!(self.id1, self.);
}
}
rust-analyzer version:
rust-analyzer version: 0.3.1850-standalone (68c506fd6 2024-02-19)
rustc version: (eg. output of rustc -V)
rustc 1.76.0 (07dca489a 2024-02-04)
Completions show up if you type one letter, this seems to be a case of bad error resilience in macro expansion. Not sure why though.
If we type self.i(or any one or more letters) the macro is fully expanded despite of possible semantic errors that no such field exists, but if we type self. only, the macro is not expanded enough due to parser level error, because it expects an Expr after .
https://github.com/rust-lang/rust-analyzer/blob/master/crates/mbe/src/expander/matcher.rs#L497-L526
Since the ide-completion deals with this for some cases by inserting a fake token - quite interesting word, intellijRulezz - after .
But as it checks whether the both original file that has parser level error and the speculative file with fake token inserted can be accessed by same offset, if the original file's expansion is too short due to parser level error, this fake token inserting try cannot reach enough offset that we need for completion.
I think that "tinkering" this with some hacks is not that difficult, but fixing this in "right way" needs some discussions
The fake token does not and is not intended to help with macro expansion, as you noticed we need the original macro call without the fake token to expand properly as well. It's only to help determine what syntactic role a text token would take at the cursor even if there is nothing there at the moment.
the macro is not expanded enough due to parser level error, because it expects an Expr after .
Yes, this is the problem; we need to be able to expand macros even if the input is incomplete, and we do try to do that, but it doesn't work in all cases. Since the dbg macro isn't that complicated, it's surprising to me that it doesn't work, but I haven't looked in detail why it doesn't.
The reason why dbg! isn't expanded is in my first link.
https://github.com/rust-lang/rust-analyzer/blob/4a8d0f7f565b6df45da5522dd7366a4df3460cd7/crates/mbe/src/expander/matcher.rs#L494-L527
In L497, function match_meta_var gets result from the parser, so it makes error for no proper expression following . in self..
Thus, the following tokens after self. just pushed as fragments, instead of expanded properly.
Ignoring this err just makes the completion working, but it shouldn't be done like that.
I'm not sure what's the proper pinpointed solution for this. Maybe adding more granular error kinds for parser and keep expansion working for some cases?
pub struct Foo {
bar: i32,
}
macro_rules! our_dbg {
($val:expr $(,)?) => {
$val
};
($($val:expr),+ $(,)?) => {
($(our_dbg!($val)),+,)
};
}
fn baz(foo: Foo) {
our_dbg!(foo.bar, foo.$0);
}
Here's a case with more simplified dbg! macro replacement
Hmm, wonder why the parser behavior changes in the error case? It feels like it shouldn't (aside from setting the is_error flag)?
Well, though I haven't looked into the every detail, but the logic diverges on error for whether or not to push item into bb_items
And that bb_items differece made parsing logic early to exit early as LeftoverTokens in the following lines, IIRC
https://github.com/rust-lang/rust-analyzer/blob/4a8d0f7f565b6df45da5522dd7366a4df3460cd7/crates/mbe/src/expander/matcher.rs#L684-L699
That made the macro expansion result much shorter.
Having error doesn't hinder ide completions by itself, but it does if the expanded macro has very different offset compared to the on with fake token inserted, it does
https://github.com/rust-lang/rust-analyzer/blob/4a8d0f7f565b6df45da5522dd7366a4df3460cd7/crates/ide-completion/src/context/analysis.rs#L184-L187