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
End game for find usages #7427
Comments
@steffahn provides an interesting macro-less example of this on irlo: trait Foo {
type Ty;
}
impl Foo for [(); 42] {
type Ty = Bar;
}
struct Bar {
x: u32,
}
fn main() {
let x = 1;
type T = <[(); 40+2] as Foo>::Ty;
let t = T { x }; // <- this is usage of Bar!
t.x;
} It makes me think that our hope for a correct fast-path for find usages which doesn't rely on type inference is not really feasible :( |
Hm, as pointed out by @vlad20012 this might actually be not that bad -- all the interesting stuff happens on the item level. That is, the example is type T = <[(); 40+2] as Foo>::Ty;
fn main() {
let x = 1;
let t = T { x }; // <- this is usage of Bar!
t.x;
} which actually isn't that much different from type T = Bar;
fn main() {
let x = 1;
let t = T { x }; // <- this is usage of Bar!
t.x;
} That is, searches already have to close over type aliases. |
I did say that for the original example the usage of |
Well, arguably, the (is there a usage of fn foo<T: Foo>(t: T) {
let o: Option<T::Ty> = None;
}
fn main() {
foo::<[(); 42]>();
} |
For renaming-of |
For renaming the fields, we search for textual occurences of the field name (and then check that the record expression has the right type), not the struct. That's why e.g. renaming struct Struct {
field: u32,
}
macro_rules! construct {
($i:ident) => { Struct { $i: 0 } }
}
fn test2() {
let x = construct!(field);
} |
@flodiebold I don’t quite understand what you’re trying to argue; I was talking about code in this comment, which doesn’t feature macros. And in that code example if I ask rust-analzer (IDK what version I have, probably current stable or something like that…) to rename the field If you simplify the |
Neither of those problems are related to or fixed by doing type inference when searching for usages; the first is caused by limitations in our const eval, and the second one a bug in our type inference (it seems we don't resolve projections for record literals? there might be a FIXME for that somewhere). If you change |
Thanks for clarifying, this makes complete sense to me. |
One case that was brougth up in the IRLO thread was refactoring between tuple structs or record structs, and that syntactical searching is faster than type-inference-based search. Arguably, such a refactor will need to touch all kinds of field expressions, too, anyways; so especially for tuple-struct-to-record struct all To relate this to the example, do something like trait Foo {
type Ty;
}
impl Foo for [(); 42] {
type Ty = Bar;
}
struct Bar(u32);
fn main() {
let x = 1;
type T = <[(); 40 + 2] as Foo>::Ty;
let t = T{ 0: x };
t.0;
} and then “Convert to named struct” on There remains the question of whether or not this refactor logically operates by “finding a usage of There doesn’t appear to be a refactor to turn a record struct back into a tuple struct, so I can’t comment on |
Yeah, in the end it doesn't matter much for assists like "Convert to named struct", because as you've noted we have to find all instances of
The only case I can currently come up with where we might be forced to run inference on everything is if an assist needs to find occurrences of |
Zulip thread: https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/End.20Game.20for.20Find.20Usages
Consider this code:
Does the
m!()
call constitute a usage of thefoo
function? Under our current model, the answer is no: a usage requires a literalfoo
present in the source code. This is because find usages works by pruning a super-set of textual occurrences (https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html), and there's no textual occurrence to prune here!There are two ways we can deal with it, which lead to dramatically different architectures.
First approach is to stick with our current model, and just implement heuristics that would flag a potential usage in the macro definition. Note that no heuristic would work for procedural macros.
Second approach is to always eagerly expand all macros for find usage. This is still much cheaper than typecheking everything, but is way costlier than our current text-based pruning.
If we go with the second approach, that has implications for the overall architecture. For example, if we are going to expand all the macros anyway, we might want to dump expansions to disk and treat them as inputs.
The text was updated successfully, but these errors were encountered: