Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
| -rw-r--r-- | crates/ide-completion/src/context/analysis.rs | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 440ac9ad07..873eceff5f 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -926,7 +926,7 @@ fn classify_name_ref<'db>( receiver_ty, kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -941,7 +941,7 @@ fn classify_name_ref<'db>( receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), kind: DotAccessKind::Method { has_parens }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -1229,7 +1229,7 @@ fn classify_name_ref<'db>( let make_path_kind_expr = |expr: ast::Expr| { let it = expr.syntax(); let in_block_expr = is_in_block(it); - let in_loop_body = is_in_breakable(it); + let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip(); let after_if_expr = after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); @@ -1283,6 +1283,11 @@ fn classify_name_ref<'db>( None => (None, None), } }; + let innermost_breakable_ty = innermost_breakable + .and_then(ast::Expr::cast) + .and_then(|expr| find_node_in_file_compensated(sema, original_file, &expr)) + .and_then(|expr| sema.type_of_expr(&expr)) + .map(|ty| if ty.original.is_never() { ty.adjusted() } else { ty.original() }); let is_func_update = func_update_record(it); let in_condition = is_in_condition(&expr); let after_incomplete_let = after_incomplete_let(it.clone()).is_some(); @@ -1316,6 +1321,7 @@ fn classify_name_ref<'db>( after_amp, is_func_update, innermost_ret_ty, + innermost_breakable_ty, self_param, in_value, incomplete_let, @@ -1865,24 +1871,22 @@ fn is_in_token_of_for_loop(path: &ast::Path) -> bool { .unwrap_or(false) } -fn is_in_breakable(node: &SyntaxNode) -> BreakableKind { +fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> { node.ancestors() .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR) .find_map(|it| { let (breakable, loop_body) = match_ast! { match it { - ast::ForExpr(it) => (BreakableKind::For, it.loop_body()), - ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()), - ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()), - ast::BlockExpr(it) => return it.label().map(|_| BreakableKind::Block), + ast::ForExpr(it) => (BreakableKind::For, it.loop_body()?), + ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()?), + ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()?), + ast::BlockExpr(it) => return it.label().map(|_| (BreakableKind::Block, it.syntax().clone())), _ => return None, } }; - loop_body - .filter(|it| it.syntax().text_range().contains_range(node.text_range())) - .map(|_| breakable) + loop_body.syntax().text_range().contains_range(node.text_range()) + .then_some((breakable, it)) }) - .unwrap_or(BreakableKind::None) } fn is_in_block(node: &SyntaxNode) -> bool { |