mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Fix impl_trait
function to emit correct ast
`impl_trait` code copied from `generate_impl_text_inner` to properly handle the bounds for the generic parameters.
This commit is contained in:
parent
e0e8d877c0
commit
55a4813151
2 changed files with 67 additions and 14 deletions
|
@ -3,7 +3,7 @@ use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
|
||||||
use ide_db::items_locator;
|
use ide_db::items_locator;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, AstNode, HasGenericParams, HasName},
|
ast::{self, make, AstNode, HasName},
|
||||||
SyntaxKind::{IDENT, WHITESPACE},
|
SyntaxKind::{IDENT, WHITESPACE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,11 +160,8 @@ fn impl_def_from_trait(
|
||||||
if trait_items.is_empty() {
|
if trait_items.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let impl_def = make::impl_trait(
|
let impl_def = make::impl_trait(&trait_path, &adt, "");
|
||||||
trait_path.clone(),
|
|
||||||
make::ext::ident_path(&annotated_name.text()),
|
|
||||||
adt.generic_param_list(),
|
|
||||||
);
|
|
||||||
let (impl_def, first_assoc_item) =
|
let (impl_def, first_assoc_item) =
|
||||||
add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
|
add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,13 @@
|
||||||
//! `parse(format!())` we use internally is an implementation detail -- long
|
//! `parse(format!())` we use internally is an implementation detail -- long
|
||||||
//! term, it will be replaced with direct tree manipulation.
|
//! term, it will be replaced with direct tree manipulation.
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use smol_str::SmolStr;
|
||||||
use stdx::{format_to, never};
|
use stdx::{format_to, never};
|
||||||
|
|
||||||
use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};
|
use crate::{
|
||||||
|
ast::{self, HasAttrs, HasGenericParams, HasName, HasTypeBounds},
|
||||||
|
AstNode, SourceFile, SyntaxKind, SyntaxToken,
|
||||||
|
};
|
||||||
|
|
||||||
/// While the parent module defines basic atomic "constructors", the `ext`
|
/// While the parent module defines basic atomic "constructors", the `ext`
|
||||||
/// module defines shortcuts for common things.
|
/// module defines shortcuts for common things.
|
||||||
|
@ -149,13 +153,65 @@ pub fn impl_(
|
||||||
ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
|
ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_trait(
|
pub fn impl_trait(trait_: &ast::Path, adt: &ast::Adt, code: &str) -> ast::Impl {
|
||||||
trait_: ast::Path,
|
let generic_params = adt.generic_param_list();
|
||||||
ty: ast::Path,
|
let mut buf = String::with_capacity(code.len());
|
||||||
ty_params: Option<ast::GenericParamList>,
|
buf.push_str("\n\n");
|
||||||
) -> ast::Impl {
|
adt.attrs()
|
||||||
let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
|
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
|
||||||
ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
|
.for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
|
||||||
|
buf.push_str("impl");
|
||||||
|
if let Some(generic_params) = &generic_params {
|
||||||
|
let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
|
||||||
|
let type_params = generic_params.type_params().map(|type_param| {
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Some(it) = type_param.name() {
|
||||||
|
format_to!(buf, "{}", it.syntax());
|
||||||
|
}
|
||||||
|
if let Some(it) = type_param.colon_token() {
|
||||||
|
format_to!(buf, "{} ", it);
|
||||||
|
}
|
||||||
|
if let Some(it) = type_param.type_bound_list() {
|
||||||
|
format_to!(buf, "{}", it.syntax());
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
});
|
||||||
|
let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
|
||||||
|
let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
|
||||||
|
format_to!(buf, "<{}>", generics);
|
||||||
|
}
|
||||||
|
buf.push(' ');
|
||||||
|
let trait_text = trait_.to_string();
|
||||||
|
buf.push_str(&trait_text);
|
||||||
|
buf.push_str(" for ");
|
||||||
|
|
||||||
|
buf.push_str(&adt.name().unwrap().text());
|
||||||
|
if let Some(generic_params) = generic_params {
|
||||||
|
let lifetime_params = generic_params
|
||||||
|
.lifetime_params()
|
||||||
|
.filter_map(|it| it.lifetime())
|
||||||
|
.map(|it| SmolStr::from(it.text()));
|
||||||
|
let type_params = generic_params
|
||||||
|
.type_params()
|
||||||
|
.filter_map(|it| it.name())
|
||||||
|
.map(|it| SmolStr::from(it.text()));
|
||||||
|
let const_params = generic_params
|
||||||
|
.const_params()
|
||||||
|
.filter_map(|it| it.name())
|
||||||
|
.map(|it| SmolStr::from(it.text()));
|
||||||
|
format_to!(buf, "<{}>", lifetime_params.chain(type_params).chain(const_params).format(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
match adt.where_clause() {
|
||||||
|
Some(where_clause) => {
|
||||||
|
format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format_to!(buf, " {{\n{}\n}}", code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_from_text(&buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generic_arg_list() -> ast::GenericArgList {
|
pub(crate) fn generic_arg_list() -> ast::GenericArgList {
|
||||||
|
|
Loading…
Reference in a new issue