Fix impl_def_from_trait

Revert "Fix `impl_trait` function to emit correct ast"

This reverts commit 55a4813151.

Fix `impl_def_from_trait`

It now generates the correct `ast::Impl` using
`generate_trait_impl_text` and parses it to form the right node (copied
from the private fn 'make::ast_from_text').
This commit is contained in:
TheDoctor314 2021-11-15 20:51:48 +05:30
parent 55a4813151
commit 58a24de7d8
2 changed files with 26 additions and 65 deletions

View file

@ -160,7 +160,24 @@ fn impl_def_from_trait(
if trait_items.is_empty() {
return None;
}
let impl_def = make::impl_trait(&trait_path, &adt, "");
let impl_def = {
use syntax::ast::Impl;
let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
let parse = syntax::SourceFile::parse(&text);
let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
Some(it) => it,
None => {
panic!(
"Failed to make ast node `{}` from text {}",
std::any::type_name::<Impl>(),
text
)
}
};
let node = node.clone_subtree();
assert_eq!(node.syntax().text_range().start(), 0.into());
node
};
let (impl_def, first_assoc_item) =
add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);

View file

@ -10,13 +10,9 @@
//! `parse(format!())` we use internally is an implementation detail -- long
//! term, it will be replaced with direct tree manipulation.
use itertools::Itertools;
use smol_str::SmolStr;
use stdx::{format_to, never};
use crate::{
ast::{self, HasAttrs, HasGenericParams, HasName, HasTypeBounds},
AstNode, SourceFile, SyntaxKind, SyntaxToken,
};
use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};
/// While the parent module defines basic atomic "constructors", the `ext`
/// module defines shortcuts for common things.
@ -153,65 +149,13 @@ pub fn impl_(
ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
}
pub fn impl_trait(trait_: &ast::Path, adt: &ast::Adt, code: &str) -> ast::Impl {
let generic_params = adt.generic_param_list();
let mut buf = String::with_capacity(code.len());
buf.push_str("\n\n");
adt.attrs()
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
.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 fn impl_trait(
trait_: ast::Path,
ty: ast::Path,
ty_params: Option<ast::GenericParamList>,
) -> ast::Impl {
let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
}
pub(crate) fn generic_arg_list() -> ast::GenericArgList {