Skip to content

Commit

Permalink
the "implement missing members" assist's const transformation patched
Browse files Browse the repository at this point in the history
  • Loading branch information
ponyii committed Jun 15, 2023
1 parent 8a3c214 commit b50a9a9
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 13 deletions.
23 changes: 23 additions & 0 deletions crates/ide-assists/src/handlers/add_missing_impl_members.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,29 @@ impl<const X: usize, Y, Z> Foo<X, Z> for S<Y> {
)
}

#[test]
fn test_const_substitution_2() {
check_assist(
add_missing_default_members,
r#"
trait Foo<const N: usize, const M: usize, T> {
fn get_product(&self, arg: &T) -> usize { N * M }
}
impl<X> Foo<{20 + 22}, 42, X> for () {
$0
}"#,
r#"
trait Foo<const N: usize, const M: usize, T> {
fn get_product(&self, arg: &T) -> usize { N * M }
}
impl<X> Foo<{20 + 22}, 42, X> for () {
$0fn get_product(&self, arg: &X) -> usize { ({20 + 22}) * 42 }
}"#,
)
}

#[test]
fn test_cursor_after_empty_impl_def() {
check_assist(
Expand Down
43 changes: 30 additions & 13 deletions crates/ide-db/src/path_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ use syntax::{

#[derive(Default)]
struct AstSubsts {
// ast::TypeArgs stands in fact for both type and const params
// as consts declared elsewhere look just like type params.
types_and_consts: Vec<ast::TypeArg>,
types_and_consts: Vec<TypeOrConst>,
lifetimes: Vec<ast::LifetimeArg>,
}

enum TypeOrConst {
Either(ast::TypeArg), // indistinguishable type or const param
Const(ast::ConstArg),
}

type LifetimeName = String;

/// `PathTransform` substitutes path in SyntaxNodes in bulk.
Expand Down Expand Up @@ -125,27 +128,37 @@ impl<'a> PathTransform<'a> {
// the resulting change can be applied correctly.
.zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None)))
.for_each(|(k, v)| match (k.split(db), v) {
(Either::Right(t), Some(v)) => {
(Either::Right(k), Some(TypeOrConst::Either(v))) => {
if let Some(ty) = v.ty() {
type_substs.insert(t, ty.clone());
type_substs.insert(k, ty.clone());
}
}
(Either::Right(t), None) => {
if let Some(default) = t.default(db) {
(Either::Right(k), None) => {
if let Some(default) = k.default(db) {
if let Some(default) =
&default.display_source_code(db, source_module.into(), false).ok()
{
type_substs.insert(t, ast::make::ty(default).clone_for_update());
default_types.push(t);
type_substs.insert(k, ast::make::ty(default).clone_for_update());
default_types.push(k);
}
}
}
(Either::Left(c), Some(v)) => {
(Either::Left(k), Some(TypeOrConst::Either(v))) => {
if let Some(ty) = v.ty() {
const_substs.insert(c, ty.syntax().clone());
const_substs.insert(k, ty.syntax().clone());
}
}
(Either::Left(k), Some(TypeOrConst::Const(v))) => {
if let Some(mut expr) = v.expr() {
// expressions in curly brackets can cause syntax errors after insertion
if expr.syntax().text().contains_char('{') {
expr = ast::make::expr_paren(expr);
}
const_substs.insert(k, expr.syntax().clone());
}
}
(Either::Left(_), None) => (), // FIXME: get default const value
_ => (), // ignore mismatching params
});
let lifetime_substs: FxHashMap<_, _> = self
.generic_def
Expand Down Expand Up @@ -326,8 +339,12 @@ fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<
// Const params are marked as consts on definition only,
// being passed to the trait they are indistguishable from type params;
// anyway, we don't really need to distinguish them here.
ast::GenericArg::TypeArg(type_or_const_arg) => {
result.types_and_consts.push(type_or_const_arg)
ast::GenericArg::TypeArg(type_arg) => {
result.types_and_consts.push(TypeOrConst::Either(type_arg))
}
// Only const values are recognized correctly.
ast::GenericArg::ConstArg(const_arg) => {
result.types_and_consts.push(TypeOrConst::Const(const_arg));
}
ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg),
_ => (),
Expand Down

0 comments on commit b50a9a9

Please sign in to comment.