Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-completion/src/completions/expr.rs6
-rw-r--r--crates/ide-completion/src/completions/keyword.rs40
-rw-r--r--crates/ide-completion/src/context.rs1
-rw-r--r--crates/ide-completion/src/context/analysis.rs41
-rw-r--r--crates/ide-completion/src/tests/expression.rs149
5 files changed, 220 insertions, 17 deletions
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 1972f16613..2c7d9e97c4 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -61,6 +61,7 @@ pub(crate) fn complete_expr_path(
after_if_expr,
in_condition,
incomplete_let,
+ after_incomplete_let,
in_value,
ref ref_expr_parent,
after_amp,
@@ -385,8 +386,11 @@ pub(crate) fn complete_expr_path(
add_keyword("let", "let $1 = $0;");
}
- if after_if_expr {
+ if after_if_expr || after_incomplete_let {
add_keyword("else", "else {\n $0\n}");
+ }
+
+ if after_if_expr {
add_keyword("else if", "else if $1 {\n $0\n}");
}
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index aea4e119f2..b3d770997a 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -248,6 +248,46 @@ fn main() {
);
check_edit(
+ "else",
+ r#"
+fn main() {
+ let x = if true {
+ ()
+ } $0
+ let y = 92;
+}
+"#,
+ r#"
+fn main() {
+ let x = if true {
+ ()
+ } else {
+ $0
+};
+ let y = 92;
+}
+"#,
+ );
+
+ check_edit(
+ "else",
+ r#"
+fn main() {
+ let x = 2 $0
+ let y = 92;
+}
+"#,
+ r#"
+fn main() {
+ let x = 2 else {
+ $0
+};
+ let y = 92;
+}
+"#,
+ );
+
+ check_edit(
"loop",
r#"
fn main() {
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 265462d220..007475688d 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -147,6 +147,7 @@ pub(crate) struct PathExprCtx<'db> {
/// Whether this expression is the direct condition of an if or while expression
pub(crate) in_condition: bool,
pub(crate) incomplete_let: bool,
+ pub(crate) after_incomplete_let: bool,
pub(crate) in_value: bool,
pub(crate) ref_expr_parent: Option<ast::RefExpr>,
pub(crate) after_amp: bool,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 17978b4c10..33b98a33ca 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -947,25 +947,29 @@ fn classify_name_ref<'db>(
None
}
};
- let after_if_expr = |node: SyntaxNode| {
- let prev_expr = (|| {
- let node = match node.parent().and_then(ast::ExprStmt::cast) {
- Some(stmt) => stmt.syntax().clone(),
- None => node,
- };
- let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
+ let prev_expr = |node: SyntaxNode| {
+ let node = match node.parent().and_then(ast::ExprStmt::cast) {
+ Some(stmt) => stmt.syntax().clone(),
+ None => node,
+ };
+ let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
- match_ast! {
- match prev_sibling {
- ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()),
- ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()),
- ast::Expr(expr) => Some(expr),
- _ => None,
- }
+ match_ast! {
+ match prev_sibling {
+ ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()),
+ ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()),
+ ast::Expr(expr) => Some(expr),
+ _ => None,
}
- })();
+ }
+ };
+ let after_if_expr = |node: SyntaxNode| {
+ let prev_expr = prev_expr(node);
matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
};
+ let after_incomplete_let = |node: SyntaxNode| {
+ prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
+ };
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
// ex. trait Foo $0 {}
@@ -1265,10 +1269,14 @@ fn classify_name_ref<'db>(
};
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();
+ let incomplete_expr_stmt =
+ it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none());
let incomplete_let = it
.parent()
.and_then(ast::LetStmt::cast)
- .is_some_and(|it| it.semicolon_token().is_none());
+ .is_some_and(|it| it.semicolon_token().is_none())
+ || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true);
let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
@@ -1292,6 +1300,7 @@ fn classify_name_ref<'db>(
self_param,
in_value,
incomplete_let,
+ after_incomplete_let,
impl_,
in_match_guard,
},
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 7a0d004441..56fbd91a60 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -451,6 +451,155 @@ fn completes_in_let_initializer() {
}
#[test]
+fn completes_let_else() {
+ check(
+ r#"fn main() { let _ = 2 $0 }"#,
+ expect![[r#"
+ fn main() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+
+ check(
+ r#"fn main() { let _ = 2 el$0 }"#,
+ expect![[r#"
+ fn main() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+
+ check_edit(
+ "else",
+ r#"
+fn main() {
+ let _ = 2 $0
+}
+"#,
+ r#"
+fn main() {
+ let _ = 2 else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "else",
+ r#"
+fn main() {
+ let _ = 2 el$0
+}
+"#,
+ r#"
+fn main() {
+ let _ = 2 else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "else",
+ r#"
+fn main() {
+ let _ = 2 $0;
+}
+"#,
+ r#"
+fn main() {
+ let _ = 2 else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "else",
+ r#"
+fn main() {
+ let _ = 2 el$0;
+}
+"#,
+ r#"
+fn main() {
+ let _ = 2 else {
+ $0
+};
+}
+"#,
+ );
+}
+
+#[test]
fn completes_after_ref_expr() {
check(
r#"fn main() { let _ = &$0 }"#,