Fix various IDE features

As a side benefit, we got `let` guard support for `move_guard` for free.
This commit is contained in:
Chayim Refael Friedman 2022-01-24 00:37:59 +02:00
parent fe1e324694
commit 13ac5c3491
15 changed files with 95 additions and 93 deletions

View File

@ -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

View File

@ -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 '{}': ()

View File

@ -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>

View File

@ -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 {

View File

@ -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.

View File

@ -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)))),
) )

View File

@ -48,25 +48,28 @@ 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()?;
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => { match let_.pat() {
let path = pat.path()?; Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
if path.qualifier().is_some() { let path = pat.path()?;
return None; if path.qualifier().is_some() {
} return None;
}
let bound_ident = pat.fields().next().unwrap(); let bound_ident = pat.fields().next().unwrap();
if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) { if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
return None; return None;
} }
Some((path, bound_ident)) (Some((path, bound_ident)), let_.expr()?)
}
_ => return None, // Unsupported IfLet.
} }
Some(_) => 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()
} }

View File

@ -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 {
} let if_cond = invert_boolean_expression(while_cond);
None => { let if_expr = make::expr_if(if_cond, break_block, None);
let if_cond = make::condition(invert_boolean_expression(while_cond_expr), None); let stmts = once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
let if_expr = make::expr_if(if_cond, break_block, None); make::block_expr(stmts, while_body.tail_expr())
let stmts =
once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
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));

View File

@ -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(
make::tuple_struct_pat(
controlflow_break_path,
iter::once(make::wildcard_pat().into()),
)
.into(),
call_expr, call_expr,
Some(
make::tuple_struct_pat(
controlflow_break_path,
iter::once(make::wildcard_pat().into()),
)
.into(),
),
); );
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";

View File

@ -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,

View File

@ -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,18 +41,11 @@ 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())), .indent(arm_expr.indent_level());
None,
)
.indent(arm_expr.indent_level());
let target = guard.syntax().text_range(); let target = guard.syntax().text_range();
acc.add( acc.add(
@ -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)) => {

View File

@ -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),
) )

View File

@ -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));

View File

@ -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,
} }

View File

@ -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),
} }
} }