Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-expand/src/builtin/derive_macro.rs | 13 | ||||
| -rw-r--r-- | crates/ide-assists/src/handlers/move_bounds.rs | 52 | ||||
| -rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 61 | ||||
| -rw-r--r-- | crates/syntax/src/ast/make.rs | 3 |
4 files changed, 111 insertions, 18 deletions
diff --git a/crates/hir-expand/src/builtin/derive_macro.rs b/crates/hir-expand/src/builtin/derive_macro.rs index 68283b916d..d135584a08 100644 --- a/crates/hir-expand/src/builtin/derive_macro.rs +++ b/crates/hir-expand/src/builtin/derive_macro.rs @@ -1,5 +1,6 @@ //! Builtin derives. +use either::Either; use intern::sym; use itertools::{Itertools, izip}; use parser::SyntaxKind; @@ -1179,10 +1180,10 @@ fn coerce_pointee_expand( }; new_predicates.push( make::where_pred( - make::ty_path(make::path_from_segments( + Either::Right(make::ty_path(make::path_from_segments( [make::path_segment(new_bounds_target)], false, - )), + ))), new_bounds, ) .clone_for_update(), @@ -1245,7 +1246,9 @@ fn coerce_pointee_expand( substitute_type_in_bound(ty, &pointee_param_name.text(), ADDED_PARAM) }) }); - new_predicates.push(make::where_pred(pred_target, new_bounds).clone_for_update()); + new_predicates.push( + make::where_pred(Either::Right(pred_target), new_bounds).clone_for_update(), + ); } } @@ -1260,10 +1263,10 @@ fn coerce_pointee_expand( // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it. where_clause.add_predicate( make::where_pred( - make::ty_path(make::path_from_segments( + Either::Right(make::ty_path(make::path_from_segments( [make::path_segment(make::name_ref(&pointee_param_name.text()))], false, - )), + ))), [make::type_bound(make::ty_path(make::path_from_segments( [ make::path_segment(make::name_ref("core")), diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs index 7e8735bd7a..a9df6f6fc3 100644 --- a/crates/ide-assists/src/handlers/move_bounds.rs +++ b/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,3 +1,4 @@ +use either::Either; use syntax::{ ast::{ self, AstNode, HasName, HasTypeBounds, @@ -30,10 +31,11 @@ pub(crate) fn move_bounds_to_where_clause( ) -> Option<()> { let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?; - let mut type_params = type_param_list.type_or_const_params(); + let mut type_params = type_param_list.generic_params(); if type_params.all(|p| match p { - ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(), - ast::TypeOrConstParam::Const(_) => true, + ast::GenericParam::TypeParam(t) => t.type_bound_list().is_none(), + ast::GenericParam::LifetimeParam(l) => l.type_bound_list().is_none(), + ast::GenericParam::ConstParam(_) => true, }) { return None; } @@ -53,20 +55,23 @@ pub(crate) fn move_bounds_to_where_clause( match parent { ast::Fn(it) => it.get_or_create_where_clause(), ast::Trait(it) => it.get_or_create_where_clause(), + ast::TraitAlias(it) => it.get_or_create_where_clause(), ast::Impl(it) => it.get_or_create_where_clause(), ast::Enum(it) => it.get_or_create_where_clause(), ast::Struct(it) => it.get_or_create_where_clause(), + ast::TypeAlias(it) => it.get_or_create_where_clause(), _ => return, } }; - for toc_param in type_param_list.type_or_const_params() { - let type_param = match toc_param { - ast::TypeOrConstParam::Type(x) => x, - ast::TypeOrConstParam::Const(_) => continue, + for generic_param in type_param_list.generic_params() { + let param: &dyn HasTypeBounds = match &generic_param { + ast::GenericParam::TypeParam(t) => t, + ast::GenericParam::LifetimeParam(l) => l, + ast::GenericParam::ConstParam(_) => continue, }; - if let Some(tbl) = type_param.type_bound_list() { - if let Some(predicate) = build_predicate(type_param) { + if let Some(tbl) = param.type_bound_list() { + if let Some(predicate) = build_predicate(generic_param) { where_clause.add_predicate(predicate) } tbl.remove() @@ -76,9 +81,23 @@ pub(crate) fn move_bounds_to_where_clause( ) } -fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { - let path = make::ext::ident_path(¶m.name()?.syntax().to_string()); - let predicate = make::where_pred(make::ty_path(path), param.type_bound_list()?.bounds()); +fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> { + let target = match ¶m { + ast::GenericParam::TypeParam(t) => { + Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string()))) + } + ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?), + ast::GenericParam::ConstParam(_) => return None, + }; + let predicate = make::where_pred( + target, + match param { + ast::GenericParam::TypeParam(t) => t.type_bound_list()?, + ast::GenericParam::LifetimeParam(l) => l.type_bound_list()?, + ast::GenericParam::ConstParam(_) => return None, + } + .bounds(), + ); Some(predicate.clone_for_update()) } @@ -123,4 +142,13 @@ mod tests { r#"struct Pair<T>(T, T) where T: u32;"#, ); } + + #[test] + fn move_bounds_to_where_clause_trait() { + check_assist( + move_bounds_to_where_clause, + r#"trait T<'a: 'static, $0T: u32> {}"#, + r#"trait T<'a, T> where 'a: 'static, T: u32 {}"#, + ); + } } diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index da0bfd4f37..e60243f2c9 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -109,6 +109,67 @@ impl GenericParamsOwnerEdit for ast::Trait { } } +impl GenericParamsOwnerEdit for ast::TraitAlias { + fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { + match self.generic_param_list() { + Some(it) => it, + None => { + let position = if let Some(name) = self.name() { + Position::after(name.syntax) + } else if let Some(trait_token) = self.trait_token() { + Position::after(trait_token) + } else { + Position::last_child_of(self.syntax()) + }; + create_generic_param_list(position) + } + } + } + + fn get_or_create_where_clause(&self) -> ast::WhereClause { + if self.where_clause().is_none() { + let position = match self.semicolon_token() { + Some(tok) => Position::before(tok), + None => Position::last_child_of(self.syntax()), + }; + create_where_clause(position); + } + self.where_clause().unwrap() + } +} + +impl GenericParamsOwnerEdit for ast::TypeAlias { + fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { + match self.generic_param_list() { + Some(it) => it, + None => { + let position = if let Some(name) = self.name() { + Position::after(name.syntax) + } else if let Some(trait_token) = self.type_token() { + Position::after(trait_token) + } else { + Position::last_child_of(self.syntax()) + }; + create_generic_param_list(position) + } + } + } + + fn get_or_create_where_clause(&self) -> ast::WhereClause { + if self.where_clause().is_none() { + let position = match self.eq_token() { + Some(tok) => Position::before(tok), + None => match self.semicolon_token() { + Some(tok) => Position::before(tok), + None => Position::last_child_of(self.syntax()), + }, + }; + create_where_clause(position); + } + self.where_clause().unwrap() + } +} + impl GenericParamsOwnerEdit for ast::Struct { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { match self.generic_param_list() { diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 596f73e0b1..fab4cb287c 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -13,6 +13,7 @@ mod quote; +use either::Either; use itertools::Itertools; use parser::{Edition, T}; use rowan::NodeOrToken; @@ -881,7 +882,7 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat } pub fn where_pred( - path: ast::Type, + path: Either<ast::Lifetime, ast::Type>, bounds: impl IntoIterator<Item = ast::TypeBound>, ) -> ast::WherePred { let bounds = bounds.into_iter().join(" + "); |