mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Merge #4445
4445: Correctly fill default type parameters r=flodiebold a=montekki Fixes #3877 So, basically even if the parameters are omitted from the `impl` block, check the parameters in `trait` if they have a default type, and if they do go from `hir` to `ast::TypeArg`. I've added a helper for that but I am not sure that it's a proper way to go from `hir` to `ast` here. Co-authored-by: Fedor Sakharov <fedor.sakharov@gmail.com>
This commit is contained in:
commit
f1587ac263
5 changed files with 92 additions and 2 deletions
|
@ -1,7 +1,7 @@
|
||||||
//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
|
//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use hir::{PathResolution, SemanticsScope};
|
use hir::{HirDisplay, PathResolution, SemanticsScope};
|
||||||
use ra_ide_db::RootDatabase;
|
use ra_ide_db::RootDatabase;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::SyntaxRewriter,
|
algo::SyntaxRewriter,
|
||||||
|
@ -51,7 +51,27 @@ impl<'a> SubstituteTypeParams<'a> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
|
// this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.zip(substs.into_iter())
|
// The actual list of trait type parameters may be longer than the one
|
||||||
|
// used in the `impl` block due to trailing default type parametrs.
|
||||||
|
// For that case we extend the `substs` with an empty iterator so we
|
||||||
|
// can still hit those trailing values and check if they actually have
|
||||||
|
// a default type. If they do, go for that type from `hir` to `ast` so
|
||||||
|
// the resulting change can be applied correctly.
|
||||||
|
.zip(substs.into_iter().map(Some).chain(std::iter::repeat(None)))
|
||||||
|
.filter_map(|(k, v)| match v {
|
||||||
|
Some(v) => Some((k, v)),
|
||||||
|
None => {
|
||||||
|
let default = k.default(source_scope.db)?;
|
||||||
|
Some((
|
||||||
|
k,
|
||||||
|
ast::make::type_ref(
|
||||||
|
&default
|
||||||
|
.display_source_code(source_scope.db, source_scope.module()?.into())
|
||||||
|
.ok()?,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
return SubstituteTypeParams {
|
return SubstituteTypeParams {
|
||||||
source_scope,
|
source_scope,
|
||||||
|
|
|
@ -615,6 +615,56 @@ trait Foo {
|
||||||
struct S;
|
struct S;
|
||||||
impl Foo for S {
|
impl Foo for S {
|
||||||
<|>fn valid(some: u32) -> bool { false }
|
<|>fn valid(some: u32) -> bool { false }
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generic_single_default_parameter() {
|
||||||
|
check_assist(
|
||||||
|
add_missing_impl_members,
|
||||||
|
r#"
|
||||||
|
trait Foo<T = Self> {
|
||||||
|
fn bar(&self, other: &T);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
impl Foo for S { <|> }"#,
|
||||||
|
r#"
|
||||||
|
trait Foo<T = Self> {
|
||||||
|
fn bar(&self, other: &T);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
impl Foo for S {
|
||||||
|
<|>fn bar(&self, other: &Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generic_default_parameter_is_second() {
|
||||||
|
check_assist(
|
||||||
|
add_missing_impl_members,
|
||||||
|
r#"
|
||||||
|
trait Foo<T1, T2 = Self> {
|
||||||
|
fn bar(&self, this: &T1, that: &T2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S<T>;
|
||||||
|
impl Foo<T> for S<T> { <|> }"#,
|
||||||
|
r#"
|
||||||
|
trait Foo<T1, T2 = Self> {
|
||||||
|
fn bar(&self, this: &T1, that: &T2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S<T>;
|
||||||
|
impl Foo<T> for S<T> {
|
||||||
|
<|>fn bar(&self, this: &T, that: &Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}"#,
|
}"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -989,6 +989,17 @@ impl TypeParam {
|
||||||
ty: InEnvironment { value: ty, environment },
|
ty: InEnvironment { value: ty, environment },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
|
||||||
|
let params = db.generic_defaults(self.id.parent);
|
||||||
|
let local_idx = hir_ty::param_idx(db, self.id)?;
|
||||||
|
let resolver = self.id.parent.resolver(db.upcast());
|
||||||
|
let environment = TraitEnvironment::lower(db, &resolver);
|
||||||
|
params.get(local_idx).cloned().map(|ty| Type {
|
||||||
|
krate: self.id.parent.module(db.upcast()).krate,
|
||||||
|
ty: InEnvironment { value: ty, environment },
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: rename from `ImplDef` to `Impl`
|
// FIXME: rename from `ImplDef` to `Impl`
|
||||||
|
|
|
@ -427,6 +427,11 @@ impl Substs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return an index of a parameter in the generic type parameter list by it's id.
|
||||||
|
pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
|
||||||
|
generics(db.upcast(), id.parent).param_idx(id)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SubstsBuilder {
|
pub struct SubstsBuilder {
|
||||||
vec: Vec<Ty>,
|
vec: Vec<Ty>,
|
||||||
|
|
|
@ -13,6 +13,10 @@ pub fn name_ref(text: &str) -> ast::NameRef {
|
||||||
ast_from_text(&format!("fn f() {{ {}; }}", text))
|
ast_from_text(&format!("fn f() {{ {}; }}", text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_ref(text: &str) -> ast::TypeRef {
|
||||||
|
ast_from_text(&format!("impl {} for D {{}};", text))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
|
pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
|
||||||
ast_from_text(&format!("use {};", name_ref))
|
ast_from_text(&format!("use {};", name_ref))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue