Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/ast/make.rs')
-rw-r--r--crates/syntax/src/ast/make.rs155
1 files changed, 136 insertions, 19 deletions
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 5aebe4cd9f..a07561e79a 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -158,34 +158,148 @@ fn ty_from_text(text: &str) -> ast::Type {
ast_from_text(&format!("type _T = {text};"))
}
+pub fn ty_alias(
+ ident: &str,
+ generic_param_list: Option<ast::GenericParamList>,
+ type_param_bounds: Option<ast::TypeParam>,
+ where_clause: Option<ast::WhereClause>,
+ assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
+) -> ast::TypeAlias {
+ let mut s = String::new();
+ s.push_str(&format!("type {} ", ident));
+
+ if let Some(list) = generic_param_list {
+ s.push_str(&list.to_string());
+ }
+
+ if let Some(list) = type_param_bounds {
+ s.push_str(&format!(" : {}", &list));
+ }
+
+ if let Some(cl) = where_clause {
+ s.push_str(&format!(" {}", &cl.to_string()));
+ }
+
+ if let Some(exp) = assignment {
+ if let Some(cl) = exp.1 {
+ s.push_str(&format!("= {} {}", &exp.0.to_string(), &cl.to_string()));
+ } else {
+ s.push_str(&format!("= {}", &exp.0.to_string()));
+ }
+ }
+
+ s.push(';');
+ ast_from_text(&s)
+}
+
pub fn assoc_item_list() -> ast::AssocItemList {
ast_from_text("impl C for D {}")
}
-// FIXME: `ty_params` should be `ast::GenericArgList`
+fn merge_gen_params(
+ ps: Option<ast::GenericParamList>,
+ bs: Option<ast::GenericParamList>,
+) -> Option<ast::GenericParamList> {
+ match (ps, bs) {
+ (None, None) => None,
+ (None, Some(bs)) => Some(bs),
+ (Some(ps), None) => Some(ps),
+ (Some(ps), Some(bs)) => {
+ for b in bs.generic_params() {
+ ps.add_generic_param(b);
+ }
+ Some(ps)
+ }
+ }
+}
+
pub fn impl_(
- ty: ast::Path,
- params: Option<ast::GenericParamList>,
- ty_params: Option<ast::GenericParamList>,
+ generic_params: Option<ast::GenericParamList>,
+ generic_args: Option<ast::GenericParamList>,
+ path_type: ast::Type,
+ where_clause: Option<ast::WhereClause>,
+ body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
) -> ast::Impl {
- let params = match params {
- Some(params) => params.to_string(),
- None => String::new(),
+ let (gen_params, tr_gen_args) = match (generic_params, generic_args) {
+ (None, None) => (String::new(), String::new()),
+ (None, Some(args)) => (String::new(), args.to_generic_args().to_string()),
+ (Some(params), None) => (params.to_string(), params.to_generic_args().to_string()),
+ (Some(params), Some(args)) => match merge_gen_params(Some(params.clone()), Some(args)) {
+ Some(merged) => (params.to_string(), merged.to_generic_args().to_string()),
+ None => (params.to_string(), String::new()),
+ },
};
- let ty_params = match ty_params {
- Some(params) => params.to_string(),
+
+ let where_clause = match where_clause {
+ Some(pr) => pr.to_string(),
+ None => " ".to_string(),
+ };
+
+ let body = match body {
+ Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
None => String::new(),
};
- ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
+
+ ast_from_text(&format!("impl{gen_params} {path_type}{tr_gen_args}{where_clause}{{{}}}", body))
}
+// FIXME : We must make *_gen_args' type ast::GenericArgList but in order to do so we must implement in `edit_in_place.rs`
+// `add_generic_arg()` just like `add_generic_param()`
+// is implemented for `ast::GenericParamList`
pub fn impl_trait(
- trait_: ast::Path,
- ty: ast::Path,
- ty_params: Option<ast::GenericParamList>,
+ is_unsafe: bool,
+ trait_gen_params: Option<ast::GenericParamList>,
+ trait_gen_args: Option<ast::GenericParamList>,
+ type_gen_params: Option<ast::GenericParamList>,
+ type_gen_args: Option<ast::GenericParamList>,
+ is_negative: bool,
+ path_type: ast::Type,
+ ty: ast::Type,
+ trait_where_clause: Option<ast::WhereClause>,
+ ty_where_clause: Option<ast::WhereClause>,
+ body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
) -> ast::Impl {
- let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
- ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
+ let is_unsafe = if is_unsafe { "unsafe " } else { "" };
+ let ty_gen_args = match merge_gen_params(type_gen_params.clone(), type_gen_args) {
+ Some(pars) => pars.to_generic_args().to_string(),
+ None => String::new(),
+ };
+
+ let tr_gen_args = match merge_gen_params(trait_gen_params.clone(), trait_gen_args) {
+ Some(pars) => pars.to_generic_args().to_string(),
+ None => String::new(),
+ };
+
+ let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
+ Some(pars) => pars.to_string(),
+ None => String::new(),
+ };
+
+ let is_negative = if is_negative { "! " } else { "" };
+
+ let where_clause = match (ty_where_clause, trait_where_clause) {
+ (None, None) => " ".to_string(),
+ (None, Some(tr)) => format!("\n{}\n", tr).to_string(),
+ (Some(ty), None) => format!("\n{}\n", ty).to_string(),
+ (Some(ty), Some(tr)) => {
+ let updated = ty.clone_for_update();
+ tr.predicates().for_each(|p| {
+ ty.add_predicate(p);
+ });
+ format!("\n{}\n", updated).to_string()
+ }
+ };
+
+ let body = match body {
+ Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
+ None => String::new(),
+ };
+
+ ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{tr_gen_args} for {ty}{ty_gen_args}{where_clause}{{{}}}" , body))
+}
+
+pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType {
+ ast_from_text(&format!("fn f(x: impl {bounds}) {{}}"))
}
pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
@@ -355,7 +469,7 @@ pub fn hacky_block_expr(
format_to!(buf, " {t}\n")
} else if kind == SyntaxKind::WHITESPACE {
let content = t.text().trim_matches(|c| c != '\n');
- if content.len() >= 1 {
+ if !content.is_empty() {
format_to!(buf, "{}", &content[1..])
}
}
@@ -827,6 +941,8 @@ pub fn fn_(
body: ast::BlockExpr,
ret_type: Option<ast::RetType>,
is_async: bool,
+ is_const: bool,
+ is_unsafe: bool,
) -> ast::Fn {
let type_params = match type_params {
Some(type_params) => format!("{type_params}"),
@@ -846,12 +962,13 @@ pub fn fn_(
};
let async_literal = if is_async { "async " } else { "" };
+ let const_literal = if is_const { "const " } else { "" };
+ let unsafe_literal = if is_unsafe { "unsafe " } else { "" };
ast_from_text(&format!(
- "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
+ "{visibility}{async_literal}{const_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
))
}
-
pub fn struct_(
visibility: Option<ast::Visibility>,
strukt_name: ast::Name,
@@ -901,7 +1018,7 @@ pub mod tokens {
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
SourceFile::parse(
- "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p)\n;\n\n",
+ "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p)\n;\n\n",
)
});