rust-analyzer
rust-analyzer copied to clipboard
GAT support
Since generic associated types are on their way to stabilization, we'll need to start looking into implementing them :sweat_smile:
#9602 was a step on the way there. I haven't run into other issues where they fail to parse since then, but I imagine more information can be modeled around them for refactoring and introspection.
// I'm not sure if here is the proper place to ask about this though, One thing I'm suffered by is similar to #9602 but its rustfmt side support. rustfmt has already merged a PL to support GAT in associated type constraints, though rustfmt version is not bumped since February so the code is not yet in the released version. Is there a way to specify a certain rustfmt git commit version to use in rust-analyzer?
@wada314 we run the installed rustfmt
, but you can override the command to e.g. cargo +nightly rustfmt
or gat-rustfmt
if that works.
Thanks for the info! I was thinking the change is already merged into rustfmt, but actually I couldn't trigger that feature so I'm asking at their issue thread about how to use the feature.
Even in the nightly
, I think rustfmt
is only updated periodically and testing on play.rust-lang.org shows that it's still mangling GATs.
But you can also build your own rustfmt
from source, it's easier than I expected.
I think I'm missing some command-line config parameters to use the feature... I cloned the repository by myself and added a testcase for handling GAT in constraints, but it didn't work. I posted on their thread so I wait for the response, thanks!
Yeah, it doesn't work for me either.
Before opening a new issue I stumbled across this one. I think my problem is either the same or related.
I'm experimenting with generic_associated_types
and (min_)type_alias_impl_trait
and found a few issues with type deduction. Try the following example:
pub trait SomeTrait {
type ResultFut: Future<Output = String>;
type ResultWithGatFut<'a, T: 'a>: Future<Output = String> + 'a;
fn do_it_type_alias_impl_trait(&self) -> Self::ResultFut;
fn do_it_boxed(&self) -> Pin<Box<dyn Future<Output = String>>>;
fn do_gat<'a, T: 'a>(&'a self, p: T) -> Self::ResultWithGatFut<'a, T>;
}
pub struct Impl {}
impl SomeTrait for Impl {
type ResultFut = impl Future<Output = String>;
type ResultWithGatFut<'a, T: 'a> = impl Future<Output = String> + 'a;
fn do_it_type_alias_impl_trait(&self) -> Self::ResultFut {
async { "test".to_owned() }
}
fn do_it_boxed(&self) -> Pin<Box<dyn Future<Output = String>>> {
Box::pin(async { "test".to_owned() })
}
fn do_gat<'a, T: 'a>(&'a self, _p: T) -> Self::ResultWithGatFut<'a, T> {
async { "test".to_owned() }
}
}
fn make_impl() -> impl SomeTrait {
Impl {}
}
async fn do_it_generic<T: SomeTrait>(p: &T) {
// correct: <T as SomeTrait>::ResultFut
let fut = p.do_it_type_alias_impl_trait();
// correct: String
let _res = fut.await;
// correct: Pin<Box<dyn Future<Output = ...>>>
let fut = p.do_it_boxed();
// correct: String
let _res = fut.await;
// INCORRECT: no type info whatsoever, no code completion
let fut = p.do_gat(33);
// INCORRECT: no type info whatsoever, no code completion
let _res = fut.await;
}
async fn do_it_concrete(p: &Impl) {
// INCORRECT: no type info whatsoever, no code completion
let fut = p.do_it_type_alias_impl_trait();
// INCORRECT: no type info whatsoever, no code completion
let _res = fut.await;
// correct: Pin<Box<dyn Future<Output = ...>>>
let fut = p.do_it_boxed();
// correct: String
let _res = fut.await;
// INCORRECT: no type info whatsoever, no code completion
let fut = p.do_gat(33);
// INCORRECT: no type info whatsoever, no code completion
let _res = fut.await;
}
async fn do_it_impl_arg(p: impl SomeTrait) {
// correct: <impl SomeTrait as SomeTrait>::ResultFut; but could be shortened to impl SomeTrait::ResultFut
let fut = p.do_it_type_alias_impl_trait();
// correct: String
let _res = fut.await;
// correct: Pin<Box<dyn Future<Output = ...>>>
let fut = p.do_it_boxed();
// correct: String
let _res = fut.await;
// INCORRECT: no type info whatsoever, no code completion
let fut = p.do_gat(33);
// INCORRECT: no type info whatsoever, no code completion
let _res = fut.await;
}
async fn do_it_impl_local_variable() {
let p = make_impl();
// correct: <impl SomeTrait as SomeTrait>::ResultFut; but could be shortened to impl SomeTrait::ResultFut
let fut = p.do_it_type_alias_impl_trait();
// INCORRECT: <<impl SomeTrait as SomeTrait>::ResultFut as Future>::Output -- no type completion
let _res = fut.await;
// correct: Pin<Box<dyn Future<Output = ...>>>
let fut = p.do_it_boxed();
// correct: String
let _res = fut.await;
// INCORRECT: no type info whatsoever, no code completion
let fut = p.do_gat(33);
// INCORRECT: no type info whatsoever, no code completion
let _res = fut.await;
}
Depending on how the trait/concrete type is accessed, type hints and code completion works or not, as described in the comments (they show what rust-analyzer returns). If a type (as opposed to a lifetime) is passed as a generic to an associated trait type, then type deduction fails completely.
I hope this helps to analyze & fix the issue quickly. Thanks in advance.