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

Commit 3924a0e

Browse files
committed
Add ast versions of generate{_trait}_impl_text{_intransitive}
1 parent 8c0661b commit 3924a0e

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

crates/ide-assists/src/utils.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
470470

471471
/// Generates the surrounding `impl Type { <code> }` including type and lifetime
472472
/// parameters.
473+
// FIXME: migrate remaining uses to `generate_impl`
473474
pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
474475
generate_impl_text_inner(adt, None, true, code)
475476
}
@@ -478,6 +479,7 @@ pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
478479
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
479480
///
480481
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
482+
// FIXME: migrate remaining uses to `generate_trait_impl`
481483
pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
482484
generate_impl_text_inner(adt, Some(trait_text), true, code)
483485
}
@@ -486,6 +488,7 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
486488
/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
487489
///
488490
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
491+
// FIXME: migrate remaining uses to `generate_trait_impl_intransitive`
489492
pub(crate) fn generate_trait_impl_text_intransitive(
490493
adt: &ast::Adt,
491494
trait_text: &str,
@@ -516,7 +519,7 @@ fn generate_impl_text_inner(
516519
// Add the current trait to `bounds` if the trait is transitive,
517520
// meaning `impl<T> Trait for U<T>` requires `T: Trait`.
518521
if trait_is_transitive {
519-
bounds.push(make::type_bound(trait_));
522+
bounds.push(make::type_bound_text(trait_));
520523
}
521524
};
522525
// `{ty_param}: {bounds}`
@@ -574,6 +577,101 @@ fn generate_impl_text_inner(
574577
buf
575578
}
576579

580+
/// Generates the corresponding `impl Type {}` including type and lifetime
581+
/// parameters.
582+
pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
583+
generate_impl_inner(adt, None, true)
584+
}
585+
586+
/// Generates the corresponding `impl <trait> for Type {}` including type
587+
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
588+
///
589+
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
590+
pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
591+
generate_impl_inner(adt, Some(trait_), true)
592+
}
593+
594+
/// Generates the corresponding `impl <trait> for Type {}` including type
595+
/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
596+
///
597+
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
598+
pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
599+
generate_impl_inner(adt, Some(trait_), false)
600+
}
601+
602+
fn generate_impl_inner(
603+
adt: &ast::Adt,
604+
trait_: Option<ast::Type>,
605+
trait_is_transitive: bool,
606+
) -> ast::Impl {
607+
// Ensure lifetime params are before type & const params
608+
let generic_params = adt.generic_param_list().map(|generic_params| {
609+
let lifetime_params =
610+
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
611+
let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
612+
match param {
613+
ast::TypeOrConstParam::Type(param) => {
614+
let param = param.clone_for_update();
615+
// remove defaults since they can't be specified in impls
616+
param.remove_default();
617+
let mut bounds =
618+
param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
619+
if let Some(trait_) = &trait_ {
620+
// Add the current trait to `bounds` if the trait is transitive,
621+
// meaning `impl<T> Trait for U<T>` requires `T: Trait`.
622+
if trait_is_transitive {
623+
bounds.push(make::type_bound(trait_.clone()));
624+
}
625+
};
626+
// `{ty_param}: {bounds}`
627+
let param =
628+
make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
629+
ast::GenericParam::TypeParam(param)
630+
}
631+
ast::TypeOrConstParam::Const(param) => {
632+
let param = param.clone_for_update();
633+
// remove defaults since they can't be specified in impls
634+
param.remove_default();
635+
ast::GenericParam::ConstParam(param)
636+
}
637+
}
638+
});
639+
640+
make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
641+
});
642+
let generic_args =
643+
generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
644+
let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
645+
646+
let impl_ = match trait_ {
647+
Some(trait_) => make::impl_trait(
648+
false,
649+
None,
650+
None,
651+
generic_params,
652+
generic_args,
653+
false,
654+
trait_,
655+
ty,
656+
None,
657+
adt.where_clause(),
658+
None,
659+
),
660+
None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), None),
661+
}
662+
.clone_for_update();
663+
664+
// Copy any cfg attrs from the original adt
665+
let cfg_attrs = adt
666+
.attrs()
667+
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
668+
for attr in cfg_attrs {
669+
impl_.add_attr(attr.clone_for_update());
670+
}
671+
672+
impl_
673+
}
674+
577675
pub(crate) fn add_method_to_adt(
578676
builder: &mut SourceChangeBuilder,
579677
adt: &ast::Adt,

crates/syntax/src/ast/make.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,12 @@ pub fn trait_(
895895
ast_from_text(&text)
896896
}
897897

898-
pub fn type_bound(bound: &str) -> ast::TypeBound {
898+
// FIXME: remove when no one depends on `generate_impl_text_inner`
899+
pub fn type_bound_text(bound: &str) -> ast::TypeBound {
900+
ast_from_text(&format!("fn f<T: {bound}>() {{ }}"))
901+
}
902+
903+
pub fn type_bound(bound: ast::Type) -> ast::TypeBound {
899904
ast_from_text(&format!("fn f<T: {bound}>() {{ }}"))
900905
}
901906

0 commit comments

Comments
 (0)