Merge pull request #20689 from ShoyuVanilla/accurate-flycheck
fix: Make flycheck clearing dependency-aware
diff --git a/Cargo.lock b/Cargo.lock
index 097bb81..17dea1b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1807,9 +1807,9 @@
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "016c05852e89655395fbf7d5e729e31cd58b2690480b3a8468eb2b38c91f3756"
+checksum = "597bb303548ddcca3a2eb05af254508aaf39cf334d4350bb5da51de1eb728859"
dependencies = [
"bitflags 2.9.1",
"ra-ap-rustc_hashes",
@@ -1819,24 +1819,24 @@
[[package]]
name = "ra-ap-rustc_ast_ir"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5bff48bd0a26f17a4e2e8610bc393296c3d002e221f5c6c4d2875e6a64a3b4b"
+checksum = "78982b4e4432ee4b938e47bb5c8f1a5a5a88c27c782f193aefcc12a3250bd2e2"
[[package]]
name = "ra-ap-rustc_hashes"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d15e7571f6f31f6112fd2fcbc3450a6ef477cc6bfe51643a2b110436a7455f0"
+checksum = "2f7f33a422f724cc1ab43972cdd76a556b17fc256f301d23be620adfc8351df7"
dependencies = [
"rustc-stable-hash",
]
[[package]]
name = "ra-ap-rustc_index"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a30f0a15682f1194e5812cc3544266f3494ca8fb3c5033e8b9c08f4f8b8c6d"
+checksum = "8a6006023c8be18c3ac225d69c1b42f55b3f597f3db03fb40764b4cf1454fd13"
dependencies = [
"ra-ap-rustc_index_macros",
"smallvec",
@@ -1844,9 +1844,9 @@
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2f82c9176b964591e1657a9f0fae2850525542d39075c49c2459afc291f4804"
+checksum = "9217c29f7fcc30d07ed13a62262144f665410ef1460202599ae924f9ae47ad78"
dependencies = [
"proc-macro2",
"quote",
@@ -1855,9 +1855,9 @@
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "585c71ff7da5ca1e8a0c65d5e7cec7ab2a7e9e45b6859543bd2d0be21bee631c"
+checksum = "573ad4f5da620e8ba1849d8862866abd7bc765c3d81cb2488c3ecbef33ce2c69"
dependencies = [
"memchr",
"unicode-properties",
@@ -1866,9 +1866,9 @@
[[package]]
name = "ra-ap-rustc_next_trait_solver"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "839f521a6cd97c71b2b6681604ace38a9c6737f7a223d072fa8f909879f9dc4b"
+checksum = "0d42b095b99e988aeb94622ae62ebda4b7de55d7d98846eec352b8a5a2b8a858"
dependencies = [
"derive-where",
"ra-ap-rustc_index",
@@ -1879,9 +1879,9 @@
[[package]]
name = "ra-ap-rustc_parse_format"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83e7872a4fa0620937b60fc6270aa8c31864cb324357553e2be5b2bdc25fa89a"
+checksum = "a21b4e95cb45f840c172493c05f5b9471cf44adb2eccf95d76a0d76e88007870"
dependencies = [
"ra-ap-rustc_lexer",
"rustc-literal-escaper 0.0.5",
@@ -1889,9 +1889,9 @@
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ecd7f9b960c8cf1e9d02a25297f52a520134132164cfedd3e69fee4f294d41c"
+checksum = "b6aeacef1248066f7b67e7296ef135eeab6446d5d2a5c7f02b8d7b747b41e39b"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.1.1",
@@ -1902,9 +1902,9 @@
[[package]]
name = "ra-ap-rustc_type_ir"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9494498f8f7c57a5b4ea4e35a6c554cca8d5323adb534d13dc6cd117a7e00e4d"
+checksum = "52e35ee9e052406035016b8e6d54ca202bc39ccba1702780b33b2d5fb10d1da8"
dependencies = [
"arrayvec",
"bitflags 2.9.1",
@@ -1922,9 +1922,9 @@
[[package]]
name = "ra-ap-rustc_type_ir_macros"
-version = "0.131.0"
+version = "0.132.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28ed893760b86529080af59438c28dfa9ca976b821cfd0a3b0eb9591932847e6"
+checksum = "9b934c956b0c88df8176803416b69d85d2c392a69c8aa794a4c338f22c527d38"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index cfbd8a5..0401367 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -87,14 +87,14 @@
vfs = { path = "./crates/vfs", version = "0.0.0" }
edition = { path = "./crates/edition", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.131", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.131", default-features = false }
-ra-ap-rustc_index = { version = "0.131", default-features = false }
-ra-ap-rustc_abi = { version = "0.131", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.131", default-features = false }
-ra-ap-rustc_ast_ir = { version = "0.131", default-features = false }
-ra-ap-rustc_type_ir = { version = "0.131", default-features = false }
-ra-ap-rustc_next_trait_solver = { version = "0.131", default-features = false }
+ra-ap-rustc_lexer = { version = "0.132", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.132", default-features = false }
+ra-ap-rustc_index = { version = "0.132", default-features = false }
+ra-ap-rustc_abi = { version = "0.132", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.132", default-features = false }
+ra-ap-rustc_ast_ir = { version = "0.132", default-features = false }
+ra-ap-rustc_type_ir = { version = "0.132", default-features = false }
+ra-ap-rustc_next_trait_solver = { version = "0.132", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
diff --git a/crates/hir-ty/src/next_solver/inspect.rs b/crates/hir-ty/src/next_solver/inspect.rs
index 128135d..bc19d51 100644
--- a/crates/hir-ty/src/next_solver/inspect.rs
+++ b/crates/hir-ty/src/next_solver/inspect.rs
@@ -2,11 +2,9 @@
use rustc_ast_ir::try_visit;
use rustc_next_trait_solver::{
+ canonical::instantiate_canonical_state,
resolve::eager_resolve_vars,
- solve::{
- SolverDelegateEvalExt,
- inspect::{self, instantiate_canonical_state},
- },
+ solve::{SolverDelegateEvalExt, inspect},
};
use rustc_type_ir::{
VisitorResult,
diff --git a/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 397327c..63a41ae 100644
--- a/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -7,7 +7,7 @@
search::{FileReference, SearchScope},
};
use itertools::Itertools;
-use syntax::ast::syntax_factory::SyntaxFactory;
+use syntax::ast::{HasName, syntax_factory::SyntaxFactory};
use syntax::syntax_editor::SyntaxEditor;
use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast};
@@ -71,13 +71,14 @@
struct StructEditData {
ident_pat: ast::IdentPat,
+ name: ast::Name,
kind: hir::StructKind,
struct_def_path: hir::ModPath,
visible_fields: Vec<hir::Field>,
usages: Vec<FileReference>,
names_in_scope: FxHashSet<SmolStr>,
has_private_members: bool,
- is_nested: bool,
+ need_record_field_name: bool,
is_ref: bool,
edition: Edition,
}
@@ -114,7 +115,11 @@
}
let is_ref = ty.is_reference();
- let is_nested = ident_pat.syntax().parent().and_then(ast::RecordPatField::cast).is_some();
+ let need_record_field_name = ident_pat
+ .syntax()
+ .parent()
+ .and_then(ast::RecordPatField::cast)
+ .is_some_and(|field| field.colon_token().is_none());
let usages = ctx
.sema
@@ -133,6 +138,7 @@
let names_in_scope = get_names_in_scope(ctx, &ident_pat, &usages).unwrap_or_default();
Some(StructEditData {
+ name: ident_pat.name()?,
ident_pat,
kind,
struct_def_path,
@@ -140,7 +146,7 @@
has_private_members,
visible_fields,
names_in_scope,
- is_nested,
+ need_record_field_name,
is_ref,
edition: module.krate().edition(ctx.db()),
})
@@ -177,6 +183,7 @@
field_names: &[(SmolStr, SmolStr)],
) {
let ident_pat = &data.ident_pat;
+ let name = &data.name;
let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
let is_ref = ident_pat.ref_token().is_some();
@@ -194,9 +201,9 @@
hir::StructKind::Record => {
let fields = field_names.iter().map(|(old_name, new_name)| {
// Use shorthand syntax if possible
- if old_name == new_name && !is_mut {
+ if old_name == new_name {
make.record_pat_field_shorthand(
- make.ident_pat(false, false, make.name(old_name)).into(),
+ make.ident_pat(is_ref, is_mut, make.name(old_name)).into(),
)
} else {
make.record_pat_field(
@@ -215,8 +222,8 @@
// If the binding is nested inside a record, we need to wrap the new
// destructured pattern in a non-shorthand record field
- let destructured_pat = if data.is_nested {
- make.record_pat_field(make.name_ref(&ident_pat.to_string()), new_pat).syntax().clone()
+ let destructured_pat = if data.need_record_field_name {
+ make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone()
} else {
new_pat.syntax().clone()
};
@@ -579,7 +586,7 @@
struct Foo { bar: i32, baz: i32 }
fn main() {
- let Foo { bar: mut bar, baz: mut baz } = Foo { bar: 1, baz: 2 };
+ let Foo { mut bar, mut baz } = Foo { bar: 1, baz: 2 };
let bar2 = bar;
let baz2 = &baz;
}
@@ -588,6 +595,86 @@
}
#[test]
+ fn mut_record_field() {
+ check_assist(
+ destructure_struct_binding,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { mut $0foo }: Bar) {}
+ "#,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { foo: Foo { mut x } }: Bar) {}
+ "#,
+ )
+ }
+
+ #[test]
+ fn ref_record_field() {
+ check_assist(
+ destructure_struct_binding,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { ref $0foo }: Bar) {
+ let _ = foo.x;
+ }
+ "#,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { foo: Foo { ref x } }: Bar) {
+ let _ = *x;
+ }
+ "#,
+ )
+ }
+
+ #[test]
+ fn ref_mut_record_field() {
+ check_assist(
+ destructure_struct_binding,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { ref mut $0foo }: Bar) {
+ let _ = foo.x;
+ }
+ "#,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+ let _ = *x;
+ }
+ "#,
+ )
+ }
+
+ #[test]
+ fn ref_mut_record_renamed_field() {
+ check_assist(
+ destructure_struct_binding,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { foo: ref mut $0foo1 }: Bar) {
+ let _ = foo1.x;
+ }
+ "#,
+ r#"
+ struct Foo { x: () }
+ struct Bar { foo: Foo }
+ fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+ let _ = *x;
+ }
+ "#,
+ )
+ }
+
+ #[test]
fn mut_ref() {
check_assist(
destructure_struct_binding,
diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs
index bd88e8b..da59626 100644
--- a/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/crates/ide-assists/src/handlers/extract_variable.rs
@@ -285,7 +285,7 @@
/// In general that's true for any expression, but in some cases that would produce invalid code.
fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
match node.kind() {
- SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR => None,
+ SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
SyntaxKind::BLOCK_EXPR => {
@@ -1404,6 +1404,25 @@
}
#[test]
+ fn extract_var_let_expr() {
+ check_assist_by_label(
+ extract_variable,
+ r#"
+fn main() {
+ if $0let$0 Some(x) = Some(2+2) {}
+}
+"#,
+ r#"
+fn main() {
+ let $0var_name = Some(2+2);
+ if let Some(x) = var_name {}
+}
+"#,
+ "Extract into variable",
+ );
+ }
+
+ #[test]
fn extract_var_for_cast() {
check_assist_by_label(
extract_variable,
@@ -1739,6 +1758,14 @@
}
#[test]
+ fn extract_var_for_let_expr_not_applicable() {
+ check_assist_not_applicable(
+ extract_variable,
+ "fn main() { if $0let Some(x) = Some(2+2) {} }",
+ );
+ }
+
+ #[test]
fn extract_var_unit_expr_not_applicable() {
check_assist_not_applicable(
extract_variable,
diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index 5ef8ba4..f507cae 100644
--- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -31,6 +31,9 @@
ast::Expr::MethodCallExpr(call) => call,
_ => return None,
};
+ if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
+ return None;
+ }
let name_ref = call_expr.name_ref()?;
match name_ref.text().as_str() {
@@ -191,4 +194,19 @@
"#,
);
}
+
+ #[test]
+ fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
+ check_assist_not_applicable(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ if x.is_some() {
+ ()$0
+ }
+}
+"#,
+ );
+ }
}
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index a7df0ab..080875e 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -59,6 +59,7 @@
in_block_expr,
in_breakable,
after_if_expr,
+ before_else_kw,
in_condition,
incomplete_let,
after_incomplete_let,
@@ -386,7 +387,7 @@
add_keyword("let", "let $1 = $0;");
}
- if after_if_expr || after_incomplete_let {
+ if !before_else_kw && (after_if_expr || after_incomplete_let) {
add_keyword("else", "else {\n $0\n}");
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 0074756..9deaaf6 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -144,6 +144,7 @@
pub(crate) in_block_expr: bool,
pub(crate) in_breakable: BreakableKind,
pub(crate) after_if_expr: bool,
+ pub(crate) before_else_kw: bool,
/// Whether this expression is the direct condition of an if or while expression
pub(crate) in_condition: bool,
pub(crate) incomplete_let: bool,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index b33a547..7b78a97 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1282,11 +1282,12 @@
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 before_else_kw = before_else_kw(it);
let incomplete_let = it
.parent()
.and_then(ast::LetStmt::cast)
.is_some_and(|it| it.semicolon_token().is_none())
- || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it);
+ || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
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());
@@ -1302,6 +1303,7 @@
in_block_expr,
in_breakable: in_loop_body,
after_if_expr,
+ before_else_kw,
in_condition,
ref_expr_parent,
after_amp,
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 5cc72ef..c420953 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1673,7 +1673,133 @@
kw async
kw const
kw crate::
- kw else
+ kw else if
+ 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 foo() { let x = if foo {} $0 else if true {}; }
+"#,
+ expect![[r#"
+ fn foo fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else if
+ 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 foo() { let x = if foo {} el$0 else if true {} else {}; }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ lc x ()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw else if
+ 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 foo() { let x = if foo {} $0 else if true {} else {}; }
+"#,
+ expect![[r#"
+ fn foo fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
kw else if
kw enum
kw extern