mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-14 09:46:00 +00:00
Auto merge of #13763 - rami3l:fix/gen-partial-eq-generic, r=Veykril
fix: add generic `TypeBoundList` in generated derivable impl Potentially fixes #13727. Continuing with the work in #13732, this fix tries to add correct type bounds in the generated `impl` block: ```diff enum Either<T, U> { Left(T), Right(U), } - impl<T, U> PartialEq for Either<T, U> { + impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Left(l0), Self::Left(r0)) => l0 == r0, (Self::Right(l0), Self::Right(r0)) => l0 == r0, _ => false, } } } ```
This commit is contained in:
commit
ae659125a5
5 changed files with 130 additions and 23 deletions
|
|
@ -434,35 +434,67 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
|
|||
Some(end)
|
||||
}
|
||||
|
||||
// Generates the surrounding `impl Type { <code> }` including type and lifetime
|
||||
// parameters
|
||||
/// Generates the surrounding `impl Type { <code> }` including type and lifetime
|
||||
/// parameters.
|
||||
pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
|
||||
generate_impl_text_inner(adt, None, code)
|
||||
generate_impl_text_inner(adt, None, true, code)
|
||||
}
|
||||
|
||||
// Generates the surrounding `impl <trait> for Type { <code> }` including type
|
||||
// and lifetime parameters
|
||||
/// Generates the surrounding `impl <trait> for Type { <code> }` including type
|
||||
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
|
||||
///
|
||||
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
|
||||
pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
|
||||
generate_impl_text_inner(adt, Some(trait_text), code)
|
||||
generate_impl_text_inner(adt, Some(trait_text), true, code)
|
||||
}
|
||||
|
||||
fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
|
||||
/// Generates the surrounding `impl <trait> for Type { <code> }` including type
|
||||
/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
|
||||
///
|
||||
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
|
||||
pub(crate) fn generate_trait_impl_text_intransitive(
|
||||
adt: &ast::Adt,
|
||||
trait_text: &str,
|
||||
code: &str,
|
||||
) -> String {
|
||||
generate_impl_text_inner(adt, Some(trait_text), false, code)
|
||||
}
|
||||
|
||||
fn generate_impl_text_inner(
|
||||
adt: &ast::Adt,
|
||||
trait_text: Option<&str>,
|
||||
trait_is_transitive: bool,
|
||||
code: &str,
|
||||
) -> String {
|
||||
// Ensure lifetime params are before type & const params
|
||||
let generic_params = adt.generic_param_list().map(|generic_params| {
|
||||
let lifetime_params =
|
||||
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
|
||||
let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
|
||||
// remove defaults since they can't be specified in impls
|
||||
let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
|
||||
match param {
|
||||
ast::TypeOrConstParam::Type(param) => {
|
||||
let param = param.clone_for_update();
|
||||
// remove defaults since they can't be specified in impls
|
||||
param.remove_default();
|
||||
Some(ast::GenericParam::TypeParam(param))
|
||||
let mut bounds =
|
||||
param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
|
||||
if let Some(trait_) = trait_text {
|
||||
// Add the current trait to `bounds` if the trait is transitive,
|
||||
// meaning `impl<T> Trait for U<T>` requires `T: Trait`.
|
||||
if trait_is_transitive {
|
||||
bounds.push(make::type_bound(trait_));
|
||||
}
|
||||
};
|
||||
// `{ty_param}: {bounds}`
|
||||
let param =
|
||||
make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
|
||||
ast::GenericParam::TypeParam(param)
|
||||
}
|
||||
ast::TypeOrConstParam::Const(param) => {
|
||||
let param = param.clone_for_update();
|
||||
// remove defaults since they can't be specified in impls
|
||||
param.remove_default();
|
||||
Some(ast::GenericParam::ConstParam(param))
|
||||
ast::GenericParam::ConstParam(param)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue