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.rs28
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 {