Fix various IDE features
As a side benefit, we got `let` guard support for `move_guard` for free.
This commit is contained in:
parent
fe1e324694
commit
13ac5c3491
@ -811,10 +811,10 @@ pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
|
|||||||
MACRO_TYPE => ExpandTo::Type,
|
MACRO_TYPE => ExpandTo::Type,
|
||||||
|
|
||||||
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
|
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
|
||||||
| CLOSURE_EXPR | CONDITION | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM
|
| CLOSURE_EXPR | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM | MATCH_GUARD
|
||||||
| MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
|
| RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR
|
||||||
| FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR
|
| AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR
|
||||||
| BIN_EXPR => ExpandTo::Expr,
|
| LET_EXPR => ExpandTo::Expr,
|
||||||
LET_STMT => {
|
LET_STMT => {
|
||||||
// FIXME: Handle LHS Pattern
|
// FIXME: Handle LHS Pattern
|
||||||
ExpandTo::Expr
|
ExpandTo::Expr
|
||||||
|
@ -55,6 +55,7 @@ fn test(x: &i32) {
|
|||||||
139..140 'g': {unknown}
|
139..140 'g': {unknown}
|
||||||
143..144 'e': {unknown}
|
143..144 'e': {unknown}
|
||||||
157..204 'if let... }': ()
|
157..204 'if let... }': ()
|
||||||
|
160..175 'let [val] = opt': bool
|
||||||
164..169 '[val]': [{unknown}]
|
164..169 '[val]': [{unknown}]
|
||||||
165..168 'val': {unknown}
|
165..168 'val': {unknown}
|
||||||
172..175 'opt': [{unknown}]
|
172..175 'opt': [{unknown}]
|
||||||
@ -62,6 +63,7 @@ fn test(x: &i32) {
|
|||||||
190..191 'h': {unknown}
|
190..191 'h': {unknown}
|
||||||
194..197 'val': {unknown}
|
194..197 'val': {unknown}
|
||||||
210..236 'if let...rue {}': ()
|
210..236 'if let...rue {}': ()
|
||||||
|
213..233 'let x ... &true': bool
|
||||||
217..225 'x @ true': &bool
|
217..225 'x @ true': &bool
|
||||||
221..225 'true': bool
|
221..225 'true': bool
|
||||||
221..225 'true': bool
|
221..225 'true': bool
|
||||||
@ -111,36 +113,42 @@ fn test(x: &i32) {
|
|||||||
37..38 'x': &i32
|
37..38 'x': &i32
|
||||||
46..208 '{ ...) {} }': ()
|
46..208 '{ ...) {} }': ()
|
||||||
52..75 'if let...y() {}': ()
|
52..75 'if let...y() {}': ()
|
||||||
|
55..72 'let "f... any()': bool
|
||||||
59..64 '"foo"': &str
|
59..64 '"foo"': &str
|
||||||
59..64 '"foo"': &str
|
59..64 '"foo"': &str
|
||||||
67..70 'any': fn any<&str>() -> &str
|
67..70 'any': fn any<&str>() -> &str
|
||||||
67..72 'any()': &str
|
67..72 'any()': &str
|
||||||
73..75 '{}': ()
|
73..75 '{}': ()
|
||||||
80..99 'if let...y() {}': ()
|
80..99 'if let...y() {}': ()
|
||||||
|
83..96 'let 1 = any()': bool
|
||||||
87..88 '1': i32
|
87..88 '1': i32
|
||||||
87..88 '1': i32
|
87..88 '1': i32
|
||||||
91..94 'any': fn any<i32>() -> i32
|
91..94 'any': fn any<i32>() -> i32
|
||||||
91..96 'any()': i32
|
91..96 'any()': i32
|
||||||
97..99 '{}': ()
|
97..99 '{}': ()
|
||||||
104..126 'if let...y() {}': ()
|
104..126 'if let...y() {}': ()
|
||||||
|
107..123 'let 1u... any()': bool
|
||||||
111..115 '1u32': u32
|
111..115 '1u32': u32
|
||||||
111..115 '1u32': u32
|
111..115 '1u32': u32
|
||||||
118..121 'any': fn any<u32>() -> u32
|
118..121 'any': fn any<u32>() -> u32
|
||||||
118..123 'any()': u32
|
118..123 'any()': u32
|
||||||
124..126 '{}': ()
|
124..126 '{}': ()
|
||||||
131..153 'if let...y() {}': ()
|
131..153 'if let...y() {}': ()
|
||||||
|
134..150 'let 1f... any()': bool
|
||||||
138..142 '1f32': f32
|
138..142 '1f32': f32
|
||||||
138..142 '1f32': f32
|
138..142 '1f32': f32
|
||||||
145..148 'any': fn any<f32>() -> f32
|
145..148 'any': fn any<f32>() -> f32
|
||||||
145..150 'any()': f32
|
145..150 'any()': f32
|
||||||
151..153 '{}': ()
|
151..153 '{}': ()
|
||||||
158..179 'if let...y() {}': ()
|
158..179 'if let...y() {}': ()
|
||||||
|
161..176 'let 1.0 = any()': bool
|
||||||
165..168 '1.0': f64
|
165..168 '1.0': f64
|
||||||
165..168 '1.0': f64
|
165..168 '1.0': f64
|
||||||
171..174 'any': fn any<f64>() -> f64
|
171..174 'any': fn any<f64>() -> f64
|
||||||
171..176 'any()': f64
|
171..176 'any()': f64
|
||||||
177..179 '{}': ()
|
177..179 '{}': ()
|
||||||
184..206 'if let...y() {}': ()
|
184..206 'if let...y() {}': ()
|
||||||
|
187..203 'let tr... any()': bool
|
||||||
191..195 'true': bool
|
191..195 'true': bool
|
||||||
191..195 'true': bool
|
191..195 'true': bool
|
||||||
198..201 'any': fn any<bool>() -> bool
|
198..201 'any': fn any<bool>() -> bool
|
||||||
@ -163,10 +171,12 @@ fn test(x: &i32) {
|
|||||||
8..9 'x': &i32
|
8..9 'x': &i32
|
||||||
17..75 '{ ...2 {} }': ()
|
17..75 '{ ...2 {} }': ()
|
||||||
23..45 'if let...u32 {}': ()
|
23..45 'if let...u32 {}': ()
|
||||||
|
26..42 'let 1....= 2u32': bool
|
||||||
30..35 '1..76': u32
|
30..35 '1..76': u32
|
||||||
38..42 '2u32': u32
|
38..42 '2u32': u32
|
||||||
43..45 '{}': ()
|
43..45 '{}': ()
|
||||||
50..73 'if let...u32 {}': ()
|
50..73 'if let...u32 {}': ()
|
||||||
|
53..70 'let 1....= 2u32': bool
|
||||||
57..63 '1..=76': u32
|
57..63 '1..=76': u32
|
||||||
66..70 '2u32': u32
|
66..70 '2u32': u32
|
||||||
71..73 '{}': ()
|
71..73 '{}': ()
|
||||||
|
@ -2248,6 +2248,7 @@ fn test() {
|
|||||||
176..193 'Thing ...1i32 }': Thing<i32>
|
176..193 'Thing ...1i32 }': Thing<i32>
|
||||||
187..191 '1i32': i32
|
187..191 '1i32': i32
|
||||||
199..240 'if let... }': ()
|
199..240 'if let... }': ()
|
||||||
|
202..221 'let Th... } = z': bool
|
||||||
206..217 'Thing { t }': Thing<i32>
|
206..217 'Thing { t }': Thing<i32>
|
||||||
214..215 't': i32
|
214..215 't': i32
|
||||||
220..221 'z': Thing<i32>
|
220..221 'z': Thing<i32>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
algo, ast,
|
algo, ast,
|
||||||
display::{fn_as_proc_macro_label, macro_label},
|
display::{fn_as_proc_macro_label, macro_label},
|
||||||
match_ast, AstNode, Direction,
|
match_ast, AstNode, Direction,
|
||||||
SyntaxKind::{CONDITION, LET_STMT},
|
SyntaxKind::{LET_EXPR, LET_STMT},
|
||||||
SyntaxToken, T,
|
SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -484,7 +484,7 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
|||||||
let let_kw = if ident
|
let let_kw = if ident
|
||||||
.syntax()
|
.syntax()
|
||||||
.parent()
|
.parent()
|
||||||
.map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION)
|
.map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR)
|
||||||
{
|
{
|
||||||
"let "
|
"let "
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,7 +243,7 @@ fn is_named_constructor(
|
|||||||
let expr = match_ast! {
|
let expr = match_ast! {
|
||||||
match let_node {
|
match let_node {
|
||||||
ast::LetStmt(it) => it.initializer(),
|
ast::LetStmt(it) => it.initializer(),
|
||||||
ast::Condition(it) => it.expr(),
|
ast::LetExpr(it) => it.expr(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
@ -372,15 +372,10 @@ fn should_not_display_type_hint(
|
|||||||
match node {
|
match node {
|
||||||
ast::LetStmt(it) => return it.ty().is_some(),
|
ast::LetStmt(it) => return it.ty().is_some(),
|
||||||
ast::Param(it) => return it.ty().is_some(),
|
ast::Param(it) => return it.ty().is_some(),
|
||||||
ast::MatchArm(_it) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||||
ast::IfExpr(it) => {
|
ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
ast::IfExpr(_) => return false,
|
||||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
ast::WhileExpr(_) => return false,
|
||||||
},
|
|
||||||
ast::WhileExpr(it) => {
|
|
||||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
|
||||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
|
||||||
},
|
|
||||||
ast::ForExpr(it) => {
|
ast::ForExpr(it) => {
|
||||||
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
|
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
|
||||||
// Type of expr should be iterable.
|
// Type of expr should be iterable.
|
||||||
|
@ -46,7 +46,6 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cond = expr.condition().filter(|cond| !cond.is_pattern_cond())?;
|
let cond = expr.condition().filter(|cond| !cond.is_pattern_cond())?;
|
||||||
let cond = cond.expr()?;
|
|
||||||
let then = expr.then_branch()?;
|
let then = expr.then_branch()?;
|
||||||
let else_ = match expr.else_branch()? {
|
let else_ = match expr.else_branch()? {
|
||||||
ast::ElseBranch::Block(b) => b,
|
ast::ElseBranch::Block(b) => b,
|
||||||
@ -209,7 +208,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext) ->
|
|||||||
_ => receiver,
|
_ => receiver,
|
||||||
};
|
};
|
||||||
let if_expr = make::expr_if(
|
let if_expr = make::expr_if(
|
||||||
make::condition(cond, None),
|
cond,
|
||||||
closure_body.reset_indent(),
|
closure_body.reset_indent(),
|
||||||
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
|
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
|
||||||
)
|
)
|
||||||
|
@ -48,8 +48,9 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
|||||||
let cond = if_expr.condition()?;
|
let cond = if_expr.condition()?;
|
||||||
|
|
||||||
// Check if there is an IfLet that we can handle.
|
// Check if there is an IfLet that we can handle.
|
||||||
let if_let_pat = match cond.pat() {
|
let (if_let_pat, cond_expr) = if cond.is_pattern_cond() {
|
||||||
None => None, // No IfLet, supported.
|
let let_ = cond.single_let()?;
|
||||||
|
match let_.pat() {
|
||||||
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
||||||
let path = pat.path()?;
|
let path = pat.path()?;
|
||||||
if path.qualifier().is_some() {
|
if path.qualifier().is_some() {
|
||||||
@ -61,12 +62,14 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((path, bound_ident))
|
(Some((path, bound_ident)), let_.expr()?)
|
||||||
}
|
}
|
||||||
Some(_) => return None, // Unsupported IfLet.
|
_ => return None, // Unsupported IfLet.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(None, cond)
|
||||||
};
|
};
|
||||||
|
|
||||||
let cond_expr = cond.expr()?;
|
|
||||||
let then_block = if_expr.then_branch()?;
|
let then_block = if_expr.then_branch()?;
|
||||||
let then_block = then_block.stmt_list()?;
|
let then_block = then_block.stmt_list()?;
|
||||||
|
|
||||||
@ -119,8 +122,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
|||||||
let then_branch =
|
let then_branch =
|
||||||
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
||||||
let cond = invert_boolean_expression(cond_expr);
|
let cond = invert_boolean_expression(cond_expr);
|
||||||
make::expr_if(make::condition(cond, None), then_branch, None)
|
make::expr_if(cond, then_branch, None).indent(if_indent_level)
|
||||||
.indent(if_indent_level)
|
|
||||||
};
|
};
|
||||||
new_expr.syntax().clone_for_update()
|
new_expr.syntax().clone_for_update()
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
|
|||||||
let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
|
let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
|
||||||
let while_body = while_expr.loop_body()?;
|
let while_body = while_expr.loop_body()?;
|
||||||
let while_cond = while_expr.condition()?;
|
let while_cond = while_expr.condition()?;
|
||||||
let while_cond_expr = while_cond.expr()?;
|
|
||||||
|
|
||||||
let target = while_expr.syntax().text_range();
|
let target = while_expr.syntax().text_range();
|
||||||
acc.add(
|
acc.add(
|
||||||
@ -55,19 +54,15 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
|
|||||||
let break_block =
|
let break_block =
|
||||||
make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
|
make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
|
||||||
.indent(while_indent_level);
|
.indent(while_indent_level);
|
||||||
let block_expr = match while_cond.pat() {
|
let block_expr = if while_cond.is_pattern_cond() {
|
||||||
Some(_) => {
|
|
||||||
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
||||||
let stmts = once(make::expr_stmt(if_expr).into());
|
let stmts = once(make::expr_stmt(if_expr).into());
|
||||||
make::block_expr(stmts, None)
|
make::block_expr(stmts, None)
|
||||||
}
|
} else {
|
||||||
None => {
|
let if_cond = invert_boolean_expression(while_cond);
|
||||||
let if_cond = make::condition(invert_boolean_expression(while_cond_expr), None);
|
|
||||||
let if_expr = make::expr_if(if_cond, break_block, None);
|
let if_expr = make::expr_if(if_cond, break_block, None);
|
||||||
let stmts =
|
let stmts = once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
|
||||||
once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
|
|
||||||
make::block_expr(stmts, while_body.tail_expr())
|
make::block_expr(stmts, while_body.tail_expr())
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let replacement = make::expr_loop(block_expr.indent(while_indent_level));
|
let replacement = make::expr_loop(block_expr.indent(while_indent_level));
|
||||||
|
@ -1219,28 +1219,26 @@ fn make_call_expr(&self, call_expr: ast::Expr) -> ast::Expr {
|
|||||||
let stmt = make::expr_stmt(action);
|
let stmt = make::expr_stmt(action);
|
||||||
let block = make::block_expr(iter::once(stmt.into()), None);
|
let block = make::block_expr(iter::once(stmt.into()), None);
|
||||||
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
|
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
|
||||||
let condition = make::condition(
|
let condition = make::expr_let(
|
||||||
call_expr,
|
|
||||||
Some(
|
|
||||||
make::tuple_struct_pat(
|
make::tuple_struct_pat(
|
||||||
controlflow_break_path,
|
controlflow_break_path,
|
||||||
iter::once(make::wildcard_pat().into()),
|
iter::once(make::wildcard_pat().into()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
),
|
call_expr,
|
||||||
);
|
);
|
||||||
make::expr_if(condition, block, None)
|
make::expr_if(condition.into(), block, None)
|
||||||
}
|
}
|
||||||
FlowHandler::IfOption { action } => {
|
FlowHandler::IfOption { action } => {
|
||||||
let path = make::ext::ident_path("Some");
|
let path = make::ext::ident_path("Some");
|
||||||
let value_pat = make::ext::simple_ident_pat(make::name("value"));
|
let value_pat = make::ext::simple_ident_pat(make::name("value"));
|
||||||
let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
||||||
let cond = make::condition(call_expr, Some(pattern.into()));
|
let cond = make::expr_let(pattern.into(), call_expr);
|
||||||
let value = make::expr_path(make::ext::ident_path("value"));
|
let value = make::expr_path(make::ext::ident_path("value"));
|
||||||
let action_expr = action.make_result_handler(Some(value));
|
let action_expr = action.make_result_handler(Some(value));
|
||||||
let action_stmt = make::expr_stmt(action_expr);
|
let action_stmt = make::expr_stmt(action_expr);
|
||||||
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
||||||
make::expr_if(cond, then, None)
|
make::expr_if(cond.into(), then, None)
|
||||||
}
|
}
|
||||||
FlowHandler::MatchOption { none } => {
|
FlowHandler::MatchOption { none } => {
|
||||||
let some_name = "value";
|
let some_name = "value";
|
||||||
|
@ -34,12 +34,12 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cond = expr.condition()?;
|
||||||
// This assist should not apply for if-let.
|
// This assist should not apply for if-let.
|
||||||
if expr.condition()?.is_pattern_cond() {
|
if cond.is_pattern_cond() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cond = expr.condition()?.expr()?;
|
|
||||||
let then_node = expr.then_branch()?.syntax().clone();
|
let then_node = expr.then_branch()?.syntax().clone();
|
||||||
let else_block = match expr.else_branch()? {
|
let else_block = match expr.else_branch()? {
|
||||||
ast::ElseBranch::Block(it) => it,
|
ast::ElseBranch::Block(it) => it,
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat},
|
||||||
edit::AstNodeEdit, make, AstNode, BlockExpr, Condition, ElseBranch, Expr, IfExpr, MatchArm,
|
|
||||||
Pat,
|
|
||||||
},
|
|
||||||
SyntaxKind::WHITESPACE,
|
SyntaxKind::WHITESPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,17 +41,10 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
|
|||||||
}
|
}
|
||||||
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
||||||
|
|
||||||
// FIXME: support `if let` guards too
|
let guard_condition = guard.condition()?;
|
||||||
if guard.let_token().is_some() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let guard_condition = guard.expr()?;
|
|
||||||
let arm_expr = match_arm.expr()?;
|
let arm_expr = match_arm.expr()?;
|
||||||
let if_expr = make::expr_if(
|
let if_expr =
|
||||||
make::condition(guard_condition, None),
|
make::expr_if(guard_condition, make::block_expr(None, Some(arm_expr.clone())), None)
|
||||||
make::block_expr(None, Some(arm_expr.clone())),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.indent(arm_expr.indent_level());
|
.indent(arm_expr.indent_level());
|
||||||
|
|
||||||
let target = guard.syntax().text_range();
|
let target = guard.syntax().text_range();
|
||||||
@ -193,17 +183,13 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses an if-else-if chain to get the conditons and the then branches until we encounter an else
|
// Parses an if-else-if chain to get the conditions and the then branches until we encounter an else
|
||||||
// branch or the end.
|
// branch or the end.
|
||||||
fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Condition, BlockExpr)>, Option<BlockExpr>)> {
|
fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Expr, BlockExpr)>, Option<BlockExpr>)> {
|
||||||
let mut conds_blocks = Vec::new();
|
let mut conds_blocks = Vec::new();
|
||||||
let mut curr_if = if_expr;
|
let mut curr_if = if_expr;
|
||||||
let tail = loop {
|
let tail = loop {
|
||||||
let cond = curr_if.condition()?;
|
let cond = curr_if.condition()?;
|
||||||
// Not support moving if let to arm guard
|
|
||||||
if cond.is_pattern_cond() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
conds_blocks.push((cond, curr_if.then_branch()?));
|
conds_blocks.push((cond, curr_if.then_branch()?));
|
||||||
match curr_if.else_branch() {
|
match curr_if.else_branch() {
|
||||||
Some(ElseBranch::IfExpr(e)) => {
|
Some(ElseBranch::IfExpr(e)) => {
|
||||||
|
@ -60,15 +60,22 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let scrutinee_to_be_expr = if_expr.condition()?.expr()?;
|
let scrutinee_to_be_expr = if_expr.condition()?;
|
||||||
|
let scrutinee_to_be_expr = match scrutinee_to_be_expr.single_let() {
|
||||||
|
Some(cond) => cond.expr()?,
|
||||||
|
None => scrutinee_to_be_expr,
|
||||||
|
};
|
||||||
|
|
||||||
let mut pat_seen = false;
|
let mut pat_seen = false;
|
||||||
let mut cond_bodies = Vec::new();
|
let mut cond_bodies = Vec::new();
|
||||||
for if_expr in if_exprs {
|
for if_expr in if_exprs {
|
||||||
let cond = if_expr.condition()?;
|
let cond = if_expr.condition()?;
|
||||||
let expr = cond.expr()?;
|
let cond = match cond.single_let() {
|
||||||
let cond = match cond.pat() {
|
Some(let_) => {
|
||||||
Some(pat) => {
|
let pat = let_.pat()?;
|
||||||
|
let expr = let_.expr()?;
|
||||||
|
// FIXME: If one `let` is wrapped in parentheses and the second is not,
|
||||||
|
// we'll exit here.
|
||||||
if scrutinee_to_be_expr.syntax().text() != expr.syntax().text() {
|
if scrutinee_to_be_expr.syntax().text() != expr.syntax().text() {
|
||||||
// Only if all condition expressions are equal we can merge them into a match
|
// Only if all condition expressions are equal we can merge them into a match
|
||||||
return None;
|
return None;
|
||||||
@ -76,7 +83,9 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
|||||||
pat_seen = true;
|
pat_seen = true;
|
||||||
Either::Left(pat)
|
Either::Left(pat)
|
||||||
}
|
}
|
||||||
None => Either::Right(expr),
|
// Multiple `let`, unsupported.
|
||||||
|
None if cond.is_pattern_cond() => return None,
|
||||||
|
None => Either::Right(cond),
|
||||||
};
|
};
|
||||||
let body = if_expr.then_branch()?;
|
let body = if_expr.then_branch()?;
|
||||||
cond_bodies.push((cond, body));
|
cond_bodies.push((cond, body));
|
||||||
@ -217,11 +226,11 @@ fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let condition = make::condition(scrutinee, Some(if_let_pat));
|
let condition = make::expr_let(if_let_pat, scrutinee);
|
||||||
let then_block = make_block_expr(then_expr.reset_indent());
|
let then_block = make_block_expr(then_expr.reset_indent());
|
||||||
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
||||||
let if_let_expr = make::expr_if(
|
let if_let_expr = make::expr_if(
|
||||||
condition,
|
condition.into(),
|
||||||
then_block,
|
then_block,
|
||||||
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
||||||
)
|
)
|
||||||
|
@ -62,7 +62,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
|
|||||||
|
|
||||||
let block =
|
let block =
|
||||||
make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
|
make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
|
||||||
let if_ = make::expr_if(make::condition(init, Some(pat)), block, None);
|
let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None);
|
||||||
let stmt = make::expr_stmt(if_);
|
let stmt = make::expr_stmt(if_);
|
||||||
|
|
||||||
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
||||||
|
@ -575,6 +575,14 @@ fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
|
|||||||
|
|
||||||
(ty, name)
|
(ty, name)
|
||||||
},
|
},
|
||||||
|
ast::LetExpr(it) => {
|
||||||
|
cov_mark::hit!(expected_type_if_let_without_leading_char);
|
||||||
|
let ty = it.pat()
|
||||||
|
.and_then(|pat| self.sema.type_of_pat(&pat))
|
||||||
|
.or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it)))
|
||||||
|
.map(TypeInfo::original);
|
||||||
|
(ty, None)
|
||||||
|
},
|
||||||
ast::ArgList(_) => {
|
ast::ArgList(_) => {
|
||||||
cov_mark::hit!(expected_type_fn_param);
|
cov_mark::hit!(expected_type_fn_param);
|
||||||
ActiveParameter::at_token(
|
ActiveParameter::at_token(
|
||||||
@ -641,9 +649,7 @@ fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
|
|||||||
(ty, None)
|
(ty, None)
|
||||||
},
|
},
|
||||||
ast::IfExpr(it) => {
|
ast::IfExpr(it) => {
|
||||||
cov_mark::hit!(expected_type_if_let_without_leading_char);
|
|
||||||
let ty = it.condition()
|
let ty = it.condition()
|
||||||
.and_then(|cond| cond.expr())
|
|
||||||
.and_then(|e| self.sema.type_of_expr(&e))
|
.and_then(|e| self.sema.type_of_expr(&e))
|
||||||
.map(TypeInfo::original);
|
.map(TypeInfo::original);
|
||||||
(ty, None)
|
(ty, None)
|
||||||
@ -939,7 +945,7 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
|
|||||||
return (PatternRefutability::Irrefutable, has_type_ascription)
|
return (PatternRefutability::Irrefutable, has_type_ascription)
|
||||||
},
|
},
|
||||||
ast::MatchArm(_) => PatternRefutability::Refutable,
|
ast::MatchArm(_) => PatternRefutability::Refutable,
|
||||||
ast::Condition(_) => PatternRefutability::Refutable,
|
ast::LetExpr(_) => PatternRefutability::Refutable,
|
||||||
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
||||||
_ => PatternRefutability::Irrefutable,
|
_ => PatternRefutability::Irrefutable,
|
||||||
}
|
}
|
||||||
|
@ -226,6 +226,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
|
|||||||
| ast::Expr::TryExpr(_)
|
| ast::Expr::TryExpr(_)
|
||||||
| ast::Expr::TupleExpr(_)
|
| ast::Expr::TupleExpr(_)
|
||||||
| ast::Expr::WhileExpr(_)
|
| ast::Expr::WhileExpr(_)
|
||||||
|
| ast::Expr::LetExpr(_)
|
||||||
| ast::Expr::YieldExpr(_) => cb(expr),
|
| ast::Expr::YieldExpr(_) => cb(expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user