- And add logic operation suggest
Example
---
In the old implementation, it always suggested conditions,
this is a lot of noise, e.g `contract_checks()~(use std::intrinsics::contract_checks) const fn() -> bool`
```rust
fn foo() {
if true {
c$0
}
}
```
Example
---
```rust
fn foo() {
let x = if true {
1
} el$0 else {
2
};
}
```
**Before this PR**:
```text
else~ k [LS]
else if~ k [LS]
```
**After this PR**:
```text
else if~ k [LS]
```
Example
---
```rust
fn main() {
let x = if true {
()
} $0 else {};
}
```
**Before this PR**:
```rust
fn main() {
let x = if true {
()
} else if $1 {
$0
}; else {};
}
```
**After this PR**:
```rust
fn main() {
let x = if true {
()
} else if $1 {
$0
} else {};
}
```
Example
===
```rust
let x = $0;
```
Old completions:
```rust
let x = if $1 {
$0
};
```
This PR current completions:
```rust
let x = if $1 {
$2
} else {
$0
};
```
This is because our detection is imperfect, and miss some cases such as an impersonating `test` macro, so we hope we'll expand successfully in this case.
This time, when completing the keyword (e.g. `fn` + whitespace).
The bug was actually a double-bug:
First, we did not resolve the impl in the macro-expanded file but in the real file, which of course cannot work.
Second, in analysis the whitespace was correlated with the `impl` and not the incomplete `fn`, which caused fake (where we insert an identifier after the whitespace) and real expansions to go out of sync, which failed analysis. The fix is to skip whitespaces in analysis.
It should be left biased, not right biased, because when e.g. the use has typed `h` then requested completion, the `h` is what we want to find, not the next token (which might indeed be inside a macro call).
I'm not sure why I wrote `right_biased()` to begin with (I remember I had a reason and not just "both should work"), I might've copied the code in `expand_and_analyze()` (which is wrong, because there it lookups on the speculative file, where right biased will always find the correct token and left biased not).
This is still not perfect, because there might not be an identifier already typed then we might still end up in a macro call, but this is the best we can do.
Which caused the macros of the popular `tracing` crate to not offer completions.
The reason is rather complicated: it boils down to macro ignoring their input and completion always choosing the first expansion.
This mainly aids in error recovery but also makes it a bit easier to handle lifetime resolution.
While doing so it also came apparent that we were not actually lowering lifetime outlives relationships within lifetime parameter declaration bounds, so this fixes that.
This PR touches a lot of parts. But the main changes are changing
`hir_expand::Name` to be raw edition-dependently and only when necessary
(unrelated to how the user originally wrote the identifier),
and changing `is_keyword()` and `is_raw_identifier()` to be edition-aware
(this was done in #17896, but the FIXMEs were fixed here).
It is possible that I missed some cases, but most IDE parts should properly
escape (or not escape) identifiers now.
The rules of thumb are:
- If we show the identifier to the user, its rawness should be determined
by the edition of the edited crate. This is nice for IDE features,
but really important for changes we insert to the source code.
- For tests, I chose `Edition::CURRENT` (so we only have to (maybe) update
tests when an edition becomes stable, to avoid churn).
- For debugging tools (helper methods and logs), I used `Edition::LATEST`.