You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Find Usages is currently very limited on large projects, since many natural categories of usages are lacking. I propose the following additions:
For traits, add usage categories
Trait objects (dyn Trait usages)
Implementations (impl Trait for Foo)
Trait bounds (foo<T1, T2: Trait>(x: impl Trait) where T1: Trait, as well as bounds on generics parameters and associated types).
Opaque types (foo(_: impl Trait) -> impl Trait, as well as impl Trait in type aliases and nested types).
Supertrait (trait T: Trait).
For structs, there are ostensibly many categories (although some don't make sense, what the hell is "dot expr"?). However, in practice the categorization is very incoherent, and the same type of expression appear to be dumped in different categories ostensibly at random. Also, almost all usages are dumped in the catch-all "type reference" category. For example, searching for std::option::Option in all of my dependencies gives me the following category counts:
Unclassified - 7
argument - 20
dot expr - 2
expr - 3
function call - 17
impl - 82
type reference - 10 235 (sic!)
use - 22
This is plain useless. The only categories which seem to work as indended are impl and use. type_reference is just a dump which can't meaningfully be analyzed, and the others contain expressions like Option::from in all of them.
I propose the following categories:
impl - as above, impl Trait for Type.
use - as above, all use foo::Type and pub use bar::Type statements.
inherent method calls - all calls of inherent methods on Type.
trait method calls - all calls of trait methods on Trait. We separate it from inherent methods, since the set of inherent methods is closed (only in the declaring crate) and usually small, while anyone can add trait methods.
usage in return type - foo() -> Struct
usage in argument type - foo(_: Struct). We separate return and argument position, since they are quite different from the PoV of an API consumer. One is the way to use a type, while the other is a way to construct it. Include type in nested positions (foo(_: Box<Struct>) -> Vec<Struct>), because they are part of the same use-vs-create paradigm.
field type - struct Foo { a: Struct }, struct Foo(Struct), and same with enums and unions. As above, we include type in nested position.
associated type - impl Trait for Foo { type T = Struct; }, and also default associated types (unstable).
type aliases - type Foo = Struct. This includes inherent type aliases on types (unstable, impl Foo { type Bar = Struct; }). This is different from associated types, even though the syntax is similar. Associated types are more widely used, and they have semantic meaning (the return value of a type-level function corresponding to a trait), while type aliases are just a convenient name for a more complex type, and are semantically equivalent to that type.
trait bounds - .. where Struct: Trait. This is an uncommon usage, since the trait bounds are usually placed directly on generic parameters (e.g. T: Trait rather than Option<T>: Trait), but it is allowed by the language and is occasionally useful. For example, look at the trait bounds in futures crate. It would be more widely used if chalk was stable, since the current trait resolution hits critical bugs for more complex types in where-clauses.
qualified paths - Struct::foo. Note that it's separate from methods, which don't explicitly mention the type.
type ascription - let x: Struct = ...;. Note that type ascription expressions were removed from the language, so only let-bindings need to be searched.
It should be possible to select the required usage categories from the "Find Usages" dialogue. If I'm only interested in trait impls, there is no point in dumping all other usages on me. This also saves time and memory when dealing with huge number of usages (like for std types).
The text was updated successfully, but these errors were encountered:
Environment
Suggestion
Find Usages is currently very limited on large projects, since many natural categories of usages are lacking. I propose the following additions:
For traits, add usage categories
dyn Trait
usages)impl Trait for Foo
)foo<T1, T2: Trait>(x: impl Trait) where T1: Trait
, as well as bounds on generics parameters and associated types).foo(_: impl Trait) -> impl Trait
, as well asimpl Trait
in type aliases and nested types).trait T: Trait
).For structs, there are ostensibly many categories (although some don't make sense, what the hell is "dot expr"?). However, in practice the categorization is very incoherent, and the same type of expression appear to be dumped in different categories ostensibly at random. Also, almost all usages are dumped in the catch-all "type reference" category. For example, searching for
std::option::Option
in all of my dependencies gives me the following category counts:This is plain useless. The only categories which seem to work as indended are impl and use. type_reference is just a dump which can't meaningfully be analyzed, and the others contain expressions like
Option::from
in all of them.I propose the following categories:
impl Trait for Type
.use foo::Type
andpub use bar::Type
statements.Type
.Trait
. We separate it from inherent methods, since the set of inherent methods is closed (only in the declaring crate) and usually small, while anyone can add trait methods.foo() -> Struct
foo(_: Struct)
. We separate return and argument position, since they are quite different from the PoV of an API consumer. One is the way to use a type, while the other is a way to construct it. Include type in nested positions (foo(_: Box<Struct>) -> Vec<Struct>
), because they are part of the same use-vs-create paradigm.struct Foo { a: Struct }
,struct Foo(Struct)
, and same with enums and unions. As above, we include type in nested position.impl Trait for Foo { type T = Struct; }
, and also default associated types (unstable).type Foo = Struct
. This includes inherent type aliases on types (unstable,impl Foo { type Bar = Struct; }
). This is different from associated types, even though the syntax is similar. Associated types are more widely used, and they have semantic meaning (the return value of a type-level function corresponding to a trait), while type aliases are just a convenient name for a more complex type, and are semantically equivalent to that type... where Struct: Trait
. This is an uncommon usage, since the trait bounds are usually placed directly on generic parameters (e.g.T: Trait
rather thanOption<T>: Trait
), but it is allowed by the language and is occasionally useful. For example, look at the trait bounds infutures
crate. It would be more widely used ifchalk
was stable, since the current trait resolution hits critical bugs for more complex types in where-clauses.Struct::foo
. Note that it's separate from methods, which don't explicitly mention the type.let x: Struct = ...;
. Note that type ascription expressions were removed from the language, so only let-bindings need to be searched.foo::<Struct>()
.Struct { a: 3, b: 4 }
,Enum::Variant
.It should be possible to select the required usage categories from the "Find Usages" dialogue. If I'm only interested in trait impls, there is no point in dumping all other usages on me. This also saves time and memory when dealing with huge number of usages (like for
std
types).The text was updated successfully, but these errors were encountered: