mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-03 05:13:35 +00:00
fix: Fix move_bounds assists not working for lifetimes
This commit is contained in:
parent
cb18ead726
commit
f9c83edf12
8 changed files with 194 additions and 45 deletions
|
|
@ -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")),
|
||||
|
|
|
|||
|
|
@ -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 {}"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,16 +168,38 @@ impl server::TokenStream for RaSpanServer {
|
|||
}
|
||||
|
||||
bridge::TokenTree::Literal(literal) => {
|
||||
let literal = tt::Literal {
|
||||
symbol: literal.symbol,
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
let token_trees =
|
||||
if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
|
||||
let punct = tt::Punct {
|
||||
spacing: tt::Spacing::Alone,
|
||||
span: literal.span,
|
||||
char: '-' as char,
|
||||
};
|
||||
let leaf: tt::Leaf = tt::Leaf::from(punct);
|
||||
let minus_tree = tt::TokenTree::from(leaf);
|
||||
|
||||
let leaf: tt::Leaf = tt::Leaf::from(literal);
|
||||
let tree = tt::TokenTree::from(leaf);
|
||||
TokenStream { token_trees: vec![tree] }
|
||||
let literal = tt::Literal {
|
||||
symbol: Symbol::intern(symbol),
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
let leaf: tt::Leaf = tt::Leaf::from(literal);
|
||||
let tree = tt::TokenTree::from(leaf);
|
||||
vec![minus_tree, tree]
|
||||
} else {
|
||||
let literal = tt::Literal {
|
||||
symbol: literal.symbol,
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
|
||||
let leaf: tt::Leaf = tt::Leaf::from(literal);
|
||||
let tree = tt::TokenTree::from(leaf);
|
||||
vec![tree]
|
||||
};
|
||||
TokenStream { token_trees }
|
||||
}
|
||||
|
||||
bridge::TokenTree::Punct(p) => {
|
||||
|
|
|
|||
|
|
@ -153,16 +153,38 @@ impl server::TokenStream for TokenIdServer {
|
|||
}
|
||||
|
||||
bridge::TokenTree::Literal(literal) => {
|
||||
let literal = Literal {
|
||||
symbol: literal.symbol,
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
let token_trees =
|
||||
if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
|
||||
let punct = tt::Punct {
|
||||
spacing: tt::Spacing::Alone,
|
||||
span: literal.span,
|
||||
char: '-' as char,
|
||||
};
|
||||
let leaf: tt::Leaf = tt::Leaf::from(punct);
|
||||
let minus_tree = tt::TokenTree::from(leaf);
|
||||
|
||||
let leaf = tt::Leaf::from(literal);
|
||||
let tree = TokenTree::from(leaf);
|
||||
TokenStream { token_trees: vec![tree] }
|
||||
let literal = Literal {
|
||||
symbol: Symbol::intern(symbol),
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
let leaf: tt::Leaf = tt::Leaf::from(literal);
|
||||
let tree = tt::TokenTree::from(leaf);
|
||||
vec![minus_tree, tree]
|
||||
} else {
|
||||
let literal = Literal {
|
||||
symbol: literal.symbol,
|
||||
suffix: literal.suffix,
|
||||
span: literal.span,
|
||||
kind: literal_kind_to_internal(literal.kind),
|
||||
};
|
||||
|
||||
let leaf: tt::Leaf = tt::Leaf::from(literal);
|
||||
let tree = tt::TokenTree::from(leaf);
|
||||
vec![tree]
|
||||
};
|
||||
TokenStream { token_trees }
|
||||
}
|
||||
|
||||
bridge::TokenTree::Punct(p) => {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ impl<S: Copy> TokenStream<S> {
|
|||
span: ident.span,
|
||||
}))
|
||||
}
|
||||
// Note, we do not have to assemble our `-` punct and literal split into a single
|
||||
// negative bridge literal here. As the proc-macro docs state
|
||||
// > Literals created from negative numbers might not survive round-trips through
|
||||
// > TokenStream or strings and may be broken into two tokens (- and positive
|
||||
// > literal).
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
||||
result.push(bridge::TokenTree::Literal(bridge::Literal {
|
||||
span: lit.span,
|
||||
|
|
|
|||
|
|
@ -248,13 +248,17 @@ fn test_fn_like_mk_literals() {
|
|||
LITERAL Str string 1
|
||||
LITERAL CStr cstring 1
|
||||
LITERAL Float 3.14f64 1
|
||||
LITERAL Float -3.14f64 1
|
||||
PUNCH - [alone] 1
|
||||
LITERAL Float 3.14f64 1
|
||||
LITERAL Float 3.14 1
|
||||
PUNCH - [alone] 1
|
||||
LITERAL Float 3.14 1
|
||||
LITERAL Float -3.14 1
|
||||
LITERAL Integer 123i64 1
|
||||
LITERAL Integer -123i64 1
|
||||
PUNCH - [alone] 1
|
||||
LITERAL Integer 123i64 1
|
||||
LITERAL Integer 123 1
|
||||
LITERAL Integer -123 1"#]],
|
||||
PUNCH - [alone] 1
|
||||
LITERAL Integer 123 1"#]],
|
||||
expect![[r#"
|
||||
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
|
||||
|
||||
|
|
@ -266,13 +270,17 @@ fn test_fn_like_mk_literals() {
|
|||
LITERAL Str string 42:2@0..100#ROOT2024
|
||||
LITERAL CStr cstring 42:2@0..100#ROOT2024
|
||||
LITERAL Float 3.14f64 42:2@0..100#ROOT2024
|
||||
LITERAL Float -3.14f64 42:2@0..100#ROOT2024
|
||||
PUNCH - [alone] 42:2@0..100#ROOT2024
|
||||
LITERAL Float 3.14f64 42:2@0..100#ROOT2024
|
||||
LITERAL Float 3.14 42:2@0..100#ROOT2024
|
||||
PUNCH - [alone] 42:2@0..100#ROOT2024
|
||||
LITERAL Float 3.14 42:2@0..100#ROOT2024
|
||||
LITERAL Float -3.14 42:2@0..100#ROOT2024
|
||||
LITERAL Integer 123i64 42:2@0..100#ROOT2024
|
||||
LITERAL Integer -123i64 42:2@0..100#ROOT2024
|
||||
PUNCH - [alone] 42:2@0..100#ROOT2024
|
||||
LITERAL Integer 123i64 42:2@0..100#ROOT2024
|
||||
LITERAL Integer 123 42:2@0..100#ROOT2024
|
||||
LITERAL Integer -123 42:2@0..100#ROOT2024"#]],
|
||||
PUNCH - [alone] 42:2@0..100#ROOT2024
|
||||
LITERAL Integer 123 42:2@0..100#ROOT2024"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +408,6 @@ fn test_fn_like_macro_clone_literals() {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_fn_like_macro_negative_literals() {
|
||||
assert_expand(
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(" + ");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue