Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4e2be8e

Browse files
committed
the "add missing members" assists: implemented the transformation of const param default values
1 parent 4ebdc6f commit 4e2be8e

File tree

3 files changed

+49
-11
lines changed

3 files changed

+49
-11
lines changed

crates/hir-ty/src/lower.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,12 +1612,12 @@ pub(crate) fn generic_defaults_query(
16121612
let unknown = unknown_const_as_generic(
16131613
db.const_param_ty(ConstParamId::from_unchecked(id)),
16141614
);
1615-
let val = p.default.as_ref().map_or(unknown, |c| {
1615+
let mut val = p.default.as_ref().map_or(unknown, |c| {
16161616
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
16171617
chalk_ir::GenericArg::new(Interner, GenericArgData::Const(c))
16181618
});
1619-
// FIXME: check if complex default values refer to
1620-
// previous parameters they should not.
1619+
// Each default can only refer to previous parameters, see above.
1620+
val = fallback_bound_vars(val, idx, parent_start_idx);
16211621
return make_binders(db, &generic_params, val);
16221622
}
16231623
};

crates/ide-assists/src/handlers/add_missing_impl_members.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,37 @@ impl<X> Foo<X> for () {
518518
);
519519
}
520520

521+
#[test]
522+
fn test_const_substitution_with_defaults_2() {
523+
check_assist(
524+
add_missing_impl_members,
525+
r#"
526+
mod m {
527+
pub const LEN: usize = 42;
528+
pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
529+
fn get_t(&self) -> T;
530+
}
531+
}
532+
533+
impl m::Foo for () {
534+
$0
535+
}"#,
536+
r#"
537+
mod m {
538+
pub const LEN: usize = 42;
539+
pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
540+
fn get_t(&self) -> T;
541+
}
542+
}
543+
544+
impl m::Foo for () {
545+
fn get_t(&self) -> [bool; m::LEN] {
546+
${0:todo!()}
547+
}
548+
}"#,
549+
)
550+
}
551+
521552
#[test]
522553
fn test_cursor_after_empty_impl_def() {
523554
check_assist(

crates/ide-db/src/path_transform.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum TypeOrConst {
2121
}
2222

2323
type LifetimeName = String;
24+
type DefaultedParam = Either<hir::TypeParam, hir::ConstParam>;
2425

2526
/// `PathTransform` substitutes path in SyntaxNodes in bulk.
2627
///
@@ -115,7 +116,7 @@ impl<'a> PathTransform<'a> {
115116
};
116117
let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default();
117118
let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default();
118-
let mut default_types: Vec<hir::TypeParam> = Default::default();
119+
let mut defaulted_params: Vec<DefaultedParam> = Default::default();
119120
self.generic_def
120121
.into_iter()
121122
.flat_map(|it| it.type_params(db))
@@ -139,7 +140,7 @@ impl<'a> PathTransform<'a> {
139140
&default.display_source_code(db, source_module.into(), false).ok()
140141
{
141142
type_substs.insert(k, ast::make::ty(default).clone_for_update());
142-
default_types.push(k);
143+
defaulted_params.push(Either::Left(k));
143144
}
144145
}
145146
}
@@ -162,7 +163,7 @@ impl<'a> PathTransform<'a> {
162163
if let Some(default) = k.default(db) {
163164
if let Some(default) = ast::make::expr_const_value(&default).expr() {
164165
const_substs.insert(k, default.syntax().clone_for_update());
165-
// FIXME: transform the default value
166+
defaulted_params.push(Either::Right(k));
166167
}
167168
}
168169
}
@@ -182,7 +183,7 @@ impl<'a> PathTransform<'a> {
182183
target_module,
183184
source_scope: self.source_scope,
184185
};
185-
ctx.transform_default_type_substs(default_types);
186+
ctx.transform_default_values(defaulted_params);
186187
ctx
187188
}
188189
}
@@ -219,13 +220,19 @@ impl Ctx<'_> {
219220
});
220221
}
221222

222-
fn transform_default_type_substs(&self, default_types: Vec<hir::TypeParam>) {
223-
for k in default_types {
224-
let v = self.type_substs.get(&k).unwrap();
223+
fn transform_default_values(&self, defaulted_params: Vec<DefaultedParam>) {
224+
// By now the default values are simply copied from where they are declared
225+
// and should be transformed. As any value is allowed to refer to previous
226+
// generic (both type and const) parameters, they should be all iterated left-to-right.
227+
for param in defaulted_params {
228+
let value = match param {
229+
Either::Left(k) => self.type_substs.get(&k).unwrap().syntax(),
230+
Either::Right(k) => self.const_substs.get(&k).unwrap(),
231+
};
225232
// `transform_path` may update a node's parent and that would break the
226233
// tree traversal. Thus all paths in the tree are collected into a vec
227234
// so that such operation is safe.
228-
let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::<Vec<_>>();
235+
let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
229236
for path in paths {
230237
self.transform_path(path);
231238
}

0 commit comments

Comments
 (0)