From 95bf87563a1d0eee53de6af41b7795a222c8a590 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 25 Nov 2024 14:52:58 +0200 Subject: Fix a bug when synthetic AST node were searched in the AST ID map and caused panics --- .../rust-analyzer/crates/hir-def/src/lower.rs | 26 ++++++++++++- .../rust-analyzer/crates/hir/src/semantics.rs | 13 +++++-- .../src/handlers/add_missing_impl_members.rs | 45 ++++++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index 6d1a3d17447..350bb8d5172 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -2,7 +2,7 @@ use std::{cell::OnceCell, mem}; use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile}; -use span::{AstIdMap, AstIdNode}; +use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap}; use stdx::thin_vec::ThinVec; use syntax::ast; use triomphe::Arc; @@ -63,6 +63,30 @@ impl<'a> LowerCtx<'a> { } } + /// Prepares a `LowerCtx` for synthetic AST that needs to be lowered. This is intended for IDE things. + pub fn for_synthetic_ast( + db: &'a dyn DefDatabase, + ast_id_map: Arc, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, + ) -> Self { + let file_id = EditionedFileId::new( + FileId::from_raw(EditionedFileId::MAX_FILE_ID), + Edition::Edition2015, + ); + LowerCtx { + db, + // Make up an invalid file id, so that if we will try to actually access it salsa will panic. + file_id: file_id.into(), + span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(), + ast_id_map: ast_id_map.into(), + impl_trait_bounds: Vec::new(), + outer_impl_trait: false, + types_map, + types_source_map, + } + } + pub(crate) fn span_map(&self) -> &SpanMap { self.span_map.get_or_init(|| self.db.span_map(self.file_id)) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 9d3f8e5fba4..46766fcc5b1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -34,7 +34,7 @@ use intern::Symbol; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use span::{EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; +use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, @@ -42,6 +42,7 @@ use syntax::{ AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::HirDatabase, @@ -1973,10 +1974,16 @@ impl SemanticsScope<'_> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option { + let root = ast_path.syntax().ancestors().last().unwrap(); + let ast_id_map = Arc::new(AstIdMap::from_source(&root)); let (mut types_map, mut types_source_map) = (TypesMap::default(), TypesSourceMap::default()); - let mut ctx = - LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map); + let mut ctx = LowerCtx::for_synthetic_ast( + self.db.upcast(), + ast_id_map, + &mut types_map, + &mut types_source_map, + ); let path = Path::from_src(&mut ctx, ast_path.clone())?; resolve_hir_path( self.db, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 7f8ea44fb12..57df39d541e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2318,4 +2318,49 @@ impl<'a> Test<'a, i32> for bool { "#, ); } + + #[test] + fn issue_17321() { + check_assist( + add_missing_impl_members, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct$0 {}"#, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct { + $0type Iter; +}"#, + ); + } } -- cgit 1.4.1-3-g733a5 From f091ec669e3f46bbf62048cb2a4b42ea5d9536ad Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 25 Nov 2024 01:01:50 +0900 Subject: Migrate `add_turbo_fish` to `SyntaxEditor` --- .../ide-assists/src/handlers/add_turbo_fish.rs | 83 +++++++++++++++------- .../syntax/src/ast/syntax_factory/constructors.rs | 18 +++++ 2 files changed, 77 insertions(+), 24 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 17efbcbd6c9..0f6970d9403 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -1,8 +1,9 @@ use either::Either; use ide_db::defs::{Definition, NameRefClass}; use syntax::{ - ast::{self, make, HasArgList, HasGenericArgs}, - ted, AstNode, + ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs}, + syntax_editor::Position, + AstNode, }; use crate::{ @@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_type_ascription", AssistKind::RefactorRewrite), "Add `: _` before assignment operator", ident.text_range(), - |edit| { - let let_stmt = edit.make_mut(let_stmt); + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); if let_stmt.semicolon_token().is_none() { - ted::append_child(let_stmt.syntax(), make::tokens::semicolon()); + editor.insert( + Position::last_child_of(let_stmt.syntax()), + make::tokens::semicolon(), + ); } let placeholder_ty = make::ty_placeholder().clone_for_update(); - let_stmt.set_ty(Some(placeholder_ty.clone())); - - if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, placeholder_ty); + if let Some(pat) = let_stmt.pat() { + let elements = vec![ + make::token(syntax::SyntaxKind::COLON).into(), + make::token(syntax::SyntaxKind::WHITESPACE).into(), + placeholder_ty.syntax().clone().into(), + ]; + editor.insert_all(Position::after(pat.syntax()), elements); + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation( + placeholder_ty.syntax(), + builder.make_placeholder_snippet(cap), + ); + } } + + builder.add_file_edits(ctx.file_id(), editor); }, )? } else { @@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_turbo_fish", AssistKind::RefactorRewrite), "Add `::<>`", ident.text_range(), - |edit| { - edit.trigger_parameter_hints(); + |builder| { + builder.trigger_parameter_hints(); + + let make = SyntaxFactory::new(); + let mut editor = match &turbofish_target { + Either::Left(it) => builder.make_editor(it.syntax()), + Either::Right(it) => builder.make_editor(it.syntax()), + }; + + let fish_head = get_fish_head(&make, number_of_arguments); - let new_arg_list = match turbofish_target { + match turbofish_target { Either::Left(path_segment) => { - edit.make_mut(path_segment).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = path_segment.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + editor.insert( + Position::last_child_of(path_segment.syntax()), + fish_head.syntax(), + ); + } } Either::Right(method_call) => { - edit.make_mut(method_call).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = method_call.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + let position = if let Some(arg_list) = method_call.arg_list() { + Position::before(arg_list.syntax()) + } else { + Position::last_child_of(method_call.syntax()) + }; + editor.insert(position, fish_head.syntax()); + } } }; - let fish_head = get_fish_head(number_of_arguments).clone_for_update(); - - // Note: we need to replace the `new_arg_list` instead of being able to use something like - // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list` - // always creates a non-turbofish form generic arg list. - ted::replace(new_arg_list.syntax(), fish_head.syntax()); - if let Some(cap) = ctx.config.snippet_cap { for arg in fish_head.generic_args() { - edit.add_placeholder_snippet(cap, arg) + editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap)); } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } /// This will create a turbofish generic arg list corresponding to the number of arguments -fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList { +fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); - make::turbofish_generic_arg_list(args) + make.turbofish_generic_arg_list(args) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 9f88add0f78..6e90b2ba47f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -107,4 +107,22 @@ impl SyntaxFactory { ast } + + pub fn turbofish_generic_arg_list( + &self, + args: impl IntoIterator + Clone, + ) -> ast::GenericArgList { + let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + args.into_iter().map(|arg| arg.syntax().clone()), + ast.generic_args().map(|arg| arg.syntax().clone()), + ); + builder.finish(&mut mapping); + } + + ast + } } -- cgit 1.4.1-3-g733a5 From c876903523d59ae902970556ebe383605540c4af Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Tue, 26 Nov 2024 00:42:27 -0500 Subject: Add macro expansion test for raw variable names --- .../src/macro_expansion_tests/mbe/matching.rs | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index 23d8b023b8b..e9a977da913 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -184,3 +184,31 @@ fn test() { "#]], ); } + +#[test] +fn meta_variable_raw_name_equals_non_raw() { + check( + r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + m!(1234) +} +"#, + expect![[r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + 1234 +} +"#]], + ); +} -- cgit 1.4.1-3-g733a5 From 4866fb457a396669fc2d96a8cf5938f4cce5e162 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 26 Nov 2024 18:37:39 +0100 Subject: Revert #18197 Our first attempt to make flycheck only check the current crate if the crate is one of bin/bench/test targets had caused `check_workspace` to be ignored, which should have been a config with higher precedence all along. This commit revert #18197 and closes #18562 --- .../rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index bb03eb3c89b..49b1ba32a79 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -380,7 +380,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { if id == flycheck.id() { updated = true; match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) && target.is_some() + !world.config.flycheck_workspace(source_root_id) || target.is_some() }) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), -- cgit 1.4.1-3-g733a5 From c33c9518f0a4eed527139a9fc34459a5ca83c229 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 26 Nov 2024 18:54:25 +0100 Subject: Remove target.is_some() to handle it later inside ra::flycheck --- .../rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 49b1ba32a79..5e7262b14ca 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -379,9 +379,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { for (id, package) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) || target.is_some() - }) { + match package.filter(|_| !world.config.flycheck_workspace(source_root_id)) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), None => flycheck.restart_workspace(saved_file.clone()), -- cgit 1.4.1-3-g733a5 From f3d83ba114d9c84fd190d3ba4ef58fe87afe2bb9 Mon Sep 17 00:00:00 2001 From: Laurențiu Nicola Date: Thu, 28 Nov 2024 16:01:40 +0200 Subject: Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 8f41ed9e14f..945939a2ff4 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f005c7437def424a1c43cbc380352a58d8ac920b +9b4d7c6a40b328d212095c28670c629facf1557d -- cgit 1.4.1-3-g733a5 From fb662a2e5c58b25a553e53d5c39e2518fcf90f04 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Nov 2024 03:33:33 +0000 Subject: Remove redundant associated type bounds from dyn --- src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 54aa18ce207..4d0539c135a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -666,7 +666,7 @@ impl<'a> InferenceTable<'a> { highest_known_var: InferenceVar, } impl TypeFolder for VarFudger<'_, '_> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -1004,7 +1004,7 @@ mod resolve { where F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 22e7b1d920f..975625fdfab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -646,7 +646,7 @@ pub(crate) fn fold_free_vars + TypeFoldable< F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const, > TypeFolder for FreeVarFolder { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -697,7 +697,7 @@ pub(crate) fn fold_tys_and_consts + TypeFold impl, DebruijnIndex) -> Either> TypeFolder for TyFolder { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } -- cgit 1.4.1-3-g733a5 From 868668e05dca0a6516f37e6fa2bfab3526f02868 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 25 Nov 2024 15:06:43 +0000 Subject: Run `cargo update` and update licenses --- Cargo.lock | 580 ++++++++++++++++++++-------------- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- library/Cargo.lock | 12 +- src/tools/run-make-support/Cargo.toml | 2 +- src/tools/rustbook/Cargo.lock | 443 ++++++++++++++++++++------ src/tools/tidy/src/deps.rs | 4 +- 6 files changed, 686 insertions(+), 357 deletions(-) (limited to 'src/tools') diff --git a/Cargo.lock b/Cargo.lock index 8ccf05cc5b8..89e7d70d839 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "ammonia" @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" dependencies = [ "backtrace", ] @@ -255,12 +255,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -269,9 +263,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -291,12 +285,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "serde", ] @@ -356,9 +350,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "camino" @@ -384,9 +378,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -411,9 +405,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -476,9 +470,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -496,9 +490,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -509,9 +503,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -525,14 +519,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clippy" @@ -556,7 +550,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "tempfile", "termize", "tokio", @@ -650,23 +644,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -770,9 +764,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -857,9 +851,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.77+curl-8.10.1" +version = "0.4.78+curl-8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f469e8a5991f277a208224f6c7ad72ecb5f986e36d09ae1f2c1bb9259478a480" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" dependencies = [ "cc", "libc", @@ -891,7 +885,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -902,7 +896,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -939,7 +933,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -960,7 +954,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -970,7 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -982,7 +976,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1060,7 +1054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1142,12 +1136,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1185,9 +1179,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "field-offset" @@ -1213,9 +1207,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1357,7 +1351,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1482,7 +1476,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -1497,11 +1491,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -1522,9 +1517,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash", ] @@ -1590,7 +1585,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1631,6 +1626,18 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + [[package]] name = "icu_list" version = "1.5.0" @@ -1684,6 +1691,51 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + [[package]] name = "icu_provider" version = "1.5.0" @@ -1722,7 +1774,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1739,12 +1791,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1763,7 +1826,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -1777,27 +1840,27 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "rustc-rayon", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width 0.1.14", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -1828,15 +1891,6 @@ dependencies = [ "xz2", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "intl-memoizer" version = "0.5.2" @@ -1873,9 +1927,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jemalloc-sys" @@ -1898,10 +1952,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1924,7 +1979,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustdoc-json-types", "serde", "serde_json", @@ -1967,9 +2022,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -2002,9 +2057,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2022,7 +2077,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "redox_syscall", ] @@ -2064,9 +2119,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lld-wrapper" @@ -2157,9 +2212,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -2317,7 +2372,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -2420,6 +2475,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2473,7 +2543,7 @@ checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "indexmap", "memchr", "ruzstd", @@ -2621,9 +2691,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2671,7 +2741,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2773,9 +2843,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -2816,18 +2886,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" dependencies = [ "cc", ] @@ -2838,7 +2908,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "unicase", ] @@ -2849,7 +2919,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -2861,7 +2931,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.11.0", "unicase", @@ -2965,7 +3035,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -2987,7 +3057,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3011,9 +3081,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3079,9 +3149,9 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3114,7 +3184,7 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser 0.216.0", + "wasmparser 0.219.1", ] [[package]] @@ -3143,9 +3213,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-main" @@ -3210,7 +3280,7 @@ version = "1.0.1" name = "rustc_abi" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rand", "rand_xoshiro", "rustc_data_structures", @@ -3224,11 +3294,11 @@ dependencies = [ [[package]] name = "rustc_apfloat" -version = "0.2.1+llvm-462a31f5a5ab" +version = "0.2.2+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" dependencies = [ - "bitflags 1.3.2", + "bitflags", "smallvec", ] @@ -3243,7 +3313,7 @@ dependencies = [ name = "rustc_ast" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "rustc_ast_ir", "rustc_data_structures", @@ -3406,7 +3476,7 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "itertools", "libc", "measureme", @@ -3444,7 +3514,7 @@ version = "0.0.0" dependencies = [ "ar_archive_writer", "arrayvec", - "bitflags 2.6.0", + "bitflags", "cc", "either", "itertools", @@ -3481,7 +3551,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder 0.216.0", + "wasm-encoder 0.219.1", "windows", ] @@ -3516,7 +3586,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "arrayvec", - "bitflags 2.6.0", + "bitflags", "either", "elsa", "ena", @@ -3527,7 +3597,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3700,7 +3770,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid", ] @@ -3834,7 +3904,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3982,7 +4052,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -3990,7 +4060,7 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "libloading", "odht", @@ -4021,7 +4091,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "either", "field-offset", @@ -4172,7 +4242,7 @@ dependencies = [ name = "rustc_parse" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -4229,7 +4299,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc_abi", "rustc_apfloat", "rustc_arena", @@ -4312,7 +4382,7 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", @@ -4340,7 +4410,7 @@ dependencies = [ name = "rustc_sanitizers" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_abi", "rustc_data_structures", "rustc_hir", @@ -4367,7 +4437,7 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "getopts", "libc", "rustc_abi", @@ -4448,7 +4518,7 @@ dependencies = [ name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "object 0.36.5", "rustc_abi", "rustc_data_structures", @@ -4549,7 +4619,7 @@ dependencies = [ name = "rustc_type_ir" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "indexmap", "rustc-hash 1.1.0", @@ -4571,7 +4641,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -4625,7 +4695,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", ] @@ -4660,7 +4730,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4694,11 +4764,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -4737,9 +4807,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4782,29 +4852,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap", "itoa", @@ -4894,9 +4964,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4914,9 +4984,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2" dependencies = [ "smallvec", ] @@ -5055,9 +5125,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5072,7 +5142,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5109,9 +5179,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -5153,9 +5223,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -5190,22 +5260,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5249,7 +5319,7 @@ dependencies = [ "ignore", "miropt-test-tools", "regex", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "semver", "similar", "termcolor", @@ -5318,9 +5388,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -5390,13 +5460,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5411,9 +5481,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -5567,7 +5637,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid-impl", ] @@ -5577,17 +5647,11 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" @@ -5670,9 +5734,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5685,12 +5749,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -5748,9 +5824,9 @@ checksum = "0f76d9fa52234153eeb40b088de91a8c13dc28a912cf6f31cd89ca4bac9024e0" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -5759,24 +5835,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5784,22 +5860,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-component-ld" @@ -5827,21 +5903,22 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.216.0" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" +checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" dependencies = [ "leb128", + "wasmparser 0.219.1", ] [[package]] name = "wasm-encoder" -version = "0.219.1" +version = "0.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" +checksum = "de35b6c3ef1f53ac7a31b5e69bc00f1542ea337e7e7162dc34c68b537ff82690" dependencies = [ "leb128", - "wasmparser 0.219.1", + "wasmparser 0.221.0", ] [[package]] @@ -5860,23 +5937,13 @@ dependencies = [ "wasmparser 0.219.1", ] -[[package]] -name = "wasmparser" -version = "0.216.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" -dependencies = [ - "bitflags 2.6.0", - "indexmap", -] - [[package]] name = "wasmparser" version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -5886,35 +5953,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags", "hashbrown 0.14.5", "indexmap", "semver", "serde", ] +[[package]] +name = "wasmparser" +version = "0.221.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8659e755615170cfe20da468865c989da78c5da16d8652e69a75acda02406a92" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + [[package]] name = "wast" -version = "219.0.1" +version = "221.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f79a9d9df79986a68689a6b40bcc8d5d40d807487b235bebc2ac69a242b54a1" +checksum = "9d8eb1933d493dd07484a255c3f52236123333f5befaa3be36182a50d393ec54" dependencies = [ "bumpalo", "leb128", "memchr", - "unicode-width 0.1.14", - "wasm-encoder 0.219.1", + "unicode-width 0.2.0", + "wasm-encoder 0.221.0", ] [[package]] name = "wat" -version = "1.219.1" +version = "1.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc3cf014fb336883a411cd662f987abf6a1d2a27f2f0008616a0070bbf6bd0d" +checksum = "c813fd4e5b2b97242830b56e7b7dc5479bc17aaa8730109be35e61909af83993" dependencies = [ "wast", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5966,7 +6054,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "windows-metadata", ] @@ -5999,7 +6087,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6010,7 +6098,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6192,7 +6280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags", "indexmap", "log", "serde", @@ -6222,6 +6310,12 @@ dependencies = [ "wasmparser 0.219.1", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.5.5" @@ -6259,9 +6353,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6271,13 +6365,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6299,27 +6393,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6342,5 +6436,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index b898cfec796..e40a2aa3612 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -42,7 +42,7 @@ tempfile = "3.2" thin-vec = "0.2.12" thorin-dwp = "0.8" tracing = "0.1" -wasm-encoder = "0.216.0" +wasm-encoder = "0.219" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] diff --git a/library/Cargo.lock b/library/Cargo.lock index f9b0af2c6e8..490c989300f 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" +checksum = "e2c6cb20f236dae10c69b0b45d82ef50af8b7e45c10e429e7901d26b49b4dbf3" dependencies = [ "compiler_builtins", "gimli 0.31.1", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3c172b2d956..15ed03ad5c2 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bstr = "1.6.0" object = "0.36.2" similar = "2.5.0" -wasmparser = { version = "0.216", default-features = false, features = ["std"] } +wasmparser = { version = "0.219", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" build_helper = { path = "../../build_helper" } diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 400eb7c5e0d..3d35779be90 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "autocfg" @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "regex-automata", @@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" @@ -252,9 +252,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -311,6 +311,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -360,25 +371,25 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -456,9 +467,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -524,21 +535,150 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -552,16 +692,17 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -573,9 +714,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -602,6 +743,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -646,9 +793,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -852,9 +999,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -996,9 +1143,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1120,9 +1267,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1150,9 +1297,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -1190,18 +1337,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1210,9 +1357,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1258,6 +1405,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "string_cache" version = "0.8.7" @@ -1292,15 +1445,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syntect" version = "5.2.0" @@ -1323,9 +1487,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -1347,9 +1511,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -1363,18 +1527,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -1382,20 +1546,15 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.5.11" @@ -1463,26 +1622,11 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -1492,9 +1636,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -1507,6 +1651,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1537,9 +1693,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -1548,9 +1704,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -1563,9 +1719,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1573,9 +1729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -1586,9 +1742,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "winapi" @@ -1721,6 +1877,42 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1741,3 +1933,46 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index e065f01ebba..493d9f5d5ec 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -12,7 +12,8 @@ use cargo_metadata::{Metadata, Package, PackageId}; #[rustfmt::skip] const LICENSES: &[&str] = &[ // tidy-alphabetical-start - "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident + "(MIT OR Apache-2.0) AND Unicode-3.0", // unicode_ident (1.0.14) + "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident (1.0.12) "0BSD OR MIT OR Apache-2.0", // adler license "0BSD", "Apache-2.0 / MIT", @@ -94,7 +95,6 @@ const EXCEPTIONS: ExceptionList = &[ ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("foldhash", "Zlib"), // rustc - ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) -- cgit 1.4.1-3-g733a5 From 5a52142eeafd00fcda88f60f9fe0aee8f912c625 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Dec 2024 12:58:43 +0100 Subject: Fix debug configuration querying not inheriting environment --- src/tools/rust-analyzer/editors/code/src/config.ts | 27 ++++- src/tools/rust-analyzer/editors/code/src/debug.ts | 12 +- src/tools/rust-analyzer/editors/code/src/run.ts | 35 ++---- .../editors/code/tests/unit/runnable_env.test.ts | 122 --------------------- 4 files changed, 42 insertions(+), 154 deletions(-) delete mode 100644 src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 67bc72f1e12..f979d545471 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -261,9 +261,9 @@ export class Config { return this.get("testExplorer"); } - get runnablesExtraEnv() { + runnablesExtraEnv(label: string): Record | undefined { const item = this.get("runnables.extraEnv") ?? this.get("runnableEnv"); - if (!item) return item; + if (!item) return undefined; const fixRecord = (r: Record) => { for (const key in r) { if (typeof r[key] !== "string") { @@ -271,11 +271,28 @@ export class Config { } } }; + + const platform = process.platform; + const checkPlatform = (it: RunnableEnvCfgItem) => { + if (it.platform) { + const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; + return platforms.indexOf(platform) >= 0; + } + return true; + }; + if (item instanceof Array) { - item.forEach((x) => fixRecord(x.env)); - } else { - fixRecord(item); + const env = {}; + for (const it of item) { + const masked = !it.mask || new RegExp(it.mask).test(label); + if (masked && checkPlatform(it)) { + Object.assign(env, it.env); + } + } + fixRecord(env); + return env; } + fixRecord(item); return item; } diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 9e2e3d2185b..f21ca2e8f96 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -148,8 +148,16 @@ async function getDebugConfiguration( return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`); } - const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv); - const executable = await getDebugExecutable(runnableArgs, env); + const executable = await getDebugExecutable( + runnableArgs, + prepareEnv(true, {}, config.runnablesExtraEnv(runnable.label)), + ); + + const env = prepareEnv( + inheritEnv, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ); let sourceFileMap = debugOptions.sourceFileMap; if (sourceFileMap === "auto") { diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 8a82a5a58cf..f71ab7ffbd8 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -5,7 +5,7 @@ import * as tasks from "./tasks"; import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; -import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config"; +import type { Config } from "./config"; import type { LanguageClient } from "vscode-languageclient/node"; import { unwrapUndefinable, type RustEditor } from "./util"; @@ -81,32 +81,13 @@ export function prepareBaseEnv( export function prepareEnv( inheritEnv: boolean, - label: string, - runnableArgs: ra.CargoRunnableArgs, - runnableEnvCfg?: RunnableEnvCfg, + runnableEnv?: Record, + runnableEnvCfg?: Record, ): Record { - const env = prepareBaseEnv(inheritEnv, runnableArgs.environment); - const platform = process.platform; - - const checkPlatform = (it: RunnableEnvCfgItem) => { - if (it.platform) { - const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; - return platforms.indexOf(platform) >= 0; - } - return true; - }; + const env = prepareBaseEnv(inheritEnv, runnableEnv); if (runnableEnvCfg) { - if (Array.isArray(runnableEnvCfg)) { - for (const it of runnableEnvCfg) { - const masked = !it.mask || new RegExp(it.mask).test(label); - if (masked && checkPlatform(it)) { - Object.assign(env, it.env); - } - } - } else { - Object.assign(env, runnableEnvCfg); - } + Object.assign(env, runnableEnvCfg); } return env; @@ -140,7 +121,11 @@ export async function createTaskFromRunnable( }; options = { cwd: runnableArgs.workspaceRoot || ".", - env: prepareEnv(true, runnable.label, runnableArgs, config.runnablesExtraEnv), + env: prepareEnv( + true, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ), }; } else { const runnableArgs = runnable.args; diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts deleted file mode 100644 index f0a62a3cce2..00000000000 --- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as assert from "assert"; -import { prepareEnv } from "../../src/run"; -import type { RunnableEnvCfg } from "../../src/config"; -import type { Context } from "."; -import type * as ra from "../../src/lsp_ext"; - -function makeRunnable(label: string): ra.Runnable { - return { - label, - kind: "cargo", - args: { - cargoArgs: [], - cwd: ".", - executableArgs: [], - }, - }; -} - -function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record { - const runnable = makeRunnable(runnableName); - const runnableArgs = runnable.args as ra.CargoRunnableArgs; - return prepareEnv(false, runnable.label, runnableArgs, config); -} - -export async function getTests(ctx: Context) { - await ctx.suite("Runnable env", (suite) => { - suite.addTest("Global config works", async () => { - const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" }); - assert.strictEqual(binEnv["GLOBAL"], "g"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" }); - assert.strictEqual(testEnv["GLOBAL"], "g"); - }); - - suite.addTest("null mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "data"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - }); - - suite.addTest("order works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - env: { DATA: "newdata" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "newdata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "newdata"); - }); - - suite.addTest("mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "^run", - env: { DATA: "rundata" }, - }, - { - mask: "special_test$", - env: { DATA: "special_test" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "rundata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - - const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); - assert.strictEqual(specialTestEnv["DATA"], "special_test"); - }); - - suite.addTest("exact test name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod::test_name", - env: { DATA: "test special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "test special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "data"); - }); - - suite.addTest("test mod name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod", - env: { DATA: "mod special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "mod special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "mod special"); - }); - }); -} -- cgit 1.4.1-3-g733a5 From 03ae70dcacf96e50c52b0df20a99d655d33255d4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Dec 2024 13:35:58 +0100 Subject: fix: Fix syntax fixup inserting unnecessary semicolons --- src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index b6d5828da96..0af29681a13 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -110,7 +110,8 @@ pub(crate) fn fixup_syntax( } }, ast::ExprStmt(it) => { - if it.semicolon_token().is_none() { + let needs_semi = it.semicolon_token().is_none() && it.expr().map_or(false, |e| e.syntax().kind() != SyntaxKind::BLOCK_EXPR); + if needs_semi { append.insert(node.clone().into(), vec![ Leaf::Punct(Punct { char: ';', @@ -905,6 +906,21 @@ fn foo() { "#, expect![[r#" fn foo () {|| __ra_fixup} +"#]], + ); + } + + #[test] + fn fixup_regression_() { + check( + r#" +fn foo() { + {} + {} +} +"#, + expect![[r#" +fn foo () {{} {}} "#]], ); } -- cgit 1.4.1-3-g733a5 From aede6e136567d25d23c802fa6950a4e2ccca0d45 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 3 Dec 2024 10:41:29 +0200 Subject: Advertise completions and inlay hints resolve server capabilities based on the client capabilities. --- .../rust-analyzer/crates/ide-completion/src/lib.rs | 14 +++++++++++++- .../rust-analyzer/crates/ide/src/inlay_hints.rs | 12 +++++++++++- .../crates/rust-analyzer/src/config.rs | 22 ++++++---------------- .../crates/rust-analyzer/src/lsp/capabilities.rs | 19 +++++++++++++++---- 4 files changed, 45 insertions(+), 22 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index dfee01b187e..cffdfa29f1a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -19,7 +19,7 @@ use ide_db::{ }, items_locator, syntax_helpers::tree_diff::diff, - FilePosition, RootDatabase, + FilePosition, FxHashSet, RootDatabase, }; use crate::{ @@ -50,6 +50,18 @@ pub struct CompletionFieldsToResolve { } impl CompletionFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_label_details: client_capability_fields.contains("labelDetails"), + resolve_tags: client_capability_fields.contains("tags"), + resolve_detail: client_capability_fields.contains("detail"), + resolve_documentation: client_capability_fields.contains("documentation"), + resolve_filter_text: client_capability_fields.contains("filterText"), + resolve_text_edit: client_capability_fields.contains("textEdit"), + resolve_command: client_capability_fields.contains("command"), + } + } + pub const fn empty() -> Self { Self { resolve_label_details: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index c58ca0f01cd..1ae8bfa9b6e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,8 +8,8 @@ use hir::{ sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics, }; -use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; +use ide_db::{text_edit::TextEdit, FxHashSet}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; use span::{Edition, EditionedFileId}; @@ -289,6 +289,16 @@ pub struct InlayFieldsToResolve { } impl InlayFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_text_edits: client_capability_fields.contains("textEdits"), + resolve_hint_tooltip: client_capability_fields.contains("tooltip"), + resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), + resolve_label_location: client_capability_fields.contains("label.location"), + resolve_label_command: client_capability_fields.contains("label.command"), + } + } + pub const fn empty() -> Self { Self { resolve_text_edits: false, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 37d45255e29..152ce2944a0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1446,15 +1446,9 @@ impl Config { limit: self.completion_limit(source_root).to_owned(), enable_term_search: self.completion_termSearch_enable(source_root).to_owned(), term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64, - fields_to_resolve: CompletionFieldsToResolve { - resolve_label_details: client_capability_fields.contains("labelDetails"), - resolve_tags: client_capability_fields.contains("tags"), - resolve_detail: client_capability_fields.contains("detail"), - resolve_documentation: client_capability_fields.contains("documentation"), - resolve_filter_text: client_capability_fields.contains("filterText"), - resolve_text_edit: client_capability_fields.contains("textEdit"), - resolve_command: client_capability_fields.contains("command"), - }, + fields_to_resolve: CompletionFieldsToResolve::from_client_capabilities( + &client_capability_fields, + ), } } @@ -1614,13 +1608,9 @@ impl Config { } else { None }, - fields_to_resolve: InlayFieldsToResolve { - resolve_text_edits: client_capability_fields.contains("textEdits"), - resolve_hint_tooltip: client_capability_fields.contains("tooltip"), - resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), - resolve_label_location: client_capability_fields.contains("label.location"), - resolve_label_command: client_capability_fields.contains("label.command"), - }, + fields_to_resolve: InlayFieldsToResolve::from_client_capabilities( + &client_capability_fields, + ), implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(), range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 1db616898e8..bd496e8ddc3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -1,4 +1,5 @@ //! Advertises the capabilities of the LSP Server. +use ide::{CompletionFieldsToResolve, InlayFieldsToResolve}; use ide_db::{line_index::WideEncoding, FxHashSet}; use lsp_types::{ CallHierarchyServerCapability, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, @@ -40,7 +41,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { })), hover_provider: Some(HoverProviderCapability::Simple(true)), completion_provider: Some(CompletionOptions { - resolve_provider: config.caps().completions_resolve_provider(), + resolve_provider: Some(config.caps().completions_resolve_provider()), trigger_characters: Some(vec![ ":".to_owned(), ".".to_owned(), @@ -136,7 +137,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( InlayHintOptions { work_done_progress_options: Default::default(), - resolve_provider: Some(true), + resolve_provider: Some(config.caps().inlay_hints_resolve_provider()), }, ))), inline_value_provider: None, @@ -176,8 +177,18 @@ impl ClientCapabilities { Self(caps) } - fn completions_resolve_provider(&self) -> Option { - self.completion_item_edit_resolve().then_some(true) + fn completions_resolve_provider(&self) -> bool { + let client_capabilities = self.completion_resolve_support_properties(); + let fields_to_resolve = + CompletionFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != CompletionFieldsToResolve::empty() + } + + fn inlay_hints_resolve_provider(&self) -> bool { + let client_capabilities = self.inlay_hint_resolve_support_properties(); + let fields_to_resolve = + InlayFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != InlayFieldsToResolve::empty() } fn experimental_bool(&self, index: &'static str) -> bool { -- cgit 1.4.1-3-g733a5 From 97feb0334493d870e09f7a5a02c6d320a7e8a4ae Mon Sep 17 00:00:00 2001 From: David Richey Date: Tue, 3 Dec 2024 14:14:53 +0000 Subject: Only show status bar item in relevant files --- src/tools/rust-analyzer/editors/code/package.json | 35 ++++++++++++++++++++++ src/tools/rust-analyzer/editors/code/src/config.ts | 4 +++ src/tools/rust-analyzer/editors/code/src/ctx.ts | 18 ++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 82c43b76fdd..46f7803c8a8 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -425,6 +425,41 @@ ], "default": "openLogs", "markdownDescription": "Action to run when clicking the extension status bar item." + }, + "rust-analyzer.statusBar.documentSelector": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "language": { + "type": [ + "string", + "null" + ] + }, + "pattern": { + "type": [ + "string", + "null" + ] + } + } + }, + "default": [ + { + "language": "rust" + }, + { + "pattern": "**/Cargo.toml" + }, + { + "pattern": "**/Cargo.lock" + } + ], + "markdownDescription": "Determines when to show the extension status bar item based on the currently open file. Use `{ \"pattern\": \"**\" }` to always show. Use `null` to never show." } } }, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index f979d545471..f7ef80df2ba 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -348,6 +348,10 @@ export class Config { return this.get("statusBar.clickAction"); } + get statusBarDocumentSelector() { + return this.get("statusBar.documentSelector"); + } + get initializeStopped() { return this.get("initializeStopped"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 234fe6ab024..4a3f66b00d0 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -88,6 +88,7 @@ export class Ctx implements RustAnalyzerExtensionApi { private _treeView: vscode.TreeView | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; + private statusBarActiveEditorListener: Disposable; get serverPath(): string | undefined { return this._serverPath; @@ -119,6 +120,10 @@ export class Ctx implements RustAnalyzerExtensionApi { this._serverVersion = ""; this.config = new Config(extCtx.subscriptions); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + this.updateStatusBarVisibility(vscode.window.activeTextEditor); + this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) => + this.updateStatusBarVisibility(editor), + ); if (this.config.testExplorer) { this.testController = vscode.tests.createTestController( "rustAnalyzerTestController", @@ -141,6 +146,7 @@ export class Ctx implements RustAnalyzerExtensionApi { dispose() { this.config.dispose(); this.statusBar.dispose(); + this.statusBarActiveEditorListener.dispose(); this.testController?.dispose(); void this.disposeClient(); this.commandDisposables.forEach((disposable) => disposable.dispose()); @@ -404,7 +410,6 @@ export class Ctx implements RustAnalyzerExtensionApi { let icon = ""; const status = this.lastStatus; const statusBar = this.statusBar; - statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -472,6 +477,17 @@ export class Ctx implements RustAnalyzerExtensionApi { statusBar.text = `${icon}rust-analyzer`; } + private updateStatusBarVisibility(editor: vscode.TextEditor | undefined) { + const documentSelector = this.config.statusBarDocumentSelector; + if (documentSelector != null) { + if (editor != null && vscode.languages.match(documentSelector, editor.document) > 0) { + this.statusBar.show(); + return; + } + } + this.statusBar.hide(); + } + pushExtCleanup(d: Disposable) { this.extCtx.subscriptions.push(d); } -- cgit 1.4.1-3-g733a5 From 879312ed633a5611748963f0a012d2d03bc9c87b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 3 Dec 2024 20:46:45 +0200 Subject: Support `AsyncFnX` traits Only in calls, because to support them in bounds we need support from Chalk. However we don't yet report error from bounds anyway, so this is less severe. The returned future is shown in its name within inlay hints instead of as a nicer `impl Future`, but that can wait for another PR. --- .../rust-analyzer/crates/hir-def/src/lang_item.rs | 3 + .../rust-analyzer/crates/hir-ty/src/infer/expr.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/infer/unify.rs | 114 ++++++++++---------- .../rust-analyzer/crates/hir-ty/src/mir/lower.rs | 12 ++- .../crates/hir-ty/src/tests/traits.rs | 50 +++++++++ .../rust-analyzer/crates/hir-ty/src/traits.rs | 26 ++++- .../src/handlers/expected_function.rs | 21 ++++ .../crates/intern/src/symbol/symbols.rs | 8 ++ .../crates/test-utils/src/minicore.rs | 119 ++++++++++++++++++++- 9 files changed, 291 insertions(+), 68 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 166c965d14c..0629d87e544 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -376,6 +376,9 @@ language_item_table! { Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 32b4ea2f28b..c21ff19c45d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1287,8 +1287,8 @@ impl InferenceContext<'_> { tgt_expr: ExprId, ) { match fn_x { - FnTrait::FnOnce => (), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => (), + FnTrait::FnMut | FnTrait::AsyncFnMut => { if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) { if adjustments .last() @@ -1312,7 +1312,7 @@ impl InferenceContext<'_> { )); } } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) { adjustments.push(Adjustment::borrow( Mutability::Not, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 4d0539c135a..165861c1b17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -794,69 +794,75 @@ impl<'a> InferenceTable<'a> { ty: &Ty, num_args: usize, ) -> Option<(FnTrait, Vec, Ty)> { - let krate = self.trait_env.krate; - let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; - let trait_data = self.db.trait_data(fn_once_trait); - let output_assoc_type = - trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; - - let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = TyBuilder::tuple(num_args) - .fill(|it| { - let arg = match it { - ParamKind::Type => self.new_type_var(), - ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), - ParamKind::Const(_) => unreachable!("Tuple with const parameter"), - }; - arg_tys.push(arg.clone()); - arg.cast(Interner) - }) - .build(); - - let b = TyBuilder::trait_ref(self.db, fn_once_trait); - if b.remaining() != 2 { - return None; - } - let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); + for (fn_trait_name, output_assoc_name, subtraits) in [ + (FnTrait::FnOnce, sym::Output.clone(), &[FnTrait::Fn, FnTrait::FnMut][..]), + (FnTrait::AsyncFnMut, sym::CallRefFuture.clone(), &[FnTrait::AsyncFn]), + (FnTrait::AsyncFnOnce, sym::CallOnceFuture.clone(), &[]), + ] { + let krate = self.trait_env.krate; + let fn_trait = fn_trait_name.get_id(self.db, krate)?; + let trait_data = self.db.trait_data(fn_trait); + let output_assoc_type = + trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; + + let mut arg_tys = Vec::with_capacity(num_args); + let arg_ty = TyBuilder::tuple(num_args) + .fill(|it| { + let arg = match it { + ParamKind::Type => self.new_type_var(), + ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), + ParamKind::Const(_) => unreachable!("Tuple with const parameter"), + }; + arg_tys.push(arg.clone()); + arg.cast(Interner) + }) + .build(); + + let b = TyBuilder::trait_ref(self.db, fn_trait); + if b.remaining() != 2 { + return None; + } + let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); - let projection = { - TyBuilder::assoc_type_projection( + let projection = TyBuilder::assoc_type_projection( self.db, output_assoc_type, Some(trait_ref.substitution.clone()), ) - .build() - }; + .fill_with_unknown() + .build(); - let trait_env = self.trait_env.env.clone(); - let obligation = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() { - self.register_obligation(obligation.goal); - let return_ty = self.normalize_projection_ty(projection); - for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { - let fn_x_trait = fn_x.get_id(self.db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let obligation: chalk_ir::InEnvironment> = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self - .db - .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .is_some() - { - return Some((fn_x, arg_tys, return_ty)); + let trait_env = self.trait_env.env.clone(); + let obligation = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() + { + self.register_obligation(obligation.goal); + let return_ty = self.normalize_projection_ty(projection); + for &fn_x in subtraits { + let fn_x_trait = fn_x.get_id(self.db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment> = + InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self + .db + .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) + .is_some() + { + return Some((fn_x, arg_tys, return_ty)); + } } + return Some((fn_trait_name, arg_tys, return_ty)); } - unreachable!("It should at least implement FnOnce at this point"); - } else { - None } + None } pub(super) fn insert_type_vars(&mut self, ty: T) -> T diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index c4e06400510..1d1044df6e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -2023,11 +2023,11 @@ pub fn mir_body_for_closure_query( ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); let closure_local = ctx.result.locals.alloc(Local { ty: match kind { - FnTrait::FnOnce => infer[expr].clone(), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].clone(), + FnTrait::FnMut | FnTrait::AsyncFnMut => { TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].clone()).intern(Interner) } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].clone()).intern(Interner) } }, @@ -2055,8 +2055,10 @@ pub fn mir_body_for_closure_query( let mut err = None; let closure_local = ctx.result.locals.iter().nth(1).unwrap().0; let closure_projection = match kind { - FnTrait::FnOnce => vec![], - FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], + FnTrait::FnOnce | FnTrait::AsyncFnOnce => vec![], + FnTrait::FnMut | FnTrait::Fn | FnTrait::AsyncFnMut | FnTrait::AsyncFn => { + vec![ProjectionElem::Deref] + } }; ctx.result.walk_places(|p, store| { if let Some(it) = upvar_map.get(&p.local) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 624148cab20..82ff51927e0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4811,3 +4811,53 @@ fn bar(v: *const ()) { "#]], ); } + +#[test] +fn async_fn_traits() { + check_infer( + r#" +//- minicore: async_fn +async fn foo i32>(a: T) { + let fut1 = a(0); + fut1.await; +} +async fn bar i32>(mut b: T) { + let fut2 = b(0); + fut2.await; +} +async fn baz i32>(c: T) { + let fut3 = c(0); + fut3.await; +} + "#, + expect![[r#" + 37..38 'a': T + 43..83 '{ ...ait; }': () + 43..83 '{ ...ait; }': impl Future + 53..57 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 60..61 'a': T + 60..64 'a(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 62..63 '0': u32 + 70..74 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 70..80 'fut1.await': i32 + 124..129 'mut b': T + 134..174 '{ ...ait; }': () + 134..174 '{ ...ait; }': impl Future + 144..148 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 151..152 'b': T + 151..155 'b(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 153..154 '0': u32 + 161..165 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 161..171 'fut2.await': i32 + 216..217 'c': T + 222..262 '{ ...ait; }': () + 222..262 '{ ...ait; }': impl Future + 232..236 'fut3': AsyncFnOnce::CallOnceFuture + 239..240 'c': T + 239..243 'c(0)': AsyncFnOnce::CallOnceFuture + 241..242 '0': u32 + 249..253 'fut3': AsyncFnOnce::CallOnceFuture + 249..259 'fut3.await': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 51ccd4ef293..8cb7dbf60f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -220,6 +220,10 @@ pub enum FnTrait { FnOnce, FnMut, Fn, + + AsyncFnOnce, + AsyncFnMut, + AsyncFn, } impl fmt::Display for FnTrait { @@ -228,6 +232,9 @@ impl fmt::Display for FnTrait { FnTrait::FnOnce => write!(f, "FnOnce"), FnTrait::FnMut => write!(f, "FnMut"), FnTrait::Fn => write!(f, "Fn"), + FnTrait::AsyncFnOnce => write!(f, "AsyncFnOnce"), + FnTrait::AsyncFnMut => write!(f, "AsyncFnMut"), + FnTrait::AsyncFn => write!(f, "AsyncFn"), } } } @@ -238,6 +245,9 @@ impl FnTrait { FnTrait::FnOnce => "call_once", FnTrait::FnMut => "call_mut", FnTrait::Fn => "call", + FnTrait::AsyncFnOnce => "async_call_once", + FnTrait::AsyncFnMut => "async_call_mut", + FnTrait::AsyncFn => "async_call", } } @@ -246,6 +256,9 @@ impl FnTrait { FnTrait::FnOnce => LangItem::FnOnce, FnTrait::FnMut => LangItem::FnMut, FnTrait::Fn => LangItem::Fn, + FnTrait::AsyncFnOnce => LangItem::AsyncFnOnce, + FnTrait::AsyncFnMut => LangItem::AsyncFnMut, + FnTrait::AsyncFn => LangItem::AsyncFn, } } @@ -254,15 +267,19 @@ impl FnTrait { LangItem::FnOnce => Some(FnTrait::FnOnce), LangItem::FnMut => Some(FnTrait::FnMut), LangItem::Fn => Some(FnTrait::Fn), + LangItem::AsyncFnOnce => Some(FnTrait::AsyncFnOnce), + LangItem::AsyncFnMut => Some(FnTrait::AsyncFnMut), + LangItem::AsyncFn => Some(FnTrait::AsyncFn), _ => None, } } pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind { + // Chalk doesn't support async fn traits. match self { - FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, - FnTrait::FnMut => rust_ir::ClosureKind::FnMut, - FnTrait::Fn => rust_ir::ClosureKind::Fn, + FnTrait::AsyncFnOnce | FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, + FnTrait::AsyncFnMut | FnTrait::FnMut => rust_ir::ClosureKind::FnMut, + FnTrait::AsyncFn | FnTrait::Fn => rust_ir::ClosureKind::Fn, } } @@ -271,6 +288,9 @@ impl FnTrait { FnTrait::FnOnce => Name::new_symbol_root(sym::call_once.clone()), FnTrait::FnMut => Name::new_symbol_root(sym::call_mut.clone()), FnTrait::Fn => Name::new_symbol_root(sym::call.clone()), + FnTrait::AsyncFnOnce => Name::new_symbol_root(sym::async_call_once.clone()), + FnTrait::AsyncFnMut => Name::new_symbol_root(sym::async_call_mut.clone()), + FnTrait::AsyncFn => Name::new_symbol_root(sym::async_call.clone()), } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index 02299197b12..e3a1e12e029 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -37,4 +37,25 @@ fn foo() { "#, ); } + + #[test] + fn no_error_for_async_fn_traits() { + check_diagnostics( + r#" +//- minicore: async_fn +async fn f(it: impl AsyncFn(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn g(mut it: impl AsyncFnMut(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn h(it: impl AsyncFnOnce(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 865518fe941..ee96eff3309 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -150,6 +150,9 @@ define_symbols! { C, call_mut, call_once, + async_call_once, + async_call_mut, + async_call, call, cdecl, Center, @@ -221,6 +224,9 @@ define_symbols! { fn_mut, fn_once_output, fn_once, + async_fn_once, + async_fn_mut, + async_fn, fn_ptr_addr, fn_ptr_trait, format_alignment, @@ -334,6 +340,8 @@ define_symbols! { Option, Ord, Output, + CallRefFuture, + CallOnceFuture, owned_box, packed, panic_2015, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 07767d5ae9f..f5c8466cb9f 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -12,6 +12,7 @@ //! asm: //! assert: //! as_ref: sized +//! async_fn: fn, tuple, future, copy //! bool_impl: option, fn //! builtin_impls: //! cell: copy, drop @@ -29,7 +30,7 @@ //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fn: +//! fn: tuple //! from: sized //! future: pin //! coroutine: pin @@ -60,6 +61,7 @@ //! sync: sized //! transmute: //! try: infallible +//! tuple: //! unpin: sized //! unsize: sized //! todo: panic @@ -138,10 +140,10 @@ pub mod marker { } // endregion:copy - // region:fn + // region:tuple #[lang = "tuple_trait"] pub trait Tuple {} - // endregion:fn + // endregion:tuple // region:phantom_data #[lang = "phantom_data"] @@ -682,6 +684,116 @@ pub mod ops { } pub use self::function::{Fn, FnMut, FnOnce}; // endregion:fn + + // region:async_fn + mod async_function { + use crate::{future::Future, marker::Tuple}; + + #[lang = "async_fn"] + #[fundamental] + pub trait AsyncFn: AsyncFnMut { + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_mut"] + #[fundamental] + pub trait AsyncFnMut: AsyncFnOnce { + #[lang = "call_ref_future"] + type CallRefFuture<'a>: Future + where + Self: 'a; + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_once"] + #[fundamental] + pub trait AsyncFnOnce { + #[lang = "async_fn_once_output"] + type Output; + #[lang = "call_once_future"] + type CallOnceFuture: Future; + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; + } + + mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::marker::Tuple; + + impl AsyncFn for &F + where + F: AsyncFn, + { + extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl AsyncFnMut for &F + where + F: AsyncFn, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F + where + F: AsyncFn, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call(self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl AsyncFnMut for &mut F + where + F: AsyncFnMut, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call_mut(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F + where + F: AsyncFnMut, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call_mut(self, args) + } + } + } + } + pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + // endregion:async_fn + // region:try mod try_ { use crate::convert::Infallible; @@ -1684,6 +1796,7 @@ pub mod prelude { marker::Sync, // :sync mem::drop, // :drop ops::Drop, // :drop + ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn ops::{Fn, FnMut, FnOnce}, // :fn option::Option::{self, None, Some}, // :option panic, // :panic -- cgit 1.4.1-3-g733a5 From b94c5355b207568b4c66852e46f823437455dcf4 Mon Sep 17 00:00:00 2001 From: Tarek Date: Sun, 17 Nov 2024 15:25:23 +0200 Subject: internal: Make exclude characters for typing assists configurable, default to None Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 6 ++++++ src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 6 ++++++ .../crates/rust-analyzer/src/handlers/request.rs | 9 +++++++-- src/tools/rust-analyzer/docs/user/generated_config.adoc | 5 +++++ src/tools/rust-analyzer/editors/code/package.json | 13 +++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d4ef9570e1a..b4f3de3b178 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -411,6 +411,7 @@ impl Analysis { position: FilePosition, char_typed: char, autoclose: bool, + chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { @@ -419,6 +420,11 @@ impl Analysis { if char_typed == '<' && !autoclose { return Ok(None); } + if let Some(chars_to_exclude) = chars_to_exclude { + if chars_to_exclude.contains(char_typed) { + return Ok(None); + } + } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 152ce2944a0..c2d6196ca41 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -310,6 +310,8 @@ config_data! { /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. typing_autoClosingAngleBrackets_enable: bool = false, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -2160,6 +2162,10 @@ impl Config { *self.typing_autoClosingAngleBrackets_enable() } + pub fn typing_exclude_chars(&self) -> Option { + self.typing_excludeChars().clone() + } + // VSCode is our reference implementation, so we allow ourselves to work around issues by // special casing certain versions pub fn visual_studio_code_version(&self) -> Option<&Version> { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 4975467ece9..29820a3e37e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -459,9 +459,14 @@ pub(crate) fn handle_on_type_formatting( if char_typed == '>' { return Ok(None); } + let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = - snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?; + let edit = snap.analysis.on_char_typed( + position, + char_typed, + snap.config.typing_autoclose_angle(), + chars_to_exclude, + )?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 052d0a2a41d..d0c95912c3d 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -997,6 +997,11 @@ Show documentation. -- Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. -- +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: ++ +-- +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +-- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 46f7803c8a8..e98205e0eab 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2612,6 +2612,19 @@ } } }, + { + "title": "typing", + "properties": { + "rust-analyzer.typing.excludeChars": { + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", + "default": null, + "type": [ + "null", + "string" + ] + } + } + }, { "title": "workspace", "properties": { -- cgit 1.4.1-3-g733a5 From 68cd57940a2f82ab1bdbc0c799ffecc095c03f88 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 22:38:21 +0200 Subject: chore: deprecate `typing.autoClosingAngleBrackets` configuration Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 ---- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 6 ------ .../rust-analyzer/crates/rust-analyzer/src/handlers/request.rs | 7 +------ src/tools/rust-analyzer/docs/user/generated_config.adoc | 5 ----- src/tools/rust-analyzer/editors/code/package.json | 10 ---------- 5 files changed, 1 insertion(+), 31 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b4f3de3b178..b43685ffeed 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -410,16 +410,12 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - autoclose: bool, chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if char_typed == '<' && !autoclose { - return Ok(None); - } if let Some(chars_to_exclude) = chars_to_exclude { if chars_to_exclude.contains(char_typed) { return Ok(None); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index c2d6196ca41..392bfbf15fe 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,6 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = false, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. typing_excludeChars: Option = None, @@ -2158,10 +2156,6 @@ impl Config { } } - pub fn typing_autoclose_angle(&self) -> bool { - *self.typing_autoClosingAngleBrackets_enable() - } - pub fn typing_exclude_chars(&self) -> Option { self.typing_excludeChars().clone() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 29820a3e37e..0fadfa6c420 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -461,12 +461,7 @@ pub(crate) fn handle_on_type_formatting( } let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = snap.analysis.on_char_typed( - position, - char_typed, - snap.config.typing_autoclose_angle(), - chars_to_exclude, - )?; + let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index d0c95912c3d..a3172c7ca2c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,11 +992,6 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`):: -+ --- -Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. --- [[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index e98205e0eab..68c61e4bf62 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2602,16 +2602,6 @@ } } }, - { - "title": "typing", - "properties": { - "rust-analyzer.typing.autoClosingAngleBrackets.enable": { - "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", - "default": false, - "type": "boolean" - } - } - }, { "title": "typing", "properties": { -- cgit 1.4.1-3-g733a5 From 337725ddc894f312387dbee936d484a09af44162 Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Tue, 3 Dec 2024 17:30:17 -0500 Subject: Remove references to platform-intrinsic ABI --- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 3 --- .../rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs | 1 - src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs | 1 - 3 files changed, 5 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 975625fdfab..fdc65797632 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -385,7 +385,6 @@ pub enum FnAbi { Fastcall, FastcallUnwind, Msp430Interrupt, - PlatformIntrinsic, PtxKernel, RiscvInterruptM, RiscvInterruptS, @@ -444,7 +443,6 @@ impl FnAbi { s if *s == sym::fastcall_dash_unwind => FnAbi::FastcallUnwind, s if *s == sym::fastcall => FnAbi::Fastcall, s if *s == sym::msp430_dash_interrupt => FnAbi::Msp430Interrupt, - s if *s == sym::platform_dash_intrinsic => FnAbi::PlatformIntrinsic, s if *s == sym::ptx_dash_kernel => FnAbi::PtxKernel, s if *s == sym::riscv_dash_interrupt_dash_m => FnAbi::RiscvInterruptM, s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS, @@ -487,7 +485,6 @@ impl FnAbi { FnAbi::Fastcall => "fastcall", FnAbi::FastcallUnwind => "fastcall-unwind", FnAbi::Msp430Interrupt => "msp430-interrupt", - FnAbi::PlatformIntrinsic => "platform-intrinsic", FnAbi::PtxKernel => "ptx-kernel", FnAbi::RiscvInterruptM => "riscv-interrupt-m", FnAbi::RiscvInterruptS => "riscv-interrupt-s", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index b0e417e6b33..847fa4cf889 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -38,7 +38,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "system-unwind", "rust-intrinsic", "rust-call", - "platform-intrinsic", "unadjusted", ]; diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 865518fe941..8f79cf20079 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -99,7 +99,6 @@ define_symbols! { cdecl_dash_unwind = "cdecl-unwind", fastcall_dash_unwind = "fastcall-unwind", msp430_dash_interrupt = "msp430-interrupt", - platform_dash_intrinsic = "platform-intrinsic", ptx_dash_kernel = "ptx-kernel", riscv_dash_interrupt_dash_m = "riscv-interrupt-m", riscv_dash_interrupt_dash_s = "riscv-interrupt-s", -- cgit 1.4.1-3-g733a5 From bc003049cfe3c85bfc3069ae8e76899efa6d08d1 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 03:15:32 +0200 Subject: Fixed another bug with glob imports When a glob import overriding the visibility of a previous glob import was not properly resolved when the items are only available in the next fixpoint iteration. The bug was hidden until #18390. --- .../crates/hir-def/src/nameres/collector.rs | 9 +++-- .../crates/hir-def/src/nameres/tests/globs.rs | 39 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index a37e3c70e22..98b08bcf708 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -910,8 +910,13 @@ impl DefCollector<'_> { self.update(module_id, &items, vis, Some(ImportType::Glob(id))); // record the glob import in case we add further items let glob = self.glob_imports.entry(m.local_id).or_default(); - if !glob.iter().any(|(mid, _, _)| *mid == module_id) { - glob.push((module_id, vis, id)); + match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) { + None => glob.push((module_id, vis, id)), + Some((_, old_vis, _)) => { + if let Some(new_vis) = old_vis.max(vis, &self.def_map) { + *old_vis = new_vis; + } + } } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs index 543ab41cd59..8963a576794 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs @@ -451,3 +451,42 @@ mod glob_target { "#]], ); } + +#[test] +fn regression_18580() { + check( + r#" +pub mod libs { + pub struct Placeholder; +} + +pub mod reexport_2 { + use reexport_1::*; + pub use reexport_1::*; + + pub mod reexport_1 { + pub use crate::libs::*; + } +} + +use reexport_2::*; +"#, + expect![[r#" + crate + Placeholder: t v + libs: t + reexport_1: t + reexport_2: t + + crate::libs + Placeholder: t v + + crate::reexport_2 + Placeholder: t v + reexport_1: t + + crate::reexport_2::reexport_1 + Placeholder: t v + "#]], + ); +} -- cgit 1.4.1-3-g733a5 From 0d328a81ec0543ffbe63906f0e0b88bb2179ecc2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 03:38:37 +0200 Subject: Improve soundness a bit by making `TaggedArcPtr::try_as_arc_owned()` unsafe Since the `ManuallyDrop` it returns can be safely used to consume the `Arc`, which is can cause UB if done incorrectly. See #18499. --- .../rust-analyzer/crates/intern/src/symbol.rs | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index ef76192ba83..200b14027f8 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -77,8 +77,12 @@ impl TaggedArcPtr { } /// Retrieves the tag. + /// + /// # Safety + /// + /// You can only drop the `Arc` if the instance is dropped. #[inline] - pub(crate) fn try_as_arc_owned(self) -> Option>>> { + pub(crate) unsafe fn try_as_arc_owned(self) -> Option>>> { // Unpack the tag from the alignment niche let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS; if tag != 0 { @@ -245,16 +249,14 @@ impl Symbol { } } - ManuallyDrop::into_inner( - match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { - RawEntryMut::Occupied(occ) => occ.remove_entry(), - RawEntryMut::Vacant(_) => unreachable!(), - } - .0 - .0 - .try_as_arc_owned() - .unwrap(), - ); + let ptr = match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { + RawEntryMut::Occupied(occ) => occ.remove_entry(), + RawEntryMut::Vacant(_) => unreachable!(), + } + .0 + .0; + // SAFETY: We're dropping, we have ownership. + ManuallyDrop::into_inner(unsafe { ptr.try_as_arc_owned().unwrap() }); debug_assert_eq!(Arc::count(arc), 1); // Shrink the backing storage if the shard is less than 50% occupied. @@ -267,7 +269,8 @@ impl Symbol { impl Drop for Symbol { #[inline] fn drop(&mut self) { - let Some(arc) = self.repr.try_as_arc_owned() else { + // SAFETY: We're dropping, we have ownership. + let Some(arc) = (unsafe { self.repr.try_as_arc_owned() }) else { return; }; // When the last `Ref` is dropped, remove the object from the global map. @@ -288,7 +291,8 @@ impl Clone for Symbol { } fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr { - let Some(arc) = repr.try_as_arc_owned() else { + // SAFETY: We're not dropping the `Arc`. + let Some(arc) = (unsafe { repr.try_as_arc_owned() }) else { return repr; }; // increase the ref count -- cgit 1.4.1-3-g733a5 From 45f0e817bbcf36320a90eeb0da212a5c804bcb47 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 04:02:54 +0200 Subject: Fix shadowing of record enum variant in patterns --- .../rust-analyzer/crates/hir-def/src/body/lower.rs | 14 ++++++------- .../rust-analyzer/crates/hir-def/src/body/tests.rs | 23 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 1ab49e91569..3b73d409634 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -1510,20 +1510,20 @@ impl ExprCollector<'_> { BuiltinShadowMode::Other, None, ); + // Funnily enough, record structs/variants *can* be shadowed + // by pattern bindings (but unit or tuple structs/variants + // can't). match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), - Some(ModuleDefId::EnumVariantId(_)) => { - // this is only really valid for unit variants, but - // shadowing other enum variants with a pattern is - // an error anyway + Some(ModuleDefId::EnumVariantId(variant)) + if self.db.variant_data(variant.into()).kind() + != StructKind::Record => + { (None, Pat::Path(name.into())) } Some(ModuleDefId::AdtId(AdtId::StructId(s))) if self.db.struct_data(s).variant_data.kind() != StructKind::Record => { - // Funnily enough, record structs *can* be shadowed - // by pattern bindings (but unit or tuple structs - // can't). (None, Pat::Path(name.into())) } // shadowing statics is an error as well, so we just ignore that case here diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 3b29d98d198..82d46d2e492 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -404,3 +404,26 @@ fn foo() { }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } + +#[test] +fn shadowing_record_variant() { + let (_, body, _) = lower( + r#" +enum A { + B { field: i32 }, +} +fn f() { + use A::*; + match () { + B => {} + }; +} + "#, + ); + assert_eq!(body.bindings.len(), 1, "should have a binding for `B`"); + assert_eq!( + body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(), + "B", + "should have a binding for `B`", + ); +} -- cgit 1.4.1-3-g733a5 From 05aac8cd69ff15c6353dab1c27ad47e9def2d96f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 06:27:43 +0100 Subject: Better parser recovery for incomplete attributes --- .../crates/parser/src/grammar/attributes.rs | 10 ++- .../crates/parser/src/grammar/paths.rs | 19 +++-- .../rust-analyzer/crates/parser/src/parser.rs | 11 ++- .../crates/parser/test_data/generated/runner.rs | 2 + .../parser/err/0004_use_path_bad_segment.rast | 5 +- .../test_data/parser/err/0048_double_fish.rast | 10 ++- .../test_data/parser/inline/err/meta_recovery.rast | 86 ++++++++++++++++++++++ .../test_data/parser/inline/err/meta_recovery.rs | 6 ++ 8 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs index 82e4d661488..ccb556b2cca 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs @@ -36,6 +36,14 @@ fn attr(p: &mut Parser<'_>, inner: bool) { attr.complete(p, ATTR); } +// test_err meta_recovery +// #![] +// #![p = ] +// #![p::] +// #![p:: =] +// #![unsafe] +// #![unsafe =] + // test metas // #![simple_ident] // #![simple::path] @@ -63,7 +71,7 @@ pub(super) fn meta(p: &mut Parser<'_>) { if is_unsafe { p.expect(T!['(']); } - paths::use_path(p); + paths::attr_path(p); match p.current() { T![=] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 09db921803f..057a691ef03 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -19,6 +19,10 @@ pub(super) fn use_path(p: &mut Parser<'_>) { path(p, Mode::Use); } +pub(super) fn attr_path(p: &mut Parser<'_>) { + path(p, Mode::Attr); +} + pub(crate) fn type_path(p: &mut Parser<'_>) { path(p, Mode::Type); } @@ -37,6 +41,7 @@ pub(crate) fn type_path_for_qualifier( #[derive(Clone, Copy, Eq, PartialEq)] enum Mode { Use, + Attr, Type, Expr, } @@ -93,12 +98,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { p.error("expected `::`"); } } else { - let empty = if first { - p.eat(T![::]); - false - } else { - true - }; + let mut empty = if first { !p.eat(T![::]) } else { true }; match p.current() { IDENT => { name_ref(p); @@ -114,10 +114,13 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { _ => { let recover_set = match mode { Mode::Use => items::ITEM_RECOVERY_SET, + Mode::Attr => { + items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) + } Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, }; - p.err_recover("expected identifier", recover_set); + empty &= p.err_recover("expected identifier", recover_set); if empty { // test_err empty_segment // use crate::; @@ -132,7 +135,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { - Mode::Use => {} + Mode::Use | Mode::Attr => {} Mode::Type => { // test typepathfn_with_coloncolon // type F = Start::(Middle) -> (Middle)::End; diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index f6b3783d1ca..8078532e0bb 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -258,22 +258,25 @@ impl<'t> Parser<'t> { self.err_recover(message, TokenSet::EMPTY); } - /// Create an error node and consume the next token. - pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { + /// Create an error node and consume the next token unless it is in the recovery set. + /// + /// Returns true if recovery kicked in. + pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) -> bool { if matches!(self.current(), T!['{'] | T!['}']) { self.error(message); - return; + return true; } if self.at_ts(recovery) { self.error(message); - return; + return true; } let m = self.start(); self.error(message); self.bump_any(); m.complete(self, ERROR); + false } fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 62b381b6688..3db8b51a4ba 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -772,6 +772,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/match_arms_recovery.rs"); } #[test] + fn meta_recovery() { run_and_expect_errors("test_data/parser/inline/err/meta_recovery.rs"); } + #[test] fn method_call_missing_argument_list() { run_and_expect_errors("test_data/parser/inline/err/method_call_missing_argument_list.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast index 44e192a5fcb..cf455934e91 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast @@ -9,7 +9,8 @@ SOURCE_FILE NAME_REF IDENT "foo" COLON2 "::" - ERROR - INT_NUMBER "92" + PATH_SEGMENT + ERROR + INT_NUMBER "92" SEMICOLON ";" error 9: expected identifier diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast index 207a5c24dff..7ef1eb98fcd 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast @@ -39,8 +39,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" TYPE_ARG PATH_TYPE PATH @@ -91,8 +92,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" EXPR_STMT BIN_EXPR PATH_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast new file mode 100644 index 00000000000..c4bec849e7b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -0,0 +1,86 @@ +SOURCE_FILE + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + WHITESPACE " " + EQ "=" + WHITESPACE " " + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + WHITESPACE " " + EQ "=" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + PATH + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + WHITESPACE " " + PATH + EQ "=" + R_BRACK "]" + WHITESPACE "\n" +error 3: expected identifier +error 11: expected expression +error 11: expected expression +error 20: expected identifier +error 28: expected identifier +error 30: expected expression +error 30: expected expression +error 41: expected L_PAREN +error 41: expected identifier +error 41: expected R_PAREN +error 52: expected L_PAREN +error 53: expected identifier +error 54: expected expression +error 54: expected expression +error 54: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs new file mode 100644 index 00000000000..51d30adf8b4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs @@ -0,0 +1,6 @@ +#![] +#![p = ] +#![p::] +#![p:: =] +#![unsafe] +#![unsafe =] -- cgit 1.4.1-3-g733a5 From 7efe7eb3769a88814e9898313757dbd468f22e0f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 06:49:27 +0100 Subject: fix: Don't create empty path nodes --- .../rust-analyzer/crates/parser/src/grammar.rs | 4 ++-- .../crates/parser/src/grammar/generic_args.rs | 4 ++-- .../crates/parser/src/grammar/paths.rs | 23 +++++++++++++++------- .../rust-analyzer/crates/parser/src/parser.rs | 8 ++++---- .../inline/err/crate_visibility_empty_recover.rast | 6 +----- .../test_data/parser/inline/err/meta_recovery.rast | 5 +---- 6 files changed, 26 insertions(+), 24 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index a50a2182a7b..c402c498553 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -242,7 +242,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { // struct MyStruct(pub ()); if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { p.bump(T!['(']); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } } @@ -252,7 +252,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { T![in] => { p.bump(T!['(']); p.bump(T![in]); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } _ => {} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index c62c8a9d3f9..77379ef1471 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -168,10 +168,10 @@ pub(super) fn const_arg_expr(p: &mut Parser<'_>) { expressions::literal(p); lm.complete(p, PREFIX_EXPR); } - _ if paths::is_use_path_start(p) => { + _ if paths::is_path_start(p) => { // This shouldn't be hit by `const_arg` let lm = p.start(); - paths::use_path(p); + paths::expr_path(p); lm.complete(p, PATH_EXPR); } _ => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 057a691ef03..15b35296423 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -19,6 +19,10 @@ pub(super) fn use_path(p: &mut Parser<'_>) { path(p, Mode::Use); } +pub(super) fn vis_path(p: &mut Parser<'_>) { + path(p, Mode::Vis); +} + pub(super) fn attr_path(p: &mut Parser<'_>) { path(p, Mode::Attr); } @@ -44,13 +48,17 @@ enum Mode { Attr, Type, Expr, + Vis, } -fn path(p: &mut Parser<'_>, mode: Mode) { +fn path(p: &mut Parser<'_>, mode: Mode) -> Option { let path = p.start(); - path_segment(p, mode, true); + if path_segment(p, mode, true).is_none() { + path.abandon(p); + return None; + } let qual = path.complete(p, PATH); - path_for_qualifier(p, mode, qual); + Some(path_for_qualifier(p, mode, qual)) } fn path_for_qualifier( @@ -76,7 +84,7 @@ const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; -fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { +fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { let m = p.start(); // test qual_paths // type X = ::Output; @@ -117,6 +125,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { Mode::Attr => { items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) } + Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, }; @@ -125,17 +134,17 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { // test_err empty_segment // use crate::; m.abandon(p); - return; + return None; } } }; } - m.complete(p, PATH_SEGMENT); + Some(m.complete(p, PATH_SEGMENT)) } fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { - Mode::Use | Mode::Attr => {} + Mode::Use | Mode::Attr | Mode::Vis => {} Mode::Type => { // test typepathfn_with_coloncolon // type F = Start::(Middle) -> (Middle)::End; diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index 8078532e0bb..75a75f601cf 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -327,10 +327,10 @@ impl Marker { self.bomb.defuse(); let idx = self.pos as usize; if idx == p.events.len() - 1 { - match p.events.pop() { - Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (), - _ => unreachable!(), - } + assert!(matches!( + p.events.pop(), + Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) + )); } } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 0fe4ca42d79..681ca6b6e05 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -3,10 +3,7 @@ SOURCE_FILE VISIBILITY PUB_KW "pub" L_PAREN "(" - PATH - PATH_SEGMENT - ERROR - R_PAREN ")" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -15,4 +12,3 @@ SOURCE_FILE SEMICOLON ";" WHITESPACE "\n" error 4: expected identifier -error 5: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast index c4bec849e7b..926dd50fc85 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -4,7 +4,6 @@ SOURCE_FILE BANG "!" L_BRACK "[" META - PATH R_BRACK "]" WHITESPACE "\n" ATTR @@ -55,7 +54,6 @@ SOURCE_FILE L_BRACK "[" META UNSAFE_KW "unsafe" - PATH R_BRACK "]" WHITESPACE "\n" ATTR @@ -65,7 +63,6 @@ SOURCE_FILE META UNSAFE_KW "unsafe" WHITESPACE " " - PATH EQ "=" R_BRACK "]" WHITESPACE "\n" @@ -80,7 +77,7 @@ error 41: expected L_PAREN error 41: expected identifier error 41: expected R_PAREN error 52: expected L_PAREN -error 53: expected identifier +error 52: expected identifier error 54: expected expression error 54: expected expression error 54: expected R_PAREN -- cgit 1.4.1-3-g733a5 From 1e47f7d073b06910795ed0ce2d5ae8560d2fb6ac Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 07:03:01 +0100 Subject: Update mbe test output --- .../rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index d568f6faa72..5c03fad6131 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1759,8 +1759,9 @@ fn f() { // NAME_REF@6..7 // IDENT@6..7 "K" // COLON2@7..9 "::" -// ERROR@9..10 -// L_PAREN@9..10 "(" +// PATH_SEGMENT@9..10 +// ERROR@9..10 +// L_PAREN@9..10 "(" // EXPR_STMT@10..16 // CALL_EXPR@10..16 // PATH_EXPR@10..11 -- cgit 1.4.1-3-g733a5 From d2ee916c3094c100216c93d4ddd8b57519e7c599 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 01:34:52 +0200 Subject: Complete derive helper attributes Only their names, anything can go inside. --- .../rust-analyzer/crates/hir/src/semantics.rs | 16 ++++++ .../ide-completion/src/completions/attribute.rs | 13 ++++- .../crates/ide-completion/src/context.rs | 5 +- .../crates/ide-completion/src/context/analysis.rs | 17 +++++- .../crates/ide-completion/src/tests/attribute.rs | 64 ++++++++++++++++++++++ 5 files changed, 111 insertions(+), 4 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 46766fcc5b1..65470d061b3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -510,6 +510,22 @@ impl<'db> SemanticsImpl<'db> { self.with_ctx(|ctx| ctx.has_derives(adt)) } + pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option> { + let sa = self.analyze_no_infer(adt.syntax())?; + let id = self.db.ast_id_map(sa.file_id).ast_id(adt); + let result = sa + .resolver + .def_map() + .derive_helpers_in_scope(InFile::new(sa.file_id, id))? + .iter() + .map(|(name, macro_, _)| { + let macro_name = Macro::from(*macro_).name(self.db).symbol().clone(); + (name.symbol().clone(), macro_name) + }) + .collect(); + Some(result) + } + pub fn derive_helper(&self, attr: &ast::Attr) -> Option> { let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it { ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index d0b489c4e83..cf5427bae38 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path( acc: &mut Completions, ctx: &CompletionContext<'_>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &AttrCtx { kind, annotated_item_kind }: &AttrCtx, + &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx, ) { let is_inner = kind == AttrKind::Inner; + for (derive_helper, derive_name) in derive_helpers { + let mut item = CompletionItem::new( + SymbolKind::Attribute, + ctx.source_range(), + derive_helper.as_str(), + ctx.edition, + ); + item.detail(format!("derive helper of `{derive_name}`")); + item.add_to(acc, ctx.db); + } + match qualified { Qualified::With { resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index efbee39a2d4..5b8d1c30a29 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -7,8 +7,8 @@ mod tests; use std::{iter, ops::ControlFlow}; use hir::{ - HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, - TypeInfo, + HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, + Symbol, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition, @@ -133,6 +133,7 @@ pub(crate) type ExistingDerives = FxHashSet; pub(crate) struct AttrCtx { pub(crate) kind: AttrKind, pub(crate) annotated_item_kind: Option, + pub(crate) derive_helpers: Vec<(Symbol, Symbol)>, } #[derive(Debug, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 468ad81ad2f..a4e018b1800 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1129,7 +1129,22 @@ fn classify_name_ref( let is_trailing_outer_attr = kind != AttrKind::Inner && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none(); let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) }; - Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } }) + let derive_helpers = annotated_item_kind + .filter(|kind| { + matches!( + kind, + SyntaxKind::STRUCT + | SyntaxKind::ENUM + | SyntaxKind::UNION + | SyntaxKind::VARIANT + | SyntaxKind::TUPLE_FIELD + | SyntaxKind::RECORD_FIELD + ) + }) + .and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast)) + .and_then(|adt| sema.derive_helpers_in_scope(&adt)) + .unwrap_or_default(); + Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } }) }; // Infer the path kind diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 45679355b42..1443ebc6c0c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -8,6 +8,70 @@ fn check(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual); } +#[test] +fn derive_helpers() { + check( + r#" +//- /mac.rs crate:mac +#![crate_type = "proc-macro"] + +#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))] +pub fn my_derive() {} + +//- /lib.rs crate:lib deps:mac +#[rustc_builtin_macro] +pub macro derive($item:item) {} + +#[derive(mac::MyDerive)] +pub struct Foo(#[m$0] i32); +"#, + expect![[r#" + at allow(…) + at automatically_derived + at cfg(…) + at cfg_attr(…) + at cold + at deny(…) + at deprecated + at derive macro derive + at derive(…) + at doc = "…" + at doc(alias = "…") + at doc(hidden) + at expect(…) + at export_name = "…" + at forbid(…) + at global_allocator + at ignore = "…" + at inline + at link + at link_name = "…" + at link_section = "…" + at macro_export + at macro_use + at must_use + at my_cool_helper_attribute derive helper of `MyDerive` + at no_mangle + at non_exhaustive + at panic_handler + at path = "…" + at proc_macro + at proc_macro_attribute + at proc_macro_derive(…) + at repr(…) + at should_panic + at target_feature(enable = "…") + at test + at track_caller + at used + at warn(…) + md mac + kw crate:: + kw self:: + "#]], + ) +} + #[test] fn proc_macros() { check( -- cgit 1.4.1-3-g733a5 From 9296578960673092625dc4955f153a52a8a93750 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 08:05:23 +0200 Subject: Extend reported unsafe operations We add union fields access (in both expressions and patterns) and inline assembly. That completes the unsafe check (there are some other unsafe things but they are unstable), and so also opens the door to reporting unused unsafe without annoying people about their not-unused unsafe blocks. --- src/tools/rust-analyzer/crates/hir-def/src/body.rs | 133 ++++++++- .../rust-analyzer/crates/hir-ty/src/diagnostics.rs | 2 +- .../crates/hir-ty/src/diagnostics/unsafe_check.rs | 301 +++++++++++++++------ .../rust-analyzer/crates/hir/src/diagnostics.rs | 7 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 9 +- .../crates/hir/src/source_analyzer.rs | 6 +- .../ide-diagnostics/src/handlers/missing_unsafe.rs | 154 +++++++++-- 7 files changed, 499 insertions(+), 113 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 5a386f6cf8d..d4a1120908f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -408,7 +408,8 @@ impl Body { f(else_branch); } } - Expr::Let { expr, .. } => { + Expr::Let { expr, pat } => { + self.walk_exprs_in_pat(*pat, &mut f); f(*expr); } Expr::Block { statements, tail, .. } @@ -444,7 +445,10 @@ impl Body { } Expr::Match { expr, arms } => { f(*expr); - arms.iter().map(|arm| arm.expr).for_each(f); + arms.iter().for_each(|arm| { + f(arm.expr); + self.walk_exprs_in_pat(arm.pat, &mut f); + }); } Expr::Break { expr, .. } | Expr::Return { expr } @@ -505,6 +509,131 @@ impl Body { } } + pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, .. } => { + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().map(|arm| arm.expr).for_each(f); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target: _, value } => f(value), + } + } + pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) { self.walk_pats(pat_id, &mut |pat| { if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index af4d2c9fc04..30c02a2936d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -9,5 +9,5 @@ pub use crate::diagnostics::{ expr::{ record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, }, - unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, + unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index c7f7fb7ad3d..193aaa52c26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -1,12 +1,16 @@ //! Provides validations for unsafe code. Currently checks if unsafe functions are missing //! unsafe blocks. +use std::mem; + +use either::Either; use hir_def::{ body::Body, - hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp}, - resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp}, + path::Path, + resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, type_ref::Rawness, - DefWithBodyId, + AdtId, DefWithBodyId, FieldId, VariantId, }; use crate::{ @@ -16,7 +20,10 @@ use crate::{ /// Returns `(unsafe_exprs, fn_is_unsafe)`. /// /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`. -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec, bool) { +pub fn missing_unsafe( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> (Vec<(ExprOrPatId, UnsafetyReason)>, bool) { let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); @@ -30,111 +37,243 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec { + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + resolver: Resolver, def: DefWithBodyId, - current: ExprId, - inside_unsafe_block: bool, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), -) { - let mut mark_unsafe_path = |path, node| { - let g = resolver.update_to_inner_scope(db.upcast(), def, current); - let hygiene = body.expr_or_pat_path_hygiene(node); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene); - if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - let static_data = db.static_data(id); - if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { - unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block }); + inside_unsafe_block: InsideUnsafeBlock, + inside_assignment: bool, + inside_union_destructure: bool, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), +} + +impl<'a> UnsafeVisitor<'a> { + fn new( + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + def: DefWithBodyId, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), + ) -> Self { + let resolver = def.resolver(db.upcast()); + Self { + db, + infer, + body, + resolver, + def, + inside_unsafe_block: InsideUnsafeBlock::No, + inside_assignment: false, + inside_union_destructure: false, + unsafe_expr_cb, + } + } + + fn call_cb(&mut self, node: ExprOrPatId, reason: UnsafetyReason) { + (self.unsafe_expr_cb)(node, self.inside_unsafe_block, reason); + } + + fn walk_pats_top(&mut self, pats: impl Iterator, parent_expr: ExprId) { + let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.def, parent_expr); + pats.for_each(|pat| self.walk_pat(pat)); + self.resolver.reset_to_guard(guard); + } + + fn walk_pat(&mut self, current: PatId) { + let pat = &self.body.pats[current]; + + if self.inside_union_destructure { + match pat { + Pat::Tuple { .. } + | Pat::Record { .. } + | Pat::Range { .. } + | Pat::Slice { .. } + | Pat::Path(..) + | Pat::Lit(..) + | Pat::Bind { .. } + | Pat::TupleStruct { .. } + | Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Expr(..) + | Pat::ConstBlock(..) => self.call_cb(current.into(), UnsafetyReason::UnionField), + // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. + Pat::Missing | Pat::Wild | Pat::Or(_) => {} } } - resolver.reset_to_guard(g); - }; - let expr = &body.exprs[current]; - match expr { - &Expr::Call { callee, .. } => { - if let Some(func) = infer[callee].as_fn_def(db) { - if is_fn_unsafe_to_call(db, func) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + match pat { + Pat::Record { .. } => { + if let Some((AdtId::UnionId(_), _)) = self.infer[current].as_adt() { + let old_inside_union_destructure = + mem::replace(&mut self.inside_union_destructure, true); + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + self.inside_union_destructure = old_inside_union_destructure; + return; } } - } - Expr::Path(path) => mark_unsafe_path(path, current.into()), - Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { - if let Expr::Path(_) = body.exprs[*expr] { - // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, - // see https://github.com/rust-lang/rust/pull/125834. - return; + Pat::Path(path) => self.mark_unsafe_path(current.into(), path), + &Pat::ConstBlock(expr) => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); + self.walk_expr(expr); + self.inside_assignment = old_inside_assignment; } + &Pat::Expr(expr) => self.walk_expr(expr), + _ => {} } - Expr::MethodCall { .. } => { - if infer - .method_resolution(current) - .map(|(func, _)| is_fn_unsafe_to_call(db, func)) - .unwrap_or(false) - { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + } + + fn walk_expr(&mut self, current: ExprId) { + let expr = &self.body.exprs[current]; + let inside_assignment = mem::replace(&mut self.inside_assignment, false); + match expr { + &Expr::Call { callee, .. } => { + if let Some(func) = self.infer[callee].as_fn_def(self.db) { + if is_fn_unsafe_to_call(self.db, func) { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); + } + } } - } - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &infer[*expr].kind(Interner) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + Expr::Path(path) => { + let guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.def, current); + self.mark_unsafe_path(current.into(), path); + self.resolver.reset_to_guard(guard); } - } - Expr::Unsafe { .. } => { - return body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb); - }); - } - &Expr::Assignment { target, value: _ } => { - body.walk_pats(target, &mut |pat| { - if let Pat::Path(path) = &body[pat] { - mark_unsafe_path(path, pat.into()); + Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { + if let Expr::Path(_) = self.body.exprs[*expr] { + // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, + // see https://github.com/rust-lang/rust/pull/125834. + return; + } + } + Expr::MethodCall { .. } => { + if self + .infer + .method_resolution(current) + .map(|(func, _)| is_fn_unsafe_to_call(self.db, func)) + .unwrap_or(false) + { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); } - }); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let TyKind::Raw(..) = &self.infer[*expr].kind(Interner) { + self.call_cb(current.into(), UnsafetyReason::RawPtrDeref); + } + } + Expr::Unsafe { .. } => { + let old_inside_unsafe_block = + mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes); + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); + self.inside_unsafe_block = old_inside_unsafe_block; + return; + } + &Expr::Assignment { target, value: _ } => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, true); + self.walk_pats_top(std::iter::once(target), current); + self.inside_assignment = old_inside_assignment; + } + Expr::InlineAsm(_) => self.call_cb(current.into(), UnsafetyReason::InlineAsm), + // rustc allows union assignment to propagate through field accesses and casts. + Expr::Cast { .. } => self.inside_assignment = inside_assignment, + Expr::Field { .. } => { + self.inside_assignment = inside_assignment; + if !inside_assignment { + if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) = + self.infer.field_resolution(current) + { + self.call_cb(current.into(), UnsafetyReason::UnionField); + } + } + } + Expr::Block { statements, .. } | Expr::Async { statements, .. } => { + self.walk_pats_top( + statements.iter().filter_map(|statement| match statement { + &Statement::Let { pat, .. } => Some(pat), + _ => None, + }), + current, + ); + } + Expr::Match { arms, .. } => { + self.walk_pats_top(arms.iter().map(|arm| arm.pat), current); + } + &Expr::Let { pat, .. } => { + self.walk_pats_top(std::iter::once(pat), current); + } + Expr::Closure { args, .. } => { + self.walk_pats_top(args.iter().copied(), current); + } + _ => {} } - _ => {} + + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); } - body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb); - }); + fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) { + let hygiene = self.body.expr_or_pat_path_hygiene(node); + let value_or_partial = + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene); + if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { + let static_data = self.db.static_data(id); + if static_data.mutable { + self.call_cb(node, UnsafetyReason::MutableStatic); + } else if static_data.is_extern && !static_data.has_safe_kw { + self.call_cb(node, UnsafetyReason::ExternStatic); + } + } + } } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 8297acde857..9ca021027d5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -5,7 +5,9 @@ //! be expressed in terms of hir types themselves. pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; use hir_ty::{ - db::HirDatabase, diagnostics::BodyValidationDiagnostic, CastError, InferenceDiagnostic, + db::HirDatabase, + diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, + CastError, InferenceDiagnostic, }; use cfg::{CfgExpr, CfgOptions}; @@ -258,9 +260,10 @@ pub struct PrivateField { #[derive(Debug)] pub struct MissingUnsafe { - pub expr: InFile>>, + pub node: InFile>>, /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error. pub only_lint: bool, + pub reason: UnsafetyReason, } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c9498b3aead..0b2ba56b1ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -147,6 +147,7 @@ pub use { }, hir_ty::{ consteval::ConstEvalError, + diagnostics::UnsafetyReason, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, @@ -1890,10 +1891,10 @@ impl DefWithBody { ); } - let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); - for expr in unafe_exprs { - match source_map.expr_or_pat_syntax(expr) { - Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()), + let (unsafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); + for (node, reason) in unsafe_exprs { + match source_map.expr_or_pat_syntax(node) { + Ok(node) => acc.push(MissingUnsafe { node, only_lint, reason }.into()), Err(SyntheticSyntax) => { // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index c16454cff68..56ed81f053c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -36,7 +36,7 @@ use hir_expand::{ use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, - UnsafeExpr, + InsideUnsafeBlock, }, lang_items::lang_items_for_bin_op, method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, @@ -939,8 +939,8 @@ impl SourceAnalyzer { *def, body, expr_id, - &mut |UnsafeExpr { inside_unsafe_block, .. }| { - is_unsafe |= !inside_unsafe_block + &mut |_, inside_unsafe_block, _| { + is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No }, ) }; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a630d3c7c36..2bfdda35659 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,5 +1,5 @@ use hir::db::ExpandDatabase; -use hir::HirFileIdExt; +use hir::{HirFileIdExt, UnsafetyReason}; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, SyntaxNode}; @@ -16,23 +16,35 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf } else { DiagnosticCode::RustcHardError("E0133") }; + let operation = display_unsafety_reason(d.reason); Diagnostic::new_with_syntax_node_ptr( ctx, code, - "this operation is unsafe and requires an unsafe function or block", - d.expr.map(|it| it.into()), + format!("{operation} is unsafe and requires an unsafe function or block"), + d.node.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } +fn display_unsafety_reason(reason: UnsafetyReason) -> &'static str { + match reason { + UnsafetyReason::UnionField => "access to union field", + UnsafetyReason::UnsafeFnCall => "call to unsafe function", + UnsafetyReason::InlineAsm => "use of inline assembly", + UnsafetyReason::RawPtrDeref => "dereference of raw pointer", + UnsafetyReason::MutableStatic => "use of mutable static", + UnsafetyReason::ExternStatic => "use of extern static", + } +} + fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option> { // The fixit will not work correctly for macro expansions, so we don't offer it in that case. - if d.expr.file_id.is_macro() { + if d.node.file_id.is_macro() { return None; } - let root = ctx.sema.db.parse_or_expand(d.expr.file_id); - let node = d.expr.value.to_node(&root); + let root = ctx.sema.db.parse_or_expand(d.node.file_id); + let node = d.node.value.to_node(&root); let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?; let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; @@ -40,7 +52,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option u8 { fn main() { ed2021::safe(); ed2024::not_safe(); - //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ) @@ -591,7 +603,7 @@ unsafe fn foo(p: *mut i32) { #![warn(unsafe_op_in_unsafe_fn)] unsafe fn foo(p: *mut i32) { *p = 123; - //^^💡 warn: this operation is unsafe and requires an unsafe function or block + //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block } "#, ) @@ -618,17 +630,119 @@ unsafe extern { fn main() { f(); g(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block h(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block let _ = S1; let _ = S2; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _ = S3; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn no_unsafe_diagnostic_when_destructuring_union_with_wildcard() { + check_diagnostics( + r#" +union Union { field: i32 } +fn foo(v: &Union) { + let Union { field: _ } = v; + let Union { field: _ | _ } = v; + Union { field: _ } = *v; +} +"#, + ); + } + + #[test] + fn union_destructuring() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v @ Union { field: _field }: &Union) { + // ^^^^^^ error: access to union field is unsafe and requires an unsafe function or block + let Union { mut field } = v; + // ^^^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0 + // ^💡 error: access to union field is unsafe and requires an unsafe function or block + | 1..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + Union { field } = *v; + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + match v { + Union { field: _field } => {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + } + if let Union { field: _field } = v {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + (|&Union { field }| { _ = field; })(v); + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn union_field_access() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v: &Union) { + v.field; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block } "#, ); } + + #[test] + fn inline_asm() { + check_diagnostics( + r#" +//- minicore: asm +fn foo() { + core::arch::asm!(""); + // ^^^^ error: use of inline assembly is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn unsafe_op_in_unsafe_fn_dismissed_in_signature() { + check_diagnostics( + r#" +#![warn(unsafe_op_in_unsafe_fn)] +union Union { field: u32 } +unsafe fn foo(Union { field: _field }: Union) {} + "#, + ) + } + + #[test] + fn union_assignment_allowed() { + check_diagnostics( + r#" +union Union { field: u32 } +fn foo(mut v: Union) { + v.field = 123; + (v.field,) = (123,); + *&mut v.field = 123; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +struct Struct { field: u32 } +union Union2 { field: Struct } +fn bar(mut v: Union2) { + v.field.field = 123; +} + + "#, + ) + } } -- cgit 1.4.1-3-g733a5 From baf4862fb277c06bf7750a09f949ba81500b6497 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 27 Nov 2024 12:08:21 +0200 Subject: feat: migrate `sort_items` assist to use `SyntaxFactory` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/sort_items.rs | 40 ++++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 64e30b18345..6a37a72996f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use syntax::{ ast::{self, HasName}, - ted, AstNode, TextRange, + AstNode, SyntaxNode, }; use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists}; @@ -114,7 +114,7 @@ trait AddRewrite { label: &str, old: Vec, new: Vec, - target: TextRange, + target: SyntaxNode, ) -> Option<()>; } @@ -124,15 +124,24 @@ impl AddRewrite for Assists { label: &str, old: Vec, new: Vec, - target: TextRange, + target: SyntaxNode, ) -> Option<()> { - self.add(AssistId("sort_items", AssistKind::RefactorRewrite), label, target, |builder| { - let mutable: Vec = old.into_iter().map(|it| builder.make_mut(it)).collect(); - mutable - .into_iter() - .zip(new) - .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax())); - }) + let node = old.first().unwrap().syntax().parent().unwrap(); + self.add( + AssistId("sort_items", AssistKind::RefactorRewrite), + label, + target.text_range(), + |builder| { + let mut editor = builder.make_editor(&node); + + old.into_iter().zip(new).for_each(|(old, new)| { + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(old.syntax(), new.clone_for_update().syntax()) + }); + + builder.add_file_edits(builder.file_id, editor) + }, + ) } } @@ -167,7 +176,7 @@ fn add_sort_methods_assist( return None; } - acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().text_range()) + acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().clone()) } fn add_sort_fields_assist( @@ -186,7 +195,7 @@ fn add_sort_fields_assist( "Sort fields alphabetically", fields, sorted, - record_field_list.syntax().text_range(), + record_field_list.syntax().clone(), ) } @@ -199,12 +208,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) - return None; } - acc.add_rewrite( - "Sort variants alphabetically", - variants, - sorted, - variant_list.syntax().text_range(), - ) + acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax().clone()) } fn sort_by_name(initial: &[T]) -> Vec { -- cgit 1.4.1-3-g733a5 From a1fa4971a6e71a4011b004024ae85a68d0d550e1 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 12:42:07 +0200 Subject: refactor: change target parameter to a reference in add_rewrite method Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/sort_items.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 6a37a72996f..7307325e496 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -114,7 +114,7 @@ trait AddRewrite { label: &str, old: Vec, new: Vec, - target: SyntaxNode, + target: &SyntaxNode, ) -> Option<()>; } @@ -124,15 +124,14 @@ impl AddRewrite for Assists { label: &str, old: Vec, new: Vec, - target: SyntaxNode, + target: &SyntaxNode, ) -> Option<()> { - let node = old.first().unwrap().syntax().parent().unwrap(); self.add( AssistId("sort_items", AssistKind::RefactorRewrite), label, target.text_range(), |builder| { - let mut editor = builder.make_editor(&node); + let mut editor = builder.make_editor(target); old.into_iter().zip(new).for_each(|(old, new)| { // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us @@ -176,7 +175,7 @@ fn add_sort_methods_assist( return None; } - acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().clone()) + acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax()) } fn add_sort_fields_assist( @@ -191,12 +190,7 @@ fn add_sort_fields_assist( return None; } - acc.add_rewrite( - "Sort fields alphabetically", - fields, - sorted, - record_field_list.syntax().clone(), - ) + acc.add_rewrite("Sort fields alphabetically", fields, sorted, record_field_list.syntax()) } fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -> Option<()> { @@ -208,7 +202,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) - return None; } - acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax().clone()) + acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax()) } fn sort_by_name(initial: &[T]) -> Vec { -- cgit 1.4.1-3-g733a5 From 2b4dc9caac1c05ae53e0d09907c40de1b1a75392 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Dec 2024 18:29:00 +0100 Subject: Fix parsing of parenthesized type args and RTN --- .../rust-analyzer/crates/hir-def/src/path/lower.rs | 8 +- .../crates/ide-db/src/path_transform.rs | 3 +- .../rust-analyzer/crates/ide-ssr/src/matching.rs | 4 +- .../crates/ide/src/inlay_hints/lifetime.rs | 94 +++-- .../crates/parser/src/grammar/expressions.rs | 2 +- .../crates/parser/src/grammar/generic_args.rs | 65 ++- .../crates/parser/src/grammar/params.rs | 18 +- .../crates/parser/src/grammar/paths.rs | 100 +++-- .../crates/parser/src/grammar/types.rs | 4 +- .../crates/parser/src/syntax_kind/generated.rs | 1 + .../crates/parser/test_data/generated/runner.rs | 32 +- .../inline/err/generic_arg_list_recover.rast | 33 ++ .../parser/inline/err/generic_arg_list_recover.rs | 1 + .../inline/err/generic_arg_list_recover_expr.rast | 79 ++++ .../inline/err/generic_arg_list_recover_expr.rs | 2 + .../parser/inline/ok/assoc_type_bound.rast | 39 ++ .../test_data/parser/inline/ok/assoc_type_bound.rs | 1 + .../parser/inline/ok/associated_type_bounds.rast | 111 ----- .../parser/inline/ok/associated_type_bounds.rs | 1 - .../parser/inline/ok/async_trait_bound.rast | 4 +- .../bare_dyn_types_with_paren_as_generic_args.rast | 175 -------- .../bare_dyn_types_with_paren_as_generic_args.rs | 4 - .../parser/inline/ok/generic_arg_bounds.rast | 461 +++++++++++++++++++++ .../parser/inline/ok/generic_arg_bounds.rs | 4 + .../parser/inline/ok/param_list_opt_patterns.rast | 48 --- .../parser/inline/ok/param_list_opt_patterns.rs | 1 - .../parser/inline/ok/path_fn_trait_args.rast | 128 +++++- .../parser/inline/ok/path_fn_trait_args.rs | 3 + .../ok/return_type_syntax_assoc_type_bound.rast | 49 --- .../ok/return_type_syntax_assoc_type_bound.rs | 1 - .../inline/ok/return_type_syntax_in_path.rast | 43 ++ .../parser/inline/ok/return_type_syntax_in_path.rs | 2 + .../inline/ok/typepathfn_with_coloncolon.rast | 10 +- .../inline/ok/value_parameters_no_patterns.rast | 60 --- .../inline/ok/value_parameters_no_patterns.rs | 1 - .../test_data/parser/inline/ok/where_pred_for.rast | 4 +- .../test_data/parser/ok/0045_block_attrs.rast | 2 +- .../test_data/parser/ok/0051_parameter_attrs.rast | 57 --- .../test_data/parser/ok/0051_parameter_attrs.rs | 2 - .../parser/ok/0054_qual_path_in_type_arg.rast | 8 +- .../parser/ok/0065_plus_after_fn_trait_bound.rast | 2 +- .../test_data/parser/ok/0067_where_for_pred.rast | 8 +- src/tools/rust-analyzer/crates/syntax/rust.ungram | 5 +- .../crates/syntax/src/ast/generated/nodes.rs | 38 +- 44 files changed, 1020 insertions(+), 698 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 553e615b94f..37c94a5f118 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -48,7 +48,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< .or_else(|| { lower_generic_args_from_fn_path( ctx, - segment.param_list(), + segment.parenthesized_arg_list(), segment.ret_type(), ) }); @@ -247,12 +247,12 @@ pub(super) fn lower_generic_args( /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). fn lower_generic_args_from_fn_path( ctx: &mut LowerCtx<'_>, - params: Option, + args: Option, ret_type: Option, ) -> Option { - let params = params?; + let params = args?; let mut param_types = Vec::new(); - for param in params.params() { + for param in params.type_args() { let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); param_types.push(type_ref); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 49b3ca290f0..a508f2fedd6 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -286,7 +286,8 @@ impl Ctx<'_> { return None; } if path.segment().map_or(false, |s| { - s.param_list().is_some() || (s.self_token().is_some() && path.parent_path().is_none()) + s.parenthesized_arg_list().is_some() + || (s.self_token().is_some() && path.parent_path().is_none()) }) { // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway // don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 6569f0f5552..4edc3633fbe 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -359,8 +359,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> { )?; self.attempt_match_opt( phase, - pattern_segment.param_list(), - code_segment.param_list(), + pattern_segment.parenthesized_arg_list(), + code_segment.parenthesized_arg_list(), )?; } if matches!(phase, Phase::Second(_)) { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index 2163c959b18..1fdd6989917 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -41,7 +41,15 @@ pub(super) fn fn_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, self_param, @@ -90,7 +98,15 @@ pub(super) fn fn_ptr_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, None, @@ -148,7 +164,7 @@ pub(super) fn fn_path_hints( fd, config, file_id, - param_list, + param_list.type_args().filter_map(|it| Some((None, it.ty()?))), generic_param_list, ret_type, None, @@ -177,8 +193,8 @@ pub(super) fn fn_path_hints( ) } -fn path_as_fn(path: &ast::Path) -> Option<(ast::ParamList, Option)> { - path.segment().and_then(|it| it.param_list().zip(Some(it.ret_type()))) +fn path_as_fn(path: &ast::Path) -> Option<(ast::ParenthesizedArgList, Option)> { + path.segment().and_then(|it| it.parenthesized_arg_list().zip(Some(it.ret_type()))) } fn hints_( @@ -187,7 +203,7 @@ fn hints_( FamousDefs(_, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, _file_id: EditionedFileId, - param_list: ast::ParamList, + params: impl Iterator, ast::Type)>, generic_param_list: Option, ret_type: Option, self_param: Option, @@ -217,45 +233,34 @@ fn hints_( let is_elided = is_elided(&lifetime); acc.push((None, self_param.amp_token(), lifetime, is_elided)); } - param_list - .params() - .filter_map(|it| { - Some(( - it.pat().and_then(|it| match it { - ast::Pat::IdentPat(p) => p.name(), - _ => None, - }), - it.ty()?, - )) - }) - .for_each(|(name, ty)| { - // FIXME: check path types - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(r) => { - let lifetime = r.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); - false - } - ast::Type::FnPtrType(_) => { + params.for_each(|(name, ty)| { + // FIXME: check path types + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(r) => { + let lifetime = r.lifetime(); + let is_elided = is_elided(&lifetime); + acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() + { is_trivial = false; true + } else { + false } - ast::Type::PathType(t) => { - if t.path() - .and_then(|it| it.segment()) - .and_then(|it| it.param_list()) - .is_some() - { - is_trivial = false; - true - } else { - false - } - } - _ => false, - }) - }); + } + _ => false, + }) + }); acc }; @@ -339,7 +344,10 @@ fn hints_( true } ast::Type::PathType(t) => { - if t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() { is_trivial = false; true diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index e565874a421..349bce09390 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -525,7 +525,7 @@ fn method_call_expr( p.bump(T![.]); } name_ref(p); - generic_args::opt_generic_arg_list(p, true); + generic_args::opt_generic_arg_list_expr(p); if p.at(T!['(']) { arg_list(p); } else { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index 77379ef1471..737010985b2 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -1,14 +1,13 @@ use super::*; -// test_err generic_arg_list_recover -// type T = T<0, ,T>; -pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) { +// test_err generic_arg_list_recover_expr +// const _: () = T::<0, ,T>; +// const _: () = T::<0, ,T>(); +pub(super) fn opt_generic_arg_list_expr(p: &mut Parser<'_>) { let m; if p.at(T![::]) && p.nth(2) == T![<] { m = p.start(); p.bump(T![::]); - } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] { - m = p.start(); } else { return; } @@ -25,7 +24,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo m.complete(p, GENERIC_ARG_LIST); } -const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ +pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ LIFETIME_IDENT, IDENT, T!['{'], @@ -47,20 +46,23 @@ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); // test generic_arg // type T = S; -fn generic_arg(p: &mut Parser<'_>) -> bool { +pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), T!['{'] | T![true] | T![false] | T![-] => const_arg(p), k if k.is_literal() => const_arg(p), - // test associated_type_bounds - // fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} + // test generic_arg_bounds + // type Plain = Foo; + // type GenericArgs = Foo, Item::, Item: Bound, Item::: Bound, Item = Item, Item:: = Item>; + // type ParenthesizedArgs = Foo; + // type RTN = Foo; // test macro_inside_generic_arg // type A = Foo; - IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => { + IDENT => { let m = p.start(); name_ref(p); - opt_generic_arg_list(p, false); + paths::opt_path_type_args(p); match p.current() { T![=] => { p.bump_any(); @@ -88,45 +90,26 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { } // test assoc_type_bound // type T = StreamingIterator: Clone>; + // type T = StreamingIterator; T![:] if !p.at(T![::]) => { generic_params::bounds(p); m.complete(p, ASSOC_TYPE_ARG); } + // Turned out to be just a normal path type (mirror `path_or_macro_type`) _ => { let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); let m = paths::type_path_for_qualifier(p, m); - m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG); + let m = if p.at(T![!]) && !p.at(T![!=]) { + let m = m.precede(p); + items::macro_call_after_excl(p); + m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_TYPE) + } else { + m.precede(p).complete(p, PATH_TYPE) + }; + types::opt_type_bounds_as_dyn_trait_type(p, m).precede(p).complete(p, TYPE_ARG); } } } - IDENT if p.nth_at(1, T!['(']) => { - let m = p.start(); - name_ref(p); - if p.nth_at(1, T![..]) { - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - // test return_type_syntax_assoc_type_bound - // fn foo>() {} - generic_params::bounds(p); - m.complete(p, ASSOC_TYPE_ARG); - } else { - params::param_list_fn_trait(p); - // test bare_dyn_types_with_paren_as_generic_args - // type A = S; - // type A = S; - // type B = S i32>; - // type C = S i32 + Send>; - opt_ret_type(p); - let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); - let m = paths::type_path_for_qualifier(p, m); - let m = m.precede(p).complete(p, PATH_TYPE); - let m = types::opt_type_bounds_as_dyn_trait_type(p, m); - m.precede(p).complete(p, TYPE_ARG); - } - } _ if p.at_ts(types::TYPE_FIRST) => type_arg(p), _ => return false, } @@ -190,7 +173,7 @@ pub(super) fn const_arg(p: &mut Parser<'_>) { m.complete(p, CONST_ARG); } -fn type_arg(p: &mut Parser<'_>) { +pub(crate) fn type_arg(p: &mut Parser<'_>) { let m = p.start(); types::type_(p); m.complete(p, TYPE_ARG); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs index c535267c165..51ffcd07069 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs @@ -14,12 +14,6 @@ pub(super) fn param_list_fn_def(p: &mut Parser<'_>) { list_(p, Flavor::FnDef); } -// test param_list_opt_patterns -// fn foo)>(){} -pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) { - list_(p, Flavor::FnTrait); -} - pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { list_(p, Flavor::FnPointer); } @@ -28,10 +22,9 @@ pub(super) fn param_list_closure(p: &mut Parser<'_>) { list_(p, Flavor::Closure); } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Flavor { - FnDef, // Includes trait fn params; omitted param idents are not supported - FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations + FnDef, // Includes trait fn params; omitted param idents are not supported FnPointer, Closure, } @@ -41,7 +34,7 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) { let (bra, ket) = match flavor { Closure => (T![|], T![|]), - FnDef | FnTrait | FnPointer => (T!['('], T![')']), + FnDef | FnPointer => (T!['('], T![')']), }; let list_marker = p.start(); @@ -119,11 +112,6 @@ fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) { } } } - // test value_parameters_no_patterns - // type F = Box; - Flavor::FnTrait => { - types::type_(p); - } // test fn_pointer_param_ident_path // type Foo = fn(Bar::Baz); // type Qux = fn(baz: Bar::Baz); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 15b35296423..b3652f7cd3f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -110,7 +110,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { name_ref(p); - opt_path_type_args(p, mode); + opt_path_args(p, mode); } // test crate_path // use crate::foo; @@ -142,38 +142,74 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option, mode: Mode) { +pub(crate) fn opt_path_type_args(p: &mut Parser<'_>) { + // test typepathfn_with_coloncolon + // type F = Start::(Middle) -> (Middle)::End; + // type GenericArg = S; + let m; + if p.at(T![::]) && matches!(p.nth(2), T![<] | T!['(']) { + m = p.start(); + p.bump(T![::]); + } else if (p.current() == T![<] && p.nth(1) != T![=]) || p.current() == T!['('] { + m = p.start(); + } else { + return; + } + let current = p.current(); + if current == T![<] { + // test_err generic_arg_list_recover + // type T = T<0, ,T>; + // type T = T::<0, ,T>; + delimited( + p, + T![<], + T![>], + T![,], + || "expected generic argument".into(), + generic_args::GENERIC_ARG_FIRST, + generic_args::generic_arg, + ); + m.complete(p, GENERIC_ARG_LIST); + } else if p.nth_at(1, T![..]) { + // test return_type_syntax_in_path + // fn foo() + // where + // T::method(..): Send, + // method(..): Send, + // method::(..): Send, + // {} + p.bump(T!['(']); + p.bump(T![..]); + p.expect(T![')']); + m.complete(p, RETURN_TYPE_SYNTAX); + } else { + // test path_fn_trait_args + // type F = Box ()>; + // type F = Box<::Fn(i32) -> ()>; + // type F = Box ()>; + // type F = Box<::Fn::(i32) -> ()>; + delimited( + p, + T!['('], + T![')'], + T![,], + || "expected type".into(), + types::TYPE_FIRST, + |p| { + let progress = types::TYPE_FIRST.contains(p.current()); + generic_args::type_arg(p); + progress + }, + ); + m.complete(p, PARENTHESIZED_ARG_LIST); + opt_ret_type(p); + } +} + +fn opt_path_args(p: &mut Parser<'_>, mode: Mode) { match mode { Mode::Use | Mode::Attr | Mode::Vis => {} - Mode::Type => { - // test typepathfn_with_coloncolon - // type F = Start::(Middle) -> (Middle)::End; - // type GenericArg = S; - if p.at(T![::]) && p.nth_at(2, T!['(']) { - p.bump(T![::]); - } - if p.at(T!['(']) { - if p.nth_at(1, T![..]) { - // test return_type_syntax_in_path - // fn foo() - // where - // T::method(..): Send, - // {} - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - } else { - // test path_fn_trait_args - // type F = Box ()>; - params::param_list_fn_trait(p); - opt_ret_type(p); - } - } else { - generic_args::opt_generic_arg_list(p, false); - } - } - Mode::Expr => generic_args::opt_generic_arg_list(p, true), + Mode::Type => opt_path_type_args(p), + Mode::Expr => generic_args::opt_generic_arg_list_expr(p), } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index f4e57d3d6f3..35198ccbe35 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -50,7 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { // Some path types are not allowed to have bounds (no plus) T![<] => path_type_bounds(p, allow_bounds), T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p), - _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), + _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds), LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), _ => { p.err_recover("expected type", TYPE_RECOVERY_SET); @@ -337,7 +337,7 @@ pub(super) fn path_type(p: &mut Parser<'_>) { // test macro_call_type // type A = foo!(); // type B = crate::foo!(); -fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { +fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); let r = p.start(); let m = p.start(); diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 21730244a33..0c9c6ffd715 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -256,6 +256,7 @@ pub enum SyntaxKind { OR_PAT, PARAM, PARAM_LIST, + PARENTHESIZED_ARG_LIST, PAREN_EXPR, PAREN_PAT, PAREN_TYPE, diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 3db8b51a4ba..6d114037bf9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -39,10 +39,6 @@ mod ok { #[test] fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); } #[test] - fn associated_type_bounds() { - run_and_expect_no_errors("test_data/parser/inline/ok/associated_type_bounds.rs"); - } - #[test] fn async_trait_bound() { run_and_expect_no_errors("test_data/parser/inline/ok/async_trait_bound.rs"); } @@ -59,12 +55,6 @@ mod ok { ); } #[test] - fn bare_dyn_types_with_paren_as_generic_args() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs", - ); - } - #[test] fn become_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/become_expr.rs"); } #[test] fn bind_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/bind_pat.rs"); } @@ -281,6 +271,10 @@ mod ok { #[test] fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); } #[test] + fn generic_arg_bounds() { + run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs"); + } + #[test] fn generic_param_attribute() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs"); } @@ -423,10 +417,6 @@ mod ok { #[test] fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); } #[test] - fn param_list_opt_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/param_list_opt_patterns.rs"); - } - #[test] fn param_list_vararg() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list_vararg.rs"); } @@ -521,12 +511,6 @@ mod ok { #[test] fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); } #[test] - fn return_type_syntax_assoc_type_bound() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs", - ); - } - #[test] fn return_type_syntax_in_path() { run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs"); } @@ -685,10 +669,6 @@ mod ok { #[test] fn use_tree_star() { run_and_expect_no_errors("test_data/parser/inline/ok/use_tree_star.rs"); } #[test] - fn value_parameters_no_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/value_parameters_no_patterns.rs"); - } - #[test] fn variant_discriminant() { run_and_expect_no_errors("test_data/parser/inline/ok/variant_discriminant.rs"); } @@ -754,6 +734,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover.rs"); } #[test] + fn generic_arg_list_recover_expr() { + run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover_expr.rs"); + } + #[test] fn generic_param_list_recover() { run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast index 4cf5a3386b9..16183ce9ef5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast @@ -30,4 +30,37 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" error 14: expected generic argument +error 35: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs index 7d849aa1bee..aa65a0673a4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs @@ -1 +1,2 @@ type T = T<0, ,T>; +type T = T::<0, ,T>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast new file mode 100644 index 00000000000..de403d30494 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast @@ -0,0 +1,79 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" +error 21: expected generic argument +error 47: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs new file mode 100644 index 00000000000..74cc63ac4a0 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs @@ -0,0 +1,2 @@ +const _: () = T::<0, ,T>; +const _: () = T::<0, ,T>(); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast index f2e4e01069c..0f62e1dd184 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast @@ -35,3 +35,42 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "StreamingIterator" + GENERIC_ARG_LIST + L_ANGLE "<" + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Clone" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs index daae97e4fd5..83fea1c6c87 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs @@ -1 +1,2 @@ type T = StreamingIterator: Clone>; +type T = StreamingIterator; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast deleted file mode 100644 index 8cbc98c51ca..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast +++ /dev/null @@ -1,111 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "print_all" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - CONST_ARG - LITERAL - TRUE_KW "true" - R_ANGLE ">" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Display" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "printables" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs deleted file mode 100644 index 0f7a2d16083..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast index ebf758286a7..df0ba55d03d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast @@ -23,9 +23,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast deleted file mode 100644 index d5f97bad898..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast +++ /dev/null @@ -1,175 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs deleted file mode 100644 index 800002b1b82..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs +++ /dev/null @@ -1,4 +0,0 @@ -type A = S; -type A = S; -type B = S i32>; -type C = S i32 + Send>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast new file mode 100644 index 00000000000..fee5913acaa --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast @@ -0,0 +1,461 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "Plain" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "GenericArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "ParenthesizedArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "RTN" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs new file mode 100644 index 00000000000..1abd0aeb592 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs @@ -0,0 +1,4 @@ +type Plain = Foo; +type GenericArgs = Foo, Item::, Item: Bound, Item::: Bound, Item = Item, Item:: = Item>; +type ParenthesizedArgs = Foo; +type RTN = Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast deleted file mode 100644 index e9d93a0d0a4..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs deleted file mode 100644 index 9b93442c0f2..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo)>(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast index fd83daf841f..924f7ba2c9d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast @@ -20,9 +20,133 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs index 17ed20e5b13..7aa655d7ea9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs @@ -1 +1,4 @@ type F = Box ()>; +type F = Box<::Fn(i32) -> ()>; +type F = Box ()>; +type F = Box<::Fn::(i32) -> ()>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast deleted file mode 100644 index 30e0e73bbd6..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "method" - RETURN_TYPE_SYNTAX - L_PAREN "(" - DOT2 ".." - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs deleted file mode 100644 index 8a4cf4c3a07..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast index 501dccd79db..15a0558b53d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast @@ -42,6 +42,49 @@ SOURCE_FILE NAME_REF IDENT "Send" COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + COLON2 "::" + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," WHITESPACE "\n" BLOCK_EXPR STMT_LIST diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs index a9b63fb01c8..64b48c1638e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs @@ -1,4 +1,6 @@ fn foo() where T::method(..): Send, + method(..): Send, + method::(..): Send, {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast index 67277d0639a..fb442bfb739 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast @@ -13,10 +13,10 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - COLON2 "::" - PARAM_LIST + PARENTHESIZED_ARG_LIST + COLON2 "::" L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT @@ -63,9 +63,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast deleted file mode 100644 index 902b06484c8..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs deleted file mode 100644 index 93636e926e1..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -type F = Box; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast index 8407e99f614..0cc365efbe6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast index fad574a4769..c22d99f1ae1 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast @@ -180,7 +180,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast index f8b11e7782c..eafee90db42 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast @@ -138,63 +138,6 @@ SOURCE_FILE WHITESPACE " " R_CURLY "}" WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" TRAIT TRAIT_KW "trait" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs index de350d8587a..0a0100e5d00 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs @@ -3,8 +3,6 @@ fn g2(#[attr1] x: u8) {} extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } -fn foo)>(){} - trait Foo { fn bar(#[attr] _: u64, # [attr] mut x: i32); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast index 4e1e31f3767..31cca601ca2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast @@ -58,9 +58,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH @@ -101,9 +101,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast index ba7b6042a9e..d7ee11077cd 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast @@ -32,7 +32,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast index 136fce93d7e..cd3b21ae94f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME @@ -165,9 +165,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 02c59646a99..30428329dd9 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -37,7 +37,7 @@ Path = PathSegment = '::'? NameRef | NameRef GenericArgList? -| NameRef ParamList RetType? +| NameRef ParenthesizedArgList RetType? | NameRef ReturnTypeSyntax | '<' Type ('as' PathType)? '>' @@ -49,6 +49,9 @@ ReturnTypeSyntax = // Generics // //*************************// +ParenthesizedArgList = + '::'? '(' (TypeArg (',' TypeArg)* ','?)? ')' + GenericArgList = '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 23d2b355a94..01dcb646b37 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1362,6 +1362,21 @@ impl ParenType { pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParenthesizedArgList { + pub(crate) syntax: SyntaxNode, +} +impl ParenthesizedArgList { + #[inline] + pub fn type_args(&self) -> AstChildren { support::children(&self.syntax) } + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + #[inline] + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub(crate) syntax: SyntaxNode, @@ -1403,7 +1418,9 @@ impl PathSegment { #[inline] pub fn name_ref(&self) -> Option { support::child(&self.syntax) } #[inline] - pub fn param_list(&self) -> Option { support::child(&self.syntax) } + pub fn parenthesized_arg_list(&self) -> Option { + support::child(&self.syntax) + } #[inline] pub fn path_type(&self) -> Option { support::child(&self.syntax) } #[inline] @@ -3760,6 +3777,20 @@ impl AstNode for ParenType { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for ParenthesizedArgList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for Path { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } @@ -7097,6 +7128,11 @@ impl std::fmt::Display for ParenType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ParenthesizedArgList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Path { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) -- cgit 1.4.1-3-g733a5 From 2a949d8725a1027ffe8ef49c1303bc95d6192ce8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 19 Nov 2024 19:57:07 +0200 Subject: Store some hir_def Paths in the type ref source maps Most paths are types and therefore already are in the source map, but the trait in impl trait and in bounds are not. We do this by storing them basically as `TypeRef`s. For convenience, I created a wrapper around `TypeRefId` called `PathId` that always stores a path, and implemented indexing from the types map to it. Fortunately, this change impacts memory usage negligibly (adds 2mb to `analysis-stats .`, but that could be just fluff). Probably because there aren't that many trait bounds and impl traits, and this also shrinks `TypeBound` by 8 bytes. I also added an accessor to `TypesSourceMap` to get the source code, which will be needed for diagnostics. --- src/tools/rust-analyzer/crates/hir-def/src/body.rs | 5 +- src/tools/rust-analyzer/crates/hir-def/src/data.rs | 2 +- .../rust-analyzer/crates/hir-def/src/generics.rs | 22 +++--- .../crates/hir-def/src/hir/type_ref.rs | 84 ++++++++++++++++------ .../crates/hir-def/src/item_tree/lower.rs | 9 +-- .../crates/hir-def/src/item_tree/pretty.rs | 2 +- src/tools/rust-analyzer/crates/hir-def/src/lib.rs | 3 + .../rust-analyzer/crates/hir-def/src/lower.rs | 6 +- .../rust-analyzer/crates/hir-def/src/pretty.rs | 4 +- .../rust-analyzer/crates/hir-def/src/resolver.rs | 10 +-- .../rust-analyzer/crates/hir-ty/src/display.rs | 6 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 33 +++++---- src/tools/rust-analyzer/crates/hir-ty/src/tests.rs | 4 +- src/tools/rust-analyzer/crates/hir-ty/src/utils.rs | 2 +- .../rust-analyzer/crates/hir/src/diagnostics.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/display.rs | 18 +++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +- .../crates/rust-analyzer/src/cli/analysis_stats.rs | 3 +- 18 files changed, 144 insertions(+), 77 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index d4a1120908f..908f2050b5f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -31,7 +31,7 @@ use crate::{ path::{ModPath, Path}, src::HasSource, type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, - BlockId, DefWithBodyId, HasModule, Lookup, + BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax, }; /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. @@ -160,9 +160,6 @@ pub struct BodySourceMap { diagnostics: Vec, } -#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] -pub struct SyntheticSyntax; - #[derive(Debug, Eq, PartialEq)] pub enum BodyDiagnostic { InactiveCode { node: InFile, cfg: CfgExpr, opts: CfgOptions }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 2a13f74aac7..15dd6aba311 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -369,7 +369,7 @@ impl ImplData { let item_tree = tree_id.item_tree(db); let impl_def = &item_tree[tree_id.value]; - let target_trait = impl_def.target_trait.clone(); + let target_trait = impl_def.target_trait; let self_ty = impl_def.self_ty; let is_negative = impl_def.is_negative; let is_unsafe = impl_def.is_unsafe; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 11e9bb0d886..fdcb10e9988 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -26,8 +26,8 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, type_ref::{ - ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap, - TypesSourceMap, + ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId, + TypesMap, TypesSourceMap, }, AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, @@ -874,14 +874,20 @@ fn copy_type_bound( to: &mut TypesMap, to_source_map: &mut TypesSourceMap, ) -> TypeBound { + let mut copy_path_id = |path: PathId| { + let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map); + let new_path_id = to.types.alloc(TypeRef::Path(new_path)); + if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) { + to_source_map.types_map_back.insert(new_path_id, ptr); + } + PathId::from_type_ref_unchecked(new_path_id) + }; + match bound { - TypeBound::Path(path, modifier) => { - TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier) + &TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier), + TypeBound::ForLifetime(lifetimes, path) => { + TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path)) } - TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime( - lifetimes.clone(), - copy_path(path, from, from_source_map, to, to_source_map), - ), TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()), TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()), TypeBound::Error => TypeBound::Error, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 4d83ef99c84..15980ddccaf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -23,6 +23,7 @@ use crate::{ hir::Literal, lower::LowerCtx, path::{GenericArg, Path}, + SyntheticSyntax, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -91,19 +92,37 @@ impl Rawness { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like +/// impl's trait, that are always paths but need to be traced back to source code. +pub struct PathId(TypeRefId); + +impl PathId { + #[inline] + pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self { + Self(type_ref) + } + + #[inline] + pub fn type_ref(self) -> TypeRefId { + self.0 + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct TraitRef { - pub path: Path, + pub path: PathId, } impl TraitRef { /// Converts an `ast::PathType` to a `hir::TraitRef`. pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option { // FIXME: Use `Path::from_src` - match node { - ast::Type::PathType(path) => { - path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) - } + match &node { + ast::Type::PathType(path) => path + .path() + .and_then(|it| ctx.lower_path(it)) + .map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }), _ => None, } } @@ -173,11 +192,24 @@ impl TypesMap { impl Index for TypesMap { type Output = TypeRef; + #[inline] fn index(&self, index: TypeRefId) -> &Self::Output { &self.types[index] } } +impl Index for TypesMap { + type Output = Path; + + #[inline] + fn index(&self, index: PathId) -> &Self::Output { + let TypeRef::Path(path) = &self[index.type_ref()] else { + unreachable!("`PathId` always points to `TypeRef::Path`"); + }; + path + } +} + pub type TypePtr = AstPtr; pub type TypeSource = InFile; @@ -187,6 +219,10 @@ pub struct TypesSourceMap { } impl TypesSourceMap { + pub fn type_syntax(&self, id: TypeRefId) -> Result { + self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax) + } + pub(crate) fn shrink_to_fit(&mut self) { let TypesSourceMap { types_map_back } = self; types_map_back.shrink_to_fit(); @@ -214,15 +250,15 @@ impl LifetimeRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { - Path(Path, TraitBoundModifier), - ForLifetime(Box<[Name]>, Path), + Path(PathId, TraitBoundModifier), + ForLifetime(Box<[Name]>, PathId), Lifetime(LifetimeRef), Use(Box<[UseArgRef]>), Error, } #[cfg(target_pointer_width = "64")] -const _: [(); 32] = [(); ::std::mem::size_of::()]; +const _: [(); 24] = [(); ::std::mem::size_of::()]; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum UseArgRef { @@ -365,8 +401,8 @@ impl TypeRef { TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -397,8 +433,8 @@ impl TypeRef { } for bound in binding.bounds.iter() { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -425,7 +461,7 @@ pub(crate) fn type_bounds_from_ast( impl TypeBound { pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self { - let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?); + let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?); match node.kind() { ast::TypeBoundKind::PathType(path_type) => { @@ -433,8 +469,10 @@ impl TypeBound { Some(_) => TraitBoundModifier::Maybe, None => TraitBoundModifier::None, }; - lower_path_type(path_type) - .map(|p| TypeBound::Path(p, m)) + lower_path_type(&path_type) + .map(|p| { + TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m) + }) .unwrap_or(TypeBound::Error) } ast::TypeBoundKind::ForType(for_type) => { @@ -445,12 +483,14 @@ impl TypeBound { .collect(), None => Box::default(), }; - let path = for_type.ty().and_then(|ty| match ty { - ast::Type::PathType(path_type) => lower_path_type(path_type), + let path = for_type.ty().and_then(|ty| match &ty { + ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)), _ => None, }); match path { - Some(p) => TypeBound::ForLifetime(lt_refs, p), + Some((p, ty)) => { + TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty))) + } None => TypeBound::Error, } } @@ -470,10 +510,10 @@ impl TypeBound { } } - pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> { + pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> { match self { - TypeBound::Path(p, m) => Some((p, m)), - TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), + &TypeBound::Path(p, m) => Some((&map[p], m)), + &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index d519c1708b3..71848845a84 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -34,7 +34,7 @@ use crate::{ lower::LowerCtx, path::AssociatedTypeBinding, type_ref::{ - LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, + LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, visibility::RawVisibility, @@ -514,7 +514,7 @@ impl<'a> Ctx<'a> { }; let ret_type = if func.async_token().is_some() { - let future_impl = desugar_future_path(ret_type); + let future_impl = desugar_future_path(&mut body_ctx, ret_type); let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None); body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))) } else { @@ -936,7 +936,7 @@ impl<'a> Ctx<'a> { } } -fn desugar_future_path(orig: TypeRefId) -> Path { +fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId { let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); @@ -948,7 +948,8 @@ fn desugar_future_path(orig: TypeRefId) -> Path { }; generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() })); - Path::from_known_path(path, generic_args) + let path = Path::from_known_path(path, generic_args); + PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path))) } enum HasImplicitSelf { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index b6816a1f968..0c5e3a3620a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -484,7 +484,7 @@ impl Printer<'_> { w!(self, "!"); } if let Some(tr) = target_trait { - self.print_path(&tr.path, types_map); + self.print_path(&types_map[tr.path], types_map); w!(self, " for "); } self.print_type_ref(*self_ty, types_map); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index eb55ba1d53d..8af27513ebc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1535,3 +1535,6 @@ fn macro_call_as_call_id_with_eager( pub struct UnresolvedMacro { pub path: hir_expand::mod_path::ModPath, } + +#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] +pub struct SyntheticSyntax; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index 350bb8d5172..7cddd48eb17 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -10,7 +10,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, path::Path, - type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, + type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, }; pub struct LowerCtx<'a> { @@ -142,4 +142,8 @@ impl<'a> LowerCtx<'a> { pub(crate) fn alloc_error_type(&mut self) -> TypeRefId { self.types_map.types.alloc(TypeRef::Error) } + + pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId { + PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node)) + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index 9ceb82d5fd6..eb9488feaa9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -271,7 +271,7 @@ pub(crate) fn print_type_bounds( TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::ForLifetime(lifetimes, path) => { write!( @@ -279,7 +279,7 @@ pub(crate) fn print_type_bounds( "for<{}> ", lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ") )?; - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?, TypeBound::Use(args) => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 26655e40ca7..0ca7070fd05 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -576,10 +576,12 @@ impl Resolver { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::ImplDefScope(impl_) => { - if let Some(target_trait) = &db.impl_data(impl_).target_trait { - if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, &target_trait.path) - { + let impl_data = db.impl_data(impl_); + if let Some(target_trait) = impl_data.target_trait { + if let Some(TypeNs::TraitId(trait_)) = self.resolve_path_in_type_ns_fully( + db, + &impl_data.types_map[target_trait.path], + ) { traits.insert(trait_); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 4e95bdf219f..94a340fbec2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2062,12 +2062,12 @@ impl HirDisplayWithTypesMap for TypeBound { types_map: &TypesMap, ) -> Result<(), HirDisplayError> { match self { - TypeBound::Path(path, modifier) => { + &TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(f, "?")?, } - path.hir_fmt(f, types_map) + types_map[path].hir_fmt(f, types_map) } TypeBound::Lifetime(lifetime) => { write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) @@ -2079,7 +2079,7 @@ impl HirDisplayWithTypesMap for TypeBound { "for<{}> ", lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") )?; - path.hir_fmt(f, types_map) + types_map[*path].hir_fmt(f, types_map) } TypeBound::Use(args) => { let edition = f.edition(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b868ea95f85..fc0af0cec90 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -33,8 +33,8 @@ use hir_def::{ path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, type_ref::{ - ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, - TypeRefId, TypesMap, TypesSourceMap, + ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, @@ -264,7 +264,8 @@ impl<'a> TyLoweringContext<'a> { .intern(Interner) } TypeRef::Path(path) => { - let (ty, res_) = self.lower_path(path); + let (ty, res_) = + self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id)); res = res_; ty } @@ -677,7 +678,7 @@ impl<'a> TyLoweringContext<'a> { self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) } - pub(crate) fn lower_path(&mut self, path: &Path) -> (Ty, Option) { + pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option) { // Resolve the path (in type namespace) if let Some(type_ref) = path.type_anchor() { let (ty, res) = self.lower_ty_ext(type_ref); @@ -692,7 +693,7 @@ impl<'a> TyLoweringContext<'a> { if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { // trait object type without dyn - let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); + let bound = TypeBound::Path(path_id, TraitBoundModifier::None); let ty = self.lower_dyn_trait(&[bound]); return (ty, None); } @@ -998,7 +999,12 @@ impl<'a> TyLoweringContext<'a> { TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } } - fn lower_trait_ref_from_path(&mut self, path: &Path, explicit_self_ty: Ty) -> Option { + fn lower_trait_ref_from_path( + &mut self, + path_id: PathId, + explicit_self_ty: Ty, + ) -> Option { + let path = &self.types_map[path_id]; let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { // FIXME(trait_alias): We need to handle trait alias here. TypeNs::TraitId(tr) => tr, @@ -1013,7 +1019,7 @@ impl<'a> TyLoweringContext<'a> { trait_ref: &HirTraitRef, explicit_self_ty: Ty, ) -> Option { - self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) + self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty) } fn trait_ref_substs_from_path( @@ -1072,11 +1078,11 @@ impl<'a> TyLoweringContext<'a> { ) -> impl Iterator + use<'b, 'a> { let mut trait_ref = None; let clause = match bound { - TypeBound::Path(path, TraitBoundModifier::None) => { + &TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } - TypeBound::Path(path, TraitBoundModifier::Maybe) => { + &TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self .db .lang_item(self.resolver.krate(), LangItem::Sized) @@ -1092,7 +1098,7 @@ impl<'a> TyLoweringContext<'a> { } None } - TypeBound::ForLifetime(_, path) => { + &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) @@ -1121,8 +1127,8 @@ impl<'a> TyLoweringContext<'a> { trait_ref: TraitRef, ) -> impl Iterator + use<'b, 'a> { let last_segment = match bound { - TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { - path.segments().last() + &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + self.types_map[path].segments().last() } TypeBound::Path(_, TraitBoundModifier::Maybe) | TypeBound::Use(_) @@ -1593,9 +1599,10 @@ pub(crate) fn generic_predicates_for_param_query( } match bound { - TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { + &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { // Only lower the bound if the trait could possibly define the associated // type we're looking for. + let path = &ctx.types_map[path]; let Some(assoc_name) = &assoc_name else { return true }; let Some(TypeNs::TraitId(tr)) = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index bcf9d5ceff0..cabeeea2bd8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -18,13 +18,13 @@ use std::sync::LazyLock; use base_db::SourceDatabaseFileInputExt as _; use expect_test::Expect; use hir_def::{ - body::{Body, BodySourceMap, SyntheticSyntax}, + body::{Body, BodySourceMap}, db::DefDatabase, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, src::HasSource, - AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, + AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax, }; use hir_expand::{db::ExpandDatabase, FileRange, InFile}; use itertools::Itertools; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 28bda1e10e5..06719b09f73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -185,7 +185,7 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut( } }; match is_trait { - true => bound.as_path(), + true => bound.as_path(&generic_params.types_map), false => None, } } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 9ca021027d5..9df6ca58f56 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -13,7 +13,7 @@ use hir_ty::{ use cfg::{CfgExpr, CfgOptions}; use either::Either; pub use hir_def::VariantId; -use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; +use hir_def::{hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId, SyntheticSyntax}; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use triomphe::Arc; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 9275f45d881..959d62d5951 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -132,12 +132,18 @@ impl HirDisplay for Function { } else { match &data.types_map[data.ret_type] { TypeRef::ImplTrait(bounds) => match &bounds[0] { - TypeBound::Path(path, _) => Some( - *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings - [0] - .type_ref - .as_ref() - .unwrap(), + &TypeBound::Path(path, _) => Some( + *data.types_map[path] + .segments() + .iter() + .last() + .unwrap() + .args_and_bindings + .unwrap() + .bindings[0] + .type_ref + .as_ref() + .unwrap(), ), _ => None, }, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 0b2ba56b1ff..dc1d1efe60c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -43,7 +43,7 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin}; use either::Either; use hir_def::{ - body::{BodyDiagnostic, SyntheticSyntax}, + body::BodyDiagnostic, data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, @@ -57,8 +57,8 @@ use hir_def::{ AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 802d0c69a47..e3ea441f3ab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -13,8 +13,9 @@ use hir::{ ModuleDef, Name, }; use hir_def::{ - body::{BodySourceMap, SyntheticSyntax}, + body::BodySourceMap, hir::{ExprId, PatId}, + SyntheticSyntax, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use ide::{ -- cgit 1.4.1-3-g733a5 From 63acf60253262e31d8129c9134b9b4a5aab75453 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 20 Nov 2024 23:05:48 +0200 Subject: Lay the foundation for diagnostics in ty lowering, and implement a first diagnostic The diagnostic implemented is a simple one (E0109). It serves as a test for the new foundation. This commit only implements diagnostics for type in bodies and body-carrying signatures; the next commit will include diagnostics in the rest of the things. Also fix one weird bug that was detected when implementing this that caused `Fn::(A, B) -> C` (which is a valid, if bizarre, alternative syntax to `Fn(A, B) -> C` to lower incorrectly. And also fix a maybe-bug where parentheses were sneaked into a code string needlessly; this was not detected until now because the parentheses were removed (by the make-AST family API), but with a change in this commit they are now inserted. So fix that too. --- src/tools/rust-analyzer/Cargo.lock | 4 + src/tools/rust-analyzer/crates/hir-def/src/body.rs | 2 +- .../crates/hir-def/src/hir/type_ref.rs | 2 + src/tools/rust-analyzer/crates/hir-def/src/path.rs | 12 +- .../rust-analyzer/crates/hir-def/src/path/lower.rs | 80 ++++++- .../rust-analyzer/crates/hir-def/src/path/tests.rs | 126 +++++++++++ .../rust-analyzer/crates/hir-expand/src/files.rs | 7 + src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 96 ++++++-- .../rust-analyzer/crates/hir-ty/src/infer/expr.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/infer/path.rs | 6 +- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 7 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 187 +++++++++++++--- src/tools/rust-analyzer/crates/hir/Cargo.toml | 8 + .../rust-analyzer/crates/hir/src/diagnostics.rs | 67 +++++- src/tools/rust-analyzer/crates/hir/src/lib.rs | 33 ++- .../src/handlers/generic_args_prohibited.rs | 242 +++++++++++++++++++++ .../src/handlers/unresolved_method.rs | 6 +- .../crates/ide-diagnostics/src/lib.rs | 2 + .../rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- 19 files changed, 811 insertions(+), 80 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2bd4d17fe22..5861833d53a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -509,6 +509,7 @@ dependencies = [ "base-db", "cfg", "either", + "expect-test", "hir-def", "hir-expand", "hir-ty", @@ -519,6 +520,9 @@ dependencies = [ "span", "stdx", "syntax", + "syntax-bridge", + "test-fixture", + "test-utils", "tracing", "triomphe", "tt", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 908f2050b5f..867bee95bed 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -141,7 +141,7 @@ pub struct BodySourceMap { field_map_back: FxHashMap, pat_field_map_back: FxHashMap, - types: TypesSourceMap, + pub types: TypesSourceMap, // FIXME: Make this a sane struct. template_map: Option< diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 15980ddccaf..6d4d519cd2b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -219,6 +219,8 @@ pub struct TypesSourceMap { } impl TypesSourceMap { + pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() }; + pub fn type_syntax(&self, id: TypeRefId) -> Result { self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index aa2c4a6f1bc..44e132061ad 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -1,5 +1,7 @@ //! A desugared representation of paths like `crate::foo` or `::bar`. mod lower; +#[cfg(test)] +mod tests; use std::{ fmt::{self, Display}, @@ -19,6 +21,8 @@ use syntax::ast; pub use hir_expand::mod_path::{path, ModPath, PathKind}; +pub use lower::hir_segment_to_ast_segment; + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportAlias { /// Unnamed alias, as in `use Foo as _;` @@ -230,7 +234,7 @@ impl Path { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PathSegment<'a> { pub name: &'a Name, pub args_and_bindings: Option<&'a GenericArgs>, @@ -274,6 +278,12 @@ impl<'a> PathSegments<'a> { generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)), } } + pub fn strip_last(&self) -> PathSegments<'a> { + PathSegments { + segments: self.segments.split_last().map_or(&[], |it| it.1), + generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)), + } + } pub fn iter(&self) -> impl Iterator> { self.segments .iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 37c94a5f118..3b7e7653fba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -17,13 +17,31 @@ use crate::{ type_ref::{LifetimeRef, TypeBound, TypeRef}, }; +#[cfg(test)] +thread_local! { + /// This is used to test `hir_segment_to_ast_segment()`. It's a hack, but it makes testing much easier. + pub(super) static SEGMENT_LOWERING_MAP: std::cell::RefCell> = std::cell::RefCell::default(); +} + /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. +// If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()` +// also needs an update. pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option { let mut kind = PathKind::Plain; let mut type_anchor = None; let mut segments = Vec::new(); let mut generic_args = Vec::new(); + #[cfg(test)] + let mut ast_segments = Vec::new(); + #[cfg(test)] + let mut ast_segments_offset = 0; + #[allow(unused_mut)] + let mut push_segment = |_segment: &ast::PathSegment, segments: &mut Vec, name| { + #[cfg(test)] + ast_segments.push(_segment.clone()); + segments.push(name); + }; loop { let segment = path.segment()?; @@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { if name_ref.text() == "$crate" { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } break kind = resolve_crate_root( ctx.db.upcast(), ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx, @@ -56,10 +78,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< generic_args.resize(segments.len(), None); generic_args.push(args); } - segments.push(name); + push_segment(&segment, &mut segments, name); } ast::PathSegmentKind::SelfTypeKw => { - segments.push(Name::new_symbol_root(sym::Self_.clone())); + push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_.clone())); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -81,6 +103,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< kind = mod_path.kind; segments.extend(mod_path.segments().iter().cloned().rev()); + #[cfg(test)] + { + ast_segments_offset = mod_path.segments().len(); + } if let Some(path_generic_args) = path_generic_args { generic_args.resize(segments.len() - num_segments, None); generic_args.extend(Vec::from(path_generic_args).into_iter().rev()); @@ -112,10 +138,18 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } ast::PathSegmentKind::CrateKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } kind = PathKind::Crate; break; } ast::PathSegmentKind::SelfKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } // don't break out if `self` is the last segment of a path, this mean we got a // use tree like `foo::{self}` which we want to resolve as `foo` if !segments.is_empty() { @@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } + #[cfg(test)] + { + ast_segments.reverse(); + SEGMENT_LOWERING_MAP + .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..))); + } + let mod_path = Interned::new(ModPath::from_segments(kind, segments)); if type_anchor.is_none() && generic_args.is_empty() { return Some(Path::BarePath(mod_path)); @@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } +/// This function finds the AST segment that corresponds to the HIR segment +/// with index `segment_idx` on the path that is lowered from `path`. +pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option { + // Too tightly coupled to `lower_path()`, but unfortunately we cannot decouple them, + // as keeping source maps for all paths segments will have a severe impact on memory usage. + + let mut segments = path.segments(); + if let Some(ast::PathSegmentKind::Type { trait_ref: Some(trait_ref), .. }) = + segments.clone().next().and_then(|it| it.kind()) + { + segments.next(); + return find_segment(trait_ref.path()?.segments().chain(segments), segment_idx); + } + return find_segment(segments, segment_idx); + + fn find_segment( + segments: impl Iterator, + segment_idx: u32, + ) -> Option { + segments + .filter(|segment| match segment.kind() { + Some( + ast::PathSegmentKind::CrateKw + | ast::PathSegmentKind::SelfKw + | ast::PathSegmentKind::SuperKw + | ast::PathSegmentKind::Type { .. }, + ) + | None => false, + Some(ast::PathSegmentKind::Name(name)) => name.text() != "$crate", + Some(ast::PathSegmentKind::SelfTypeKw) => true, + }) + .nth(segment_idx as usize) + } +} + pub(super) fn lower_generic_args( lower_ctx: &mut LowerCtx<'_>, node: ast::GenericArgList, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs new file mode 100644 index 00000000000..67a27bf85e8 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs @@ -0,0 +1,126 @@ +use expect_test::{expect, Expect}; +use span::Edition; +use syntax::ast::{self, make}; +use test_fixture::WithFixture; + +use crate::{ + lower::LowerCtx, + path::{ + lower::{hir_segment_to_ast_segment, SEGMENT_LOWERING_MAP}, + Path, + }, + pretty, + test_db::TestDB, + type_ref::{TypesMap, TypesSourceMap}, +}; + +fn lower_path(path: ast::Path) -> (TestDB, TypesMap, Option) { + let (db, file_id) = TestDB::with_single_file(""); + let mut types_map = TypesMap::default(); + let mut types_source_map = TypesSourceMap::default(); + let mut ctx = LowerCtx::new(&db, file_id.into(), &mut types_map, &mut types_source_map); + let lowered_path = ctx.lower_path(path); + (db, types_map, lowered_path) +} + +#[track_caller] +fn check_hir_to_ast(path: &str, ignore_segments: &[&str]) { + let path = make::path_from_text(path); + SEGMENT_LOWERING_MAP.with_borrow_mut(|map| map.clear()); + let _ = lower_path(path.clone()).2.expect("failed to lower path"); + SEGMENT_LOWERING_MAP.with_borrow(|map| { + for (segment, segment_idx) in map { + if ignore_segments.contains(&&*segment.to_string()) { + continue; + } + + let restored_segment = hir_segment_to_ast_segment(&path, *segment_idx as u32) + .unwrap_or_else(|| { + panic!( + "failed to map back segment `{segment}` \ + numbered {segment_idx} in HIR from path `{path}`" + ) + }); + assert_eq!( + segment, &restored_segment, + "mapping back `{segment}` numbered {segment_idx} in HIR \ + from path `{path}` produced incorrect segment `{restored_segment}`" + ); + } + }); +} + +#[test] +fn hir_to_ast_trait_ref() { + check_hir_to_ast("::E::F", &["A"]); +} + +#[test] +fn hir_to_ast_plain_path() { + check_hir_to_ast("A::B::C::D::E::F", &[]); +} + +#[test] +fn hir_to_ast_crate_path() { + check_hir_to_ast("crate::A::B::C", &[]); + check_hir_to_ast("crate::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_self_path() { + check_hir_to_ast("self::A::B::C", &[]); + check_hir_to_ast("self::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_super_path() { + check_hir_to_ast("super::A::B::C", &[]); + check_hir_to_ast("super::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_type_anchor_path() { + check_hir_to_ast("::C::D", &["A", "B"]); +} + +#[test] +fn hir_to_ast_path_super_in_middle() { + check_hir_to_ast("A::super::B::super::super::C::D", &[]); +} + +#[track_caller] +fn check_fail_lowering(path: &str) { + let (_, _, lowered_path) = lower_path(make::path_from_text(path)); + assert!(lowered_path.is_none(), "path `{path}` should fail lowering"); +} + +#[test] +fn keywords_in_middle_fail_lowering1() { + check_fail_lowering("self::A::self::B::super::C::crate::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering2() { + check_fail_lowering("A::super::self::C::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering3() { + check_fail_lowering("A::crate::B::C::D"); +} + +#[track_caller] +fn check_path_lowering(path: &str, expected: Expect) { + let (db, types_map, lowered_path) = lower_path(make::path_from_text(path)); + let lowered_path = lowered_path.expect("failed to lower path"); + let mut buf = String::new(); + pretty::print_path(&db, &lowered_path, &types_map, &mut buf, Edition::CURRENT) + .expect("failed to pretty-print path"); + expected.assert_eq(&buf); +} + +#[test] +fn fn_like_path_with_coloncolon() { + check_path_lowering("Fn::(A, B) -> C", expect![[r#"Fn::<(A, B), Output = C>"#]]); + check_path_lowering("Fn::(A, B)", expect![[r#"Fn::<(A, B), Output = ()>"#]]); +} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index d41f69812ee..8c04d054029 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -180,6 +180,13 @@ impl InFileWrapper { } } +#[allow(private_bounds)] +impl InFileWrapper> { + pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { + self.value.to_node(&self.file_syntax(db)) + } +} + impl InFileWrapper { pub fn syntax(&self) -> InFileWrapper { self.with_value(self.value.syntax()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 01e0b635b22..dbee5a1a919 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -58,7 +58,7 @@ use crate::{ fold_tys, generics::Generics, infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable}, - lower::ImplTraitLoweringMode, + lower::{ImplTraitLoweringMode, TyLoweringDiagnostic}, mir::MirSpan, to_assoc_type_id, traits::FnTrait, @@ -191,6 +191,14 @@ impl InferOk { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum InferenceTyDiagnosticSource { + /// Diagnostics that come from types in the body. + Body, + /// Diagnostics that come from types in fn parameters/return type, or static & const types. + Signature, +} + #[derive(Debug)] pub(crate) struct TypeError; pub(crate) type InferResult = Result, TypeError>; @@ -264,6 +272,10 @@ pub enum InferenceDiagnostic { expr_ty: Ty, cast_ty: Ty, }, + TyDiagnostic { + source: InferenceTyDiagnosticSource, + diag: TyLoweringDiagnostic, + }, } /// A mismatch between an expected and an inferred type. @@ -858,7 +870,8 @@ impl<'a> InferenceContext<'a> { } fn collect_const(&mut self, data: &ConstData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Constants might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -867,7 +880,8 @@ impl<'a> InferenceContext<'a> { } fn collect_static(&mut self, data: &StaticData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Statics might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -877,11 +891,12 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Param); - data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>() - }); + let mut param_tys = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Param); + data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>() + }); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { @@ -918,11 +933,12 @@ impl<'a> InferenceContext<'a> { } let return_ty = data.ret_type; - let return_ty = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Opaque) - .lower_ty(return_ty) - }); + let return_ty = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Opaque) + .lower_ty(return_ty) + }); let return_ty = self.insert_type_vars(return_ty); let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { @@ -1226,9 +1242,20 @@ impl<'a> InferenceContext<'a> { self.result.diagnostics.push(diagnostic); } + fn push_ty_diagnostics( + &mut self, + source: InferenceTyDiagnosticSource, + diagnostics: Vec, + ) { + self.result.diagnostics.extend( + diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }), + ); + } + fn with_ty_lowering( - &self, + &mut self, types_map: &TypesMap, + types_source: InferenceTyDiagnosticSource, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { let mut ctx = crate::lower::TyLoweringContext::new( @@ -1237,32 +1264,41 @@ impl<'a> InferenceContext<'a> { types_map, self.owner.into(), ); - f(&mut ctx) + let result = f(&mut ctx); + self.push_ty_diagnostics(types_source, ctx.diagnostics); + result } fn with_body_ty_lowering( - &self, + &mut self, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { - self.with_ty_lowering(&self.body.types, f) + self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f) } - fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty { - let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref)); + fn make_ty( + &mut self, + type_ref: TypeRefId, + types_map: &TypesMap, + type_source: InferenceTyDiagnosticSource, + ) -> Ty { + let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref)); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { - self.make_ty(type_ref, &self.body.types) + self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body) } fn err_ty(&self) -> Ty { self.result.standard_types.unknown.clone() } - fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { - let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref)); + fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { + let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| { + ctx.lower_lifetime(lifetime_ref) + }); self.insert_type_vars(lt) } @@ -1431,12 +1467,20 @@ impl<'a> InferenceContext<'a> { Some(ResolveValueResult::ValueNs(value, _)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(strukt.into())); @@ -1462,18 +1506,21 @@ impl<'a> InferenceContext<'a> { return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } TypeNs::AdtId(AdtId::UnionId(u)) => { let substs = ctx.substs_from_path(path, u.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(u.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(var.into())), unresolved) @@ -1519,6 +1566,9 @@ impl<'a> InferenceContext<'a> { resolved_segment, current_segment, false, + &mut |_, _reason| { + // FIXME: Report an error. + }, ); ty = self.table.insert_type_vars(ty); @@ -1532,6 +1582,7 @@ impl<'a> InferenceContext<'a> { remaining_idx += 1; remaining_segments = remaining_segments.skip(1); } + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let variant = ty.as_adt().and_then(|(id, _)| match id { AdtId::StructId(s) => Some(VariantId::StructId(s)), @@ -1550,6 +1601,7 @@ impl<'a> InferenceContext<'a> { }; let substs = ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(it.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 32b4ea2f28b..e060b37f154 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -2155,7 +2155,7 @@ impl InferenceContext<'_> { DebruijnIndex::INNERMOST, ) }, - |this, lt_ref| this.make_lifetime(lt_ref), + |this, lt_ref| this.make_body_lifetime(lt_ref), ), }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 7550d197a3b..a6296c3af23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -19,7 +19,7 @@ use crate::{ TyBuilder, TyExt, TyKind, ValueTyDefId, }; -use super::{ExprOrPatId, InferenceContext}; +use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; impl InferenceContext<'_> { pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { @@ -163,6 +163,7 @@ impl InferenceContext<'_> { let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? @@ -265,6 +266,9 @@ impl InferenceContext<'_> { resolved_segment, remaining_segments_for_ty, true, + &mut |_, _reason| { + // FIXME: Report an error. + }, ) }); if ty.is_unknown() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index fdc65797632..77ae295cee4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -84,12 +84,13 @@ pub use infer::{ cast::CastError, closure::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode, - InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, + InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, + PointerCast, }; pub use interner::Interner; pub use lower::{ - associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId, - TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, + ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, ValueTyDefId, }; pub use mapping::{ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index fc0af0cec90..b73967be710 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -102,6 +102,31 @@ impl ImplTraitLoweringState { } } +type TypeSource = Either; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TyLoweringDiagnostic { + pub source: TypeSource, + pub kind: TyLoweringDiagnosticKind, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TyLoweringDiagnosticKind { + GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GenericArgsProhibitedReason { + Module, + TyParam, + SelfTy, + PrimitiveTy, + /// When there is a generic enum, within the expression `Enum::Variant`, + /// either `Enum` or `Variant` are allowed to have generic arguments, but not both. + // FIXME: This is not used now but it should be. + EnumVariant, +} + #[derive(Debug)] pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, @@ -125,6 +150,7 @@ pub struct TyLoweringContext<'a> { expander: Option, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet, + pub(crate) diagnostics: Vec, } impl<'a> TyLoweringContext<'a> { @@ -159,6 +185,7 @@ impl<'a> TyLoweringContext<'a> { type_param_mode, expander: None, unsized_types: FxHashSet::default(), + diagnostics: Vec::new(), } } @@ -198,6 +225,20 @@ impl<'a> TyLoweringContext<'a> { self.type_param_mode = type_param_mode; self } + + pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { + let source = match self.types_source_map { + Some(source_map) => { + let Ok(source) = source_map.type_syntax(type_ref) else { + stdx::never!("error in synthetic type"); + return; + }; + Either::Right(source) + } + None => Either::Left(type_ref), + }; + self.diagnostics.push(TyLoweringDiagnostic { source, kind }); + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] @@ -464,6 +505,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode: mem::take(&mut self.impl_trait_mode), expander: self.expander.take(), unsized_types: mem::take(&mut self.unsized_types), + diagnostics: mem::take(&mut self.diagnostics), }; let ty = inner_ctx.lower_ty(type_ref); @@ -471,6 +513,7 @@ impl<'a> TyLoweringContext<'a> { self.impl_trait_mode = inner_ctx.impl_trait_mode; self.expander = inner_ctx.expander; self.unsized_types = inner_ctx.unsized_types; + self.diagnostics = inner_ctx.diagnostics; self.expander.as_mut().unwrap().exit(mark); Some(ty) @@ -542,6 +585,10 @@ impl<'a> TyLoweringContext<'a> { resolved_segment: PathSegment<'_>, remaining_segments: PathSegments<'_>, infer_args: bool, + on_prohibited_generics_for_resolved_segment: &mut dyn FnMut( + &mut Self, + GenericArgsProhibitedReason, + ), ) -> (Ty, Option) { let ty = match resolution { TypeNs::TraitId(trait_) => { @@ -608,28 +655,44 @@ impl<'a> TyLoweringContext<'a> { // FIXME(trait_alias): Implement trait alias. return (TyKind::Error.intern(Interner), None); } - TypeNs::GenericParam(param_id) => match self.type_param_mode { - ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + TypeNs::GenericParam(param_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::TyParam, + ); } - ParamLoweringMode::Variable => { - let idx = match self - .generics() - .expect("generics in scope") - .type_or_const_param_idx(param_id.into()) - { - None => { - never!("no matching generics"); - return (TyKind::Error.intern(Interner), None); - } - Some(idx) => idx, - }; - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + match self.type_param_mode { + ParamLoweringMode::Placeholder => { + TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + } + ParamLoweringMode::Variable => { + let idx = match self + .generics() + .expect("generics in scope") + .type_or_const_param_idx(param_id.into()) + { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; + + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + } } + .intern(Interner) } - .intern(Interner), TypeNs::SelfType(impl_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = self.generics().expect("impl should have generic param scope"); match self.type_param_mode { @@ -655,6 +718,13 @@ impl<'a> TyLoweringContext<'a> { } } TypeNs::AdtSelfType(adt) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = generics(self.db.upcast(), adt.into()); let substs = match self.type_param_mode { ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db), @@ -667,6 +737,12 @@ impl<'a> TyLoweringContext<'a> { TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), TypeNs::BuiltinType(it) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::PrimitiveTy, + ); + } self.lower_path_inner(resolved_segment, it.into(), infer_args) } TypeNs::TypeAliasId(it) => { @@ -698,14 +774,39 @@ impl<'a> TyLoweringContext<'a> { return (ty, None); } - let (resolved_segment, remaining_segments) = match remaining_index { - None => ( - path.segments().last().expect("resolved path has at least one element"), - PathSegments::EMPTY, - ), - Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), - }; - self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false) + let (module_segments, resolved_segment_idx, resolved_segment, remaining_segments) = + match remaining_index { + None => ( + path.segments().strip_last(), + path.segments().len() - 1, + path.segments().last().expect("resolved path has at least one element"), + PathSegments::EMPTY, + ), + Some(i) => ( + path.segments().take(i - 1), + i - 1, + path.segments().get(i - 1).unwrap(), + path.segments().skip(i), + ), + }; + + self.prohibit_generics(path_id, 0, module_segments, GenericArgsProhibitedReason::Module); + + self.lower_partly_resolved_path( + resolution, + resolved_segment, + remaining_segments, + false, + &mut |this, reason| { + this.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { + segment: resolved_segment_idx as u32, + reason, + }, + ) + }, + ) } fn select_associated_type(&mut self, res: Option, segment: PathSegment<'_>) -> Ty { @@ -742,12 +843,8 @@ impl<'a> TyLoweringContext<'a> { // generic params. It's inefficient to splice the `Substitution`s, so we may want // that method to optionally take parent `Substitution` as we already know them at // this point (`t.substitution`). - let substs = self.substs_from_path_segment( - segment.clone(), - Some(associated_ty.into()), - false, - None, - ); + let substs = + self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None); let len_self = crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); @@ -999,6 +1096,23 @@ impl<'a> TyLoweringContext<'a> { TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } } + fn prohibit_generics( + &mut self, + path_id: PathId, + idx: u32, + segments: PathSegments<'_>, + reason: GenericArgsProhibitedReason, + ) { + segments.iter().zip(idx..).for_each(|(segment, idx)| { + if segment.args_and_bindings.is_some() { + self.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason }, + ); + } + }); + } + fn lower_trait_ref_from_path( &mut self, path_id: PathId, @@ -1010,6 +1124,13 @@ impl<'a> TyLoweringContext<'a> { TypeNs::TraitId(tr) => tr, _ => return None, }; + // Do this after we verify it's indeed a trait to not confuse the user if they're not modules. + self.prohibit_generics( + path_id, + 0, + path.segments().strip_last(), + GenericArgsProhibitedReason::Module, + ); let segment = path.segments().last().expect("path should have at least one segment"); Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } @@ -1233,7 +1354,9 @@ impl<'a> TyLoweringContext<'a> { } _ => unreachable!(), } - ext.lower_ty(type_ref) + let ty = ext.lower_ty(type_ref); + self.diagnostics.extend(ext.diagnostics); + ty } else { self.lower_ty(type_ref) }; diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 26666d6feb0..6aadc5c4f7e 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -33,6 +33,14 @@ syntax.workspace = true tt.workspace = true span.workspace = true +[dev-dependencies] +expect-test.workspace = true + +# local deps +test-utils.workspace = true +test-fixture.workspace = true +syntax-bridge.workspace = true + [features] in-rust-tree = ["hir-expand/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 9df6ca58f56..3657cf5e162 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -3,23 +3,34 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. -pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; +use cfg::{CfgExpr, CfgOptions}; +use either::Either; +use hir_def::{ + hir::ExprOrPatId, + path::{hir_segment_to_ast_segment, ModPath}, + type_ref::TypesSourceMap, + AssocItemId, DefWithBodyId, SyntheticSyntax, +}; +use hir_expand::{name::Name, HirFileId, InFile}; use hir_ty::{ db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, - CastError, InferenceDiagnostic, + CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind, +}; +use syntax::{ + ast::{self, HasGenericArgs}, + AstPtr, SyntaxError, SyntaxNodePtr, TextRange, }; - -use cfg::{CfgExpr, CfgOptions}; -use either::Either; -pub use hir_def::VariantId; -use hir_def::{hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId, SyntheticSyntax}; -use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{AssocItem, Field, Local, Trait, Type}; +pub use hir_def::VariantId; +pub use hir_ty::{ + diagnostics::{CaseType, IncorrectCase}, + GenericArgsProhibitedReason, +}; + macro_rules! diagnostics { ($($diag:ident,)*) => { #[derive(Debug)] @@ -98,6 +109,7 @@ diagnostics![ UnresolvedIdent, UnusedMut, UnusedVariable, + GenericArgsProhibited, ]; #[derive(Debug)] @@ -388,6 +400,12 @@ pub struct InvalidCast { pub cast_ty: Type, } +#[derive(Debug)] +pub struct GenericArgsProhibited { + pub args: InFile>>, + pub reason: GenericArgsProhibitedReason, +} + impl AnyDiagnostic { pub(crate) fn body_validation_diagnostic( db: &dyn HirDatabase, @@ -527,6 +545,7 @@ impl AnyDiagnostic { db: &dyn HirDatabase, def: DefWithBodyId, d: &InferenceDiagnostic, + outer_types_source_map: &TypesSourceMap, source_map: &hir_def::body::BodySourceMap, ) -> Option { let expr_syntax = |expr| { @@ -640,6 +659,36 @@ impl AnyDiagnostic { let cast_ty = Type::new(db, def, cast_ty.clone()); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } + InferenceDiagnostic::TyDiagnostic { source, diag } => { + let source_map = match source { + InferenceTyDiagnosticSource::Body => &source_map.types, + InferenceTyDiagnosticSource::Signature => outer_types_source_map, + }; + let source = match diag.source { + Either::Left(type_ref_id) => { + let Ok(source) = source_map.type_syntax(type_ref_id) else { + stdx::never!("error on synthetic type syntax"); + return None; + }; + source + } + Either::Right(source) => source, + }; + let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); + match diag.kind { + TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { + let ast::Type::PathType(syntax) = syntax() else { return None }; + let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; + let args = if let Some(generics) = segment.generic_arg_list() { + AstPtr::new(&generics).wrap_left() + } else { + AstPtr::new(&segment.param_list()?).wrap_right() + }; + let args = source.with_value(args); + GenericArgsProhibited { args, reason }.into() + } + } + } }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index dc1d1efe60c..cd462767473 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -20,12 +20,11 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] -mod semantics; -mod source_analyzer; - mod attrs; mod from_id; mod has_source; +mod semantics; +mod source_analyzer; pub mod db; pub mod diagnostics; @@ -54,6 +53,7 @@ use hir_def::{ path::ImportAlias, per_ns::PerNs, resolver::{HasResolver, Resolver}, + type_ref::TypesSourceMap, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, @@ -1802,6 +1802,25 @@ impl DefWithBody { let krate = self.module(db).id.krate(); let (body, source_map) = db.body_with_source_map(self.into()); + let item_tree_source_maps; + let outer_types_source_map = match self { + DefWithBody::Function(function) => { + let function = function.id.lookup(db.upcast()).id; + item_tree_source_maps = function.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(function.value).item() + } + DefWithBody::Static(statik) => { + let statik = statik.id.lookup(db.upcast()).id; + item_tree_source_maps = statik.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.statik(statik.value) + } + DefWithBody::Const(konst) => { + let konst = konst.id.lookup(db.upcast()).id; + item_tree_source_maps = konst.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.konst(konst.value) + } + DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => &TypesSourceMap::EMPTY, + }; for (_, def_map) in body.blocks(db.upcast()) { Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); @@ -1861,7 +1880,13 @@ impl DefWithBody { let infer = db.infer(self.into()); for d in &infer.diagnostics { - acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map)); + acc.extend(AnyDiagnostic::inference_diagnostic( + db, + self.into(), + d, + outer_types_source_map, + &source_map, + )); } for (pat_or_expr, mismatch) in infer.type_mismatches() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs new file mode 100644 index 00000000000..c3ad6704b6d --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -0,0 +1,242 @@ +use either::Either; +use hir::GenericArgsProhibitedReason; +use ide_db::assists::Assist; +use ide_db::source_change::SourceChange; +use ide_db::text_edit::TextEdit; +use syntax::{ast, AstNode, TextRange}; + +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: generic-args-prohibited +// +// This diagnostic is shown when generic arguments are provided for a type that does not accept +// generic arguments. +pub(crate) fn generic_args_prohibited( + ctx: &DiagnosticsContext<'_>, + d: &hir::GenericArgsProhibited, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0109"), + describe_reason(d.reason), + d.args.map(Into::into), + ) + .with_fixes(fixes(ctx, d)) +} + +fn describe_reason(reason: GenericArgsProhibitedReason) -> String { + let kind = match reason { + GenericArgsProhibitedReason::Module => "modules", + GenericArgsProhibitedReason::TyParam => "type parameters", + GenericArgsProhibitedReason::SelfTy => "`Self`", + GenericArgsProhibitedReason::PrimitiveTy => "builtin types", + GenericArgsProhibitedReason::EnumVariant => { + return "you can specify generic arguments on either the enum or the variant, but not both" + .to_owned(); + } + }; + format!("generic arguments are not allowed on {kind}") +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option> { + let file_id = d.args.file_id.file_id()?; + let syntax = d.args.to_node(ctx.sema.db); + let range = match &syntax { + Either::Left(_) => syntax.syntax().text_range(), + Either::Right(param_list) => { + let path_segment = ast::PathSegment::cast(param_list.syntax().parent()?)?; + let start = if let Some(coloncolon) = path_segment.coloncolon_token() { + coloncolon.text_range().start() + } else { + param_list.syntax().text_range().start() + }; + let end = if let Some(ret_type) = path_segment.ret_type() { + ret_type.syntax().text_range().end() + } else { + param_list.syntax().text_range().end() + }; + TextRange::new(start, end) + } + }; + Some(vec![fix( + "remove_generic_args", + "Remove these generics", + SourceChange::from_text_edit(file_id, TextEdit::delete(range)), + syntax.syntax().text_range(), + )]) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn primitives() { + check_diagnostics( + r#" +//- /core.rs crate:core library +#![rustc_coherence_is_core] +impl str { + pub fn trim() {} +} + +//- /lib.rs crate:foo deps:core +fn bar() {} + +fn foo() { + let _: (bool<()>, ()); + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + let _ = >::trim; + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + bar::>(); + // ^^^^^^^^^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn modules() { + check_diagnostics( + r#" +pub mod foo { + pub mod bar { + pub struct Baz; + + impl Baz { + pub fn qux() {} + } + } +} + +fn foo() { + let _: foo::<'_>::bar::Baz; + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + let _ = ::Baz>::qux; + // ^^^^ 💡 error: generic arguments are not allowed on modules +} + "#, + ); + } + + #[test] + fn type_parameters() { + check_diagnostics( + r#" +fn foo() { + let _: T<'a>; + // ^^^^ 💡 error: generic arguments are not allowed on type parameters + let _: U::<{ 1 + 2 }>; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on type parameters +} + "#, + ); + } + + #[test] + fn fn_like_generic_args() { + check_diagnostics( + r#" +fn foo() { + let _: bool(bool, i32) -> (); + // ^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn fn_signature() { + check_diagnostics( + r#" +fn foo( + _a: bool<'_>, + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + _b: i32::, + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + _c: &(&str<1>) + // ^^^ 💡 error: generic arguments are not allowed on builtin types +) -> ((), i32) { + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + ((), 0) +} + "#, + ); + } + + #[test] + fn const_static_type() { + check_diagnostics( + r#" +const A: i32 = 0; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +static A: i32::<{ 1 + 3 }> = 0; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn fix() { + check_fix( + r#" +fn foo() { + let _: bool<'_, (), { 1 + 1 }>$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::$0<'_, (), { 1 + 1 }>; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool(i$032); +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool$0(i32) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i$032) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i32)$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 81cb4521218..4ab649cc162 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -167,9 +167,9 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - } let method_name = call.name_ref()?; - let assoc_func_call = format!("{receiver_type_adt_name}::{method_name}()"); + let assoc_func_path = format!("{receiver_type_adt_name}::{method_name}"); - let assoc_func_call = make::expr_path(make::path_from_text(&assoc_func_call)); + let assoc_func_path = make::expr_path(make::path_from_text(&assoc_func_path)); let args: Vec<_> = if need_to_take_receiver_as_first_arg { std::iter::once(receiver).chain(call.arg_list()?.args()).collect() @@ -178,7 +178,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - }; let args = make::arg_list(args); - let assoc_func_call_expr_string = make::expr_call(assoc_func_call, args).to_string(); + let assoc_func_call_expr_string = make::expr_call(assoc_func_path, args).to_string(); let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 1f1b6478d36..663fc6a6771 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -27,6 +27,7 @@ mod handlers { pub(crate) mod await_outside_of_async; pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; + pub(crate) mod generic_args_prohibited; pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; @@ -468,6 +469,7 @@ pub fn semantic_diagnostics( Some(it) => it, None => continue, }, + AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d) }; res.push(d) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 2ec83d23b27..7eb3e08f541 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -402,7 +402,7 @@ pub fn join_paths(paths: impl IntoIterator) -> ast::Path { // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {text}; }}")) + ast_from_text(&format!("fn main() {{ let test: {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { -- cgit 1.4.1-3-g733a5 From 1aae52210a57e48d03dcd9f40b1ba04d20ff4ca7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 21 Nov 2024 02:21:16 +0200 Subject: Complete diagnostics in ty lowering groundwork Implement diagnostics in all places left: generics (predicates, defaults, const params' types), fields, and type aliases. Unfortunately this results in a 20mb addition in `analysis-stats .` due to many type methods returning an addition diagnostics result now (even if it's `None` in most cases). I'm not sure if this can be improved. An alternative strategy that can prevent the memory usage growth is to never produce diagnostics in hir-ty methods. Instead, lower all types in the hir crate when computing diagnostics from scratch (with diagnostics this time). But this has two serious disadvantages: 1. This can cause code duplication (although it can probably be not that bad, it will still mean a lot more code). 2. I believe we eventually want to compute diagnostics for the *entire* workspace (either on-type or on-save or something alike), so users can know when they have diagnostics even in inactive files. Choosing this approach will mean we lose all precomputed salsa queries. For one file this is fine, for the whole workspace this will be very slow. --- .../rust-analyzer/crates/hir-def/src/generics.rs | 5 + src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 30 ++- .../rust-analyzer/crates/hir-ty/src/generics.rs | 16 +- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 3 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 213 +++++++++++++++------ .../rust-analyzer/crates/hir/src/diagnostics.rs | 59 +++--- src/tools/rust-analyzer/crates/hir/src/lib.rs | 198 ++++++++++++++++++- .../src/handlers/generic_args_prohibited.rs | 200 +++++++++++++++++++ 8 files changed, 621 insertions(+), 103 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index fdcb10e9988..7b3f1d06d21 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -224,6 +224,11 @@ impl GenericParams { self.len() == 0 } + #[inline] + pub fn no_predicates(&self) -> bool { + self.where_predicates.is_empty() + } + #[inline] pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { self.where_predicates.iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 3a3a05c369a..6856eaa3e02 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -22,7 +22,7 @@ use crate::{ consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, - lower::{GenericDefaults, GenericPredicates}, + lower::{Diagnostics, GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, @@ -115,21 +115,35 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders; + #[ra_salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] + fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders, Diagnostics); + /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. #[ra_salsa::invoke(crate::lower::value_ty_query)] fn value_ty(&self, def: ValueTyDefId) -> Option>; + #[ra_salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)] + fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders, Diagnostics); #[ra_salsa::invoke(crate::lower::impl_self_ty_query)] - #[ra_salsa::cycle(crate::lower::impl_self_ty_recover)] fn impl_self_ty(&self, def: ImplId) -> Binders; + #[ra_salsa::invoke(crate::lower::const_param_ty_with_diagnostics_query)] + fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics); #[ra_salsa::invoke(crate::lower::const_param_ty_query)] fn const_param_ty(&self, def: ConstParamId) -> Ty; + #[ra_salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)] + fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders, Diagnostics)>; #[ra_salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option>; + #[ra_salsa::invoke(crate::lower::field_types_with_diagnostics_query)] + fn field_types_with_diagnostics( + &self, + var: VariantId, + ) -> (Arc>>, Diagnostics); #[ra_salsa::invoke(crate::lower::field_types_query)] fn field_types(&self, var: VariantId) -> Arc>>; @@ -154,6 +168,11 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)] + fn generic_predicates_without_parent_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericPredicates, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)] fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; @@ -164,8 +183,13 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment(&self, def: GenericDefId) -> Arc; + #[ra_salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)] + fn generic_defaults_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericDefaults, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_defaults_query)] - #[ra_salsa::cycle(crate::lower::generic_defaults_recover)] fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; #[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index c094bc39512..fe7541d2374 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -55,6 +55,10 @@ impl Generics { self.def } + pub(crate) fn self_types_map(&self) -> &TypesMap { + &self.params.types_map + } + pub(crate) fn iter_id(&self) -> impl Iterator + '_ { self.iter_self_id().chain(self.iter_parent_id()) } @@ -86,15 +90,13 @@ impl Generics { self.iter_self().chain(self.iter_parent()) } - pub(crate) fn iter_with_types_map( + pub(crate) fn iter_parents_with_types_map( &self, ) -> impl Iterator), &TypesMap)> + '_ { - self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain( - self.iter_parent().zip( - self.parent_generics() - .into_iter() - .flat_map(|it| std::iter::repeat(&it.params.types_map)), - ), + self.iter_parent().zip( + self.parent_generics() + .into_iter() + .flat_map(|it| std::iter::repeat(&it.params.types_map)), ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 77ae295cee4..8bb90ca31e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -90,7 +90,8 @@ pub use infer::{ pub use interner::Interner; pub use lower::{ associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, - ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, ValueTyDefId, + ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + ValueTyDefId, }; pub use mapping::{ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b73967be710..b23f2749ab2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::{ all_super_traits, @@ -1652,11 +1652,24 @@ fn named_associated_type_shorthand_candidates( } } -/// Build the type of all specific fields of a struct or enum variant. +pub(crate) type Diagnostics = Option>; + +fn create_diagnostics(diagnostics: Vec) -> Diagnostics { + (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) +} + pub(crate) fn field_types_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> Arc>> { + db.field_types_with_diagnostics(variant_id).0 +} + +/// Build the type of all specific fields of a struct or enum variant. +pub(crate) fn field_types_with_diagnostics_query( + db: &dyn HirDatabase, + variant_id: VariantId, +) -> (Arc>>, Diagnostics) { let var_data = variant_id.variant_data(db.upcast()); let (resolver, def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), @@ -1672,7 +1685,7 @@ pub(crate) fn field_types_query( for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } - Arc::new(res) + (Arc::new(res), create_diagnostics(ctx.diagnostics)) } /// This query exists only to be used when resolving short-hand associated types @@ -1873,15 +1886,22 @@ pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { - generic_predicates_filtered_by(db, def, |_, _| true) + generic_predicates_filtered_by(db, def, |_, _| true).0 } -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent pub(crate) fn generic_predicates_without_parent_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { + db.generic_predicates_without_parent_with_diagnostics(def).0 +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericPredicates, Diagnostics) { generic_predicates_filtered_by(db, def, |_, d| *d == def) } @@ -1891,7 +1911,7 @@ fn generic_predicates_filtered_by( db: &dyn HirDatabase, def: GenericDefId, filter: F, -) -> GenericPredicates +) -> (GenericPredicates, Diagnostics) where F: Fn(&WherePredicate, &GenericDefId) -> bool, { @@ -1932,7 +1952,10 @@ where ); }; } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) + ( + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), + create_diagnostics(ctx.diagnostics), + ) } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. @@ -1985,75 +2008,110 @@ impl ops::Deref for GenericDefaults { } } -/// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { + db.generic_defaults_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) - .with_type_param_mode(ParamLoweringMode::Variable); - GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map( - |(idx, ((id, p), types_map))| { - ctx.types_map = types_map; - match p { - GenericParamDataRef::TypeParamData(p) => { - let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) - }); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; + let mut ctx = + TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); + let mut idx = 0; + let mut defaults = generic_params + .iter_self() + .map(|(id, p)| { + let result = + handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + }) + .collect::>(); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| { + ctx.types_map = types_map; + let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + })); + let defaults = GenericDefaults(Some(Arc::from_iter(defaults))); + return (defaults, diagnostics); + + fn handle_generic_param( + ctx: &mut TyLoweringContext<'_>, + idx: usize, + id: GenericParamId, + p: GenericParamDataRef<'_>, + parent_start_idx: usize, + generic_params: &Generics, + ) -> Binders { + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) + }); + crate::make_binders(ctx.db, generic_params, ty.cast(Interner)) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(db.const_param_ty(id)), - |c| { - let param_ty = ctx.lower_ty(p.ty); - let c = ctx.lower_const(c, param_ty); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx, parent_start_idx); - make_binders(db, &generic_params, val) - } - GenericParamDataRef::LifetimeParamData(_) => { - make_binders(db, &generic_params, error_lifetime().cast(Interner)) - } + let mut val = p.default.as_ref().map_or_else( + || unknown_const_as_generic(ctx.db.const_param_ty(id)), + |c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.cast(Interner) + }, + ); + // Each default can only refer to previous parameters, see above. + val = fallback_bound_vars(val, idx, parent_start_idx); + make_binders(ctx.db, generic_params, val) } - }, - )))) + GenericParamDataRef::LifetimeParamData(_) => { + make_binders(ctx.db, generic_params, error_lifetime().cast(Interner)) + } + } + } } -pub(crate) fn generic_defaults_recover( +pub(crate) fn generic_defaults_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, def: &GenericDefId, -) -> GenericDefaults { +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), *def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } // FIXME: this code is not covered in tests. // we still need one default per parameter - GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { + let defaults = GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) - })))) + })))); + (defaults, None) } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { @@ -2196,7 +2254,10 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { make_binders(db, &generics, ty) } -fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { +pub(crate) fn type_for_type_alias_with_diagnostics_query( + db: &dyn HirDatabase, + t: TypeAliasId, +) -> (Binders, Diagnostics) { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); let type_alias_data = db.type_alias_data(t); @@ -2211,7 +2272,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { .map(|type_ref| ctx.lower_ty(type_ref)) .unwrap_or_else(|| TyKind::Error.intern(Interner)) }; - make_binders(db, &generics, inner) + (make_binders(db, &generics, inner), create_diagnostics(ctx.diagnostics)) } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -2254,7 +2315,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders { match def { TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), TyDefId::AdtId(it) => type_for_adt(db, it), - TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, } } @@ -2279,47 +2340,73 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option< } pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { + db.impl_self_ty_with_diagnostics(impl_id).0 +} + +pub(crate) fn impl_self_ty_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> (Binders, Diagnostics) { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let generics = generics(db.upcast(), impl_id.into()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)) + ( + make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)), + create_diagnostics(ctx.diagnostics), + ) } -// returns None if def is a type arg pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { + db.const_param_ty_with_diagnostics(def).0 +} + +// returns None if def is a type arg +pub(crate) fn const_param_ty_with_diagnostics_query( + db: &dyn HirDatabase, + def: ConstParamId, +) -> (Ty, Diagnostics) { let parent_data = db.generic_params(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into()); - match data { + let ty = match data { TypeOrConstParamData::TypeParamData(_) => { never!(); Ty::new(Interner, TyKind::Error) } TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - } + }; + (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn impl_self_ty_recover( +pub(crate) fn impl_self_ty_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, impl_id: &ImplId, -) -> Binders { +) -> (Binders, Diagnostics) { let generics = generics(db.upcast(), (*impl_id).into()); - make_binders(db, &generics, TyKind::Error.intern(Interner)) + (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { + db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) +} + +pub(crate) fn impl_trait_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> Option<(Binders, Diagnostics)> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?)) + let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?); + Some((trait_ref, create_diagnostics(ctx.diagnostics))) } pub(crate) fn return_type_impl_traits( diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 3657cf5e162..612c6adb207 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -15,7 +15,8 @@ use hir_expand::{name::Name, HirFileId, InFile}; use hir_ty::{ db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, - CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind, + CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, + TyLoweringDiagnosticKind, }; use syntax::{ ast::{self, HasGenericArgs}, @@ -402,7 +403,7 @@ pub struct InvalidCast { #[derive(Debug)] pub struct GenericArgsProhibited { - pub args: InFile>>, + pub args: InFile>>, pub reason: GenericArgsProhibitedReason, } @@ -664,30 +665,38 @@ impl AnyDiagnostic { InferenceTyDiagnosticSource::Body => &source_map.types, InferenceTyDiagnosticSource::Signature => outer_types_source_map, }; - let source = match diag.source { - Either::Left(type_ref_id) => { - let Ok(source) = source_map.type_syntax(type_ref_id) else { - stdx::never!("error on synthetic type syntax"); - return None; - }; - source - } - Either::Right(source) => source, + Self::ty_diagnostic(diag, source_map, db)? + } + }) + } + + pub(crate) fn ty_diagnostic( + diag: &TyLoweringDiagnostic, + source_map: &TypesSourceMap, + db: &dyn HirDatabase, + ) -> Option { + let source = match diag.source { + Either::Left(type_ref_id) => { + let Ok(source) = source_map.type_syntax(type_ref_id) else { + stdx::never!("error on synthetic type syntax"); + return None; }; - let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); - match diag.kind { - TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { - let ast::Type::PathType(syntax) = syntax() else { return None }; - let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; - let args = if let Some(generics) = segment.generic_arg_list() { - AstPtr::new(&generics).wrap_left() - } else { - AstPtr::new(&segment.param_list()?).wrap_right() - }; - let args = source.with_value(args); - GenericArgsProhibited { args, reason }.into() - } - } + source + } + Either::Right(source) => source, + }; + let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); + Some(match diag.kind { + TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { + let ast::Type::PathType(syntax) = syntax() else { return None }; + let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; + let args = if let Some(generics) = segment.generic_arg_list() { + AstPtr::new(&generics).wrap_left() + } else { + AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right() + }; + let args = source.with_value(args); + GenericArgsProhibited { args, reason }.into() } }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index cd462767473..10365ba0028 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -76,8 +76,8 @@ use hir_ty::{ traits::FnTrait, AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, - WhereClause, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic, + ValueTyDefId, WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -89,7 +89,7 @@ use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T, }; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::db::{DefDatabase, HirDatabase}; @@ -411,6 +411,10 @@ impl ModuleDef { } } + if let Some(def) = self.as_self_generic_def() { + def.diagnostics(db, &mut acc); + } + acc } @@ -431,6 +435,23 @@ impl ModuleDef { } } + /// Returns only defs that have generics from themselves, not their parent. + pub fn as_self_generic_def(self) -> Option { + match self { + ModuleDef::Function(it) => Some(it.into()), + ModuleDef::Adt(it) => Some(it.into()), + ModuleDef::Trait(it) => Some(it.into()), + ModuleDef::TraitAlias(it) => Some(it.into()), + ModuleDef::TypeAlias(it) => Some(it.into()), + ModuleDef::Module(_) + | ModuleDef::Variant(_) + | ModuleDef::Static(_) + | ModuleDef::Const(_) + | ModuleDef::BuiltinType(_) + | ModuleDef::Macro(_) => None, + } + } + pub fn attrs(&self, db: &dyn HirDatabase) -> Option { Some(match self { ModuleDef::Module(it) => it.attrs(db), @@ -605,17 +626,42 @@ impl Module { ModuleDef::Adt(adt) => { match adt { Adt::Struct(s) => { + let tree_id = s.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(s.id.into()).1, + tree_source_maps.strukt(tree_id.value).item(), + ); for diag in db.struct_data_with_diagnostics(s.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Union(u) => { + let tree_id = u.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(u.id.into()).1, + tree_source_maps.union(tree_id.value).item(), + ); for diag in db.union_data_with_diagnostics(u.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Enum(e) => { for v in e.variants(db) { + let tree_id = v.id.lookup(db.upcast()).id; + let tree_source_maps = + tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(v.id.into()).1, + tree_source_maps.variant(tree_id.value), + ); acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); @@ -626,6 +672,17 @@ impl Module { acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), + ModuleDef::TypeAlias(type_alias) => { + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); + acc.extend(def.diagnostics(db, style_lints)); + } _ => acc.extend(def.diagnostics(db, style_lints)), } } @@ -635,8 +692,11 @@ impl Module { let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { + GenericDef::Impl(impl_def).diagnostics(db, acc); + let loc = impl_def.id.lookup(db.upcast()); - let tree = loc.id.item_tree(db.upcast()); + let (tree, tree_source_maps) = loc.id.item_tree_with_source_map(db.upcast()); + let source_map = tree_source_maps.impl_(loc.id.value).item(); let node = &tree[loc.id.value]; let file_id = loc.id.file_id(); if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) { @@ -771,6 +831,19 @@ impl Module { impl_assoc_items_scratch.clear(); } + push_ty_diagnostics( + db, + acc, + db.impl_self_ty_with_diagnostics(impl_def.id).1, + source_map, + ); + push_ty_diagnostics( + db, + acc, + db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + source_map, + ); + for &item in db.impl_data(impl_def.id).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } @@ -3350,12 +3423,22 @@ impl AssocItem { ) { match self { AssocItem::Function(func) => { + GenericDef::Function(func).diagnostics(db, acc); DefWithBody::from(func).diagnostics(db, acc, style_lints); } AssocItem::Const(const_) => { DefWithBody::from(const_).diagnostics(db, acc, style_lints); } AssocItem::TypeAlias(type_alias) => { + GenericDef::TypeAlias(type_alias).diagnostics(db, acc); + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); } @@ -3442,6 +3525,97 @@ impl GenericDef { }) .collect() } + + fn id(self) -> GenericDefId { + match self { + GenericDef::Function(it) => it.id.into(), + GenericDef::Adt(it) => it.into(), + GenericDef::Trait(it) => it.id.into(), + GenericDef::TraitAlias(it) => it.id.into(), + GenericDef::TypeAlias(it) => it.id.into(), + GenericDef::Impl(it) => it.id.into(), + GenericDef::Const(it) => it.id.into(), + } + } + + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + let def = self.id(); + + let item_tree_source_maps; + let (generics, generics_source_map) = db.generic_params_with_source_map(def); + + if generics.is_empty() && generics.no_predicates() { + return; + } + + let source_map = match &generics_source_map { + Some(it) => it, + None => match def { + GenericDefId::FunctionId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(id.value).generics() + } + GenericDefId::AdtId(AdtId::EnumId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.enum_generic(id.value) + } + GenericDefId::AdtId(AdtId::StructId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.strukt(id.value).generics() + } + GenericDefId::AdtId(AdtId::UnionId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.union(id.value).generics() + } + GenericDefId::TraitId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_generic(id.value) + } + GenericDefId::TraitAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_alias_generic(id.value) + } + GenericDefId::TypeAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.type_alias(id.value).generics() + } + GenericDefId::ImplId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.impl_(id.value).generics() + } + GenericDefId::ConstId(_) => return, + }, + }; + + push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); + push_ty_diagnostics( + db, + acc, + db.generic_predicates_without_parent_with_diagnostics(def).1, + source_map, + ); + for (param_id, param) in generics.iter_type_or_consts() { + if let TypeOrConstParamData::ConstParamData(_) = param { + push_ty_diagnostics( + db, + acc, + db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( + TypeOrConstParamId { parent: def, local_id: param_id }, + )) + .1, + source_map, + ); + } + } + } } /// A single local definition. @@ -5825,3 +5999,19 @@ pub enum DocLinkDef { Field(Field), SelfType(Trait), } + +fn push_ty_diagnostics( + db: &dyn HirDatabase, + acc: &mut Vec, + diagnostics: Option>, + source_map: &TypesSourceMap, +) { + if let Some(diagnostics) = diagnostics { + acc.extend( + diagnostics + .slice + .iter() + .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs index c3ad6704b6d..a319a0bcf6d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -68,6 +68,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option #[cfg(test)] mod tests { + // This diagnostic was the first to be emitted in ty lowering, so the tests here also test + // diagnostics in ty lowering in general (which is why there are so many of them). + use crate::tests::{check_diagnostics, check_fix}; #[test] @@ -239,4 +242,201 @@ fn foo() { }"#, ); } + + #[test] + fn in_fields() { + check_diagnostics( + r#" +struct A(bool); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +struct B { v: bool<(), 1> } + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +union C { + a: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + b: i32, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + } +enum D { + A(bool), + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B { v: i32 }, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn in_generics() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} + +struct A::Trait>(A) + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +union B::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ a: A } +enum C::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + +trait E::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl::Trait> E for () + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn assoc_items() { + check_diagnostics( + r#" +struct Foo; + +trait Trait { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Trait for Foo { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Foo { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn const_param_ty() { + check_diagnostics( + r#" +fn foo< + const A: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B, + C, + const D: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + const E: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +>() {} + "#, + ); + } + + #[test] + fn generic_defaults() { + check_diagnostics( + r#" +struct Foo>(A); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_self_ty() { + check_diagnostics( + r#" +struct Foo(A); +trait Trait {} +impl Foo> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for Foo> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_trait() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} +impl foo::<()>::Trait for () {} + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + "#, + ); + } + + #[test] + fn type_alias() { + check_diagnostics( + r#" +pub trait Trait { + type Assoc; +} +type T = bool; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for () { + type Assoc = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } } -- cgit 1.4.1-3-g733a5 From 61e8403ee20a3ab7a3b6eec3362b70dabf4911e4 Mon Sep 17 00:00:00 2001 From: Tarek Date: Mon, 28 Oct 2024 20:09:52 +0300 Subject: feat: migrate introduce_named_generic assist to use SyntaxFactory Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 25 +++++++++++++++++----- .../syntax/src/ast/syntax_factory/constructors.rs | 21 ++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index bf6ac1719f3..8edcd6db3d1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,8 +1,11 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams, HasName}, - ted, + ast::{ + self, edit_in_place::GenericParamsOwnerEdit, syntax_factory::SyntaxFactory, AstNode, + HasGenericParams, HasName, + }, + SyntaxElement, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,12 +28,20 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let type_bound_list = impl_trait_type.type_bound_list()?; + // FIXME: Is this node appropriate to use for SyntaxEditor in this case? + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; + let make = SyntaxFactory::new(); + let target = fn_.syntax().text_range(); acc.add( AssistId("introduce_named_generic", AssistKind::RefactorRewrite), "Replace impl trait with generic", target, |edit| { + let mut editor = edit.make_editor(&parent_node); let impl_trait_type = edit.make_mut(impl_trait_type); let fn_ = edit.make_mut(fn_); let fn_generic_param_list = fn_.get_or_create_generic_param_list(); @@ -47,11 +58,12 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> ) .for_impl_trait_as_generic(&impl_trait_type); - let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list)) + let type_param = make + .type_param(make.name(&type_param_name), Some(type_bound_list)) .clone_for_update(); - let new_ty = make::ty(&type_param_name).clone_for_update(); + let new_ty = make.ty(&type_param_name).clone_for_update(); - ted::replace(impl_trait_type.syntax(), new_ty.syntax()); + editor.replace(impl_trait_type.syntax(), new_ty.syntax()); fn_generic_param_list.add_generic_param(type_param.into()); if let Some(cap) = ctx.config.snippet_cap { @@ -61,6 +73,9 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> edit.add_tabstop_before(cap, generic_param); } } + + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 9f88add0f78..680ba9381dd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -14,6 +14,27 @@ impl SyntaxFactory { make::name(name).clone_for_update() } + pub fn ty(&self, text: &str) -> ast::Type { + // FIXME: Is there anything to map here? + make::ty(text).clone_for_update() + } + + pub fn type_param( + &self, + name: ast::Name, + bounds: Option, + ) -> ast::TypeParam { + let ast = make::type_param(name.clone(), bounds.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); -- cgit 1.4.1-3-g733a5 From 7fa84a3f4b74b7ab68553b5e441dc951ce9050a5 Mon Sep 17 00:00:00 2001 From: Tarek Date: Mon, 28 Oct 2024 20:45:09 +0300 Subject: fix: remove make_mut from introduce_named_generic assist Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/introduce_named_generic.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 8edcd6db3d1..cf9d58ca0d2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -42,8 +42,6 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let impl_trait_type = edit.make_mut(impl_trait_type); - let fn_ = edit.make_mut(fn_); let fn_generic_param_list = fn_.get_or_create_generic_param_list(); let existing_names = fn_generic_param_list -- cgit 1.4.1-3-g733a5 From 797eb3ebe8b2fcd41f4b03ae7f8aa72f7a47e1a8 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 30 Oct 2024 17:56:02 +0300 Subject: define syntax_editor_add_generic_param Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 8 +++----- .../crates/syntax/src/ast/edit_in_place.rs | 24 ++++++++++++++++++++++ .../syntax/src/ast/syntax_factory/constructors.rs | 9 ++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index cf9d58ca0d2..ae30dacfd01 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -56,13 +56,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> ) .for_impl_trait_as_generic(&impl_trait_type); - let type_param = make - .type_param(make.name(&type_param_name), Some(type_bound_list)) - .clone_for_update(); - let new_ty = make.ty(&type_param_name).clone_for_update(); + let type_param = make.type_param(make.name(&type_param_name), Some(type_bound_list)); + let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_generic_param_list.add_generic_param(type_param.into()); + fn_generic_param_list.syntax_editor_add_generic_param(&mut editor, type_param.into()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generic_param) = diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index f1286e7aa21..2b152a45c9a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -7,6 +7,7 @@ use parser::{SyntaxKind, T}; use crate::{ algo::{self, neighbor}, ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams}, + syntax_editor::SyntaxEditor, ted::{self, Position}, AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, @@ -257,6 +258,29 @@ impl ast::GenericParamList { } } + pub fn syntax_editor_add_generic_param( + &self, + editor: &mut SyntaxEditor, + generic_param: ast::GenericParam, + ) { + match self.generic_params().last() { + Some(last_param) => { + let position = crate::syntax_editor::Position::after(last_param.syntax()); + let elements = vec![ + make::token(T![,]).into(), + make::tokens::single_space().into(), + generic_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } + None => { + let after_l_angle = + crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); + editor.insert(after_l_angle, generic_param.syntax()); + } + } + } + /// Removes the existing generic param pub fn remove_generic_param(&self, generic_param: ast::GenericParam) { if let Some(previous) = generic_param.syntax().prev_sibling() { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 680ba9381dd..35c467a1e8c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -2,7 +2,7 @@ use itertools::Itertools; use crate::{ - ast::{self, make, HasName}, + ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, AstNode, }; @@ -15,7 +15,6 @@ impl SyntaxFactory { } pub fn ty(&self, text: &str) -> ast::Type { - // FIXME: Is there anything to map here? make::ty(text).clone_for_update() } @@ -29,6 +28,12 @@ impl SyntaxFactory { if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + if let Some(input) = bounds { + builder.map_node( + input.syntax().clone(), + ast.type_bound_list().unwrap().syntax().clone(), + ); + } builder.finish(&mut mapping); } -- cgit 1.4.1-3-g733a5 From 54b597ccf24a67f8f2e82be50b7f47ae737aaa00 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 12 Nov 2024 19:18:26 +0200 Subject: fix: implement `syntax_editor_create_generic_param_list` Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 8 ++---- .../crates/syntax/src/ast/edit_in_place.rs | 32 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index ae30dacfd01..c6945d6245e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,10 +1,7 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; use syntax::{ - ast::{ - self, edit_in_place::GenericParamsOwnerEdit, syntax_factory::SyntaxFactory, AstNode, - HasGenericParams, HasName, - }, + ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}, SyntaxElement, }; @@ -42,7 +39,8 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let fn_generic_param_list = fn_.get_or_create_generic_param_list(); + let fn_generic_param_list = + fn_.syntax_editor_get_or_create_generic_param_list(&mut editor); let existing_names = fn_generic_param_list .generic_params() diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 2b152a45c9a..61580a5cae6 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -55,6 +55,29 @@ impl GenericParamsOwnerEdit for ast::Fn { } } +impl ast::Fn { + pub fn syntax_editor_get_or_create_generic_param_list( + &self, + editor: &mut SyntaxEditor, + ) -> ast::GenericParamList { + match self.generic_param_list() { + Some(it) => it, + None => { + let position = if let Some(name) = self.name() { + crate::syntax_editor::Position::after(name.syntax) + } else if let Some(fn_token) = self.fn_token() { + crate::syntax_editor::Position::after(fn_token) + } else if let Some(param_list) = self.param_list() { + crate::syntax_editor::Position::before(param_list.syntax) + } else { + crate::syntax_editor::Position::last_child_of(self.syntax()) + }; + syntax_editor_create_generic_param_list(editor, position) + } + } + } +} + impl GenericParamsOwnerEdit for ast::Impl { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { match self.generic_param_list() { @@ -191,6 +214,15 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList { gpl } +fn syntax_editor_create_generic_param_list( + editor: &mut SyntaxEditor, + position: crate::syntax_editor::Position, +) -> ast::GenericParamList { + let gpl = make::generic_param_list(empty()).clone_for_update(); + editor.insert(position, gpl.syntax()); + gpl +} + pub trait AttrsOwnerEdit: ast::HasAttrs { fn remove_attrs_and_docs(&self) { remove_attrs_and_docs(self.syntax()); -- cgit 1.4.1-3-g733a5 From e275203e808353279d50d62ce8f4556acc0fd7ac Mon Sep 17 00:00:00 2001 From: Tarek Date: Fri, 22 Nov 2024 16:26:14 +0200 Subject: fix: refactor syntax_editor_add_generic_param to handle new generic parameters Signed-off-by: Tarek --- .../crates/syntax/src/ast/edit_in_place.rs | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 61580a5cae6..9a5c122e27c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -293,22 +293,21 @@ impl ast::GenericParamList { pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, - generic_param: ast::GenericParam, + new_param: ast::GenericParam, ) { match self.generic_params().last() { - Some(last_param) => { - let position = crate::syntax_editor::Position::after(last_param.syntax()); - let elements = vec![ - make::token(T![,]).into(), - make::tokens::single_space().into(), - generic_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); + Some(_) => { + let mut params = + self.generic_params().map(|param| param.clone()).collect::>(); + params.push(new_param.into()); + let new_param_list = make::generic_param_list(params); + + editor.replace(self.syntax(), new_param_list.syntax()); } None => { - let after_l_angle = - crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); - editor.insert(after_l_angle, generic_param.syntax()); + let position = crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); + let new_param_list = make::generic_param_list(once(new_param.clone())); + editor.insert(position, new_param_list.syntax()); } } } -- cgit 1.4.1-3-g733a5 From cfd5f7a40c4eb8b821feca1fd0c8f87c9982c47f Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 27 Nov 2024 14:56:56 +0200 Subject: fix: refactor `syntax_editor_add_generic_param` to handle adding new generic parameters Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 25 +++++---- .../crates/syntax/src/ast/edit_in_place.rs | 65 ++++++++++------------ 2 files changed, 43 insertions(+), 47 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index c6945d6245e..25628c1656a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -39,16 +39,17 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let fn_generic_param_list = - fn_.syntax_editor_get_or_create_generic_param_list(&mut editor); - - let existing_names = fn_generic_param_list - .generic_params() - .flat_map(|param| match param { - ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), - p => Some(p.to_string()), - }) - .collect_vec(); + + let existing_names = match fn_.generic_param_list() { + Some(generic_param_list) => generic_param_list + .generic_params() + .flat_map(|param| match param { + ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), + p => Some(p.to_string()), + }) + .collect_vec(), + None => Vec::new(), + }; let type_param_name = suggest_name::NameGenerator::new_with_names( existing_names.iter().map(|s| s.as_str()), ) @@ -58,13 +59,13 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_generic_param_list.syntax_editor_add_generic_param(&mut editor, type_param.into()); + fn_.syntax_editor_add_generic_param(&mut editor, type_param.into()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generic_param) = fn_.generic_param_list().and_then(|it| it.generic_params().last()) { - edit.add_tabstop_before(cap, generic_param); + editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 9a5c122e27c..360ee14fa28 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -56,13 +56,37 @@ impl GenericParamsOwnerEdit for ast::Fn { } impl ast::Fn { - pub fn syntax_editor_get_or_create_generic_param_list( + pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, - ) -> ast::GenericParamList { + new_param: GenericParam, + ) { match self.generic_param_list() { - Some(it) => it, + Some(generic_param_list) => match generic_param_list.generic_params().last() { + Some(_last_param) => { + // There exists a generic param list and it's not empty + let mut params = generic_param_list + .generic_params() + .map(|param| param.clone()) + .collect::>(); + params.push(new_param.into()); + let new_param_list = make::generic_param_list(params); + editor.replace( + generic_param_list.syntax(), + new_param_list.syntax().clone_for_update(), + ); + } + None => { + // There exists a generic param list but it's empty + let position = crate::syntax_editor::Position::after( + generic_param_list.l_angle_token().unwrap(), + ); + + editor.insert(position, new_param.syntax()); + } + }, None => { + // There was no generic param list let position = if let Some(name) = self.name() { crate::syntax_editor::Position::after(name.syntax) } else if let Some(fn_token) = self.fn_token() { @@ -72,7 +96,9 @@ impl ast::Fn { } else { crate::syntax_editor::Position::last_child_of(self.syntax()) }; - syntax_editor_create_generic_param_list(editor, position) + + let new_param_list = make::generic_param_list(once(new_param.clone())); + editor.insert(position, new_param_list.syntax().clone_for_update()); } } } @@ -214,15 +240,6 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList { gpl } -fn syntax_editor_create_generic_param_list( - editor: &mut SyntaxEditor, - position: crate::syntax_editor::Position, -) -> ast::GenericParamList { - let gpl = make::generic_param_list(empty()).clone_for_update(); - editor.insert(position, gpl.syntax()); - gpl -} - pub trait AttrsOwnerEdit: ast::HasAttrs { fn remove_attrs_and_docs(&self) { remove_attrs_and_docs(self.syntax()); @@ -290,28 +307,6 @@ impl ast::GenericParamList { } } - pub fn syntax_editor_add_generic_param( - &self, - editor: &mut SyntaxEditor, - new_param: ast::GenericParam, - ) { - match self.generic_params().last() { - Some(_) => { - let mut params = - self.generic_params().map(|param| param.clone()).collect::>(); - params.push(new_param.into()); - let new_param_list = make::generic_param_list(params); - - editor.replace(self.syntax(), new_param_list.syntax()); - } - None => { - let position = crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); - let new_param_list = make::generic_param_list(once(new_param.clone())); - editor.insert(position, new_param_list.syntax()); - } - } - } - /// Removes the existing generic param pub fn remove_generic_param(&self, generic_param: ast::GenericParam) { if let Some(previous) = generic_param.syntax().prev_sibling() { -- cgit 1.4.1-3-g733a5 From e7fd49cfb42a75da9be5d4a8f4e674a884d7076c Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 23:47:52 +0200 Subject: fix: refactor `syntax_editor_add_generic_param` Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 9 ++-- .../crates/syntax/src/ast/edit_in_place.rs | 51 ++++++++++++++++------ 2 files changed, 41 insertions(+), 19 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 25628c1656a..4b4433419a0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -59,14 +59,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_.syntax_editor_add_generic_param(&mut editor, type_param.into()); + let generic_param = syntax::ast::GenericParam::from(type_param); + fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { - if let Some(generic_param) = - fn_.generic_param_list().and_then(|it| it.generic_params().last()) - { - editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); - } + editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 360ee14fa28..22afb8297b1 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -56,6 +56,7 @@ impl GenericParamsOwnerEdit for ast::Fn { } impl ast::Fn { + /// Adds a new generic param to the function using `SyntaxEditor` pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, @@ -65,23 +66,44 @@ impl ast::Fn { Some(generic_param_list) => match generic_param_list.generic_params().last() { Some(_last_param) => { // There exists a generic param list and it's not empty - let mut params = generic_param_list - .generic_params() - .map(|param| param.clone()) - .collect::>(); - params.push(new_param.into()); - let new_param_list = make::generic_param_list(params); - editor.replace( - generic_param_list.syntax(), - new_param_list.syntax().clone_for_update(), + let position = generic_param_list.r_angle_token().map_or_else( + || crate::syntax_editor::Position::last_child_of(self.syntax()), + crate::syntax_editor::Position::before, ); + + if let Some(last_param) = generic_param_list.generic_params().last() { + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } + }; } None => { // There exists a generic param list but it's empty let position = crate::syntax_editor::Position::after( generic_param_list.l_angle_token().unwrap(), ); - editor.insert(position, new_param.syntax()); } }, @@ -96,9 +118,12 @@ impl ast::Fn { } else { crate::syntax_editor::Position::last_child_of(self.syntax()) }; - - let new_param_list = make::generic_param_list(once(new_param.clone())); - editor.insert(position, new_param_list.syntax().clone_for_update()); + let elements = vec![ + make::token(SyntaxKind::L_ANGLE).into(), + new_param.syntax().clone().into(), + make::token(T![>]).into(), + ]; + editor.insert_all(position, elements); } } } -- cgit 1.4.1-3-g733a5 From d453198999ad34232b0d3c9adf4769ae7a417ea2 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 23:57:11 +0200 Subject: fix: correct token type for closing angle bracket Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 22afb8297b1..dcaeed40073 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -121,7 +121,7 @@ impl ast::Fn { let elements = vec![ make::token(SyntaxKind::L_ANGLE).into(), new_param.syntax().clone().into(), - make::token(T![>]).into(), + make::token(SyntaxKind::R_ANGLE).into(), ]; editor.insert_all(position, elements); } -- cgit 1.4.1-3-g733a5 From b1e0d3122173fff7635e144add3b363578b5c147 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 14:32:48 +0200 Subject: fix: refactor `introduce_named_generic` assist Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 19 ++------ .../crates/syntax/src/ast/edit_in_place.rs | 54 +++++++++++----------- 2 files changed, 31 insertions(+), 42 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 4b4433419a0..1edbd01b020 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,9 +1,6 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; -use syntax::{ - ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}, - SyntaxElement, -}; +use syntax::ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,20 +22,14 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let type_bound_list = impl_trait_type.type_bound_list()?; - // FIXME: Is this node appropriate to use for SyntaxEditor in this case? - let parent_node = match ctx.covering_element() { - SyntaxElement::Node(n) => n, - SyntaxElement::Token(t) => t.parent()?, - }; let make = SyntaxFactory::new(); - let target = fn_.syntax().text_range(); acc.add( AssistId("introduce_named_generic", AssistKind::RefactorRewrite), "Replace impl trait with generic", target, - |edit| { - let mut editor = edit.make_editor(&parent_node); + |builder| { + let mut editor = builder.make_editor(fn_.syntax()); let existing_names = match fn_.generic_param_list() { Some(generic_param_list) => generic_param_list @@ -63,11 +54,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { - editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); + editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); - edit.add_file_edits(ctx.file_id(), editor); + builder.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index dcaeed40073..68447a6a271 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -64,40 +64,38 @@ impl ast::Fn { ) { match self.generic_param_list() { Some(generic_param_list) => match generic_param_list.generic_params().last() { - Some(_last_param) => { + Some(last_param) => { // There exists a generic param list and it's not empty let position = generic_param_list.r_angle_token().map_or_else( || crate::syntax_editor::Position::last_child_of(self.syntax()), crate::syntax_editor::Position::before, ); - if let Some(last_param) = generic_param_list.generic_params().last() { - if last_param - .syntax() - .next_sibling_or_token() - .map_or(false, |it| it.kind() == SyntaxKind::COMMA) - { - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - new_param.syntax().clone(), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::WHITESPACE), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::COMMA), - ); - } else { - let elements = vec![ - make::token(SyntaxKind::COMMA).into(), - make::token(SyntaxKind::WHITESPACE).into(), - new_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); - } - }; + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } } None => { // There exists a generic param list but it's empty -- cgit 1.4.1-3-g733a5 From 60e0e02a21b0a018d4cab937772f657e49afad4e Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 14:51:48 +0200 Subject: refactor: move editing for ast using `SyntaxEditor` to a separate file Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 2 +- .../crates/syntax/src/ast/edit_in_place.rs | 73 ---------------------- .../crates/syntax/src/syntax_editor.rs | 1 + .../crates/syntax/src/syntax_editor/edits.rs | 72 +++++++++++++++++++++ 4 files changed, 74 insertions(+), 74 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 1edbd01b020..ecc96f791d4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -51,7 +51,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> editor.replace(impl_trait_type.syntax(), new_ty.syntax()); let generic_param = syntax::ast::GenericParam::from(type_param); - fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); + editor.syntax_editor_add_generic_param(fn_, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 68447a6a271..f1286e7aa21 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -7,7 +7,6 @@ use parser::{SyntaxKind, T}; use crate::{ algo::{self, neighbor}, ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams}, - syntax_editor::SyntaxEditor, ted::{self, Position}, AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, @@ -55,78 +54,6 @@ impl GenericParamsOwnerEdit for ast::Fn { } } -impl ast::Fn { - /// Adds a new generic param to the function using `SyntaxEditor` - pub fn syntax_editor_add_generic_param( - &self, - editor: &mut SyntaxEditor, - new_param: GenericParam, - ) { - match self.generic_param_list() { - Some(generic_param_list) => match generic_param_list.generic_params().last() { - Some(last_param) => { - // There exists a generic param list and it's not empty - let position = generic_param_list.r_angle_token().map_or_else( - || crate::syntax_editor::Position::last_child_of(self.syntax()), - crate::syntax_editor::Position::before, - ); - - if last_param - .syntax() - .next_sibling_or_token() - .map_or(false, |it| it.kind() == SyntaxKind::COMMA) - { - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - new_param.syntax().clone(), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::WHITESPACE), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::COMMA), - ); - } else { - let elements = vec![ - make::token(SyntaxKind::COMMA).into(), - make::token(SyntaxKind::WHITESPACE).into(), - new_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); - } - } - None => { - // There exists a generic param list but it's empty - let position = crate::syntax_editor::Position::after( - generic_param_list.l_angle_token().unwrap(), - ); - editor.insert(position, new_param.syntax()); - } - }, - None => { - // There was no generic param list - let position = if let Some(name) = self.name() { - crate::syntax_editor::Position::after(name.syntax) - } else if let Some(fn_token) = self.fn_token() { - crate::syntax_editor::Position::after(fn_token) - } else if let Some(param_list) = self.param_list() { - crate::syntax_editor::Position::before(param_list.syntax) - } else { - crate::syntax_editor::Position::last_child_of(self.syntax()) - }; - let elements = vec![ - make::token(SyntaxKind::L_ANGLE).into(), - new_param.syntax().clone().into(), - make::token(SyntaxKind::R_ANGLE).into(), - ]; - editor.insert_all(position, elements); - } - } - } -} - impl GenericParamsOwnerEdit for ast::Impl { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { match self.generic_param_list() { diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 714f5a99111..7e5d0f27e0a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -16,6 +16,7 @@ use rustc_hash::FxHashMap; use crate::{SyntaxElement, SyntaxNode, SyntaxToken}; mod edit_algo; +mod edits; mod mapping; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs new file mode 100644 index 00000000000..759b46c9c79 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -0,0 +1,72 @@ +//! Structural editing for ast using `SyntaxEditor` + +use crate::{ + ast::make, ast::AstNode, ast::Fn, ast::GenericParam, ast::HasGenericParams, ast::HasName, + syntax_editor::Position, syntax_editor::SyntaxEditor, SyntaxKind, +}; + +impl SyntaxEditor { + /// Adds a new generic param to the function using `SyntaxEditor` + pub fn syntax_editor_add_generic_param(&mut self, function: Fn, new_param: GenericParam) { + match function.generic_param_list() { + Some(generic_param_list) => match generic_param_list.generic_params().last() { + Some(last_param) => { + // There exists a generic param list and it's not empty + let position = generic_param_list.r_angle_token().map_or_else( + || Position::last_child_of(function.syntax()), + Position::before, + ); + + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + self.insert( + Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + self.insert_all(position, elements); + } + } + None => { + // There exists a generic param list but it's empty + let position = Position::after(generic_param_list.l_angle_token().unwrap()); + self.insert(position, new_param.syntax()); + } + }, + None => { + // There was no generic param list + let position = if let Some(name) = function.name() { + Position::after(name.syntax) + } else if let Some(fn_token) = function.fn_token() { + Position::after(fn_token) + } else if let Some(param_list) = function.param_list() { + Position::before(param_list.syntax) + } else { + Position::last_child_of(function.syntax()) + }; + let elements = vec![ + make::token(SyntaxKind::L_ANGLE).into(), + new_param.syntax().clone().into(), + make::token(SyntaxKind::R_ANGLE).into(), + ]; + self.insert_all(position, elements); + } + } + } +} -- cgit 1.4.1-3-g733a5 From d5f3ed89cb0c1fa2164147efff25695be02bc36a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 15:25:01 +0200 Subject: Do not report warnings from proc macros, ever --- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 7 +++++++ src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs | 6 ++++++ 2 files changed, 13 insertions(+) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 7d2f556406d..2ee598dfbfd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -269,6 +269,13 @@ pub enum MacroDefKind { ProcMacro(AstId, CustomProcMacroExpander, ProcMacroKind), } +impl MacroDefKind { + #[inline] + pub fn is_declarative(&self) -> bool { + matches!(self, MacroDefKind::Declarative(..)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct EagerCallInfo { /// The expanded argument of the eager macro. diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 1f1b6478d36..9fbed7db35b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -542,7 +542,13 @@ fn handle_diag_from_macros( sema.db.lookup_intern_syntax_context(span.ctx).outer_expn.is_some_and(|expansion| { let macro_call = sema.db.lookup_intern_macro_call(expansion.as_macro_file().macro_call_id); + // We don't want to show diagnostics for non-local macros at all, but proc macros authors + // seem to rely on being able to emit non-warning-free code, so we don't want to show warnings + // for them even when the proc macro comes from the same workspace (in rustc that's not a + // problem because it doesn't have the concept of workspaces, and proc macros always reside + // in a different crate). !Crate::from(macro_call.def.krate).origin(sema.db).is_local() + || !macro_call.def.kind.is_declarative() }) }) { // Disable suggestions for external macros, they'll change library code and it's just bad. -- cgit 1.4.1-3-g733a5 From 6120a8ad0bc93b756fab12e1ae2a9c25700d1d85 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 16:02:03 +0200 Subject: fix: update `introduce_named_generic` to use `type_param` directly Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/introduce_named_generic.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index ecc96f791d4..28023ce5edb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -50,11 +50,10 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - let generic_param = syntax::ast::GenericParam::from(type_param); - editor.syntax_editor_add_generic_param(fn_, generic_param.clone()); + editor.syntax_editor_add_generic_param(fn_, type_param.clone().into()); if let Some(cap) = ctx.config.snippet_cap { - editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); + editor.add_annotation(type_param.syntax(), builder.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); -- cgit 1.4.1-3-g733a5 From a9afc99c1347eacdb9495ffa2601bb032997f2ae Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 09:44:17 +0100 Subject: Disable `<` typing handler again --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- src/tools/rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 392bfbf15fe..aa9f919679d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + typing_excludeChars: Option = Some("<".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c..96a2a5a27d3 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf62..7529651ca7a 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "default": "<", "type": [ "null", "string" -- cgit 1.4.1-3-g733a5 From 0a99a9f05f3c13fbb4fc972b6d7e6d868af14beb Mon Sep 17 00:00:00 2001 From: Tarek Date: Thu, 5 Dec 2024 13:50:43 +0200 Subject: fix: rename `syntax_editor_add_generic_param` to `add_generic_param` Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/introduce_named_generic.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 28023ce5edb..8c276415bb1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -50,7 +50,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - editor.syntax_editor_add_generic_param(fn_, type_param.clone().into()); + editor.add_generic_param(&fn_, type_param.clone().into()); if let Some(cap) = ctx.config.snippet_cap { editor.add_annotation(type_param.syntax(), builder.make_tabstop_before(cap)); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 759b46c9c79..73196f5cb1b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -7,7 +7,7 @@ use crate::{ impl SyntaxEditor { /// Adds a new generic param to the function using `SyntaxEditor` - pub fn syntax_editor_add_generic_param(&mut self, function: Fn, new_param: GenericParam) { + pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) { match function.generic_param_list() { Some(generic_param_list) => match generic_param_list.generic_params().last() { Some(last_param) => { -- cgit 1.4.1-3-g733a5 From a19e1dffe5ca8574e58826488351af8c714c9620 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: fix: Fix parsing of integer/keyword name refs in various places --- .../hir-def/src/macro_expansion_tests/mbe.rs | 2 +- .../rust-analyzer/crates/parser/src/grammar.rs | 44 ++++++++++-- .../crates/parser/src/grammar/expressions.rs | 64 ++++++++++-------- .../crates/parser/src/grammar/expressions/atom.rs | 12 +--- .../crates/parser/src/grammar/generic_args.rs | 4 +- .../crates/parser/src/grammar/generic_params.rs | 11 ++- .../crates/parser/src/grammar/items.rs | 12 +--- .../crates/parser/src/grammar/paths.rs | 49 ++++++-------- .../crates/parser/test_data/generated/runner.rs | 8 +-- .../parser/err/0004_use_path_bad_segment.rast | 2 +- .../test_data/parser/err/0048_double_fish.rast | 4 +- .../parser/inline/err/arg_list_recovery.rast | 2 +- .../inline/err/crate_visibility_empty_recover.rast | 2 +- .../test_data/parser/inline/err/empty_segment.rast | 2 +- .../test_data/parser/inline/err/meta_recovery.rast | 10 +-- .../inline/err/precise_capturing_invalid.rast | 28 ++++++++ .../parser/inline/err/precise_capturing_invalid.rs | 1 + .../record_literal_before_ellipsis_recovery.rast | 37 +++++++++- .../err/record_literal_before_ellipsis_recovery.rs | 1 + .../err/record_literal_field_eq_recovery.rast | 29 +++++++- .../inline/err/record_literal_field_eq_recovery.rs | 1 + .../record_literal_missing_ellipsis_recovery.rast | 78 ++++++++++++++++------ .../record_literal_missing_ellipsis_recovery.rs | 3 +- .../test_data/parser/inline/ok/extern_crate.rast | 9 +++ .../test_data/parser/inline/ok/extern_crate.rs | 1 + .../parser/inline/ok/extern_crate_rename.rast | 15 +++++ .../parser/inline/ok/extern_crate_rename.rs | 1 + .../parser/inline/ok/extern_crate_self.rast | 10 --- .../parser/inline/ok/extern_crate_self.rs | 1 - .../test_data/parser/inline/ok/field_expr.rast | 24 +++++++ .../test_data/parser/inline/ok/field_expr.rs | 2 + .../parser/inline/ok/method_call_expr.rast | 14 ++++ .../test_data/parser/inline/ok/method_call_expr.rs | 1 + 33 files changed, 351 insertions(+), 133 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 5c03fad6131..511626b5ed9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1733,7 +1733,7 @@ m!(C("0")); macro_rules! m { ($k:expr) => { fn f() { K::$k; } } } -/* parse error: expected identifier */ +/* parse error: expected identifier, `self`, `super`, `crate`, or `Self` */ /* parse error: expected SEMICOLON */ /* parse error: expected SEMICOLON */ /* parse error: expected expression, item or let statement */ diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index c402c498553..fe6b904bd88 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -307,13 +307,49 @@ fn name(p: &mut Parser<'_>) { name_r(p, TokenSet::EMPTY); } -fn name_ref(p: &mut Parser<'_>) { - if p.at(IDENT) { +fn name_ref_or_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![self]) { let m = p.start(); - p.bump(IDENT); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier or `self`"); + } +} + +fn name_ref_or_upper_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![Self]) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier or `Self`"); + } +} + +const PATH_NAME_REF_KINDS: TokenSet = + TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]); + +fn name_ref_mod_path(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_KINDS) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier, `self`, `super`, `crate`, or `Self`"); + } +} + +const PATH_NAME_REF_OR_INDEX_KINDS: TokenSet = + PATH_NAME_REF_KINDS.union(TokenSet::new(&[INT_NUMBER])); + +fn name_ref_mod_path_or_index(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + let m = p.start(); + p.bump_any(); m.complete(p, NAME_REF); } else { - p.err_and_bump("expected identifier"); + p.err_and_bump("expected integer, identifier, `self`, `super`, `crate`, or `Self`"); } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 349bce09390..3b3f11be130 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -449,7 +449,9 @@ fn postfix_dot_expr( let nth1 = if FLOAT_RECOVERY { 0 } else { 1 }; let nth2 = if FLOAT_RECOVERY { 1 } else { 2 }; - if p.nth(nth1) == IDENT && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) { + if PATH_NAME_REF_KINDS.contains(p.nth(nth1)) + && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) + { return Ok(method_call_expr::(p, lhs)); } @@ -510,21 +512,26 @@ fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { // y.bar::(1, 2,); // x.0.0.call(); // x.0. call(); +// x.0() // } fn method_call_expr( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> CompletedMarker { if FLOAT_RECOVERY { - assert!(p.nth(0) == IDENT && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); + assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); } else { - assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); + assert!( + p.at(T![.]) + && PATH_NAME_REF_KINDS.contains(p.nth(1)) + && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) + ); } let m = lhs.precede(p); if !FLOAT_RECOVERY { p.bump(T![.]); } - name_ref(p); + name_ref_mod_path(p); generic_args::opt_generic_arg_list_expr(p); if p.at(T!['(']) { arg_list(p); @@ -543,6 +550,8 @@ fn method_call_expr( // test field_expr // fn foo() { +// x.self; +// x.Self; // x.foo; // x.0.bar; // x.0.1; @@ -560,8 +569,8 @@ fn field_expr( if !FLOAT_RECOVERY { p.bump(T![.]); } - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + name_ref_mod_path_or_index(p); } else if p.at(FLOAT_NUMBER) { return match p.split_float(m) { (true, m) => { @@ -679,34 +688,37 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { IDENT | INT_NUMBER if p.nth_at(1, T![::]) => { // test_err record_literal_missing_ellipsis_recovery // fn main() { - // S { S::default() } + // S { S::default() }; + // S { 0::default() }; // } m.abandon(p); p.expect(T![..]); expr(p); } + IDENT | INT_NUMBER if p.nth_at(1, T![..]) => { + // test_err record_literal_before_ellipsis_recovery + // fn main() { + // S { field ..S::default() } + // S { 0 ..S::default() } + // } + name_ref_or_index(p); + p.error("expected `:`"); + m.complete(p, RECORD_EXPR_FIELD); + } IDENT | INT_NUMBER => { - if p.nth_at(1, T![..]) { - // test_err record_literal_before_ellipsis_recovery - // fn main() { - // S { field ..S::default() } - // } + // test_err record_literal_field_eq_recovery + // fn main() { + // S { field = foo } + // S { 0 = foo } + // } + if p.nth_at(1, T![:]) { name_ref_or_index(p); - p.error("expected `:`"); - } else { - // test_err record_literal_field_eq_recovery - // fn main() { - // S { field = foo } - // } - if p.nth_at(1, T![:]) { - name_ref_or_index(p); - p.bump(T![:]); - } else if p.nth_at(1, T![=]) { - name_ref_or_index(p); - p.err_and_bump("expected `:`"); - } - expr(p); + p.bump(T![:]); + } else if p.nth_at(1, T![=]) { + name_ref_or_index(p); + p.err_and_bump("expected `:`"); } + expr(p); m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 97e0392ce15..cd2ce59f627 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -259,13 +259,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option { type_(p); p.expect(T![,]); while !p.at(EOF) && !p.at(T![')']) { - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); - // } else if p.at(FLOAT_NUMBER) { - // FIXME: needs float hack - } else { - p.err_and_bump("expected field name or number"); - } + name_ref_mod_path_or_index(p); if !p.at(T![')']) { p.expect(T![.]); } @@ -465,9 +459,9 @@ fn parse_clobber_abi(p: &mut Parser<'_>) { fn parse_reg(p: &mut Parser<'_>) { p.expect(T!['(']); - if p.at(T![ident]) { + if p.at_ts(PATH_NAME_REF_KINDS) { let m = p.start(); - name_ref(p); + name_ref_mod_path(p); m.complete(p, ASM_REG_SPEC); } else if p.at(T![string]) { let m = p.start(); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index 737010985b2..c7d8040b24e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -59,9 +59,9 @@ pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { // test macro_inside_generic_arg // type A = Foo; - IDENT => { + k if PATH_NAME_REF_KINDS.contains(k) => { let m = p.start(); - name_ref(p); + name_ref_mod_path(p); paths::opt_path_type_args(p); match p.current() { T![=] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 92311238c23..08b23cd92a6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -145,6 +145,9 @@ fn type_bound(p: &mut Parser<'_>) -> bool { T![for] => types::for_type(p, false), // test precise_capturing // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} + + // test_err precise_capturing_invalid + // type T = impl use; T![use] if p.nth_at(1, T![<]) => { p.bump_any(); let m = p.start(); @@ -156,14 +159,10 @@ fn type_bound(p: &mut Parser<'_>) -> bool { || "expected identifier or lifetime".into(), TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]), |p| { - if p.at(T![Self]) { - let m = p.start(); - p.bump(T![Self]); - m.complete(p, NAME_REF); - } else if p.at(LIFETIME_IDENT) { + if p.at(LIFETIME_IDENT) { lifetime(p); } else { - name_ref(p); + name_ref_or_upper_self(p); } true }, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 7d98499008d..8ece5af527d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -254,22 +254,16 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke // test extern_crate // extern crate foo; +// extern crate self; fn extern_crate(p: &mut Parser<'_>, m: Marker) { p.bump(T![extern]); p.bump(T![crate]); - if p.at(T![self]) { - // test extern_crate_self - // extern crate self; - let m = p.start(); - p.bump(T![self]); - m.complete(p, NAME_REF); - } else { - name_ref(p); - } + name_ref_or_self(p); // test extern_crate_rename // extern crate foo as bar; + // extern crate self as bar; opt_rename(p); p.expect(T![;]); m.complete(p, EXTERN_CRATE); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index b3652f7cd3f..3410505cd46 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -107,37 +107,32 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { - name_ref(p); - opt_path_args(p, mode); - } + if p.at_ts(PATH_NAME_REF_KINDS) { // test crate_path // use crate::foo; - T![self] | T![super] | T![crate] | T![Self] => { - let m = p.start(); - p.bump_any(); - m.complete(p, NAME_REF); - } - _ => { - let recover_set = match mode { - Mode::Use => items::ITEM_RECOVERY_SET, - Mode::Attr => { - items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) - } - Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), - Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, - Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, - }; - empty &= p.err_recover("expected identifier", recover_set); - if empty { - // test_err empty_segment - // use crate::; - m.abandon(p); - return None; + name_ref_mod_path(p); + opt_path_args(p, mode); + } else { + let recover_set = match mode { + Mode::Use => items::ITEM_RECOVERY_SET, + Mode::Attr => { + items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) } + Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), + Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, + Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, + }; + empty &= p.err_recover( + "expected identifier, `self`, `super`, `crate`, or `Self`", + recover_set, + ); + if empty { + // test_err empty_segment + // use crate::; + m.abandon(p); + return None; } - }; + } } Some(m.complete(p, PATH_SEGMENT)) } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 6d114037bf9..f9486f53c25 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -210,10 +210,6 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_rename.rs"); } #[test] - fn extern_crate_self() { - run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_self.rs"); - } - #[test] fn field_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/field_expr.rs"); } #[test] fn fn_() { run_and_expect_no_errors("test_data/parser/inline/ok/fn_.rs"); } @@ -774,6 +770,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs"); } #[test] + fn precise_capturing_invalid() { + run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs"); + } + #[test] fn pub_expr() { run_and_expect_errors("test_data/parser/inline/err/pub_expr.rs"); } #[test] fn record_literal_before_ellipsis_recovery() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast index cf455934e91..7273c98456e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast @@ -13,4 +13,4 @@ SOURCE_FILE ERROR INT_NUMBER "92" SEMICOLON ";" -error 9: expected identifier +error 9: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast index 7ef1eb98fcd..47daaf7b3b3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast @@ -115,10 +115,10 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 30: expected identifier +error 30: expected identifier, `self`, `super`, `crate`, or `Self` error 31: expected COMMA error 37: expected expression -error 75: expected identifier +error 75: expected identifier, `self`, `super`, `crate`, or `Self` error 76: expected SEMICOLON error 82: expected expression error 83: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast index cd5aa680c65..755b20bb271 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast @@ -98,7 +98,7 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 25: expected identifier +error 25: expected identifier, `self`, `super`, `crate`, or `Self` error 39: expected COMMA error 39: expected expression error 55: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 681ca6b6e05..172bc099b58 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -11,4 +11,4 @@ SOURCE_FILE IDENT "S" SEMICOLON ";" WHITESPACE "\n" -error 4: expected identifier +error 4: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast index b03f5ad9f7e..7f256218eff 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast @@ -11,4 +11,4 @@ SOURCE_FILE COLON2 "::" SEMICOLON ";" WHITESPACE "\n" -error 11: expected identifier +error 11: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast index 926dd50fc85..b5c16e0798c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -66,18 +66,18 @@ SOURCE_FILE EQ "=" R_BRACK "]" WHITESPACE "\n" -error 3: expected identifier +error 3: expected identifier, `self`, `super`, `crate`, or `Self` error 11: expected expression error 11: expected expression -error 20: expected identifier -error 28: expected identifier +error 20: expected identifier, `self`, `super`, `crate`, or `Self` +error 28: expected identifier, `self`, `super`, `crate`, or `Self` error 30: expected expression error 30: expected expression error 41: expected L_PAREN -error 41: expected identifier +error 41: expected identifier, `self`, `super`, `crate`, or `Self` error 41: expected R_PAREN error 52: expected L_PAREN -error 52: expected identifier +error 52: expected identifier, `self`, `super`, `crate`, or `Self` error 54: expected expression error 54: expected expression error 54: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast new file mode 100644 index 00000000000..5ae184c5feb --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast @@ -0,0 +1,28 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + IMPL_TRAIT_TYPE + IMPL_KW "impl" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + USE_KW "use" + USE_BOUND_GENERIC_ARGS + L_ANGLE "<" + ERROR + SELF_KW "self" + COMMA "," + WHITESPACE " " + ERROR + INT_NUMBER "1" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" +error 18: expected identifier or `Self` +error 24: expected identifier or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs new file mode 100644 index 00000000000..3180338d33f --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs @@ -0,0 +1 @@ +type T = impl use; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast index 741b7845e7f..08ae906421c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast @@ -12,6 +12,38 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + DOT2 ".." + CALL_EXPR + PATH_EXPR + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +55,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " DOT2 ".." CALL_EXPR @@ -47,3 +79,6 @@ SOURCE_FILE WHITESPACE "\n" error 25: expected `:` error 25: expected COMMA +error 42: expected SEMICOLON +error 52: expected `:` +error 52: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs index a4e5b2f6933..65398ccb88e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field ..S::default() } + S { 0 ..S::default() } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast index ad4deeb0b67..ad3b6f208e6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast @@ -12,6 +12,31 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + ERROR + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +48,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " ERROR EQ "=" @@ -39,3 +64,5 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 26: expected `:` +error 33: expected SEMICOLON +error 44: expected `:` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs index 1eb1aa9b926..9ddc46e0daf 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field = foo } + S { 0 = foo } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast index 0c5b618e6f0..9cd07d2ea38 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast @@ -12,32 +12,70 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + CALL_EXPR + PATH_EXPR PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" PATH_SEGMENT NAME_REF - IDENT "S" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - R_CURLY "}" + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + ERROR + COLON ":" + ERROR + COLON ":" + RECORD_EXPR_FIELD + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" error 19: expected DOT2 +error 43: expected DOT2 +error 45: expected COMMA +error 45: expected identifier +error 46: expected COMMA +error 46: expected identifier +error 47: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs index 1b594e8ab96..a63c3c9e7c2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { - S { S::default() } + S { S::default() }; + S { 0::default() }; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast index 0a660957d15..aa555ed2293 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast @@ -8,3 +8,12 @@ SOURCE_FILE IDENT "foo" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs index 49af74e1b74..3c498c8738f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs @@ -1 +1,2 @@ extern crate foo; +extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast index 5a5aca96f91..5f0a5b5bb05 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast @@ -14,3 +14,18 @@ SOURCE_FILE IDENT "bar" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + WHITESPACE " " + RENAME + AS_KW "as" + WHITESPACE " " + NAME + IDENT "bar" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs index fc76e17dda4..6d1873d659e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs @@ -1 +1,2 @@ extern crate foo as bar; +extern crate self as bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast deleted file mode 100644 index edea4245f20..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast +++ /dev/null @@ -1,10 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - SELF_KW "self" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs deleted file mode 100644 index c969ed10936..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast index dd27dc48964..3bac226d343 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast @@ -12,6 +12,30 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + SELF_TYPE_KW "Self" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT FIELD_EXPR PATH_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs index 98dbe45a7ec..b156d6f7d88 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs @@ -1,4 +1,6 @@ fn foo() { + x.self; + x.Self; x.foo; x.0.bar; x.0.1; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast index b28b8eb673a..3245042cf24 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast @@ -101,6 +101,20 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + CALL_EXPR + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + INT_NUMBER "0" + ARG_LIST + L_PAREN "(" + R_PAREN ")" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs index 48bb6381e80..bb54d75c19b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs @@ -3,4 +3,5 @@ fn foo() { y.bar::(1, 2,); x.0.0.call(); x.0. call(); + x.0() } -- cgit 1.4.1-3-g733a5 From 70380736bc8e899d012011089fdd20d3faf6f70e Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 6 Dec 2024 01:10:46 +0900 Subject: fix: Panic when displaying generic params with defaults --- .../rust-analyzer/crates/hir-ty/src/display.rs | 6 ++- .../rust-analyzer/crates/ide/src/hover/tests.rs | 50 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 94a340fbec2..3dfa0e97cec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1047,10 +1047,14 @@ impl HirDisplay for Ty { ); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? if parameters.len() - impl_ > 0 { + let params_len = parameters.len(); // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes let parameters = generic_args_sans_defaults(f, Some(generic_def_id), parameters); - let without_impl = self_param as usize + type_ + const_ + lifetime; + assert!(params_len >= parameters.len()); + let defaults = params_len - parameters.len(); + let without_impl = + self_param as usize + type_ + const_ + lifetime - defaults; // parent's params (those from enclosing impl or trait, if any). let (fn_params, parent_params) = parameters.split_at(without_impl + impl_); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 0986d5542cd..1c08514a672 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -9416,3 +9416,53 @@ fn f "#]], ); } + +#[test] +fn issue_18613() { + check( + r#" +fn main() { + struct S(); + let x$0 = S::<()>; +}"#, + expect![[r#" + *x* + + ```rust + let x: fn S<()>() -> S<()> + ``` + + --- + + size = 0, align = 1 + "#]], + ); + + check( + r#" +pub struct Global; +pub struct Box(T, A); + +impl Box { + pub fn new(x: T) -> Self { loop {} } +} + +pub struct String; + +fn main() { + let box_value$0 = Box::new(); +} +"#, + expect![[r#" + *box_value* + + ```rust + let box_value: fn Box(String, Global) -> Box + ``` + + --- + + size = 0, align = 1 + "#]], + ); +} -- cgit 1.4.1-3-g733a5 From 085ea34357f27b3ed8d94deb0555416e95aca8d6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: Parse lifetime bounds in lifetime param into TypeBoundList This mainly aids in error recovery but also makes it a bit easier to handle lifetime resolution. While doing so it also came apparent that we were not actually lowering lifetime outlives relationships within lifetime parameter declaration bounds, so this fixes that. --- .../crates/hir-def/src/item_tree/pretty.rs | 4 +- .../crates/hir-def/src/item_tree/tests.rs | 6 ++- .../crates/hir-ty/src/tests/traits.rs | 23 +++++++++++ .../rust-analyzer/crates/hir/src/semantics.rs | 4 ++ .../ide-completion/src/completions/lifetime.rs | 36 +++++++--------- .../crates/ide-completion/src/context.rs | 5 +-- .../crates/ide-completion/src/context/analysis.rs | 17 ++++---- src/tools/rust-analyzer/crates/ide-db/src/defs.rs | 10 ----- .../crates/intern/src/symbol/symbols.rs | 1 + .../crates/parser/src/grammar/generic_params.rs | 15 ++++--- .../test_data/parser/inline/ok/lifetime_param.rast | 6 ++- .../parser/inline/ok/precise_capturing.rast | 12 ++++-- .../parser/ok/0018_struct_type_params.rast | 48 ++++++++++++++-------- .../parser/ok/0020_type_param_bounds.rast | 23 +++++++---- 14 files changed, 125 insertions(+), 85 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 0c5e3a3620a..70bf2f13c88 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -648,9 +648,9 @@ impl Printer<'_> { let (target, bound) = match pred { WherePredicate::TypeBound { target, bound } => (target, bound), WherePredicate::Lifetime { target, bound } => { - wln!( + w!( this, - "{}: {},", + "{}: {}", target.name.display(self.db.upcast(), edition), bound.name.display(self.db.upcast(), edition) ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 5c07369f4b5..0f53969d6c7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { pub(self) field: &'a &'b T, } @@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { // AstId: 9 pub(self) fn f( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 624148cab20..b62672d21e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1630,6 +1630,29 @@ fn test<'lifetime>( ); } +#[test] +fn lifetime_bounds() { + check_infer( + r#" +//- minicore: sized, coerce_unsized +trait Trait<'a>: Sized { + fn f(&'a self) {} +} +fn test<'a, 'b: 'a>(it: impl Trait<'a>){ + it.f(); +} +"#, + expect![[r#" + 38..42 'self': &'a Self + 44..46 '{}': () + 69..71 'it': impl Trait<'a> + 88..103 '{ it.f(); }': () + 94..96 'it': impl Trait<'a> + 94..100 'it.f()': () + "#]], + ); +} + #[test] fn error_bound_chalk() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 65470d061b3..0b09cf27926 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2026,6 +2026,10 @@ impl SemanticsScope<'_> { ) } + pub fn generic_def(&self) -> Option { + self.resolver.generic_def().map(|id| id.into()) + } + pub fn extern_crates(&self) -> impl Iterator + '_ { self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id })) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 9efc52428ef..0692446381b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -8,7 +8,6 @@ //! show up for normal completions, or they won't show completions other than lifetimes depending //! on the fixture input. use hir::{sym, Name, ScopeDef}; -use syntax::{ast, ToSmolStr, TokenText}; use crate::{ completions::Completions, @@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime( ctx: &CompletionContext<'_>, lifetime_ctx: &LifetimeContext, ) { - let (lp, lifetime) = match lifetime_ctx { - LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime), - LifetimeContext { - kind: LifetimeKind::LifetimeParam { is_decl: false, param }, - lifetime, - } => (Some(param), lifetime), - _ => return, - }; - let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) { - (Some(lt), Some(lp)) if lp == lt.clone() => return, - (Some(_), Some(lp)) => Some(lp), - _ => None, + let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } = + lifetime_ctx + else { + return; }; - let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text); - let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str); ctx.process_all_names_raw(&mut |name, res| { - if matches!( - res, - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) - if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr()) - ) { + if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) { acc.add_lifetime(ctx, name); } }); - if param_lifetime.is_none() { - acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + if !in_lifetime_param_bound + && def.is_some_and(|def| { + !matches!(def, hir::GenericDef::Function(_) | hir::GenericDef::Impl(_)) + }) + { + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_underscore.clone())); } } @@ -222,6 +212,8 @@ fn foo<'footime, 'lifetime: 'a$0>() {} "#, expect![[r#" lt 'footime + lt 'lifetime + lt 'static "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 5b8d1c30a29..3a661706336 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -290,15 +290,14 @@ pub(crate) struct ParamContext { /// The state of the lifetime we are completing. #[derive(Debug)] pub(crate) struct LifetimeContext { - pub(crate) lifetime: Option, pub(crate) kind: LifetimeKind, } /// The kind of lifetime we are completing. #[derive(Debug)] pub(crate) enum LifetimeKind { - LifetimeParam { is_decl: bool, param: ast::LifetimeParam }, - Lifetime, + LifetimeParam, + Lifetime { in_lifetime_param_bound: bool, def: Option }, LabelRef, LabelDef, } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index a4e018b1800..4a678963b93 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -562,7 +562,7 @@ fn expected_type_and_name( } fn classify_lifetime( - _sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'_, RootDatabase>, original_file: &SyntaxNode, lifetime: ast::Lifetime, ) -> Option { @@ -571,21 +571,22 @@ fn classify_lifetime( return None; } + let lifetime = + find_node_at_offset::(original_file, lifetime.syntax().text_range().start()); let kind = match_ast! { match parent { - ast::LifetimeParam(param) => LifetimeKind::LifetimeParam { - is_decl: param.lifetime().as_ref() == Some(&lifetime), - param - }, + ast::LifetimeParam(_) => LifetimeKind::LifetimeParam, ast::BreakExpr(_) => LifetimeKind::LabelRef, ast::ContinueExpr(_) => LifetimeKind::LabelRef, ast::Label(_) => LifetimeKind::LabelDef, - _ => LifetimeKind::Lifetime, + _ => { + let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def()); + LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def } + }, } }; - let lifetime = find_node_at_offset(original_file, lifetime.syntax().text_range().start()); - Some(LifetimeContext { lifetime, kind }) + Some(LifetimeContext { kind }) } fn classify_name( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index fdac4dd2efb..5eec33636be 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -772,16 +772,6 @@ impl NameRefClass { .map(GenericParam::LifetimeParam) .map(Definition::GenericParam) .map(NameRefClass::Definition), - // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check - // if our lifetime is in a LifetimeParam without being the constrained lifetime - _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref() - != Some(lifetime) => - { - sema.resolve_lifetime_param(lifetime) - .map(GenericParam::LifetimeParam) - .map(Definition::GenericParam) - .map(NameRefClass::Definition) - } _ => None, } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 8f79cf20079..ebc9c14059d 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -80,6 +80,7 @@ define_symbols! { self_ = "self", Self_ = "Self", tick_static = "'static", + tick_underscore = "'_", dollar_crate = "$crate", MISSING_NAME = "[missing name]", fn_ = "fn", diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 08b23cd92a6..9d4fdbfaf2e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool { fn lifetime_param(p: &mut Parser<'_>, m: Marker) { assert!(p.at(LIFETIME_IDENT)); lifetime(p); - if p.at(T![:]) { + if p.eat(T![:]) { lifetime_bounds(p); } m.complete(p, LIFETIME_PARAM); @@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) { } fn lifetime_bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - while p.at(LIFETIME_IDENT) { - lifetime(p); + let marker = p.start(); + while { + if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) { + p.error("expected lifetime"); + } + + type_bound(p) + } { if !p.eat(T![+]) { break; } } + marker.complete(p, TYPE_BOUND_LIST); } // test type_param_bounds diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast index c595031f358..315200aca21 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" PARAM_LIST L_PAREN "(" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast index f9c0a245af8..5a67cc21766 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -20,8 +22,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast index 11ebc7efb9f..1e4eb156095 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast @@ -96,6 +96,7 @@ SOURCE_FILE LIFETIME LIFETIME_IDENT "'a" COLON ":" + TYPE_BOUND_LIST R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -111,8 +112,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -128,10 +131,12 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" WHITESPACE " " R_ANGLE ">" SEMICOLON ";" @@ -148,13 +153,16 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -202,9 +210,11 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + PLUS "+" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -212,8 +222,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" COMMA "," R_ANGLE ">" SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast index 043a966ff97..448cf49446e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast @@ -237,8 +237,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'d" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'d" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -246,13 +248,16 @@ SOURCE_FILE LIFETIME_IDENT "'d" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM -- cgit 1.4.1-3-g733a5 From 64832b0ddb274bc752b1627c95fa0558d847e27d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: fix: Resolve generic parameters within use captures --- .../rust-analyzer/crates/hir-def/src/resolver.rs | 4 +- .../rust-analyzer/crates/hir/src/semantics.rs | 4 ++ .../crates/hir/src/source_analyzer.rs | 8 +++ src/tools/rust-analyzer/crates/ide-db/src/defs.rs | 7 +++ src/tools/rust-analyzer/crates/ide/src/rename.rs | 69 ++++++++++++++++++++++ 5 files changed, 90 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 0ca7070fd05..316406c151f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -642,9 +642,9 @@ impl Resolver { }) } - pub fn generic_params(&self) -> Option<&Arc> { + pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), + Scope::GenericParams { params, .. } => Some(&**params), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 0b09cf27926..f9d3f9d07e6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1517,6 +1517,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax())?.resolve_path(self.db, path) } + pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { + self.analyze(name.syntax())?.resolve_use_type_arg(name) + } + pub fn resolve_mod_path( &self, scope: &SyntaxNode, diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 56ed81f053c..4329a888b39 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -642,6 +642,14 @@ impl SourceAnalyzer { } } + pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { + let name = name.as_name(); + self.resolver + .all_generic_params() + .find_map(|(params, parent)| params.find_type_by_name(&name, *parent)) + .map(crate::TypeParam::from) + } + pub(crate) fn resolve_path( &self, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 5eec33636be..932ca373020 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -733,6 +733,12 @@ impl NameRefClass { } None }, + ast::UseBoundGenericArgs(_) => { + sema.resolve_use_type_arg(name_ref) + .map(GenericParam::TypeParam) + .map(Definition::GenericParam) + .map(NameRefClass::Definition) + }, ast::ExternCrate(extern_crate_ast) => { let extern_crate = sema.to_def(&extern_crate_ast)?; let krate = extern_crate.resolved_crate(sema.db)?; @@ -764,6 +770,7 @@ impl NameRefClass { sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition) } SyntaxKind::LIFETIME_ARG + | SyntaxKind::USE_BOUND_GENERIC_ARGS | SyntaxKind::SELF_PARAM | SyntaxKind::TYPE_BOUND | SyntaxKind::WHERE_PRED diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 665fc954d23..a9519c03b32 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -3102,6 +3102,75 @@ fn main() { let _: S; } r#" use lib::S as Baz; fn main() { let _: Baz; } +"#, + ); + } + + #[test] + fn rename_type_param_ref_in_use_bound() { + check( + "U", + r#" +fn foo() -> impl use Trait {} +"#, + r#" +fn foo() -> impl use Trait {} +"#, + ); + } + + #[test] + fn rename_type_param_in_use_bound() { + check( + "U", + r#" +fn foo() -> impl use Trait {} +"#, + r#" +fn foo() -> impl use Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_ref_in_use_bound() { + check( + "u", + r#" +fn foo<'t>() -> impl use<'t$0> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_in_use_bound() { + check( + "u", + r#" +fn foo<'t$0>() -> impl use<'t> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_parent_type_param_in_use_bound() { + check( + "U", + r#" +trait Trait { + fn foo() -> impl use Trait {} +} +"#, + r#" +trait Trait { + fn foo() -> impl use Trait {} +} "#, ); } -- cgit 1.4.1-3-g733a5 From 59a5b38bf4ebf74be954c8804789ef2cf35350e9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 20:25:05 +0100 Subject: fix: Fix parsing of dyn T in generic arg on 2015 edition --- .../crates/parser/src/grammar/generic_args.rs | 5 +++- .../crates/parser/src/grammar/types.rs | 2 +- .../crates/parser/test_data/generated/runner.rs | 7 +++++ ...edition_2015_dyn_prefix_inside_generic_arg.rast | 32 ++++++++++++++++++++++ .../edition_2015_dyn_prefix_inside_generic_arg.rs | 2 ++ .../test_data/parser/inline/ok/generic_arg.rast | 21 ++++++++++++++ .../test_data/parser/inline/ok/generic_arg.rs | 2 +- 7 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index c7d8040b24e..b9d5bff6630 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -45,7 +45,7 @@ pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); // test generic_arg -// type T = S; +// type T = S; pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), @@ -57,6 +57,9 @@ pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { // type ParenthesizedArgs = Foo; // type RTN = Foo; + // test edition_2015_dyn_prefix_inside_generic_arg 2015 + // type A = Foo; + T![ident] if !p.edition().at_least_2018() && types::is_dyn_weak(p) => type_arg(p), // test macro_inside_generic_arg // type A = Foo; k if PATH_NAME_REF_KINDS.contains(k) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 35198ccbe35..0133b7d5d82 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -58,7 +58,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { } } -fn is_dyn_weak(p: &Parser<'_>) -> bool { +pub(crate) fn is_dyn_weak(p: &Parser<'_>) -> bool { const WEAK_DYN_PATH_FIRST: TokenSet = TokenSet::new(&[ IDENT, T![self], diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index f9486f53c25..0beaf1ae3a5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -190,6 +190,13 @@ mod ok { ); } #[test] + fn edition_2015_dyn_prefix_inside_generic_arg() { + run_and_expect_no_errors_with_edition( + "test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs", + crate::Edition::Edition2015, + ); + } + #[test] fn effect_blocks() { run_and_expect_no_errors("test_data/parser/inline/ok/effect_blocks.rs"); } #[test] fn exclusive_range_pat() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast new file mode 100644 index 00000000000..24e671b3438 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast @@ -0,0 +1,32 @@ +SOURCE_FILE + TYPE_ALIAS + COMMENT "// 2015" + WHITESPACE "\n" + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs new file mode 100644 index 00000000000..84cece5748d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs @@ -0,0 +1,2 @@ +// 2015 +type A = Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast index 5a01f154bad..e32cf085657 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast @@ -20,6 +20,27 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "i32" + COMMA "," + WHITESPACE " " + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + COMMA "," + WHITESPACE " " + TYPE_ARG + FN_PTR_TYPE + FN_KW "fn" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs index f2ccc558bb5..cf991b5b366 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs @@ -1 +1 @@ -type T = S; +type T = S; -- cgit 1.4.1-3-g733a5 From 3db9b1d943f7a665ea98a6dab40ece33375f4f99 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 05:53:44 +0100 Subject: fix: Fix parser getting stuck for bad asm expressions --- .../crates/parser/src/grammar/expressions/atom.rs | 18 ++++++-- .../crates/parser/test_data/generated/runner.rs | 2 + .../test_data/parser/inline/err/bad_asm_expr.rast | 50 ++++++++++++++++++++++ .../test_data/parser/inline/err/bad_asm_expr.rs | 5 +++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index cd2ce59f627..407320e1d08 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -345,10 +345,7 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { name(p); p.bump(T![=]); allow_templates = false; - true - } else { - false - }; + } let op = p.start(); let dir_spec = p.start(); @@ -399,6 +396,19 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { op.abandon(p); op_n.abandon(p); p.err_and_bump("expected asm operand"); + + // improves error recovery and handles err_and_bump recovering from `{` which gets + // the parser stuck here + if p.at(T!['{']) { + // test_err bad_asm_expr + // fn foo() { + // builtin#asm( + // label crashy = { return; } + // ); + // } + expr(p); + } + if p.at(T!['}']) { break; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index f9486f53c25..c4ffc6cadc8 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -704,6 +704,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/async_without_semicolon.rs"); } #[test] + fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); } + #[test] fn comma_after_functional_update_syntax() { run_and_expect_errors( "test_data/parser/inline/err/comma_after_functional_update_syntax.rs", diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast new file mode 100644 index 00000000000..306446e64dd --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast @@ -0,0 +1,50 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + WHITESPACE "\n " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "label" + WHITESPACE " " + NAME + IDENT "crashy" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 41: expected COMMA +error 50: expected asm operand diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs new file mode 100644 index 00000000000..6056f925e33 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs @@ -0,0 +1,5 @@ +fn foo() { + builtin#asm( + label crashy = { return; } + ); +} -- cgit 1.4.1-3-g733a5 From 069fb0f475c6e7398e4ef75c3f765415197707aa Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Nov 2024 11:03:36 +0100 Subject: Make bracket typing handler work on more things --- src/tools/rust-analyzer/crates/ide/src/typing.rs | 321 +++++++++++++-------- .../crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- src/tools/rust-analyzer/editors/code/src/client.ts | 2 +- 5 files changed, 199 insertions(+), 130 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 9bb5de9f2e3..5840719ff68 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -16,11 +16,11 @@ mod on_enter; use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use syntax::{ algo::{ancestors_at_offset, find_node_at_offset}, ast::{self, edit::IndentLevel, AstToken}, - AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, + AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, }; use ide_db::text_edit::TextEdit; @@ -47,6 +47,7 @@ struct ExtendedTextEdit { // - typing `.` in a chain method call auto-indents // - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression // - typing `{` in a use item adds a closing `}` in the right place +// - typing `>` to complete a return type `->` will insert a whitespace after it // // VS Code:: // @@ -66,55 +67,65 @@ pub(crate) fn on_char_typed( if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { return None; } - let file = &db.parse(EditionedFileId::current_edition(position.file_id)); - if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) { + // FIXME: We need to figure out the edition of the file here, but that means hitting the + // database for more than just parsing the file which is bad. + // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily + // causing the editor to feel sluggish! + let edition = Edition::CURRENT_FIXME; + let file = &db.parse(EditionedFileId::new(position.file_id, edition)); + let char_matches_position = + file.tree().syntax().text().char_at(position.offset) == Some(char_typed); + if !stdx::always!(char_matches_position) { return None; } - let edit = on_char_typed_inner(file, position.offset, char_typed)?; + + let edit = on_char_typed_(file, position.offset, char_typed, edition)?; + let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); sc.is_snippet = edit.is_snippet; Some(sc) } -fn on_char_typed_inner( +fn on_char_typed_( file: &Parse, offset: TextSize, char_typed: char, + edition: Edition, ) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - let conv = |text_edit: Option| { - Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) - }; match char_typed { - '.' => conv(on_dot_typed(&file.tree(), offset)), - '=' => conv(on_eq_typed(&file.tree(), offset)), - '<' => on_left_angle_typed(&file.tree(), offset), - '>' => conv(on_right_angle_typed(&file.tree(), offset)), - '{' => conv(on_opening_bracket_typed(file, offset, '{')), - '(' => conv(on_opening_bracket_typed(file, offset, '(')), + '.' => on_dot_typed(&file.tree(), offset), + '=' => on_eq_typed(&file.tree(), offset), + '>' => on_right_angle_typed(&file.tree(), offset), + '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), _ => None, } + .map(conv) +} + +fn conv(edit: TextEdit) -> ExtendedTextEdit { + ExtendedTextEdit { edit, is_snippet: false } } -/// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a +/// Inserts a closing delimiter when the user types an opening bracket, wrapping an existing expression in a /// block, or a part of a `use` item (for `{`). -fn on_opening_bracket_typed( +fn on_opening_delimiter_typed( file: &Parse, offset: TextSize, opening_bracket: char, + edition: Edition, ) -> Option { - let (closing_bracket, expected_ast_bracket) = match opening_bracket { - '{' => ('}', SyntaxKind::L_CURLY), - '(' => (')', SyntaxKind::L_PAREN), + type FilterFn = fn(SyntaxKind) -> bool; + let (closing_bracket, expected_ast_bracket, allowed_kinds) = match opening_bracket { + '{' => ('}', SyntaxKind::L_CURLY, &[ast::Expr::can_cast as FilterFn] as &[FilterFn]), + '(' => ( + ')', + SyntaxKind::L_PAREN, + &[ast::Expr::can_cast, ast::Pat::can_cast, ast::Type::can_cast] as &[FilterFn], + ), + '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, }; - if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some(opening_bracket)) { - return None; - } - let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; if brace_token.kind() != expected_ast_bracket { return None; @@ -125,58 +136,53 @@ fn on_opening_bracket_typed( if !stdx::always!(range.len() == TextSize::of(opening_bracket)) { return None; } - // FIXME: Edition - let file = file.reparse(range, "", span::Edition::CURRENT_FIXME); + let reparsed = file.reparse(range, "", edition).tree(); - if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) { + if let Some(edit) = + on_delimited_node_typed(&reparsed, offset, opening_bracket, closing_bracket, allowed_kinds) + { return Some(edit); } - if closing_bracket == '}' { - if let Some(edit) = brace_use_path(&file.tree(), offset) { - return Some(edit); - } + match opening_bracket { + '{' => on_left_brace_typed(&reparsed, offset), + '<' => on_left_angle_typed(&file.tree(), &reparsed, offset), + _ => None, } +} - return None; - - fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option { - let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; - if segment.syntax().text_range().start() != offset { - return None; - } - - let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; - - Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +fn on_left_brace_typed(reparsed: &SourceFile, offset: TextSize) -> Option { + let segment: ast::PathSegment = find_node_at_offset(reparsed.syntax(), offset)?; + if segment.syntax().text_range().start() != offset { + return None; } - fn bracket_expr( - file: &SourceFile, - offset: TextSize, - opening_bracket: char, - closing_bracket: char, - ) -> Option { - let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; - if expr.syntax().text_range().start() != offset { - return None; - } - - // Enclose the outermost expression starting at `offset` - while let Some(parent) = expr.syntax().parent() { - if parent.text_range().start() != expr.syntax().text_range().start() { - break; - } + let tree: ast::UseTree = find_node_at_offset(reparsed.syntax(), offset)?; - match ast::Expr::cast(parent) { - Some(parent) => expr = parent, - None => break, - } - } + Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +} - if let Some(parent) = expr.syntax().parent().and_then(ast::Expr::cast) { - let mut node = expr.syntax().clone(); - let all_prev_sib_attr = loop { +fn on_delimited_node_typed( + reparsed: &SourceFile, + offset: TextSize, + opening_bracket: char, + closing_bracket: char, + kinds: &[fn(SyntaxKind) -> bool], +) -> Option { + let t = reparsed.syntax().token_at_offset(offset).right_biased()?; + let (filter, node) = t + .parent_ancestors() + .take_while(|n| n.text_range().start() == offset) + .find_map(|n| kinds.iter().find(|&kind_filter| kind_filter(n.kind())).zip(Some(n)))?; + let mut node = node + .ancestors() + .take_while(|n| n.text_range().start() == offset && filter(n.kind())) + .last()?; + + if let Some(parent) = node.parent().filter(|it| filter(it.kind())) { + let all_prev_sib_attr = { + let mut node = node.clone(); + loop { match node.prev_sibling() { Some(sib) if sib.kind().is_trivia() || sib.kind() == SyntaxKind::ATTR => { node = sib @@ -184,21 +190,20 @@ fn on_opening_bracket_typed( Some(_) => break false, None => break true, }; - }; - - if all_prev_sib_attr { - expr = parent; } - } + }; - // Insert the closing bracket right after the expression. - Some(TextEdit::insert( - expr.syntax().text_range().end() + TextSize::of(opening_bracket), - closing_bracket.to_string(), - )) + if all_prev_sib_attr { + node = parent; + } } -} + // Insert the closing bracket right after the node. + Some(TextEdit::insert( + node.text_range().end() + TextSize::of(opening_bracket), + closing_bracket.to_string(), + )) +} /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. @@ -342,14 +347,15 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { } /// Add closing `>` for generic arguments/parameters. -fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('<')) { - return None; - } +fn on_left_angle_typed( + file: &SourceFile, + reparsed: &SourceFile, + offset: TextSize, +) -> Option { + let file_text = reparsed.syntax().text(); - // Find the next non-whitespace char in the line. - let mut next_offset = offset + TextSize::of('<'); + // Find the next non-whitespace char in the line, check if its a `>` + let mut next_offset = offset; while file_text.char_at(next_offset) == Some(' ') { next_offset += TextSize::of(' ') } @@ -357,23 +363,14 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option".to_owned()), - is_snippet: true, - }); - } - } - - if ancestors_at_offset(file.syntax(), offset).any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) - }) { - Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_owned()), - is_snippet: true, + if ancestors_at_offset(file.syntax(), offset) + .take_while(|n| !ast::Item::can_cast(n.kind())) + .any(|n| { + ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) }) + { + // Insert the closing bracket right after + Some(TextEdit::insert(offset + TextSize::of('<'), '>'.to_string())) } else { None } @@ -411,7 +408,7 @@ mod tests { let edit = TextEdit::insert(offset, char_typed.to_string()); edit.apply(&mut before); let parse = SourceFile::parse(&before, span::Edition::CURRENT_FIXME); - on_char_typed_inner(&parse, offset, char_typed).map(|it| { + on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT_FIXME).map(|it| { it.apply(&mut before); before.to_string() }) @@ -426,7 +423,7 @@ mod tests { fn type_char_noop(char_typed: char, ra_fixture_before: &str) { let file_change = do_type_char(char_typed, ra_fixture_before); - assert!(file_change.is_none()) + assert_eq!(file_change, None) } #[test] @@ -1066,6 +1063,81 @@ fn f() { ); } + #[test] + fn adds_closing_parenthesis_for_pat() { + type_char( + '(', + r#" +fn f() { match () { $0() => () } } +"#, + r#" +fn f() { match () { (()) => () } } +"#, + ); + type_char( + '(', + r#" +fn f($0n: ()) {} +"#, + r#" +fn f((n): ()) {} +"#, + ); + } + + #[test] + fn adds_closing_parenthesis_for_ty() { + type_char( + '(', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: (())) {} +"#, + ); + type_char( + '(', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: (a::b::::c)) {} +"#, + ); + } + + #[test] + fn adds_closing_angles_for_ty() { + type_char( + '<', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: <()>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: ::c>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: a$0b::::c) {} +"#, + r#" +fn f(n: a<>b::::c) {} +"#, + ); + } + #[test] fn parenthesis_noop_in_string_literal() { // Regression test for #9351 @@ -1154,6 +1226,12 @@ use $0Thing as _; type_char_noop( '(', r#" +use some::pa$0th::to::Item; + "#, + ); + type_char_noop( + '<', + r#" use some::pa$0th::to::Item; "#, ); @@ -1170,7 +1248,7 @@ fn foo() { "#, r#" fn foo() { - bar::<$0> + bar::<> } "#, ); @@ -1184,7 +1262,7 @@ fn foo(bar: &[u64]) { "#, r#" fn foo(bar: &[u64]) { - bar.iter().collect::<$0>(); + bar.iter().collect::<>(); } "#, ); @@ -1198,7 +1276,7 @@ fn foo(bar: &[u64]) { fn foo$0() {} "#, r#" -fn foo<$0>() {} +fn foo<>() {} "#, ); type_char( @@ -1207,7 +1285,7 @@ fn foo<$0>() {} fn foo$0 "#, r#" -fn foo<$0> +fn foo<> "#, ); type_char( @@ -1216,7 +1294,7 @@ fn foo<$0> struct Foo$0 {} "#, r#" -struct Foo<$0> {} +struct Foo<> {} "#, ); type_char( @@ -1225,7 +1303,7 @@ struct Foo<$0> {} struct Foo$0(); "#, r#" -struct Foo<$0>(); +struct Foo<>(); "#, ); type_char( @@ -1234,7 +1312,7 @@ struct Foo<$0>(); struct Foo$0 "#, r#" -struct Foo<$0> +struct Foo<> "#, ); type_char( @@ -1243,7 +1321,7 @@ struct Foo<$0> enum Foo$0 "#, r#" -enum Foo<$0> +enum Foo<> "#, ); type_char( @@ -1252,7 +1330,7 @@ enum Foo<$0> trait Foo$0 "#, r#" -trait Foo<$0> +trait Foo<> "#, ); type_char( @@ -1261,16 +1339,7 @@ trait Foo<$0> type Foo$0 = Bar; "#, r#" -type Foo<$0> = Bar; - "#, - ); - type_char( - '<', - r#" -impl$0 Foo {} - "#, - r#" -impl<$0> Foo {} +type Foo<> = Bar; "#, ); type_char( @@ -1279,7 +1348,7 @@ impl<$0> Foo {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); type_char( @@ -1288,7 +1357,7 @@ impl Foo<$0> {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index aa9f919679d..392bfbf15fe 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = Some("<".to_owned()), + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 96a2a5a27d3..a3172c7ca2c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 7529651ca7a..68c61e4bf62 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": "<", + "default": null, "type": [ "null", "string" diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index eac7b849fdb..4ce19f5c665 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -324,7 +324,7 @@ class ExperimentalFeatures implements lc.StaticFeature { } fillClientCapabilities(capabilities: lc.ClientCapabilities): void { capabilities.experimental = { - snippetTextEdit: true, + snippetTextEdit: false, codeActionGroup: true, hoverActions: true, serverStatusNotification: true, -- cgit 1.4.1-3-g733a5 From 2c91563eb5f0556696f6cf3192c9757474723a3e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 09:00:08 +0100 Subject: Add implict unsafety inlay hints for extern blocks --- .../rust-analyzer/crates/ide/src/inlay_hints.rs | 21 +++- .../crates/ide/src/inlay_hints/extern_block.rs | 138 +++++++++++++++++++++ 2 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 1ae8bfa9b6e..aa99ba49bc8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -29,6 +29,7 @@ mod closing_brace; mod closure_captures; mod closure_ret; mod discriminant; +mod extern_block; mod generic_param; mod implicit_drop; mod implicit_static; @@ -116,6 +117,7 @@ pub(crate) fn inlay_hints( #[derive(Default)] struct InlayHintCtx { lifetime_stacks: Vec>, + extern_block_parent: Option, } pub(crate) fn inlay_hints_resolve( @@ -174,12 +176,18 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent) -> Option { if ast::AnyHasGenericParams::can_cast(n.kind()) { ctx.lifetime_stacks.pop(); } + if ast::ExternBlock::can_cast(n.kind()) { + ctx.extern_block_parent = None; + } None } } @@ -234,12 +242,20 @@ fn hints( ast::Item(it) => match it { ast::Item::Fn(it) => { implicit_drop::hints(hints, famous_defs, config, file_id, &it); + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block); + } lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it) }, - // static type elisions - ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)), + ast::Item::Static(it) => { + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block); + } + implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)) + }, ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)), ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), + ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it), _ => None, }, // FIXME: trait object type elisions @@ -368,6 +384,7 @@ pub enum InlayKind { Type, Drop, RangeExclusive, + ExternUnsafety, } #[derive(Debug, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs new file mode 100644 index 00000000000..4cc4925cda6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -0,0 +1,138 @@ +//! Extern block hints +use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; +use span::EditionedFileId; +use syntax::{ast, AstNode, SyntaxToken}; + +use crate::{InlayHint, InlayHintsConfig}; + +pub(super) fn extern_block_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + extern_block: ast::ExternBlock, +) -> Option<()> { + if extern_block.unsafe_token().is_some() { + return None; + } + let abi = extern_block.abi()?; + acc.push(InlayHint { + range: abi.syntax().text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())), + resolve_parent: Some(extern_block.syntax().text_range()), + }); + Some(()) +} + +pub(super) fn fn_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + fn_: &ast::Fn, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = fn_.safe_token().is_none() && fn_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let fn_ = fn_.fn_token()?; + acc.push(item_hint(extern_block, fn_)); + Some(()) +} + +pub(super) fn static_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + static_: &ast::Static, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = static_.safe_token().is_none() && static_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let static_ = static_.static_token()?; + acc.push(item_hint(extern_block, static_)); + Some(()) +} + +fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { + InlayHint { + range: token.text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: { + let mut builder = TextEdit::builder(); + builder.insert(token.text_range().start(), "unsafe ".to_owned()); + if extern_block.unsafe_token().is_none() { + if let Some(abi) = extern_block.abi() { + builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); + } + } + Some(builder.finish()) + }, + resolve_parent: Some(extern_block.syntax().text_range()), + } +} + +#[cfg(test)] +mod tests { + use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG}; + + #[test] + fn unadorned() { + check_with_config( + DISABLED_CONFIG, + r#" + extern "C" { +//^^^^^^^^^^ unsafe + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } + + #[test] + fn adorned() { + check_with_config( + DISABLED_CONFIG, + r#" +unsafe extern "C" { + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } +} -- cgit 1.4.1-3-g733a5 From a086560b23fd1523bbb88a33b66a95a1f04b9c3c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 15:00:09 +0100 Subject: Improve heuristics for on typing semicolon insertion --- src/tools/rust-analyzer/crates/ide/src/typing.rs | 27 ++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 5840719ff68..cfa1d6ff031 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -15,6 +15,8 @@ mod on_enter; +use std::iter; + use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; use span::{Edition, EditionedFileId}; use syntax::{ @@ -120,7 +122,8 @@ fn on_opening_delimiter_typed( '(' => ( ')', SyntaxKind::L_PAREN, - &[ast::Expr::can_cast, ast::Pat::can_cast, ast::Type::can_cast] as &[FilterFn], + &[ast::Expr::can_cast as FilterFn, ast::Pat::can_cast, ast::Type::can_cast] + as &[FilterFn], ), '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, @@ -208,7 +211,18 @@ fn on_delimited_node_typed( /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) { + let text = file.syntax().text(); + if !stdx::always!(text.char_at(offset) == Some('=')) { + return None; + } + + let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) + .filter_map(|offset| text.char_at(offset)) + .find(|&c| !c.is_whitespace() || c == '\n') + == Some('n'); + // don't attempt to add `;` if there is a newline after the `=`, the intent is likely to write + // out the expression afterwards! + if has_newline { return None; } @@ -466,6 +480,15 @@ fn foo() { let foo =$0 let bar = 1; } +", + ); + type_char_noop( + '=', + r" +fn foo() { + let foo =$0 + 1 + 1 +} ", ); } -- cgit 1.4.1-3-g733a5 From 3fe75c7d90e9e42dbbc7c6542337a68ff9b817cf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 15:35:13 +0100 Subject: Add typing handler for param list pipe --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 2 + src/tools/rust-analyzer/crates/ide/src/typing.rs | 67 ++++++++++++++++++---- .../crates/rust-analyzer/src/config.rs | 4 +- .../crates/rust-analyzer/src/lsp/capabilities.rs | 17 ++---- .../rust-analyzer/docs/user/generated_config.adoc | 4 +- src/tools/rust-analyzer/editors/code/package.json | 4 +- 6 files changed, 69 insertions(+), 29 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b43685ffeed..c960b88a3e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -402,6 +402,8 @@ impl Analysis { self.with_db(|db| typing::on_enter(db, position)) } + pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS; + /// Returns an edit which should be applied after a character was typed. /// /// This is useful for some on-the-fly fixups, like adding `;` to `let =` diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index cfa1d6ff031..3d9146cc4c7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -32,7 +32,7 @@ use crate::SourceChange; pub(crate) use on_enter::on_enter; // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{("; +pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|"; struct ExtendedTextEdit { edit: TextEdit, @@ -99,6 +99,7 @@ fn on_char_typed_( '=' => on_eq_typed(&file.tree(), offset), '>' => on_right_angle_typed(&file.tree(), offset), '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), + '|' => on_pipe_typed(&file.tree(), offset), _ => None, } .map(conv) @@ -212,10 +213,6 @@ fn on_delimited_node_typed( // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { let text = file.syntax().text(); - if !stdx::always!(text.char_at(offset) == Some('=')) { - return None; - } - let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) .filter_map(|offset| text.char_at(offset)) .find(|&c| !c.is_whitespace() || c == '\n') @@ -308,9 +305,6 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) { - return None; - } let whitespace = file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; @@ -380,7 +374,9 @@ fn on_left_angle_typed( if ancestors_at_offset(file.syntax(), offset) .take_while(|n| !ast::Item::can_cast(n.kind())) .any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) + ast::GenericParamList::can_cast(n.kind()) + || ast::GenericArgList::can_cast(n.kind()) + || ast::UseBoundGenericArgs::can_cast(n.kind()) }) { // Insert the closing bracket right after @@ -390,12 +386,21 @@ fn on_left_angle_typed( } } +fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option { + let pipe_token = file.syntax().token_at_offset(offset).right_biased()?; + if pipe_token.kind() != SyntaxKind::PIPE { + return None; + } + if pipe_token.parent().and_then(ast::ParamList::cast)?.r_paren_token().is_some() { + return None; + } + let after_lpipe = offset + TextSize::of('|'); + Some(TextEdit::insert(after_lpipe, "|".to_owned())) +} + /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option { let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('>')) { - return None; - } let after_arrow = offset + TextSize::of('>'); if file_text.char_at(after_arrow) != Some('{') { return None; @@ -1527,6 +1532,44 @@ fn foo() { ) $0 } +"#, + ); + } + + #[test] + fn completes_pipe_param_list() { + type_char( + '|', + r#" +fn foo() { + $0 +} +"#, + r#" +fn foo() { + || +} +"#, + ); + type_char( + '|', + r#" +fn foo() { + $0 a +} +"#, + r#" +fn foo() { + || a +} +"#, + ); + type_char_noop( + '|', + r#" +fn foo() { + let $0 +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 392bfbf15fe..0fdc48a0e7a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,8 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. + typing_excludeChars: Option = Some('<'.to_string()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index bd496e8ddc3..82e6ae2b49c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -72,9 +72,12 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), _ => Some(OneOf::Left(false)), }, - document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { - first_trigger_character: "=".to_owned(), - more_trigger_character: Some(more_trigger_character(config)), + document_on_type_formatting_provider: Some({ + let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars(); + DocumentOnTypeFormattingOptions { + first_trigger_character: chars.next().unwrap().to_string(), + more_trigger_character: Some(chars.map(|c| c.to_string()).collect()), + } }), selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), @@ -528,11 +531,3 @@ impl ClientCapabilities { .unwrap_or_default() } } - -fn more_trigger_character(config: &Config) -> Vec { - let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()]; - if config.snippet_cap().is_some() { - res.push("<".to_owned()); - } - res -} diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c..715f8d43adc 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,10 +992,10 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- -Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. -- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf62..70d26c97078 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2606,8 +2606,8 @@ "title": "typing", "properties": { "rust-analyzer.typing.excludeChars": { - "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", + "default": "<", "type": [ "null", "string" -- cgit 1.4.1-3-g733a5 From fbd671373b39918b4714dcb154748471fe559eeb Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 16 Nov 2024 20:01:05 -0500 Subject: fix: Properly determine `SyntaxEditor` replacement intersection Bordering replacements should not be considered intersecting --- src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index b769c941105..44a1fae23be 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -73,7 +73,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { }) .all(|(l, r)| { get_node_depth(l.target_parent()) != get_node_depth(r.target_parent()) - || l.target_range().intersect(r.target_range()).is_none() + || (l.target_range().end() <= r.target_range().start()) }); if stdx::never!( -- cgit 1.4.1-3-g733a5 From 25c0a002ea10cec7076656547dccb8df700f3b6d Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sun, 17 Nov 2024 15:36:57 -0500 Subject: fix: Don't produce `ChangedAncestor` for `SyntaxToken`s --- .../crates/syntax/src/syntax_editor.rs | 48 +++++++++++++++++++++- .../crates/syntax/src/syntax_editor/edit_algo.rs | 14 +++---- 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 7e5d0f27e0a..992a847663a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -327,7 +327,7 @@ mod tests { use crate::{ ast::{self, make, syntax_factory::SyntaxFactory}, - AstNode, + AstNode, SyntaxKind, }; use super::*; @@ -540,4 +540,50 @@ mod tests { }"#]]; expect.assert_eq(&edit.new_root.to_string()); } + + #[test] + fn test_replace_token_in_parent() { + let parent_fn = make::fn_( + None, + make::name("it"), + None, + None, + make::param_list(None, []), + make::block_expr([], Some(make::expr_unit())), + Some(make::ret_type(make::ty_unit())), + false, + false, + false, + false, + ); + + let mut editor = SyntaxEditor::new(parent_fn.syntax().clone()); + + if let Some(ret_ty) = parent_fn.ret_type() { + editor.delete(ret_ty.syntax().clone()); + + if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token() { + if token.kind().is_trivia() { + editor.delete(token); + } + } + } + + if let Some(tail) = parent_fn.body().unwrap().tail_expr() { + // FIXME: We do this because `xtask tidy` will not allow us to have trailing whitespace in the expect string. + if let Some(SyntaxElement::Token(token)) = tail.syntax().prev_sibling_or_token() { + if let SyntaxKind::WHITESPACE = token.kind() { + editor.delete(token); + } + } + editor.delete(tail.syntax().clone()); + } + + let edit = editor.finish(); + + let expect = expect![[r#" +fn it() { +}"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index 44a1fae23be..71b69dbec1d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -128,13 +128,14 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { // Add to changed ancestors, if applicable match change { - Change::Insert(_, _) | Change::InsertAll(_, _) => {} - Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + Change::Replace(SyntaxElement::Node(target), _) + | Change::ReplaceWithMany(SyntaxElement::Node(target), _) => { changed_ancestors.push_back(ChangedAncestor::single(target, change_index)) } Change::ReplaceAll(range, _) => { changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index)) } + _ => (), } } @@ -304,13 +305,8 @@ enum ChangedAncestorKind { } impl ChangedAncestor { - fn single(element: &SyntaxElement, change_index: usize) -> Self { - let kind = match element { - SyntaxElement::Node(node) => ChangedAncestorKind::Single { node: node.clone() }, - SyntaxElement::Token(token) => { - ChangedAncestorKind::Single { node: token.parent().unwrap() } - } - }; + fn single(node: &SyntaxNode, change_index: usize) -> Self { + let kind = ChangedAncestorKind::Single { node: node.clone() }; Self { kind, change_index } } -- cgit 1.4.1-3-g733a5 From 8877598a1d6fd44f569daf80444a6918012c003a Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:34:12 -0500 Subject: minor: Add `token` constructor to `SyntaxFactory` --- .../crates/syntax/src/ast/syntax_factory/constructors.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 8b061094073..0d8fe4cd23a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, - AstNode, + AstNode, SyntaxKind, SyntaxToken, }; use super::SyntaxFactory; @@ -151,4 +151,8 @@ impl SyntaxFactory { ast } + + pub fn token(&self, kind: SyntaxKind) -> SyntaxToken { + make::token(kind) + } } -- cgit 1.4.1-3-g733a5 From 0eed1970144b5333b7b4bc997a41e33a226a1fdd Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:16:06 -0500 Subject: minor: Add `expr_bin` constructor to `SyntaxFactory` --- .../syntax/src/ast/syntax_factory/constructors.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 0d8fe4cd23a..944724ff05c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -80,6 +80,23 @@ impl SyntaxFactory { ast } + pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr { + let ast::Expr::BinExpr(ast) = + make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lhs.syntax().clone(), ast.lhs().unwrap().syntax().clone()); + builder.map_node(rhs.syntax().clone(), ast.rhs().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_path(&self, path: ast::Path) -> ast::Expr { let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else { unreachable!() -- cgit 1.4.1-3-g733a5 From ff6b0205123fef6c5c73fd068576d7ac30fafb16 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:23:27 -0500 Subject: feat: Migrate `flip_binexpr` assist to `SyntaxEditor` --- .../ide-assists/src/handlers/flip_binexpr.rs | 55 ++++++++++++---------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs index 8b46a23f9a6..601fd29f8e7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs @@ -1,4 +1,7 @@ -use syntax::ast::{self, AstNode, BinExpr}; +use syntax::{ + ast::{self, syntax_factory::SyntaxFactory, AstNode, BinExpr}, + SyntaxKind, T, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -19,22 +22,17 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let expr = ctx.find_node_at_offset::()?; - let rhs = expr.rhs()?.syntax().clone(); - let lhs = expr.lhs()?.syntax().clone(); - - let lhs = if let Some(bin_expr) = BinExpr::cast(lhs.clone()) { - if bin_expr.op_kind() == expr.op_kind() { - bin_expr.rhs()?.syntax().clone() - } else { - lhs - } - } else { - lhs + let lhs = expr.lhs()?; + let rhs = expr.rhs()?; + + let lhs = match &lhs { + ast::Expr::BinExpr(bin_expr) if bin_expr.op_kind() == expr.op_kind() => bin_expr.rhs()?, + _ => lhs, }; - let op_range = expr.op_token()?.text_range(); + let op_token = expr.op_token()?; // The assist should be applied only if the cursor is on the operator - let cursor_in_range = op_range.contains_range(ctx.selection_trimmed()); + let cursor_in_range = op_token.text_range().contains_range(ctx.selection_trimmed()); if !cursor_in_range { return None; } @@ -47,13 +45,18 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add( AssistId("flip_binexpr", AssistKind::RefactorRewrite), "Flip binary expression", - op_range, - |edit| { - if let FlipAction::FlipAndReplaceOp(new_op) = action { - edit.replace(op_range, new_op); - } - edit.replace(lhs.text_range(), rhs.text()); - edit.replace(rhs.text_range(), lhs.text()); + op_token.text_range(), + |builder| { + let mut editor = builder.make_editor(&expr.syntax().parent().unwrap()); + let make = SyntaxFactory::new(); + if let FlipAction::FlipAndReplaceOp(binary_op) = action { + editor.replace(op_token, make.token(binary_op)) + }; + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(lhs.syntax(), rhs.syntax().clone_for_update()); + editor.replace(rhs.syntax(), lhs.syntax().clone_for_update()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } @@ -62,7 +65,7 @@ enum FlipAction { // Flip the expression Flip, // Flip the expression and replace the operator with this string - FlipAndReplaceOp(&'static str), + FlipAndReplaceOp(SyntaxKind), // Do not flip the expression DontFlip, } @@ -73,10 +76,10 @@ impl From for FlipAction { ast::BinaryOp::Assignment { .. } => FlipAction::DontFlip, ast::BinaryOp::CmpOp(ast::CmpOp::Ord { ordering, strict }) => { let rev_op = match (ordering, strict) { - (ast::Ordering::Less, true) => ">", - (ast::Ordering::Less, false) => ">=", - (ast::Ordering::Greater, true) => "<", - (ast::Ordering::Greater, false) => "<=", + (ast::Ordering::Less, true) => T![>], + (ast::Ordering::Less, false) => T![>=], + (ast::Ordering::Greater, true) => T![<], + (ast::Ordering::Greater, false) => T![<=], }; FlipAction::FlipAndReplaceOp(rev_op) } -- cgit 1.4.1-3-g733a5 From 418ad88045b0a7862508293662eb30f5aeff4b75 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:49:19 -0500 Subject: feat: Migrate `flip_trait_bound` assist to `SyntaxEditor` --- .../crates/ide-assists/src/handlers/flip_trait_bound.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs index 70b5efcb645..03366bd8616 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs @@ -23,11 +23,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let plus = ctx.find_token_syntax_at_offset(T![+])?; // Make sure we're in a `TypeBoundList` - ast::TypeBoundList::cast(plus.parent()?)?; + let parent = ast::TypeBoundList::cast(plus.parent()?)?; let (before, after) = ( - non_trivia_sibling(plus.clone().into(), Direction::Prev)?, - non_trivia_sibling(plus.clone().into(), Direction::Next)?, + non_trivia_sibling(plus.clone().into(), Direction::Prev)?.into_node()?, + non_trivia_sibling(plus.clone().into(), Direction::Next)?.into_node()?, ); let target = plus.text_range(); @@ -35,9 +35,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op AssistId("flip_trait_bound", AssistKind::RefactorRewrite), "Flip trait bounds", target, - |edit| { - edit.replace(before.text_range(), after.to_string()); - edit.replace(after.text_range(), before.to_string()); + |builder| { + let mut editor = builder.make_editor(parent.syntax()); + editor.replace(before.clone(), after.clone_for_update()); + editor.replace(after.clone(), before.clone_for_update()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } -- cgit 1.4.1-3-g733a5 From 806ffb7dbaa1067b6a62a98c3b239ba29fe4e9a4 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 23 Nov 2024 12:41:48 -0500 Subject: minor: Add `token_tree` constructor to `SyntaxFactory` --- .../syntax/src/ast/syntax_factory/constructors.rs | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 944724ff05c..54f17bd721d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, - AstNode, SyntaxKind, SyntaxToken, + AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; use super::SyntaxFactory; @@ -169,6 +169,32 @@ impl SyntaxFactory { ast } + pub fn token_tree( + &self, + delimiter: SyntaxKind, + tt: Vec>, + ) -> ast::TokenTree { + let tt: Vec<_> = tt.into_iter().collect(); + let input: Vec<_> = tt.iter().cloned().filter_map(only_nodes).collect(); + + let ast = make::token_tree(delimiter, tt).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + input.into_iter(), + ast.token_trees_and_tokens().filter_map(only_nodes), + ); + builder.finish(&mut mapping); + } + + return ast; + + fn only_nodes(element: NodeOrToken) -> Option { + element.as_node().map(|it| it.syntax().clone()) + } + } + pub fn token(&self, kind: SyntaxKind) -> SyntaxToken { make::token(kind) } -- cgit 1.4.1-3-g733a5 From 254198c340ba3efc0d0f2daa99af49d3582fd533 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 23 Nov 2024 12:42:49 -0500 Subject: feat: Migrate `flip_comma` assist to `SyntaxEditor` --- .../crates/ide-assists/src/handlers/flip_comma.rs | 122 +++++++++++++-------- 1 file changed, 79 insertions(+), 43 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs index af2c2c759ec..490a9ee3c04 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs @@ -1,7 +1,8 @@ -use ide_db::base_db::SourceDatabase; -use syntax::TextSize; use syntax::{ - algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, SyntaxToken, TextRange, T, + algo::non_trivia_sibling, + ast::{self, syntax_factory::SyntaxFactory}, + syntax_editor::{Element, SyntaxMapping}, + AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxToken, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,8 +26,6 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let comma = ctx.find_token_syntax_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; - let (mut prev_text, mut next_text) = (prev.to_string(), next.to_string()); - let (mut prev_range, mut next_range) = (prev.text_range(), next.text_range()); // Don't apply a "flip" in case of a last comma // that typically comes before punctuation @@ -40,53 +39,85 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( return None; } - if let Some(parent) = comma.parent().and_then(ast::TokenTree::cast) { - // An attribute. It often contains a path followed by a token tree (e.g. `align(2)`), so we have - // to be smarter. - let prev_start = - match comma.siblings_with_tokens(Direction::Prev).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_after_token(it.as_token().unwrap()), - None => position_after_token(&parent.left_delimiter_token()?), - }; - let prev_end = prev.text_range().end(); - let next_start = next.text_range().start(); - let next_end = - match comma.siblings_with_tokens(Direction::Next).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_before_token(it.as_token().unwrap()), - None => position_before_token(&parent.right_delimiter_token()?), - }; - prev_range = TextRange::new(prev_start, prev_end); - next_range = TextRange::new(next_start, next_end); - let file_text = ctx.db().file_text(ctx.file_id().file_id()); - prev_text = file_text[prev_range].to_owned(); - next_text = file_text[next_range].to_owned(); - } + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + let prev = match prev { + SyntaxElement::Node(node) => node.clone_for_update().syntax_element(), + _ => prev, + }; + let next = match next { + SyntaxElement::Node(node) => node.clone_for_update().syntax_element(), + _ => next, + }; acc.add( AssistId("flip_comma", AssistKind::RefactorRewrite), "Flip comma", comma.text_range(), - |edit| { - edit.replace(prev_range, next_text); - edit.replace(next_range, prev_text); + |builder| { + let parent = comma.parent().unwrap(); + let mut editor = builder.make_editor(&parent); + + if let Some(parent) = ast::TokenTree::cast(parent) { + // An attribute. It often contains a path followed by a + // token tree (e.g. `align(2)`), so we have to be smarter. + let (new_tree, mapping) = flip_tree(parent.clone(), comma); + editor.replace(parent.syntax(), new_tree.syntax()); + editor.add_mappings(mapping); + } else { + editor.replace(prev.clone(), next.clone()); + editor.replace(next.clone(), prev.clone()); + } + + builder.add_file_edits(ctx.file_id(), editor); }, ) } -fn position_before_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Prev) { - Some(prev_token) => prev_token.text_range().end(), - None => token.text_range().start(), - } -} - -fn position_after_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Next) { - Some(prev_token) => prev_token.text_range().start(), - None => token.text_range().end(), - } +fn flip_tree(tree: ast::TokenTree, comma: SyntaxToken) -> (ast::TokenTree, SyntaxMapping) { + let mut tree_iter = tree.token_trees_and_tokens(); + let before: Vec<_> = + tree_iter.by_ref().take_while(|it| it.as_token() != Some(&comma)).collect(); + let after: Vec<_> = tree_iter.collect(); + + let not_ws = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() != SyntaxKind::WHITESPACE, + NodeOrToken::Node(_) => true, + }; + + let is_comma = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() == T![,], + NodeOrToken::Node(_) => false, + }; + + let prev_start_untrimmed = match before.iter().rposition(is_comma) { + Some(pos) => pos + 1, + None => 1, + }; + let prev_end = 1 + before.iter().rposition(not_ws).unwrap(); + let prev_start = prev_start_untrimmed + + before[prev_start_untrimmed..prev_end].iter().position(not_ws).unwrap(); + + let next_start = after.iter().position(not_ws).unwrap(); + let next_end_untrimmed = match after.iter().position(is_comma) { + Some(pos) => pos, + None => after.len() - 1, + }; + let next_end = 1 + after[..next_end_untrimmed].iter().rposition(not_ws).unwrap(); + + let result = [ + &before[1..prev_start], + &after[next_start..next_end], + &before[prev_end..], + &[NodeOrToken::Token(comma)], + &after[..next_start], + &before[prev_start..prev_end], + &after[next_end..after.len() - 1], + ] + .concat(); + + let make = SyntaxFactory::new(); + let new_token_tree = make.token_tree(tree.left_delimiter_token().unwrap().kind(), result); + (new_token_tree, make.finish_with_mappings()) } #[cfg(test)] @@ -147,4 +178,9 @@ mod tests { r#"#[foo(bar, qux, baz(1 + 1), other)] struct Foo;"#, ); } + + #[test] + fn flip_comma_attribute_incomplete() { + check_assist_not_applicable(flip_comma, r#"#[repr(align(2),$0)] struct Foo;"#); + } } -- cgit 1.4.1-3-g733a5 From 667697eac6e11dc6197e4485de589b59a32bf76d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 16:26:00 +0100 Subject: Highlight right angle as part of fat arrow in macro rules arm --- .../crates/ide/src/syntax_highlighting/highlight.rs | 8 ++++++++ .../test_data/highlight_block_mod_items.html | 2 +- .../src/syntax_highlighting/test_data/highlight_const.html | 4 ++-- .../src/syntax_highlighting/test_data/highlight_doctest.html | 4 ++-- .../test_data/highlight_keywords_2015.html | 2 +- .../test_data/highlight_keywords_2018.html | 2 +- .../test_data/highlight_keywords_2021.html | 2 +- .../test_data/highlight_keywords_2024.html | 2 +- .../src/syntax_highlighting/test_data/highlight_macros.html | 12 ++++++------ .../src/syntax_highlighting/test_data/highlight_strings.html | 8 ++++---- .../src/syntax_highlighting/test_data/highlight_unsafe.html | 4 ++-- 11 files changed, 29 insertions(+), 21 deletions(-) (limited to 'src/tools') diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 96375937a12..3767a3917ce 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -151,6 +151,14 @@ fn punctuation( T!['['] | T![']'] => HlPunct::Bracket, T!['{'] | T!['}'] => HlPunct::Brace, T!['('] | T![')'] => HlPunct::Parenthesis, + T![>] + if parent + .as_ref() + .and_then(SyntaxNode::parent) + .map_or(false, |it| it.kind() == MACRO_RULES) => + { + return HlOperator::Other.into() + } T![<] | T![>] => HlPunct::Angle, T![,] => HlPunct::Comma, T![:] => HlPunct::Colon, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html index 70f2d7203e9..edd9639768a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
macro_rules! foo {
-    ($foo:ident) => {
+    ($foo:ident) => {
         mod y {
             pub struct $foo;
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
index a14f2cc88cd..05289cfe3fe 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -46,7 +46,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
 
macro_rules! id {
-    ($($tt:tt)*) => {
+    ($($tt:tt)*) => {
         $($tt)*
     };
 }
@@ -79,7 +79,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 
 macro_rules! unsafe_deref {
-    () => {
+    () => {
         *(&() as *const ())
     };
 }
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 35650bbe87f..aa9d23250c1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -147,11 +147,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } /// ``` -/// macro_rules! noop { ($expr:expr) => { $expr }} +/// macro_rules! noop { ($expr:expr) => { $expr }} /// noop!(1); /// ``` macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html index a790b385786..c2bf94fd9b6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html index 6dac066bfaa..a30d16d5327 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html index 6dac066bfaa..a30d16d5327 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html index 4ccc4079908..b82a3f9f819 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index 196552020ab..06673d1a73c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } Foo struct } macro_rules! def_fn { - ($($tt:tt)*) => {$($tt)*} + ($($tt:tt)*) => {$($tt)*} } def_fn! { @@ -64,24 +64,24 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! dont_color_me_braces { - () => {0} + () => {0} } macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } /// textually shadow previous definition macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } macro_rules! keyword_frag { - ($type:ty) => ($type) + ($type:ty) => ($type) } macro with_args($i:ident) { @@ -95,7 +95,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! id { - ($($tt:tt)*) => { + ($($tt:tt)*) => { $($tt)* }; } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 5594a36e731..1385ae0510a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
macro_rules! println {
-    ($($arg:tt)*) => ({
+    ($($arg:tt)*) => ({
         $crate::io::_print(format_args_nl!($($arg)*));
     })
 }
@@ -74,12 +74,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 
 macro_rules! toho {
-    () => ($crate::panic!("not yet implemented"));
-    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
+    () => ($crate::panic!("not yet implemented"));
+    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
 }
 
 macro_rules! reuse_twice {
-    ($literal:literal) => {{stringify!($literal); format_args!($literal)}};
+    ($literal:literal) => {{stringify!($literal); format_args!($literal)}};
 }
 
 fn main() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index be6176894b4..4e69c82f3da 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -46,12 +46,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
 
macro_rules! id {
-    ($($tt:tt)*) => {
+    ($($tt:tt)*) => {
         $($tt)*
     };
 }
 macro_rules! unsafe_deref {
-    () => {
+    () => {
         *(&() as *const ())
     };
 }
-- 
cgit 1.4.1-3-g733a5


From 29a66316ad6e86568e120153e60362d563ed8ae9 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 6 Dec 2024 17:06:18 +0100
Subject: Temporarily disable completion resolve support for helix

---
 .../crates/rust-analyzer/src/bin/main.rs           | 12 ++------
 .../crates/rust-analyzer/src/config.rs             | 34 +++++++++++++++++-----
 .../crates/rust-analyzer/src/lsp/capabilities.rs   |  6 +++-
 3 files changed, 33 insertions(+), 19 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index e872585c571..eac33be5664 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -20,7 +20,6 @@ use rust_analyzer::{
     config::{Config, ConfigChange, ConfigErrors},
     from_json,
 };
-use semver::Version;
 use tracing_subscriber::fmt::writer::BoxMakeWriter;
 use vfs::AbsPathBuf;
 
@@ -204,18 +203,12 @@ fn run_server() -> anyhow::Result<()> {
         }
     };
 
-    let mut visual_studio_code_version = None;
-    if let Some(client_info) = client_info {
+    if let Some(client_info) = &client_info {
         tracing::info!(
             "Client '{}' {}",
             client_info.name,
             client_info.version.as_deref().unwrap_or_default()
         );
-        visual_studio_code_version = client_info
-            .name
-            .starts_with("Visual Studio Code")
-            .then(|| client_info.version.as_deref().map(Version::parse).and_then(Result::ok))
-            .flatten();
     }
 
     let workspace_roots = workspace_folders
@@ -230,8 +223,7 @@ fn run_server() -> anyhow::Result<()> {
         })
         .filter(|workspaces| !workspaces.is_empty())
         .unwrap_or_else(|| vec![root_path.clone()]);
-    let mut config =
-        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version);
+    let mut config = Config::new(root_path, capabilities, workspace_roots, client_info);
     if let Some(json) = initialization_options {
         let mut change = ConfigChange::default();
         change.change_client_config(json);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 0fdc48a0e7a..a4f9246a587 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -730,6 +730,12 @@ enum RatomlFile {
     Crate(LocalConfigInput),
 }
 
+#[derive(Clone, Debug)]
+struct ClientInfo {
+    name: String,
+    version: Option,
+}
+
 #[derive(Clone)]
 pub struct Config {
     /// Projects that have a Cargo.toml or a rust-project.json in a
@@ -744,7 +750,7 @@ pub struct Config {
     caps: ClientCapabilities,
     root_path: AbsPathBuf,
     snippets: Vec,
-    visual_studio_code_version: Option,
+    client_info: Option,
 
     default_config: &'static DefaultConfigData,
     /// Config node that obtains its initial value during the server initialization and
@@ -777,7 +783,7 @@ impl fmt::Debug for Config {
             .field("caps", &self.caps)
             .field("root_path", &self.root_path)
             .field("snippets", &self.snippets)
-            .field("visual_studio_code_version", &self.visual_studio_code_version)
+            .field("client_info", &self.client_info)
             .field("client_config", &self.client_config)
             .field("user_config", &self.user_config)
             .field("ratoml_file", &self.ratoml_file)
@@ -1335,7 +1341,7 @@ impl Config {
         root_path: AbsPathBuf,
         caps: lsp_types::ClientCapabilities,
         workspace_roots: Vec,
-        visual_studio_code_version: Option,
+        client_info: Option,
     ) -> Self {
         static DEFAULT_CONFIG_DATA: OnceLock<&'static DefaultConfigData> = OnceLock::new();
 
@@ -1346,7 +1352,10 @@ impl Config {
             root_path,
             snippets: Default::default(),
             workspace_roots,
-            visual_studio_code_version,
+            client_info: client_info.map(|it| ClientInfo {
+                name: it.name,
+                version: it.version.as_deref().map(Version::parse).and_then(Result::ok),
+            }),
             client_config: (FullConfigInput::default(), ConfigErrors(vec![])),
             default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())),
             source_root_parent_map: Arc::new(FxHashMap::default()),
@@ -1446,9 +1455,11 @@ impl Config {
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
             term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
-            fields_to_resolve: CompletionFieldsToResolve::from_client_capabilities(
-                &client_capability_fields,
-            ),
+            fields_to_resolve: if self.client_is_helix() {
+                CompletionFieldsToResolve::empty()
+            } else {
+                CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields)
+            },
         }
     }
 
@@ -2163,7 +2174,14 @@ impl Config {
     // VSCode is our reference implementation, so we allow ourselves to work around issues by
     // special casing certain versions
     pub fn visual_studio_code_version(&self) -> Option<&Version> {
-        self.visual_studio_code_version.as_ref()
+        self.client_info
+            .as_ref()
+            .filter(|it| it.name.starts_with("Visual Studio Code"))
+            .and_then(|it| it.version.as_ref())
+    }
+
+    pub fn client_is_helix(&self) -> bool {
+        self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default()
     }
 }
 // Deserialization definitions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 82e6ae2b49c..03628212094 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -41,7 +41,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
-            resolve_provider: Some(config.caps().completions_resolve_provider()),
+            resolve_provider: if config.client_is_helix() {
+                None
+            } else {
+                Some(config.caps().completions_resolve_provider())
+            },
             trigger_characters: Some(vec![
                 ":".to_owned(),
                 ".".to_owned(),
-- 
cgit 1.4.1-3-g733a5


From 78496f845d198f79d546365445e904ad4e50f95c Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 6 Dec 2024 17:10:24 +0100
Subject: Temporarily disable completion resolve support for neovim

---
 src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs          | 6 +++++-
 .../rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs      | 4 ++--
 2 files changed, 7 insertions(+), 3 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index a4f9246a587..dd7351bcf26 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -1455,7 +1455,7 @@ impl Config {
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
             term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
-            fields_to_resolve: if self.client_is_helix() {
+            fields_to_resolve: if self.client_is_helix() || self.client_is_neovim() {
                 CompletionFieldsToResolve::empty()
             } else {
                 CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields)
@@ -2183,6 +2183,10 @@ impl Config {
     pub fn client_is_helix(&self) -> bool {
         self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default()
     }
+
+    pub fn client_is_neovim(&self) -> bool {
+        self.client_info.as_ref().map(|it| it.name == "Neovim").unwrap_or_default()
+    }
 }
 // Deserialization definitions
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 03628212094..6d73319e67b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -41,8 +41,8 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
-            resolve_provider: if config.client_is_helix() {
-                None
+            resolve_provider: if config.client_is_helix() || config.client_is_neovim() {
+                config.completion_item_edit_resolve().then_some(true)
             } else {
                 Some(config.caps().completions_resolve_provider())
             },
-- 
cgit 1.4.1-3-g733a5


From 0a48b96859d3d66138082ffad6a1057b54cd55c7 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Sat, 7 Dec 2024 12:35:30 +1100
Subject: Move more tests into `tests/ui/link-native-libs`

---
 src/tools/tidy/src/issues.txt                      |  10 +-
 src/tools/tidy/src/ui_tests.rs                     |   2 +-
 tests/ui/issues/issue-43925.rs                     |   4 -
 tests/ui/issues/issue-43925.stderr                 |   8 --
 tests/ui/issues/issue-43926.rs                     |   4 -
 tests/ui/issues/issue-43926.stderr                 |   8 --
 .../issue-70093/issue-70093-link-directives.rs     |  10 --
 tests/ui/issues/issue-70093/issue-70093.rs         |  10 --
 .../auxiliary/link-cfg-works-transitive-dylib.rs   |   4 +
 .../auxiliary/link-cfg-works-transitive-rlib.rs    |   7 +
 tests/ui/link-native-libs/issue-109144.rs          |   4 +
 tests/ui/link-native-libs/issue-109144.stderr      |   9 ++
 tests/ui/link-native-libs/issue-43925.rs           |   4 +
 tests/ui/link-native-libs/issue-43925.stderr       |   8 ++
 tests/ui/link-native-libs/issue-43926.rs           |   4 +
 tests/ui/link-native-libs/issue-43926.stderr       |   8 ++
 .../issue-70093/issue-70093-link-directives.rs     |  10 ++
 .../ui/link-native-libs/issue-70093/issue-70093.rs |  10 ++
 tests/ui/link-native-libs/kind-framework.rs        |   7 +
 tests/ui/link-native-libs/kind-framework.stderr    |   9 ++
 .../link-native-libs/link-attr-validation-early.rs |   8 ++
 .../link-attr-validation-early.stderr              |  21 +++
 .../link-native-libs/link-attr-validation-late.rs  |  39 ++++++
 .../link-attr-validation-late.stderr               | 147 +++++++++++++++++++++
 tests/ui/link-native-libs/link-cfg-works.rs        |  13 ++
 tests/ui/link-native-libs/uikit-framework.rs       |  25 ++++
 .../auxiliary/link-cfg-works-transitive-dylib.rs   |   4 -
 .../auxiliary/link-cfg-works-transitive-rlib.rs    |   7 -
 tests/ui/linkage-attr/issue-109144.rs              |   4 -
 tests/ui/linkage-attr/issue-109144.stderr          |   9 --
 tests/ui/linkage-attr/kind-framework.rs            |   7 -
 tests/ui/linkage-attr/kind-framework.stderr        |   9 --
 .../ui/linkage-attr/link-attr-validation-early.rs  |   8 --
 .../linkage-attr/link-attr-validation-early.stderr |  21 ---
 tests/ui/linkage-attr/link-attr-validation-late.rs |  39 ------
 .../linkage-attr/link-attr-validation-late.stderr  | 147 ---------------------
 tests/ui/linkage-attr/link-cfg-works.rs            |  13 --
 tests/ui/linkage-attr/uikit-framework.rs           |  25 ----
 38 files changed, 343 insertions(+), 343 deletions(-)
 delete mode 100644 tests/ui/issues/issue-43925.rs
 delete mode 100644 tests/ui/issues/issue-43925.stderr
 delete mode 100644 tests/ui/issues/issue-43926.rs
 delete mode 100644 tests/ui/issues/issue-43926.stderr
 delete mode 100644 tests/ui/issues/issue-70093/issue-70093-link-directives.rs
 delete mode 100644 tests/ui/issues/issue-70093/issue-70093.rs
 create mode 100644 tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs
 create mode 100644 tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs
 create mode 100644 tests/ui/link-native-libs/issue-109144.rs
 create mode 100644 tests/ui/link-native-libs/issue-109144.stderr
 create mode 100644 tests/ui/link-native-libs/issue-43925.rs
 create mode 100644 tests/ui/link-native-libs/issue-43925.stderr
 create mode 100644 tests/ui/link-native-libs/issue-43926.rs
 create mode 100644 tests/ui/link-native-libs/issue-43926.stderr
 create mode 100644 tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
 create mode 100644 tests/ui/link-native-libs/issue-70093/issue-70093.rs
 create mode 100644 tests/ui/link-native-libs/kind-framework.rs
 create mode 100644 tests/ui/link-native-libs/kind-framework.stderr
 create mode 100644 tests/ui/link-native-libs/link-attr-validation-early.rs
 create mode 100644 tests/ui/link-native-libs/link-attr-validation-early.stderr
 create mode 100644 tests/ui/link-native-libs/link-attr-validation-late.rs
 create mode 100644 tests/ui/link-native-libs/link-attr-validation-late.stderr
 create mode 100644 tests/ui/link-native-libs/link-cfg-works.rs
 create mode 100644 tests/ui/link-native-libs/uikit-framework.rs
 delete mode 100644 tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs
 delete mode 100644 tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs
 delete mode 100644 tests/ui/linkage-attr/issue-109144.rs
 delete mode 100644 tests/ui/linkage-attr/issue-109144.stderr
 delete mode 100644 tests/ui/linkage-attr/kind-framework.rs
 delete mode 100644 tests/ui/linkage-attr/kind-framework.stderr
 delete mode 100644 tests/ui/linkage-attr/link-attr-validation-early.rs
 delete mode 100644 tests/ui/linkage-attr/link-attr-validation-early.stderr
 delete mode 100644 tests/ui/linkage-attr/link-attr-validation-late.rs
 delete mode 100644 tests/ui/linkage-attr/link-attr-validation-late.stderr
 delete mode 100644 tests/ui/linkage-attr/link-cfg-works.rs
 delete mode 100644 tests/ui/linkage-attr/uikit-framework.rs

(limited to 'src/tools')

diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index ac82a17e145..4088b2de2cd 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2297,8 +2297,6 @@ ui/issues/issue-43853.rs
 ui/issues/issue-4387.rs
 ui/issues/issue-43910.rs
 ui/issues/issue-43923.rs
-ui/issues/issue-43925.rs
-ui/issues/issue-43926.rs
 ui/issues/issue-43988.rs
 ui/issues/issue-44023.rs
 ui/issues/issue-44056.rs
@@ -2547,8 +2545,6 @@ ui/issues/issue-6936.rs
 ui/issues/issue-69455.rs
 ui/issues/issue-69602-type-err-during-codegen-ice.rs
 ui/issues/issue-69683.rs
-ui/issues/issue-70093/issue-70093-link-directives.rs
-ui/issues/issue-70093/issue-70093.rs
 ui/issues/issue-7012.rs
 ui/issues/issue-70381.rs
 ui/issues/issue-7044.rs
@@ -2713,11 +2709,15 @@ ui/limits/issue-17913.rs
 ui/limits/issue-55878.rs
 ui/limits/issue-69485-var-size-diffs-too-large.rs
 ui/limits/issue-75158-64.rs
+ui/link-native-libs/issue-109144.rs
+ui/link-native-libs/issue-43925.rs
+ui/link-native-libs/issue-43926.rs
+ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
+ui/link-native-libs/issue-70093/issue-70093.rs
 ui/linkage-attr/auxiliary/issue-12133-dylib.rs
 ui/linkage-attr/auxiliary/issue-12133-dylib2.rs
 ui/linkage-attr/auxiliary/issue-12133-rlib.rs
 ui/linkage-attr/issue-10755.rs
-ui/linkage-attr/issue-109144.rs
 ui/linkage-attr/issue-12133-1.rs
 ui/linkage-attr/issue-12133-2.rs
 ui/linkage-attr/issue-12133-3.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 11f9d5bb03d..401169c838f 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1672;
+const ISSUES_ENTRY_LIMIT: u32 = 1667;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/ui/issues/issue-43925.rs b/tests/ui/issues/issue-43925.rs
deleted file mode 100644
index 1a210887154..00000000000
--- a/tests/ui/issues/issue-43925.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#[link(name = "foo", cfg("rlib"))] //~ ERROR link cfg must have a single predicate argument
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-43925.stderr b/tests/ui/issues/issue-43925.stderr
deleted file mode 100644
index 7cc347c6163..00000000000
--- a/tests/ui/issues/issue-43925.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: link cfg must have a single predicate argument
-  --> $DIR/issue-43925.rs:1:22
-   |
-LL | #[link(name = "foo", cfg("rlib"))]
-   |                      ^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/issues/issue-43926.rs b/tests/ui/issues/issue-43926.rs
deleted file mode 100644
index 6d3003552dc..00000000000
--- a/tests/ui/issues/issue-43926.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#[link(name = "foo", cfg())] //~ ERROR link cfg must have a single predicate argument
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-43926.stderr b/tests/ui/issues/issue-43926.stderr
deleted file mode 100644
index 7c5c50a38a9..00000000000
--- a/tests/ui/issues/issue-43926.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: link cfg must have a single predicate argument
-  --> $DIR/issue-43926.rs:1:22
-   |
-LL | #[link(name = "foo", cfg())]
-   |                      ^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs b/tests/ui/issues/issue-70093/issue-70093-link-directives.rs
deleted file mode 100644
index 9c60affbccd..00000000000
--- a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ compile-flags: -Zlink-directives=no
-//@ ignore-windows - this will probably only work on unixish systems
-//@ ignore-fuchsia - missing __libc_start_main for some reason (#84733)
-//@ ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
-
-#[link(name = "some-random-non-existent-library", kind = "static")]
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-70093/issue-70093.rs b/tests/ui/issues/issue-70093/issue-70093.rs
deleted file mode 100644
index 86974239338..00000000000
--- a/tests/ui/issues/issue-70093/issue-70093.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
-//@ ignore-windows - this will probably only work on unixish systems
-//@ ignore-fuchsia - missing __libc_start_main for some reason (#84733)
-//@ ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
-
-#[link(name = "some-random-non-existent-library", kind = "static")]
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs
new file mode 100644
index 00000000000..0d927117d81
--- /dev/null
+++ b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs
@@ -0,0 +1,4 @@
+#![feature(link_cfg)]
+
+#[link(name = "foo", cfg(foo))]
+extern "C" {}
diff --git a/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs
new file mode 100644
index 00000000000..49a46b202e4
--- /dev/null
+++ b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs
@@ -0,0 +1,7 @@
+//@ no-prefer-dynamic
+
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "foo", cfg(foo))]
+extern "C" {}
diff --git a/tests/ui/link-native-libs/issue-109144.rs b/tests/ui/link-native-libs/issue-109144.rs
new file mode 100644
index 00000000000..2f740e55389
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-109144.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+#[link(kind = "static", modifiers = "+whole-archive,+bundle")]
+//~^ ERROR `#[link]` attribute requires a `name = "string"` argument
+extern  {}
diff --git a/tests/ui/link-native-libs/issue-109144.stderr b/tests/ui/link-native-libs/issue-109144.stderr
new file mode 100644
index 00000000000..0748d94189c
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-109144.stderr
@@ -0,0 +1,9 @@
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/issue-109144.rs:2:1
+   |
+LL | #[link(kind = "static", modifiers = "+whole-archive,+bundle")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0459`.
diff --git a/tests/ui/link-native-libs/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs
new file mode 100644
index 00000000000..1a210887154
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-43925.rs
@@ -0,0 +1,4 @@
+#[link(name = "foo", cfg("rlib"))] //~ ERROR link cfg must have a single predicate argument
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr
new file mode 100644
index 00000000000..7cc347c6163
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-43925.stderr
@@ -0,0 +1,8 @@
+error: link cfg must have a single predicate argument
+  --> $DIR/issue-43925.rs:1:22
+   |
+LL | #[link(name = "foo", cfg("rlib"))]
+   |                      ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/link-native-libs/issue-43926.rs b/tests/ui/link-native-libs/issue-43926.rs
new file mode 100644
index 00000000000..6d3003552dc
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-43926.rs
@@ -0,0 +1,4 @@
+#[link(name = "foo", cfg())] //~ ERROR link cfg must have a single predicate argument
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr
new file mode 100644
index 00000000000..7c5c50a38a9
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-43926.stderr
@@ -0,0 +1,8 @@
+error: link cfg must have a single predicate argument
+  --> $DIR/issue-43926.rs:1:22
+   |
+LL | #[link(name = "foo", cfg())]
+   |                      ^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs b/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
new file mode 100644
index 00000000000..9c60affbccd
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
@@ -0,0 +1,10 @@
+//@ run-pass
+//@ compile-flags: -Zlink-directives=no
+//@ ignore-windows - this will probably only work on unixish systems
+//@ ignore-fuchsia - missing __libc_start_main for some reason (#84733)
+//@ ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
+
+#[link(name = "some-random-non-existent-library", kind = "static")]
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/issue-70093/issue-70093.rs b/tests/ui/link-native-libs/issue-70093/issue-70093.rs
new file mode 100644
index 00000000000..86974239338
--- /dev/null
+++ b/tests/ui/link-native-libs/issue-70093/issue-70093.rs
@@ -0,0 +1,10 @@
+//@ run-pass
+//@ compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
+//@ ignore-windows - this will probably only work on unixish systems
+//@ ignore-fuchsia - missing __libc_start_main for some reason (#84733)
+//@ ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
+
+#[link(name = "some-random-non-existent-library", kind = "static")]
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/kind-framework.rs b/tests/ui/link-native-libs/kind-framework.rs
new file mode 100644
index 00000000000..c2f90809e03
--- /dev/null
+++ b/tests/ui/link-native-libs/kind-framework.rs
@@ -0,0 +1,7 @@
+//@ ignore-apple this is supposed to succeed on Apple platforms (though it won't necessarily link)
+
+#[link(name = "foo", kind = "framework")]
+extern "C" {}
+//~^^ ERROR: link kind `framework` is only supported on Apple targets
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/kind-framework.stderr b/tests/ui/link-native-libs/kind-framework.stderr
new file mode 100644
index 00000000000..93dacd68e29
--- /dev/null
+++ b/tests/ui/link-native-libs/kind-framework.stderr
@@ -0,0 +1,9 @@
+error[E0455]: link kind `framework` is only supported on Apple targets
+  --> $DIR/kind-framework.rs:3:29
+   |
+LL | #[link(name = "foo", kind = "framework")]
+   |                             ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0455`.
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.rs b/tests/ui/link-native-libs/link-attr-validation-early.rs
new file mode 100644
index 00000000000..b9a835fb5e9
--- /dev/null
+++ b/tests/ui/link-native-libs/link-attr-validation-early.rs
@@ -0,0 +1,8 @@
+// Top-level ill-formed
+#[link] //~ ERROR attribute must be of the form
+        //~| WARN this was previously accepted
+#[link = "foo"] //~ ERROR attribute must be of the form
+                //~| WARN this was previously accepted
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr
new file mode 100644
index 00000000000..24ad9d825f8
--- /dev/null
+++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr
@@ -0,0 +1,21 @@
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/link-attr-validation-early.rs:2:1
+   |
+LL | #[link]
+   | ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/link-attr-validation-early.rs:4:1
+   |
+LL | #[link = "foo"]
+   | ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs
new file mode 100644
index 00000000000..34f720dd2d3
--- /dev/null
+++ b/tests/ui/link-native-libs/link-attr-validation-late.rs
@@ -0,0 +1,39 @@
+#![feature(link_cfg)]
+
+// Top-level ill-formed
+#[link(name = "...", "literal")] //~ ERROR unexpected `#[link]` argument
+#[link(name = "...", unknown)] //~ ERROR unexpected `#[link]` argument
+extern "C" {}
+
+// Duplicate arguments
+#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments
+#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments
+#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments
+#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments
+#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments
+extern "C" {}
+
+// Ill-formed arguments
+#[link(name)] //~ ERROR link name must be of the form `name = "string"`
+              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
+#[link(name())] //~ ERROR link name must be of the form `name = "string"`
+              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
+#[link(name = "...", kind)] //~ ERROR link kind must be of the form `kind = "string"`
+#[link(name = "...", kind())] //~ ERROR link kind must be of the form `kind = "string"`
+#[link(name = "...", modifiers)] //~ ERROR link modifiers must be of the form `modifiers = "string"`
+#[link(name = "...", modifiers())] //~ ERROR link modifiers must be of the form `modifiers = "string"`
+#[link(name = "...", cfg)] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
+#[link(name = "...", cfg = "literal")] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
+#[link(name = "...", cfg("literal"))] //~ ERROR link cfg must have a single predicate argument
+#[link(name = "...", wasm_import_module)] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
+#[link(name = "...", wasm_import_module())] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
+extern "C" {}
+
+// Basic modifier validation
+#[link(name = "...", modifiers = "")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
+#[link(name = "...", modifiers = "no-plus-minus")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
+#[link(name = "...", modifiers = "+unknown")] //~ ERROR unknown linking modifier `unknown`
+#[link(name = "...", modifiers = "+verbatim,+verbatim")] //~ ERROR multiple `verbatim` modifiers
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr
new file mode 100644
index 00000000000..1ad5fbaf7de
--- /dev/null
+++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr
@@ -0,0 +1,147 @@
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
+  --> $DIR/link-attr-validation-late.rs:4:22
+   |
+LL | #[link(name = "...", "literal")]
+   |                      ^^^^^^^^^
+
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
+  --> $DIR/link-attr-validation-late.rs:5:22
+   |
+LL | #[link(name = "...", unknown)]
+   |                      ^^^^^^^
+
+error: multiple `name` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:9:22
+   |
+LL | #[link(name = "foo", name = "bar")]
+   |                      ^^^^^^^^^^^^
+
+error: multiple `kind` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:10:38
+   |
+LL | #[link(name = "...", kind = "dylib", kind = "bar")]
+   |                                      ^^^^^^^^^^^^
+
+error: multiple `modifiers` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:11:47
+   |
+LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")]
+   |                                               ^^^^^^^^^^^^^^^^^
+
+error: multiple `cfg` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:12:34
+   |
+LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))]
+   |                                  ^^^^^^^^^^
+
+error: multiple `wasm_import_module` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:13:36
+   |
+LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: link name must be of the form `name = "string"`
+  --> $DIR/link-attr-validation-late.rs:17:8
+   |
+LL | #[link(name)]
+   |        ^^^^
+
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/link-attr-validation-late.rs:17:1
+   |
+LL | #[link(name)]
+   | ^^^^^^^^^^^^^ missing `name` argument
+
+error: link name must be of the form `name = "string"`
+  --> $DIR/link-attr-validation-late.rs:19:8
+   |
+LL | #[link(name())]
+   |        ^^^^^^
+
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/link-attr-validation-late.rs:19:1
+   |
+LL | #[link(name())]
+   | ^^^^^^^^^^^^^^^ missing `name` argument
+
+error: link kind must be of the form `kind = "string"`
+  --> $DIR/link-attr-validation-late.rs:21:22
+   |
+LL | #[link(name = "...", kind)]
+   |                      ^^^^
+
+error: link kind must be of the form `kind = "string"`
+  --> $DIR/link-attr-validation-late.rs:22:22
+   |
+LL | #[link(name = "...", kind())]
+   |                      ^^^^^^
+
+error: link modifiers must be of the form `modifiers = "string"`
+  --> $DIR/link-attr-validation-late.rs:23:22
+   |
+LL | #[link(name = "...", modifiers)]
+   |                      ^^^^^^^^^
+
+error: link modifiers must be of the form `modifiers = "string"`
+  --> $DIR/link-attr-validation-late.rs:24:22
+   |
+LL | #[link(name = "...", modifiers())]
+   |                      ^^^^^^^^^^^
+
+error: link cfg must be of the form `cfg(/* predicate */)`
+  --> $DIR/link-attr-validation-late.rs:25:22
+   |
+LL | #[link(name = "...", cfg)]
+   |                      ^^^
+
+error: link cfg must be of the form `cfg(/* predicate */)`
+  --> $DIR/link-attr-validation-late.rs:26:22
+   |
+LL | #[link(name = "...", cfg = "literal")]
+   |                      ^^^^^^^^^^^^^^^
+
+error: link cfg must have a single predicate argument
+  --> $DIR/link-attr-validation-late.rs:27:22
+   |
+LL | #[link(name = "...", cfg("literal"))]
+   |                      ^^^^^^^^^^^^^^
+
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/link-attr-validation-late.rs:28:22
+   |
+LL | #[link(name = "...", wasm_import_module)]
+   |                      ^^^^^^^^^^^^^^^^^^
+
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/link-attr-validation-late.rs:29:22
+   |
+LL | #[link(name = "...", wasm_import_module())]
+   |                      ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:33:34
+   |
+LL | #[link(name = "...", modifiers = "")]
+   |                                  ^^
+
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:34:34
+   |
+LL | #[link(name = "...", modifiers = "no-plus-minus")]
+   |                                  ^^^^^^^^^^^^^^^
+
+error: unknown linking modifier `unknown`, expected one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:35:34
+   |
+LL | #[link(name = "...", modifiers = "+unknown")]
+   |                                  ^^^^^^^^^^
+
+error: multiple `verbatim` modifiers in a single `modifiers` argument
+  --> $DIR/link-attr-validation-late.rs:36:34
+   |
+LL | #[link(name = "...", modifiers = "+verbatim,+verbatim")]
+   |                                  ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
+For more information about this error, try `rustc --explain E0459`.
diff --git a/tests/ui/link-native-libs/link-cfg-works.rs b/tests/ui/link-native-libs/link-cfg-works.rs
new file mode 100644
index 00000000000..7b936bc43b1
--- /dev/null
+++ b/tests/ui/link-native-libs/link-cfg-works.rs
@@ -0,0 +1,13 @@
+//@ run-pass
+//@ aux-build:link-cfg-works-transitive-rlib.rs
+//@ aux-build:link-cfg-works-transitive-dylib.rs
+
+#![feature(link_cfg)]
+
+extern crate link_cfg_works_transitive_dylib;
+extern crate link_cfg_works_transitive_rlib;
+
+#[link(name = "foo", cfg(foo))]
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/link-native-libs/uikit-framework.rs b/tests/ui/link-native-libs/uikit-framework.rs
new file mode 100644
index 00000000000..fca0332384a
--- /dev/null
+++ b/tests/ui/link-native-libs/uikit-framework.rs
@@ -0,0 +1,25 @@
+//! Check that linking to UIKit on platforms where that is available works.
+//@ revisions: ios tvos watchos visionos
+//@ [ios]only-ios
+//@ [tvos]only-tvos
+//@ [watchos]only-watchos
+//@ [visionos]only-visionos
+//@ build-pass
+
+use std::ffi::{c_char, c_int, c_void};
+
+#[link(name = "UIKit", kind = "framework")]
+extern "C" {
+    pub fn UIApplicationMain(
+        argc: c_int,
+        argv: *const c_char,
+        principalClassName: *const c_void,
+        delegateClassName: *const c_void,
+    ) -> c_int;
+}
+
+pub fn main() {
+    unsafe {
+        UIApplicationMain(0, core::ptr::null(), core::ptr::null(), core::ptr::null());
+    }
+}
diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs b/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs
deleted file mode 100644
index 0d927117d81..00000000000
--- a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(link_cfg)]
-
-#[link(name = "foo", cfg(foo))]
-extern "C" {}
diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs b/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs
deleted file mode 100644
index 49a46b202e4..00000000000
--- a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ no-prefer-dynamic
-
-#![feature(link_cfg)]
-#![crate_type = "rlib"]
-
-#[link(name = "foo", cfg(foo))]
-extern "C" {}
diff --git a/tests/ui/linkage-attr/issue-109144.rs b/tests/ui/linkage-attr/issue-109144.rs
deleted file mode 100644
index 2f740e55389..00000000000
--- a/tests/ui/linkage-attr/issue-109144.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![crate_type = "lib"]
-#[link(kind = "static", modifiers = "+whole-archive,+bundle")]
-//~^ ERROR `#[link]` attribute requires a `name = "string"` argument
-extern  {}
diff --git a/tests/ui/linkage-attr/issue-109144.stderr b/tests/ui/linkage-attr/issue-109144.stderr
deleted file mode 100644
index 0748d94189c..00000000000
--- a/tests/ui/linkage-attr/issue-109144.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0459]: `#[link]` attribute requires a `name = "string"` argument
-  --> $DIR/issue-109144.rs:2:1
-   |
-LL | #[link(kind = "static", modifiers = "+whole-archive,+bundle")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `name` argument
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0459`.
diff --git a/tests/ui/linkage-attr/kind-framework.rs b/tests/ui/linkage-attr/kind-framework.rs
deleted file mode 100644
index c2f90809e03..00000000000
--- a/tests/ui/linkage-attr/kind-framework.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ ignore-apple this is supposed to succeed on Apple platforms (though it won't necessarily link)
-
-#[link(name = "foo", kind = "framework")]
-extern "C" {}
-//~^^ ERROR: link kind `framework` is only supported on Apple targets
-
-fn main() {}
diff --git a/tests/ui/linkage-attr/kind-framework.stderr b/tests/ui/linkage-attr/kind-framework.stderr
deleted file mode 100644
index 93dacd68e29..00000000000
--- a/tests/ui/linkage-attr/kind-framework.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0455]: link kind `framework` is only supported on Apple targets
-  --> $DIR/kind-framework.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "framework")]
-   |                             ^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0455`.
diff --git a/tests/ui/linkage-attr/link-attr-validation-early.rs b/tests/ui/linkage-attr/link-attr-validation-early.rs
deleted file mode 100644
index b9a835fb5e9..00000000000
--- a/tests/ui/linkage-attr/link-attr-validation-early.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// Top-level ill-formed
-#[link] //~ ERROR attribute must be of the form
-        //~| WARN this was previously accepted
-#[link = "foo"] //~ ERROR attribute must be of the form
-                //~| WARN this was previously accepted
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/linkage-attr/link-attr-validation-early.stderr b/tests/ui/linkage-attr/link-attr-validation-early.stderr
deleted file mode 100644
index 24ad9d825f8..00000000000
--- a/tests/ui/linkage-attr/link-attr-validation-early.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
-  --> $DIR/link-attr-validation-early.rs:2:1
-   |
-LL | #[link]
-   | ^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #57571 
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
-
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
-  --> $DIR/link-attr-validation-early.rs:4:1
-   |
-LL | #[link = "foo"]
-   | ^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #57571 
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/linkage-attr/link-attr-validation-late.rs b/tests/ui/linkage-attr/link-attr-validation-late.rs
deleted file mode 100644
index 34f720dd2d3..00000000000
--- a/tests/ui/linkage-attr/link-attr-validation-late.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-#![feature(link_cfg)]
-
-// Top-level ill-formed
-#[link(name = "...", "literal")] //~ ERROR unexpected `#[link]` argument
-#[link(name = "...", unknown)] //~ ERROR unexpected `#[link]` argument
-extern "C" {}
-
-// Duplicate arguments
-#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments
-#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments
-#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments
-#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments
-#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments
-extern "C" {}
-
-// Ill-formed arguments
-#[link(name)] //~ ERROR link name must be of the form `name = "string"`
-              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
-#[link(name())] //~ ERROR link name must be of the form `name = "string"`
-              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
-#[link(name = "...", kind)] //~ ERROR link kind must be of the form `kind = "string"`
-#[link(name = "...", kind())] //~ ERROR link kind must be of the form `kind = "string"`
-#[link(name = "...", modifiers)] //~ ERROR link modifiers must be of the form `modifiers = "string"`
-#[link(name = "...", modifiers())] //~ ERROR link modifiers must be of the form `modifiers = "string"`
-#[link(name = "...", cfg)] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
-#[link(name = "...", cfg = "literal")] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
-#[link(name = "...", cfg("literal"))] //~ ERROR link cfg must have a single predicate argument
-#[link(name = "...", wasm_import_module)] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
-#[link(name = "...", wasm_import_module())] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
-extern "C" {}
-
-// Basic modifier validation
-#[link(name = "...", modifiers = "")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
-#[link(name = "...", modifiers = "no-plus-minus")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
-#[link(name = "...", modifiers = "+unknown")] //~ ERROR unknown linking modifier `unknown`
-#[link(name = "...", modifiers = "+verbatim,+verbatim")] //~ ERROR multiple `verbatim` modifiers
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/linkage-attr/link-attr-validation-late.stderr b/tests/ui/linkage-attr/link-attr-validation-late.stderr
deleted file mode 100644
index 1ad5fbaf7de..00000000000
--- a/tests/ui/linkage-attr/link-attr-validation-late.stderr
+++ /dev/null
@@ -1,147 +0,0 @@
-error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
-  --> $DIR/link-attr-validation-late.rs:4:22
-   |
-LL | #[link(name = "...", "literal")]
-   |                      ^^^^^^^^^
-
-error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
-  --> $DIR/link-attr-validation-late.rs:5:22
-   |
-LL | #[link(name = "...", unknown)]
-   |                      ^^^^^^^
-
-error: multiple `name` arguments in a single `#[link]` attribute
-  --> $DIR/link-attr-validation-late.rs:9:22
-   |
-LL | #[link(name = "foo", name = "bar")]
-   |                      ^^^^^^^^^^^^
-
-error: multiple `kind` arguments in a single `#[link]` attribute
-  --> $DIR/link-attr-validation-late.rs:10:38
-   |
-LL | #[link(name = "...", kind = "dylib", kind = "bar")]
-   |                                      ^^^^^^^^^^^^
-
-error: multiple `modifiers` arguments in a single `#[link]` attribute
-  --> $DIR/link-attr-validation-late.rs:11:47
-   |
-LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")]
-   |                                               ^^^^^^^^^^^^^^^^^
-
-error: multiple `cfg` arguments in a single `#[link]` attribute
-  --> $DIR/link-attr-validation-late.rs:12:34
-   |
-LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))]
-   |                                  ^^^^^^^^^^
-
-error: multiple `wasm_import_module` arguments in a single `#[link]` attribute
-  --> $DIR/link-attr-validation-late.rs:13:36
-   |
-LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")]
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: link name must be of the form `name = "string"`
-  --> $DIR/link-attr-validation-late.rs:17:8
-   |
-LL | #[link(name)]
-   |        ^^^^
-
-error[E0459]: `#[link]` attribute requires a `name = "string"` argument
-  --> $DIR/link-attr-validation-late.rs:17:1
-   |
-LL | #[link(name)]
-   | ^^^^^^^^^^^^^ missing `name` argument
-
-error: link name must be of the form `name = "string"`
-  --> $DIR/link-attr-validation-late.rs:19:8
-   |
-LL | #[link(name())]
-   |        ^^^^^^
-
-error[E0459]: `#[link]` attribute requires a `name = "string"` argument
-  --> $DIR/link-attr-validation-late.rs:19:1
-   |
-LL | #[link(name())]
-   | ^^^^^^^^^^^^^^^ missing `name` argument
-
-error: link kind must be of the form `kind = "string"`
-  --> $DIR/link-attr-validation-late.rs:21:22
-   |
-LL | #[link(name = "...", kind)]
-   |                      ^^^^
-
-error: link kind must be of the form `kind = "string"`
-  --> $DIR/link-attr-validation-late.rs:22:22
-   |
-LL | #[link(name = "...", kind())]
-   |                      ^^^^^^
-
-error: link modifiers must be of the form `modifiers = "string"`
-  --> $DIR/link-attr-validation-late.rs:23:22
-   |
-LL | #[link(name = "...", modifiers)]
-   |                      ^^^^^^^^^
-
-error: link modifiers must be of the form `modifiers = "string"`
-  --> $DIR/link-attr-validation-late.rs:24:22
-   |
-LL | #[link(name = "...", modifiers())]
-   |                      ^^^^^^^^^^^
-
-error: link cfg must be of the form `cfg(/* predicate */)`
-  --> $DIR/link-attr-validation-late.rs:25:22
-   |
-LL | #[link(name = "...", cfg)]
-   |                      ^^^
-
-error: link cfg must be of the form `cfg(/* predicate */)`
-  --> $DIR/link-attr-validation-late.rs:26:22
-   |
-LL | #[link(name = "...", cfg = "literal")]
-   |                      ^^^^^^^^^^^^^^^
-
-error: link cfg must have a single predicate argument
-  --> $DIR/link-attr-validation-late.rs:27:22
-   |
-LL | #[link(name = "...", cfg("literal"))]
-   |                      ^^^^^^^^^^^^^^
-
-error: wasm import module must be of the form `wasm_import_module = "string"`
-  --> $DIR/link-attr-validation-late.rs:28:22
-   |
-LL | #[link(name = "...", wasm_import_module)]
-   |                      ^^^^^^^^^^^^^^^^^^
-
-error: wasm import module must be of the form `wasm_import_module = "string"`
-  --> $DIR/link-attr-validation-late.rs:29:22
-   |
-LL | #[link(name = "...", wasm_import_module())]
-   |                      ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
-  --> $DIR/link-attr-validation-late.rs:33:34
-   |
-LL | #[link(name = "...", modifiers = "")]
-   |                                  ^^
-
-error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
-  --> $DIR/link-attr-validation-late.rs:34:34
-   |
-LL | #[link(name = "...", modifiers = "no-plus-minus")]
-   |                                  ^^^^^^^^^^^^^^^
-
-error: unknown linking modifier `unknown`, expected one of: bundle, verbatim, whole-archive, as-needed
-  --> $DIR/link-attr-validation-late.rs:35:34
-   |
-LL | #[link(name = "...", modifiers = "+unknown")]
-   |                                  ^^^^^^^^^^
-
-error: multiple `verbatim` modifiers in a single `modifiers` argument
-  --> $DIR/link-attr-validation-late.rs:36:34
-   |
-LL | #[link(name = "...", modifiers = "+verbatim,+verbatim")]
-   |                                  ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 24 previous errors
-
-For more information about this error, try `rustc --explain E0459`.
diff --git a/tests/ui/linkage-attr/link-cfg-works.rs b/tests/ui/linkage-attr/link-cfg-works.rs
deleted file mode 100644
index 7b936bc43b1..00000000000
--- a/tests/ui/linkage-attr/link-cfg-works.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-//@ aux-build:link-cfg-works-transitive-rlib.rs
-//@ aux-build:link-cfg-works-transitive-dylib.rs
-
-#![feature(link_cfg)]
-
-extern crate link_cfg_works_transitive_dylib;
-extern crate link_cfg_works_transitive_rlib;
-
-#[link(name = "foo", cfg(foo))]
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/linkage-attr/uikit-framework.rs b/tests/ui/linkage-attr/uikit-framework.rs
deleted file mode 100644
index fca0332384a..00000000000
--- a/tests/ui/linkage-attr/uikit-framework.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//! Check that linking to UIKit on platforms where that is available works.
-//@ revisions: ios tvos watchos visionos
-//@ [ios]only-ios
-//@ [tvos]only-tvos
-//@ [watchos]only-watchos
-//@ [visionos]only-visionos
-//@ build-pass
-
-use std::ffi::{c_char, c_int, c_void};
-
-#[link(name = "UIKit", kind = "framework")]
-extern "C" {
-    pub fn UIApplicationMain(
-        argc: c_int,
-        argv: *const c_char,
-        principalClassName: *const c_void,
-        delegateClassName: *const c_void,
-    ) -> c_int;
-}
-
-pub fn main() {
-    unsafe {
-        UIApplicationMain(0, core::ptr::null(), core::ptr::null(), core::ptr::null());
-    }
-}
-- 
cgit 1.4.1-3-g733a5


From afdf4c8ea966a7b148723e91e42f9c5040520ca3 Mon Sep 17 00:00:00 2001
From: Ali Bektas 
Date: Sun, 25 Aug 2024 13:28:07 +0200
Subject: Watch for user config ratoml

---
 .../rust-analyzer/crates/load-cargo/src/lib.rs     | 24 +++++++++++-
 .../crates/rust-analyzer/src/config.rs             | 14 ++-----
 .../crates/rust-analyzer/src/global_state.rs       | 11 +++++-
 .../crates/rust-analyzer/src/reload.rs             |  8 +++-
 .../rust-analyzer/tests/slow-tests/ratoml.rs       | 44 +++++++++++++---------
 .../rust-analyzer/tests/slow-tests/support.rs      | 30 +++++++++++++--
 6 files changed, 94 insertions(+), 37 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 0e1606a6991..ab8a780363d 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -123,7 +123,7 @@ pub fn load_workspace(
             .collect()
     };
 
-    let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]);
+    let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[], None);
     loader.set_config(vfs::loader::Config {
         load: project_folders.load,
         watch: vec![],
@@ -153,7 +153,11 @@ pub struct ProjectFolders {
 }
 
 impl ProjectFolders {
-    pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders {
+    pub fn new(
+        workspaces: &[ProjectWorkspace],
+        global_excludes: &[AbsPathBuf],
+        user_config_dir_path: Option<&'static AbsPath>,
+    ) -> ProjectFolders {
         let mut res = ProjectFolders::default();
         let mut fsc = FileSetConfig::builder();
         let mut local_filesets = vec![];
@@ -291,6 +295,22 @@ impl ProjectFolders {
             }
         }
 
+        if let Some(user_config_path) = user_config_dir_path {
+            let ratoml_path = {
+                let mut p = user_config_path.to_path_buf();
+                p.push("rust-analyzer.toml");
+                p
+            };
+
+            let file_set_roots: Vec = vec![VfsPath::from(ratoml_path.to_owned())];
+            let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
+
+            res.watch.push(res.load.len());
+            res.load.push(entry);
+            local_filesets.push(fsc.len() as u64);
+            fsc.add_file_set(file_set_roots)
+        }
+
         let fsc = fsc.build();
         res.source_root_config = SourceRootConfig { fsc, local_filesets };
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index dd7351bcf26..921c9b991c5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -804,22 +804,14 @@ impl std::ops::Deref for Config {
 }
 
 impl Config {
-    /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
-    /// This path is equal to:
-    ///
-    /// |Platform | Value                                 | Example                                  |
-    /// | ------- | ------------------------------------- | ---------------------------------------- |
-    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
-    /// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support |
-    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
-    pub fn user_config_path() -> Option<&'static AbsPath> {
+    /// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux.
+    pub fn user_config_dir_path() -> Option<&'static AbsPath> {
         static USER_CONFIG_PATH: LazyLock> = LazyLock::new(|| {
             let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
                 std::path::PathBuf::from(path)
             } else {
                 dirs::config_dir()?.join("rust-analyzer")
-            }
-            .join("rust-analyzer.toml");
+            };
             Some(AbsPathBuf::assert_utf8(user_config_path))
         });
         USER_CONFIG_PATH.as_deref()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 7fbeaa4e3ea..8d5536e1b09 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -392,7 +392,14 @@ impl GlobalState {
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
         {
             let config_change = {
-                let user_config_path = Config::user_config_path();
+                let user_config_path = {
+                    let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
+                    p.push("rust-analyzer.toml");
+                    p
+                };
+
+                let user_config_abs_path = Some(user_config_path.as_path());
+
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
 
@@ -411,7 +418,7 @@ impl GlobalState {
                     .collect_vec();
 
                 for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
-                    if vfs_path.as_path() == user_config_path {
+                    if vfs_path.as_path() == user_config_abs_path {
                         change.change_user_config(Some(db.file_text(file_id)));
                         continue;
                     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index bc85afa0e49..b0b62203528 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -590,7 +590,7 @@ impl GlobalState {
             }
 
             watchers.extend(
-                iter::once(Config::user_config_path())
+                iter::once(Config::user_config_dir_path())
                     .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
                     .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
@@ -613,7 +613,11 @@ impl GlobalState {
         }
 
         let files_config = self.config.files();
-        let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
+        let project_folders = ProjectFolders::new(
+            &self.workspaces,
+            &files_config.exclude,
+            Config::user_config_dir_path().to_owned(),
+        );
 
         if (self.proc_macro_clients.is_empty() || !same_workspaces)
             && self.config.expand_proc_macros()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index a857e0c2967..623a9f76d14 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -30,6 +30,23 @@ impl RatomlTest {
         fixtures: Vec<&str>,
         roots: Vec<&str>,
         client_config: Option,
+    ) -> Self {
+        RatomlTest::new_with_lock(fixtures, roots, client_config, false)
+    }
+
+    fn new_locked(
+        fixtures: Vec<&str>,
+        roots: Vec<&str>,
+        client_config: Option,
+    ) -> Self {
+        RatomlTest::new_with_lock(fixtures, roots, client_config, true)
+    }
+
+    fn new_with_lock(
+        fixtures: Vec<&str>,
+        roots: Vec<&str>,
+        client_config: Option,
+        prelock: bool,
     ) -> Self {
         let tmp_dir = TestDir::new();
         let tmp_path = tmp_dir.path().to_owned();
@@ -46,7 +63,7 @@ impl RatomlTest {
             project = project.with_config(client_config);
         }
 
-        let server = project.server().wait_until_workspace_is_loaded();
+        let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
 
         let mut case = Self { urls: vec![], server, tmp_path };
         let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::>();
@@ -72,7 +89,7 @@ impl RatomlTest {
         let mut spl = spl.into_iter();
         if let Some(first) = spl.next() {
             if first == "$$CONFIG_DIR$$" {
-                path = Config::user_config_path().unwrap().to_path_buf().into();
+                path = Config::user_config_dir_path().unwrap().to_path_buf().into();
             } else {
                 path = path.join(first);
             }
@@ -285,16 +302,15 @@ enum Value {
 //     }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_user_config_detected() {
     if skip_slow_tests() {
         return;
     }
 
-    let server = RatomlTest::new(
+    let server = RatomlTest::new_locked(
         vec![
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true
 "#,
             r#"
@@ -322,13 +338,12 @@ enum Value {
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_create_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -353,10 +368,7 @@ enum Value {
         1,
         InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
     );
-    server.create(
-        "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
-        RatomlTest::EMIT_MUST_USE.to_owned(),
-    );
+    server.create("//- /$$CONFIG_DIR$$/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned());
     server.query(
         InternalTestingFetchConfigOption::AssistEmitMustUse,
         1,
@@ -365,13 +377,12 @@ enum Value {
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_modify_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -386,7 +397,7 @@ enum Value {
     Text(String),
 }"#,
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true"#,
         ],
         vec!["p1"],
@@ -407,13 +418,12 @@ assist.emitMustUse = true"#,
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_delete_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -428,7 +438,7 @@ enum Value {
     Text(String),
 }"#,
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true"#,
         ],
         vec!["p1"],
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 78572e37a9b..86137e3f2cc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -1,6 +1,6 @@
 use std::{
     cell::{Cell, RefCell},
-    fs,
+    env, fs,
     sync::Once,
     time::Duration,
 };
@@ -127,7 +127,30 @@ impl Project<'_> {
     }
 
     pub(crate) fn server(self) -> Server {
+        Project::server_with_lock(self, false)
+    }
+
+    /// `prelock` : Forcefully acquire a lock that will maintain the path to the config dir throughout the whole test.
+    ///
+    /// When testing we set the user config dir by setting an envvar `__TEST_RA_USER_CONFIG_DIR`.
+    /// This value must be maintained until the end of a test case. When tests run in parallel
+    /// this value may change thus making the tests flaky. As such, we use a `MutexGuard` that locks
+    /// the process until `Server` is dropped. To optimize parallelization we use a lock only when it is
+    /// needed, that is when a test uses config directory to do stuff. Our naive approach is to use a lock
+    /// if there is a path to config dir in the test fixture. However, in certain cases we create a
+    /// file in the config dir after server is run, something where our naive approach comes short.
+    /// Using a `prelock` allows us to force a lock when we know we need it.
+    pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
         static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
+
+        let mut config_dir_guard = if prelock {
+            let v = Some(CONFIG_DIR_LOCK.lock());
+            env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
+            v
+        } else {
+            None
+        };
+
         let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
             if self.root_dir_contains_symlink {
                 TestDir::new_symlink()
@@ -160,13 +183,14 @@ impl Project<'_> {
         assert!(mini_core.is_none());
         assert!(toolchain.is_none());
 
-        let mut config_dir_guard = None;
         for entry in fixture {
             if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
                 if config_dir_guard.is_none() {
                     config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
+                    env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
                 }
-                let path = Config::user_config_path().unwrap().join(&pth['/'.len_utf8()..]);
+
+                let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
                 fs::create_dir_all(path.parent().unwrap()).unwrap();
                 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
             } else {
-- 
cgit 1.4.1-3-g733a5


From 19077860388fa32f3747632ad87b51d79a9ef9dc Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Sat, 7 Dec 2024 19:16:00 +0200
Subject: Coerce two `FnDef`s to fn pointers even if they are the same, if they
 are subtypes

That's because they can be the same function but still different substs, which mandates them to coerce to fn pointers in order to unify.
---
 .../rust-analyzer/crates/hir-ty/src/infer/coerce.rs      |  6 +++++-
 .../rust-analyzer/crates/hir-ty/src/tests/coercion.rs    | 16 ++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 366c3cb0f17..2fe90a8a924 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -125,7 +125,11 @@ impl CoerceMany {
         // pointers to have a chance at getting a match. See
         // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
         let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) {
-            (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) if x == y => None,
+            (TyKind::FnDef(x, _), TyKind::FnDef(y, _))
+                if x == y && ctx.table.unify(&self.merged_ty(), &expr_ty) =>
+            {
+                None
+            }
             (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None,
             (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
                 // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index 273571901ad..7992f1feeeb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -942,3 +942,19 @@ fn main() {
 "#,
     )
 }
+
+#[test]
+fn regression_18626() {
+    check_no_mismatches(
+        r#"
+fn f() {
+    trait T {
+        fn f() {}
+    }
+    impl T for i32 {}
+    impl T for u32 {}
+    &[i32::f, u32::f] as &[fn()];
+}
+    "#,
+    );
+}
-- 
cgit 1.4.1-3-g733a5


From 3ce35a4ec5f06828f908a018da083af5eb54301a Mon Sep 17 00:00:00 2001
From: Jack Wrenn 
Date: Fri, 6 Dec 2024 17:11:36 +0000
Subject: Make `Copy` unsafe to implement for ADTs with `unsafe` fields

As a rule, the application of `unsafe` to a declaration requires that use-sites
of that declaration also require `unsafe`. For example, a field declared
`unsafe` may only be read in the lexical context of an `unsafe` block.

For nearly all safe traits, the safety obligations of fields are explicitly
discharged when they are mentioned in method definitions. For example,
idiomatically implementing `Clone` (a safe trait) for a type with unsafe fields
will require `unsafe` to clone those fields.

Prior to this commit, `Copy` violated this rule. The trait is marked safe, and
although it has no explicit methods, its implementation permits reads of `Self`.

This commit resolves this by making `Copy` conditionally safe to implement. It
remains safe to implement for ADTs without unsafe fields, but unsafe to
implement for ADTs with unsafe fields.

Tracking: #132922
---
 .../rustc_codegen_cranelift/example/mini_core.rs   | 40 ++++++++++-----------
 compiler/rustc_codegen_gcc/example/mini_core.rs    | 36 +++++++++----------
 .../rustc_hir_analysis/src/coherence/builtin.rs    |  8 ++++-
 .../rustc_hir_analysis/src/coherence/unsafety.rs   | 38 +++++++++++++++-----
 compiler/rustc_lint/src/builtin.rs                 |  1 +
 compiler/rustc_middle/src/ty/sty.rs                |  6 +---
 compiler/rustc_middle/src/ty/util.rs               |  9 +++++
 compiler/rustc_trait_selection/src/traits/misc.rs  | 10 ++++++
 .../src/traits/select/candidate_assembly.rs        |  2 --
 .../clippy_lints/src/needless_pass_by_value.rs     |  1 +
 tests/ui/unsafe-fields/copy-trait.rs               | 41 ++++++++++++++++++++++
 tests/ui/unsafe-fields/copy-trait.stderr           | 28 +++++++++++++++
 12 files changed, 166 insertions(+), 54 deletions(-)
 create mode 100644 tests/ui/unsafe-fields/copy-trait.rs
 create mode 100644 tests/ui/unsafe-fields/copy-trait.stderr

(limited to 'src/tools')

diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 3da215fe6c0..a0a381638c0 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -55,26 +55,26 @@ impl LegacyReceiver for &mut T {}
 impl LegacyReceiver for Box {}
 
 #[lang = "copy"]
-pub unsafe trait Copy {}
-
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for u128 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for f64 {}
-unsafe impl Copy for char {}
-unsafe impl<'a, T: ?Sized> Copy for &'a T {}
-unsafe impl Copy for *const T {}
-unsafe impl Copy for *mut T {}
-unsafe impl Copy for Option {}
+pub trait Copy {}
+
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for u128 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for char {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+impl Copy for *const T {}
+impl Copy for *mut T {}
+impl Copy for Option {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index c887598f6e9..cdd151613df 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -52,24 +52,24 @@ impl LegacyReceiver for &mut T {}
 impl LegacyReceiver for Box {}
 
 #[lang = "copy"]
-pub unsafe trait Copy {}
-
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for f64 {}
-unsafe impl Copy for char {}
-unsafe impl<'a, T: ?Sized> Copy for &'a T {}
-unsafe impl Copy for *const T {}
-unsafe impl Copy for *mut T {}
+pub trait Copy {}
+
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for char {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+impl Copy for *const T {}
+impl Copy for *mut T {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 3b49bc41ffe..2eea65125b0 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -103,7 +103,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
     }
 
     let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
-    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
+    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
         Ok(()) => Ok(()),
         Err(CopyImplementationError::InfringingFields(fields)) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
@@ -123,6 +123,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
         }
+        Err(CopyImplementationError::HasUnsafeFields) => {
+            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            Err(tcx
+                .dcx()
+                .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index d66114a50d7..86839e40330 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -3,7 +3,7 @@
 
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
-use rustc_hir::Safety;
+use rustc_hir::{LangItem, Safety};
 use rustc_middle::ty::ImplPolarity::*;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt};
@@ -20,7 +20,19 @@ pub(super) fn check_item(
         tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
     let trait_ref = trait_header.trait_ref.instantiate_identity();
 
-    match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
+    let is_copy = tcx.is_lang_item(trait_def.def_id, LangItem::Copy);
+    let trait_def_safety = if is_copy {
+        // If `Self` has unsafe fields, `Copy` is unsafe to implement.
+        if trait_header.trait_ref.skip_binder().self_ty().has_unsafe_fields() {
+            rustc_hir::Safety::Unsafe
+        } else {
+            rustc_hir::Safety::Safe
+        }
+    } else {
+        trait_def.safety
+    };
+
+    match (trait_def_safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
         (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
@@ -48,12 +60,22 @@ pub(super) fn check_item(
                 "the trait `{}` requires an `unsafe impl` declaration",
                 trait_ref.print_trait_sugared()
             )
-            .with_note(format!(
-                "the trait `{}` enforces invariants that the compiler can't check. \
-                    Review the trait documentation and make sure this implementation \
-                    upholds those invariants before adding the `unsafe` keyword",
-                trait_ref.print_trait_sugared()
-            ))
+            .with_note(if is_copy {
+                format!(
+                    "the trait `{}` cannot be safely implemented for `{}` \
+                        because it has unsafe fields. Review the invariants \
+                        of those fields before adding an `unsafe impl`",
+                    trait_ref.print_trait_sugared(),
+                    trait_ref.self_ty(),
+                )
+            } else {
+                format!(
+                    "the trait `{}` enforces invariants that the compiler can't check. \
+                        Review the trait documentation and make sure this implementation \
+                        upholds those invariants before adding the `unsafe` keyword",
+                    trait_ref.print_trait_sugared()
+                )
+            })
             .with_span_suggestion_verbose(
                 span.shrink_to_lo(),
                 "add `unsafe` to this trait implementation",
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ec085198922..093cc16fb4c 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -625,6 +625,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             cx.param_env,
             ty,
             traits::ObligationCause::misc(item.span, item.owner_id.def_id),
+            hir::Safety::Safe,
         )
         .is_ok()
         {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 474062218c9..3fbc23924f5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -980,11 +980,7 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> {
     }
 
     fn has_unsafe_fields(self) -> bool {
-        if let ty::Adt(adt_def, ..) = self.kind() {
-            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
-        } else {
-            false
-        }
+        Ty::has_unsafe_fields(self)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 57054bd1a0b..b9a45ea3c2c 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1288,6 +1288,15 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    /// Checks whether this type is an ADT that has unsafe fields.
+    pub fn has_unsafe_fields(self) -> bool {
+        if let ty::Adt(adt_def, ..) = self.kind() {
+            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
+        } else {
+            false
+        }
+    }
+
     /// Get morphology of the async drop glue, needed for types which do not
     /// use async drop. To get async drop glue morphology for a definition see
     /// [`TyCtxt::async_drop_glue_morphology`]. Used for `AsyncDestruct::Destructor`
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 3b17fa6b032..d216ae72913 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -18,6 +18,7 @@ pub enum CopyImplementationError<'tcx> {
     InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
     NotAnAdt,
     HasDestructor,
+    HasUnsafeFields,
 }
 
 pub enum ConstParamTyImplementationError<'tcx> {
@@ -39,11 +40,16 @@ pub enum InfringingFieldsReason<'tcx> {
 ///
 /// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
 /// a reference or an array returns `Err(NotAnAdt)`.
+///
+/// If the impl is `Safe`, `self_type` must not have unsafe fields. When used to
+/// generate suggestions in lints, `Safe` should be supplied so as to not
+/// suggest implementing `Copy` for types with unsafe fields.
 pub fn type_allowed_to_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
     parent_cause: ObligationCause<'tcx>,
+    impl_safety: hir::Safety,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     let (adt, args) = match self_type.kind() {
         // These types used to have a builtin impl.
@@ -78,6 +84,10 @@ pub fn type_allowed_to_implement_copy<'tcx>(
         return Err(CopyImplementationError::HasDestructor);
     }
 
+    if impl_safety == hir::Safety::Safe && self_type.has_unsafe_fields() {
+        return Err(CopyImplementationError::HasUnsafeFields);
+    }
+
     Ok(())
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3e2c8467d32..5e27fd43789 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -795,8 +795,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::CoroutineWitness(..) => {
-                    use rustc_type_ir::inherent::*;
-
                     // Only consider auto impls of unsafe traits when there are
                     // no unsafe fields.
                     if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index cd90d2f90f7..6f3f371a68d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -200,6 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                                 cx.param_env,
                                 ty,
                                 traits::ObligationCause::dummy_with_span(span),
+                                rustc_hir::Safety::Safe,
                             )
                             .is_ok()
                             {
diff --git a/tests/ui/unsafe-fields/copy-trait.rs b/tests/ui/unsafe-fields/copy-trait.rs
new file mode 100644
index 00000000000..fb09ed02e3f
--- /dev/null
+++ b/tests/ui/unsafe-fields/copy-trait.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: --crate-type=lib
+
+#![feature(unsafe_fields)]
+#![allow(incomplete_features)]
+#![deny(missing_copy_implementations)]
+
+mod good_safe_impl {
+    enum SafeEnum {
+        Safe(u8),
+    }
+
+    impl Copy for SafeEnum {}
+}
+
+mod bad_safe_impl {
+    enum UnsafeEnum {
+        Safe(u8),
+        Unsafe { unsafe field: u8 },
+    }
+
+    impl Copy for UnsafeEnum {}
+    //~^ ERROR the trait `Copy` requires an `unsafe impl` declaration
+}
+
+mod good_unsafe_impl {
+    enum UnsafeEnum {
+        Safe(u8),
+        Unsafe { unsafe field: u8 },
+    }
+
+    unsafe impl Copy for UnsafeEnum {}
+}
+
+mod bad_unsafe_impl {
+    enum SafeEnum {
+        Safe(u8),
+    }
+
+    unsafe impl Copy for SafeEnum {}
+    //~^ ERROR implementing the trait `Copy` is not unsafe
+}
diff --git a/tests/ui/unsafe-fields/copy-trait.stderr b/tests/ui/unsafe-fields/copy-trait.stderr
new file mode 100644
index 00000000000..5952f8c89c1
--- /dev/null
+++ b/tests/ui/unsafe-fields/copy-trait.stderr
@@ -0,0 +1,28 @@
+error[E0200]: the trait `Copy` requires an `unsafe impl` declaration
+  --> $DIR/copy-trait.rs:21:5
+   |
+LL |     impl Copy for UnsafeEnum {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the trait `Copy` cannot be safely implemented for `bad_safe_impl::UnsafeEnum` because it has unsafe fields. Review the invariants of those fields before adding an `unsafe impl`
+help: add `unsafe` to this trait implementation
+   |
+LL |     unsafe impl Copy for UnsafeEnum {}
+   |     ++++++
+
+error[E0199]: implementing the trait `Copy` is not unsafe
+  --> $DIR/copy-trait.rs:39:5
+   |
+LL |     unsafe impl Copy for SafeEnum {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove `unsafe` from this trait implementation
+   |
+LL -     unsafe impl Copy for SafeEnum {}
+LL +     impl Copy for SafeEnum {}
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0199, E0200.
+For more information about an error, try `rustc --explain E0199`.
-- 
cgit 1.4.1-3-g733a5


From ee300059c5493ea2798803fa9a1389a682fec669 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Sun, 8 Dec 2024 15:02:14 +0200
Subject: Fix a test that didn't test what it should

That is, fix the helper function and disable the tests for now.
---
 .../hir-def/src/nameres/tests/incremental.rs       | 96 +++++++++++-----------
 1 file changed, 49 insertions(+), 47 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index d920c108266..e54b0fb78f8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -8,7 +8,8 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change:
     let krate = {
         let crate_graph = db.crate_graph();
         // Some of these tests use minicore/proc-macros which will be injected as the first crate
-        crate_graph.iter().last().unwrap()
+        let krate = crate_graph.iter().next().unwrap();
+        krate
     };
     {
         let events = db.log_executed(|| {
@@ -120,28 +121,29 @@ fn f() { foo }
     );
 }
 
-#[test]
-fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
-    check_def_map_is_not_recomputed(
-        r"
-//- proc_macros: identity
-//- /lib.rs
-mod foo;
+// #[test]
+// fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
+//     check_def_map_is_not_recomputed(
+//         r"
+// //- proc_macros: identity
+// //- /lib.rs
+// mod foo;
+
+// //- /foo/mod.rs
+// pub mod bar;
+
+// //- /foo/bar.rs
+// $0
+// #[proc_macros::identity]
+// fn f() {}
+// ",
+//         r"
+// #[proc_macros::identity(foo)]
+// fn f() {}
+// ",
+//     );
+// }
 
-//- /foo/mod.rs
-pub mod bar;
-
-//- /foo/bar.rs
-$0
-#[proc_macros::identity]
-fn f() {}
-",
-        r"
-#[proc_macros::identity(foo)]
-fn f() {}
-",
-    );
-}
 #[test]
 fn typing_inside_macro_heavy_file_should_not_invalidate_def_map() {
     check_def_map_is_not_recomputed(
@@ -198,31 +200,31 @@ pub struct S {}
     );
 }
 
-#[test]
-fn typing_inside_a_derive_should_not_invalidate_def_map() {
-    check_def_map_is_not_recomputed(
-        r"
-//- proc_macros: derive_identity
-//- minicore:derive
-//- /lib.rs
-mod foo;
-
-//- /foo/mod.rs
-pub mod bar;
-
-//- /foo/bar.rs
-$0
-#[derive(proc_macros::DeriveIdentity)]
-#[allow()]
-struct S;
-",
-        r"
-#[derive(proc_macros::DeriveIdentity)]
-#[allow(dead_code)]
-struct S;
-",
-    );
-}
+// #[test]
+// fn typing_inside_a_derive_should_not_invalidate_def_map() {
+//     check_def_map_is_not_recomputed(
+//         r"
+// //- proc_macros: derive_identity
+// //- minicore:derive
+// //- /lib.rs
+// mod foo;
+
+// //- /foo/mod.rs
+// pub mod bar;
+
+// //- /foo/bar.rs
+// $0
+// #[derive(proc_macros::DeriveIdentity)]
+// #[allow()]
+// struct S;
+// ",
+//         r"
+// #[derive(proc_macros::DeriveIdentity)]
+// #[allow(dead_code)]
+// struct S;
+// ",
+//     );
+// }
 
 #[test]
 fn typing_inside_a_function_should_not_invalidate_item_expansions() {
-- 
cgit 1.4.1-3-g733a5


From 2d8a871d4b6e1d636ac7c44742c54551e0d3fc09 Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Sun, 8 Dec 2024 18:18:03 +0000
Subject: Downgrade cc

---
 Cargo.lock                    | 4 ++--
 library/Cargo.lock            | 4 ++--
 src/tools/rustbook/Cargo.lock | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

(limited to 'src/tools')

diff --git a/Cargo.lock b/Cargo.lock
index 89e7d70d839..28478876a27 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -405,9 +405,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 490c989300f..03c2356e542 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -42,9 +42,9 @@ checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 3d35779be90..bab818899fb 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]
-- 
cgit 1.4.1-3-g733a5


From 30e3d23f0ef3ed7d43c096d768cc6386986d86f2 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:11:13 -0500
Subject: fix: Map new replacement nodes to their mutable equivalents in
 `SyntaxEditor`

---
 .../rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs | 5 ++---
 .../rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs   | 5 ++---
 .../crates/ide-assists/src/handlers/flip_trait_bound.rs           | 4 ++--
 .../crates/ide-assists/src/handlers/reorder_fields.rs             | 7 +++----
 .../crates/ide-assists/src/handlers/reorder_impl_items.rs         | 8 ++++----
 .../rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs   | 7 +++----
 .../rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs    | 6 ++++++
 7 files changed, 22 insertions(+), 20 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
index 601fd29f8e7..818a868fe34 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -52,9 +52,8 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             if let FlipAction::FlipAndReplaceOp(binary_op) = action {
                 editor.replace(op_token, make.token(binary_op))
             };
-            // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-            editor.replace(lhs.syntax(), rhs.syntax().clone_for_update());
-            editor.replace(rhs.syntax(), lhs.syntax().clone_for_update());
+            editor.replace(lhs.syntax(), rhs.syntax());
+            editor.replace(rhs.syntax(), lhs.syntax());
             editor.add_mappings(make.finish_with_mappings());
             builder.add_file_edits(ctx.file_id(), editor);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
index 490a9ee3c04..95e035c0537 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
@@ -39,13 +39,12 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         return None;
     }
 
-    // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
     let prev = match prev {
-        SyntaxElement::Node(node) => node.clone_for_update().syntax_element(),
+        SyntaxElement::Node(node) => node.syntax_element(),
         _ => prev,
     };
     let next = match next {
-        SyntaxElement::Node(node) => node.clone_for_update().syntax_element(),
+        SyntaxElement::Node(node) => node.syntax_element(),
         _ => next,
     };
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
index 03366bd8616..298e5bd82c9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
@@ -37,8 +37,8 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
         target,
         |builder| {
             let mut editor = builder.make_editor(parent.syntax());
-            editor.replace(before.clone(), after.clone_for_update());
-            editor.replace(after.clone(), before.clone_for_update());
+            editor.replace(before.clone(), after.clone());
+            editor.replace(after, before);
             builder.add_file_edits(ctx.file_id(), editor);
         },
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 4d3e85ab1b2..972303c2a04 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -92,10 +92,9 @@ fn replace(
     fields: impl Iterator,
     sorted_fields: impl IntoIterator,
 ) {
-    fields.zip(sorted_fields).for_each(|(field, sorted_field)| {
-        // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-        editor.replace(field.syntax(), sorted_field.syntax().clone_for_update())
-    });
+    fields
+        .zip(sorted_fields)
+        .for_each(|(field, sorted_field)| editor.replace(field.syntax(), sorted_field.syntax()));
 }
 
 fn compute_fields_ranks(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index d7fa8826125..eb1d538f874 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -101,10 +101,10 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         |builder| {
             let mut editor = builder.make_editor(&parent_node);
 
-            assoc_items.into_iter().zip(sorted).for_each(|(old, new)| {
-                // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-                editor.replace(old.syntax(), new.clone_for_update().syntax())
-            });
+            assoc_items
+                .into_iter()
+                .zip(sorted)
+                .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
 
             builder.add_file_edits(ctx.file_id(), editor);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
index 7307325e496..54e16d4d80a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
@@ -133,10 +133,9 @@ impl AddRewrite for Assists {
             |builder| {
                 let mut editor = builder.make_editor(target);
 
-                old.into_iter().zip(new).for_each(|(old, new)| {
-                    // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-                    editor.replace(old.syntax(), new.clone_for_update().syntax())
-                });
+                old.into_iter()
+                    .zip(new)
+                    .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
 
                 builder.add_file_edits(builder.file_id, editor)
             },
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
index 71b69dbec1d..57ecbe57019 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -155,6 +155,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
                     }
                 };
             }
+            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(new_target))) => {
+                *target = tree_mutator.make_syntax_mut(target);
+                if new_target.ancestors().any(|node| node == tree_mutator.immutable) {
+                    *new_target = new_target.clone_for_update();
+                }
+            }
             Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
                 *target = tree_mutator.make_element_mut(target);
             }
-- 
cgit 1.4.1-3-g733a5


From 3fc7101b966822ffb3b77106a16af8f806fb2001 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Wed, 30 Oct 2024 12:03:08 +0100
Subject: Fix config guard lock for ratoml tests

---
 .../rust-analyzer/crates/load-cargo/src/lib.rs     |  4 +-
 .../crates/rust-analyzer/src/config.rs             | 25 ++++-------
 .../crates/rust-analyzer/src/global_state.rs       | 10 ++---
 .../crates/rust-analyzer/src/reload.rs             |  4 +-
 .../rust-analyzer/tests/slow-tests/ratoml.rs       | 29 +++----------
 .../rust-analyzer/tests/slow-tests/support.rs      | 50 +++++++++++++++-------
 6 files changed, 59 insertions(+), 63 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index ab8a780363d..cf26845b119 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -156,7 +156,7 @@ impl ProjectFolders {
     pub fn new(
         workspaces: &[ProjectWorkspace],
         global_excludes: &[AbsPathBuf],
-        user_config_dir_path: Option<&'static AbsPath>,
+        user_config_dir_path: Option<&AbsPath>,
     ) -> ProjectFolders {
         let mut res = ProjectFolders::default();
         let mut fsc = FileSetConfig::builder();
@@ -302,7 +302,7 @@ impl ProjectFolders {
                 p
             };
 
-            let file_set_roots: Vec = vec![VfsPath::from(ratoml_path.to_owned())];
+            let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())];
             let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
 
             res.watch.push(res.load.len());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 921c9b991c5..694748f82f3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -3,11 +3,7 @@
 //! Of particular interest is the `feature_flags` hash map: while other fields
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
-use std::{
-    env, fmt, iter,
-    ops::Not,
-    sync::{LazyLock, OnceLock},
-};
+use std::{env, fmt, iter, ops::Not, sync::OnceLock};
 
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
@@ -805,16 +801,13 @@ impl std::ops::Deref for Config {
 
 impl Config {
     /// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux.
-    pub fn user_config_dir_path() -> Option<&'static AbsPath> {
-        static USER_CONFIG_PATH: LazyLock> = LazyLock::new(|| {
-            let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
-                std::path::PathBuf::from(path)
-            } else {
-                dirs::config_dir()?.join("rust-analyzer")
-            };
-            Some(AbsPathBuf::assert_utf8(user_config_path))
-        });
-        USER_CONFIG_PATH.as_deref()
+    pub fn user_config_dir_path() -> Option {
+        let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
+            std::path::PathBuf::from(path)
+        } else {
+            dirs::config_dir()?.join("rust-analyzer")
+        };
+        Some(AbsPathBuf::assert_utf8(user_config_path))
     }
 
     pub fn same_source_root_parent_map(
@@ -1254,7 +1247,7 @@ pub struct NotificationsConfig {
     pub cargo_toml_not_found: bool,
 }
 
-#[derive(Deserialize, Serialize, Debug, Clone)]
+#[derive(Debug, Clone)]
 pub enum RustfmtConfig {
     Rustfmt { extra_args: Vec, enable_range_formatting: bool },
     CustomCommand { command: String, args: Vec },
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 8d5536e1b09..5f835702840 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -392,13 +392,13 @@ impl GlobalState {
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
         {
             let config_change = {
-                let user_config_path = {
-                    let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
+                let user_config_path = (|| {
+                    let mut p = Config::user_config_dir_path()?;
                     p.push("rust-analyzer.toml");
-                    p
-                };
+                    Some(p)
+                })();
 
-                let user_config_abs_path = Some(user_config_path.as_path());
+                let user_config_abs_path = user_config_path.as_deref();
 
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index b0b62203528..4549735fef8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -590,7 +590,7 @@ impl GlobalState {
             }
 
             watchers.extend(
-                iter::once(Config::user_config_dir_path())
+                iter::once(Config::user_config_dir_path().as_deref())
                     .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
                     .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
@@ -616,7 +616,7 @@ impl GlobalState {
         let project_folders = ProjectFolders::new(
             &self.workspaces,
             &files_config.exclude,
-            Config::user_config_dir_path().to_owned(),
+            Config::user_config_dir_path().as_deref(),
         );
 
         if (self.proc_macro_clients.is_empty() || !same_workspaces)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index 623a9f76d14..5dfaf0d3650 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -30,23 +30,6 @@ impl RatomlTest {
         fixtures: Vec<&str>,
         roots: Vec<&str>,
         client_config: Option,
-    ) -> Self {
-        RatomlTest::new_with_lock(fixtures, roots, client_config, false)
-    }
-
-    fn new_locked(
-        fixtures: Vec<&str>,
-        roots: Vec<&str>,
-        client_config: Option,
-    ) -> Self {
-        RatomlTest::new_with_lock(fixtures, roots, client_config, true)
-    }
-
-    fn new_with_lock(
-        fixtures: Vec<&str>,
-        roots: Vec<&str>,
-        client_config: Option,
-        prelock: bool,
     ) -> Self {
         let tmp_dir = TestDir::new();
         let tmp_path = tmp_dir.path().to_owned();
@@ -63,7 +46,7 @@ impl RatomlTest {
             project = project.with_config(client_config);
         }
 
-        let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
+        let server = project.server_with_lock(true).wait_until_workspace_is_loaded();
 
         let mut case = Self { urls: vec![], server, tmp_path };
         let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::>();
@@ -89,7 +72,7 @@ impl RatomlTest {
         let mut spl = spl.into_iter();
         if let Some(first) = spl.next() {
             if first == "$$CONFIG_DIR$$" {
-                path = Config::user_config_dir_path().unwrap().to_path_buf().into();
+                path = Config::user_config_dir_path().unwrap().into();
             } else {
                 path = path.join(first);
             }
@@ -307,7 +290,7 @@ fn ratoml_user_config_detected() {
         return;
     }
 
-    let server = RatomlTest::new_locked(
+    let server = RatomlTest::new(
         vec![
             r#"
 //- /$$CONFIG_DIR$$/rust-analyzer.toml
@@ -343,7 +326,7 @@ fn ratoml_create_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -382,7 +365,7 @@ fn ratoml_modify_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -423,7 +406,7 @@ fn ratoml_delete_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 86137e3f2cc..5a88a5515c7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -1,7 +1,7 @@
 use std::{
     cell::{Cell, RefCell},
     env, fs,
-    sync::Once,
+    sync::{Once, OnceLock},
     time::Duration,
 };
 
@@ -140,13 +140,36 @@ impl Project<'_> {
     /// if there is a path to config dir in the test fixture. However, in certain cases we create a
     /// file in the config dir after server is run, something where our naive approach comes short.
     /// Using a `prelock` allows us to force a lock when we know we need it.
-    pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
-        static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
-
-        let mut config_dir_guard = if prelock {
-            let v = Some(CONFIG_DIR_LOCK.lock());
-            env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
-            v
+    pub(crate) fn server_with_lock(self, config_lock: bool) -> Server {
+        static CONFIG_DIR_LOCK: OnceLock<(Utf8PathBuf, Mutex<()>)> = OnceLock::new();
+
+        let config_dir_guard = if config_lock {
+            Some({
+                let (path, mutex) = CONFIG_DIR_LOCK.get_or_init(|| {
+                    let value = TestDir::new().keep().path().to_owned();
+                    env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
+                    (value, Mutex::new(()))
+                });
+                #[allow(dyn_drop)]
+                (mutex.lock(), {
+                    Box::new({
+                        struct Dropper(Utf8PathBuf);
+                        impl Drop for Dropper {
+                            fn drop(&mut self) {
+                                for entry in fs::read_dir(&self.0).unwrap() {
+                                    let path = entry.unwrap().path();
+                                    if path.is_file() {
+                                        fs::remove_file(path).unwrap();
+                                    } else if path.is_dir() {
+                                        fs::remove_dir_all(path).unwrap();
+                                    }
+                                }
+                            }
+                        }
+                        Dropper(path.clone())
+                    }) as Box
+                })
+            })
         } else {
             None
         };
@@ -185,11 +208,6 @@ impl Project<'_> {
 
         for entry in fixture {
             if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
-                if config_dir_guard.is_none() {
-                    config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
-                    env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
-                }
-
                 let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
                 fs::create_dir_all(path.parent().unwrap()).unwrap();
                 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
@@ -293,12 +311,14 @@ pub(crate) struct Server {
     client: Connection,
     /// XXX: remove the tempdir last
     dir: TestDir,
-    _config_dir_guard: Option>,
+    #[allow(dyn_drop)]
+    _config_dir_guard: Option<(MutexGuard<'static, ()>, Box)>,
 }
 
 impl Server {
+    #[allow(dyn_drop)]
     fn new(
-        config_dir_guard: Option>,
+        config_dir_guard: Option<(MutexGuard<'static, ()>, Box)>,
         dir: TestDir,
         config: Config,
     ) -> Server {
-- 
cgit 1.4.1-3-g733a5


From 4148b5345d1c33d801108ea9cc098f7544646ba3 Mon Sep 17 00:00:00 2001
From: Laurențiu Nicola 
Date: Mon, 9 Dec 2024 11:17:17 +0200
Subject: Remove unstable attributes in minicore

---
 src/tools/rust-analyzer/crates/test-utils/src/minicore.rs | 4 ----
 1 file changed, 4 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index f5c8466cb9f..99dfabe174e 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -728,7 +728,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl AsyncFnMut for &F
             where
                 F: AsyncFn,
@@ -746,7 +745,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F
             where
                 F: AsyncFn,
@@ -759,7 +757,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl AsyncFnMut for &mut F
             where
                 F: AsyncFnMut,
@@ -777,7 +774,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F
             where
                 F: AsyncFnMut,
-- 
cgit 1.4.1-3-g733a5


From b9f809a4b512034297a01ebeb0428fc7988007b0 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 09:48:54 +0100
Subject: Rename test fixture crates to ra_test_fixture

---
 .../rust-analyzer/crates/hir-def/src/body/tests.rs |   3 +-
 .../hir-def/src/macro_expansion_tests/mod.rs       |   3 +-
 .../crates/hir-def/src/nameres/tests.rs            |   4 +-
 .../hir-def/src/nameres/tests/incremental.rs       |  13 +-
 .../rust-analyzer/crates/hir-def/src/test_db.rs    |  13 +
 .../handlers/generate_documentation_template.rs    |  20 +-
 .../crates/ide-assists/src/tests/generated.rs      |   2 +-
 .../rust-analyzer/crates/ide/src/hover/tests.rs    | 744 ++++++++++-----------
 .../rust-analyzer/crates/test-fixture/src/lib.rs   |   2 +-
 9 files changed, 407 insertions(+), 397 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index 82d46d2e492..8f010915845 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -1,6 +1,5 @@
 mod block;
 
-use base_db::SourceDatabase;
 use expect_test::{expect, Expect};
 use test_fixture::WithFixture;
 
@@ -11,7 +10,7 @@ use super::*;
 fn lower(ra_fixture: &str) -> (TestDB, Arc, DefWithBodyId) {
     let db = TestDB::with_files(ra_fixture);
 
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     let def_map = db.crate_def_map(krate);
     let mut fn_def = None;
     'outer: for (_, module) in def_map.modules() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index d5b94f0ae44..0475e40c5b2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,7 +16,6 @@ mod proc_macros;
 
 use std::{iter, ops::Range, sync};
 
-use base_db::SourceDatabase;
 use expect_test::Expect;
 use hir_expand::{
     db::ExpandDatabase,
@@ -63,7 +62,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         },
     )];
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     let def_map = db.crate_def_map(krate);
     let local_id = DefMap::ROOT;
     let module = def_map.module_id(local_id);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index e1e30e5cec9..32c158415ba 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -13,13 +13,13 @@ use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
 
 fn compute_crate_def_map(ra_fixture: &str) -> Arc {
     let db = TestDB::with_files(ra_fixture);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     db.crate_def_map(krate)
 }
 
 fn render_crate_def_map(ra_fixture: &str) -> String {
     let db = TestDB::with_files(ra_fixture);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     db.crate_def_map(krate).dump(&db)
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index e54b0fb78f8..1cfbabca28c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -1,16 +1,11 @@
-use base_db::{SourceDatabase, SourceDatabaseFileInputExt as _};
+use base_db::SourceDatabaseFileInputExt as _;
 use test_fixture::WithFixture;
 
 use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId};
 
 fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
     let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
-    let krate = {
-        let crate_graph = db.crate_graph();
-        // Some of these tests use minicore/proc-macros which will be injected as the first crate
-        let krate = crate_graph.iter().next().unwrap();
-        krate
-    };
+    let krate = db.fetch_test_crate();
     {
         let events = db.log_executed(|| {
             db.crate_def_map(krate);
@@ -121,6 +116,8 @@ fn f() { foo }
     );
 }
 
+// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is
+// not currently the case.
 // #[test]
 // fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
 //     check_def_map_is_not_recomputed(
@@ -200,6 +197,8 @@ pub struct S {}
     );
 }
 
+// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is
+// not currently the case.
 // #[test]
 // fn typing_inside_a_derive_should_not_invalidate_def_map() {
 //     check_def_map_is_not_recomputed(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 0c36c88fb09..54e6c1fd206 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -78,6 +78,19 @@ impl FileLoader for TestDB {
 }
 
 impl TestDB {
+    pub(crate) fn fetch_test_crate(&self) -> CrateId {
+        let crate_graph = self.crate_graph();
+        let it = crate_graph
+            .iter()
+            .find(|&idx| {
+                crate_graph[idx].display_name.as_ref().map(|it| it.canonical_name().as_str())
+                    == Some("ra_test_fixture")
+            })
+            .or_else(|| crate_graph.iter().next())
+            .unwrap();
+        it
+    }
+
     pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
         for &krate in self.relevant_crates(file_id).iter() {
             let crate_def_map = self.crate_def_map(krate);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index c5c70c9f8eb..862be791d17 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -88,7 +88,7 @@ pub(crate) fn generate_documentation_template(
 // /// # Examples
 // ///
 // /// ```
-// /// use test::add;
+// /// use ra_test_fixture::add;
 // ///
 // /// assert_eq!(add(a, b), );
 // /// ```
@@ -596,7 +596,7 @@ pub fn noop_with_param(_a: i32) {}
 /// # Examples
 ///
 /// ```
-/// use test::noop_with_param;
+/// use ra_test_fixture::noop_with_param;
 ///
 /// noop_with_param(_a);
 /// ```
@@ -641,7 +641,7 @@ pub unsafe fn noop_unsafe() {}
 /// # Examples
 ///
 /// ```
-/// use test::noop_unsafe;
+/// use ra_test_fixture::noop_unsafe;
 ///
 /// unsafe { noop_unsafe() };
 /// ```
@@ -758,7 +758,7 @@ pub fn returns_a_value$0() -> i32 {
 /// # Examples
 ///
 /// ```
-/// use test::returns_a_value;
+/// use ra_test_fixture::returns_a_value;
 ///
 /// assert_eq!(returns_a_value(), );
 /// ```
@@ -807,7 +807,7 @@ pub fn modifies_a_value$0(a: &mut i32) {
 /// # Examples
 ///
 /// ```
-/// use test::modifies_a_value;
+/// use ra_test_fixture::modifies_a_value;
 ///
 /// let mut a = ;
 /// modifies_a_value(&mut a);
@@ -836,7 +836,7 @@ pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
 /// # Examples
 ///
 /// ```
-/// use test::sum3;
+/// use ra_test_fixture::sum3;
 ///
 /// let result = sum3(a, b, c);
 /// assert_eq!(result, );
@@ -868,7 +868,7 @@ pub mod a {
         /// # Examples
         ///
         /// ```
-        /// use test::a::b::noop;
+        /// use ra_test_fixture::a::b::noop;
         ///
         /// noop();
         /// ```
@@ -898,7 +898,7 @@ impl MyStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyStruct;
+    /// use ra_test_fixture::MyStruct;
     ///
     /// MyStruct::noop();
     /// ```
@@ -1169,7 +1169,7 @@ impl MyGenericStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyGenericStruct;
+    /// use ra_test_fixture::MyGenericStruct;
     ///
     /// let my_generic_struct = ;
     /// my_generic_struct.consume();
@@ -1199,7 +1199,7 @@ impl MyGenericStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyGenericStruct;
+    /// use ra_test_fixture::MyGenericStruct;
     ///
     /// let mut my_generic_struct = ;
     /// my_generic_struct.modify(new_value);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index eef4da55e94..69ea200db16 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1392,7 +1392,7 @@ pub fn add(a: i32, b: i32) -> i32 { a + b }
 /// # Examples
 ///
 /// ```
-/// use test::add;
+/// use ra_test_fixture::add;
 ///
 /// assert_eq!(add(a, b), );
 /// ```
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 1c08514a672..ea18b89c5c9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -288,7 +288,7 @@ m!(ab$0c);
             *abc*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -301,7 +301,7 @@ m!(ab$0c);
             ---
 
             ```rust
-            test::module
+            ra_test_fixture::module
             ```
 
             ```rust
@@ -327,7 +327,7 @@ fn main() {
 "#,
         expect![[r#"
             *foo*
-            test
+            ra_test_fixture
 
             pub fn foo() -> u32
         "#]],
@@ -487,7 +487,7 @@ fn main() {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -500,7 +500,7 @@ fn main() {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -583,7 +583,7 @@ fn main() { let foo_test = fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -605,7 +605,7 @@ fn main() { f$0oo(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -627,7 +627,7 @@ fn main() { m::f$0oo(); }
             *foo*
 
             ```rust
-            test::m
+            ra_test_fixture::m
             ```
 
             ```rust
@@ -649,7 +649,7 @@ fn main() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -667,7 +667,7 @@ fn main() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -691,7 +691,7 @@ fn main() { let foo_test = fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -715,7 +715,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -743,7 +743,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -776,7 +776,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -801,7 +801,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -830,7 +830,7 @@ fn main() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -852,7 +852,7 @@ fn main() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -880,7 +880,7 @@ fn main() {
             *0*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -900,7 +900,7 @@ fn foo(foo: Foo) {
             *0*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -920,7 +920,7 @@ struct Foo$0(pub u32) where u32: Copy;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -946,7 +946,7 @@ struct Foo$0 { field: u32 }
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -968,7 +968,7 @@ struct Foo$0 where u32: Copy { field: u32 }
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -998,7 +998,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1023,7 +1023,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1046,7 +1046,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1072,7 +1072,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1093,7 +1093,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1116,7 +1116,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1141,7 +1141,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1162,7 +1162,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1183,7 +1183,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1204,7 +1204,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1225,7 +1225,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1248,7 +1248,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1270,7 +1270,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1292,7 +1292,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1311,7 +1311,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1339,7 +1339,7 @@ fn hover_enum_limit() {
             *Enum*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1371,7 +1371,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1393,7 +1393,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1415,7 +1415,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1434,7 +1434,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1458,7 +1458,7 @@ struct Foo$0 where u32: Copy;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1484,7 +1484,7 @@ type Fo$0o: Trait = S where T: Trait;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1504,7 +1504,7 @@ fn hover_const_static() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1522,7 +1522,7 @@ const foo$0: u32 = {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1540,7 +1540,7 @@ const foo$0: u32 = {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1555,7 +1555,7 @@ const foo$0: u32 = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1573,7 +1573,7 @@ const foo$0: u32 = {
             *BAR*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1591,7 +1591,7 @@ fn hover_unsigned_max_const() {
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1612,7 +1612,7 @@ fn hover_eval_complex_constants() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1667,16 +1667,16 @@ use Option::Some;
 fn main() { So$0me(12); }
 "#,
         expect![[r#"
-                *Some*
+            *Some*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                Some(T)
-                ```
-            "#]],
+            ```rust
+            Some(T)
+            ```
+        "#]],
     );
 
     check(
@@ -1711,20 +1711,20 @@ enum Option {
 }
 "#,
         expect![[r#"
-                *None*
+            *None*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                None
-                ```
+            ```rust
+            None
+            ```
 
-                ---
+            ---
 
-                The None variant
-            "#]],
+            The None variant
+        "#]],
     );
 
     check(
@@ -1738,20 +1738,20 @@ fn main() {
 }
 "#,
         expect![[r#"
-                *Some*
+            *Some*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                Some(T)
-                ```
+            ```rust
+            Some(T)
+            ```
 
-                ---
+            ---
 
-                The Some variant
-            "#]],
+            The Some variant
+        "#]],
     );
 }
 
@@ -1885,7 +1885,7 @@ fn main() { let foo_test = wrapper::Thing::new$0(); }
             *new*
 
             ```rust
-            test::wrapper::Thing
+            ra_test_fixture::wrapper::Thing
             ```
 
             ```rust
@@ -1916,7 +1916,7 @@ fn main() {
             *C*
 
             ```rust
-            test::X
+            ra_test_fixture::X
             ```
 
             ```rust
@@ -1936,18 +1936,18 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing {
-                    x: u32,
-                }
-                ```
-            "#]],
+            ```rust
+            struct Thing {
+                x: u32,
+            }
+            ```
+        "#]],
     );
     check_hover_fields_limit(
         None,
@@ -1958,16 +1958,16 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing
-                ```
-            "#]],
+            ```rust
+            struct Thing
+            ```
+        "#]],
     );
     check(
         r#"
@@ -1977,18 +1977,18 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing {
-                    x: u32,
-                }
-                ```
-            "#]],
+            ```rust
+            struct Thing {
+                x: u32,
+            }
+            ```
+        "#]],
     );
     check(
         r#"
@@ -2001,7 +2001,7 @@ impl Thing {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2022,7 +2022,7 @@ impl Thing {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2042,7 +2042,7 @@ impl usize {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2060,7 +2060,7 @@ impl fn() -> usize {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2103,7 +2103,7 @@ fn f() { fo$0o!(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2128,7 +2128,7 @@ fn f() { fo$0o!(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2172,7 +2172,7 @@ id! {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2194,7 +2194,7 @@ fn foo$0() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2252,7 +2252,7 @@ fn foo() { let a = id!([0u32, bar$0()] ); }
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2278,7 +2278,7 @@ fn foo() {
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2302,7 +2302,7 @@ fn foo(Foo { b$0ar }: &Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -2334,7 +2334,7 @@ fn bar() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2356,7 +2356,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2370,7 +2370,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2385,7 +2385,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test::m
+            ra_test_fixture::m
             ```
 
             ```rust
@@ -2403,7 +2403,7 @@ fn test_hover_function_show_types() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2426,7 +2426,7 @@ fn main() { foo$0; }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2446,7 +2446,7 @@ fn main() { foo$0; }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2464,7 +2464,7 @@ fn test_hover_function_pointer_show_identifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2486,7 +2486,7 @@ fn test_hover_function_pointer_no_identifier() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2601,16 +2601,16 @@ mod my { pub struct Bar; }
 fn my() {}
 "#,
         expect![[r#"
-                *my*
+            *my*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod my
-                ```
-            "#]],
+            ```rust
+            mod my
+            ```
+        "#]],
     );
 }
 
@@ -2636,7 +2636,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2672,7 +2672,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2701,7 +2701,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2729,7 +2729,7 @@ pub struct B$0ar
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2760,7 +2760,7 @@ pub struct B$0ar
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2809,7 +2809,7 @@ pub fn fo$0o() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2853,7 +2853,7 @@ fn test_hover_layout_of_variant() {
             *Variant1*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -2878,7 +2878,7 @@ fn test_hover_layout_of_variant_generic() {
             *None*
 
             ```rust
-            test::Option
+            ra_test_fixture::Option
             ```
 
             ```rust
@@ -2899,7 +2899,7 @@ struct S$0(core::marker::PhantomData);
             *S*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2924,7 +2924,7 @@ fn test_hover_layout_of_enum() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2949,7 +2949,7 @@ fn test_hover_no_memory_layout() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -3003,7 +3003,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); }
             *foo*
 
             ```rust
-            test::Bar
+            ra_test_fixture::Bar
             ```
 
             ```rust
@@ -3041,7 +3041,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); }
             *foo*
 
             ```rust
-            test::Bar
+            ra_test_fixture::Bar
             ```
 
             ```rust
@@ -3069,7 +3069,7 @@ fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } }
             *foo*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -3267,7 +3267,7 @@ fn main() { let s$0t = S{ f1:0 }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3300,7 +3300,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Arg",
+                            mod_path: "ra_test_fixture::Arg",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3313,7 +3313,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3359,7 +3359,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Arg",
+                            mod_path: "ra_test_fixture::Arg",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3372,7 +3372,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3408,7 +3408,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::A",
+                            mod_path: "ra_test_fixture::A",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3421,7 +3421,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3434,7 +3434,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::M::C",
+                            mod_path: "ra_test_fixture::M::C",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3468,7 +3468,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3502,7 +3502,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3515,7 +3515,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3549,7 +3549,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3562,7 +3562,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3599,7 +3599,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3612,7 +3612,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3625,7 +3625,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S1",
+                            mod_path: "ra_test_fixture::S1",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3638,7 +3638,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3669,7 +3669,7 @@ fn foo(ar$0g: &impl Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3703,7 +3703,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3716,7 +3716,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3729,7 +3729,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3816,7 +3816,7 @@ fn foo(ar$0g: &impl Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3829,7 +3829,7 @@ fn foo(ar$0g: &impl Foo) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3866,7 +3866,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3879,7 +3879,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3892,7 +3892,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3923,7 +3923,7 @@ fn foo(ar$0g: &dyn Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3955,7 +3955,7 @@ fn foo(ar$0g: &dyn Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3968,7 +3968,7 @@ fn foo(ar$0g: &dyn Foo) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4003,7 +4003,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4016,7 +4016,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::DynTrait",
+                            mod_path: "ra_test_fixture::DynTrait",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4029,7 +4029,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::ImplTrait",
+                            mod_path: "ra_test_fixture::ImplTrait",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4042,7 +4042,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4084,7 +4084,7 @@ fn main() { let s$0t = test().get(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4117,7 +4117,7 @@ impl Foo {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4149,7 +4149,7 @@ fn foo(t: T$0){}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4182,7 +4182,7 @@ impl Foo {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4257,7 +4257,7 @@ fn main() {
             ---
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -4282,7 +4282,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4307,7 +4307,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4333,7 +4333,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4527,21 +4527,21 @@ mod Foo$0 {
 }
 "#,
         expect![[r#"
-                *Foo*
+            *Foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod Foo
-                ```
+            ```rust
+            mod Foo
+            ```
 
-                ---
+            ---
 
-                Be quick;
-                time is mana
-            "#]],
+            Be quick;
+            time is mana
+        "#]],
     );
 }
 
@@ -4558,21 +4558,21 @@ mod Foo$0 {
 }
 "#,
         expect![[r#"
-                *Foo*
+            *Foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod Foo
-                ```
+            ```rust
+            mod Foo
+            ```
 
-                ---
+            ---
 
-                Be quick;
-                time is mana
-            "#]],
+            Be quick;
+            time is mana
+        "#]],
     );
 }
 
@@ -4592,7 +4592,7 @@ fn foo$0() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4902,7 +4902,7 @@ type Fo$0o2 = Foo<2>;
             *Foo2*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4948,7 +4948,7 @@ enum E {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -4977,7 +4977,7 @@ enum E {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5007,7 +5007,7 @@ enum E {
             *B*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5037,7 +5037,7 @@ enum E {
             *B*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5074,7 +5074,7 @@ fn main() {
             *B*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5111,7 +5111,7 @@ fn main() {
             *AA*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5138,7 +5138,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5167,7 +5167,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5199,7 +5199,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5222,7 +5222,7 @@ const FOO$0: usize = 1 << 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5243,7 +5243,7 @@ const FOO$0: usize = (1 << 3) + (1 << 2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5265,7 +5265,7 @@ const FOO$0: usize = 2 - 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5287,7 +5287,7 @@ const FOO$0: i32 = 2 - 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5308,7 +5308,7 @@ const FOO$0: &str = "bar";
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5330,7 +5330,7 @@ const FOO$0: char = 'a';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5352,7 +5352,7 @@ const FOO$0: char = '\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5374,7 +5374,7 @@ const FOO$0: u8 = b'a';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5396,7 +5396,7 @@ const FOO$0: u8 = b'\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5418,7 +5418,7 @@ const FOO$0: u8 = b'\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5440,7 +5440,7 @@ const FOO$0: f32 = 1f32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5462,7 +5462,7 @@ const FOO$0: &i32 = &2;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5484,7 +5484,7 @@ const FOO$0: f64 = 1.0f64;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5512,7 +5512,7 @@ const FOO$0: f64 = expf64(1.2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5530,7 +5530,7 @@ const FOO$0: f32 = 1.9999999403953552_f32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5552,7 +5552,7 @@ const FOO$0: f16 = -1.0f16;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5573,7 +5573,7 @@ const FOO$0: f128 = -1.0f128;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5604,7 +5604,7 @@ const FOO$0: Enum = VX;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5621,7 +5621,7 @@ const FOO$0: Option = Some(2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5638,7 +5638,7 @@ const FOO$0: Option<&i32> = Some(2).as_ref();
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5661,7 +5661,7 @@ const FOO$0: &dyn Debug = &2i32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5682,7 +5682,7 @@ const FOO$0: &[i32] = &[1, 2, 3 + 4];
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5699,7 +5699,7 @@ const FOO$0: &[i32; 5] = &[12; 5];
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5720,7 +5720,7 @@ const FOO$0: (&i32, &[i32], &i32) = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5743,7 +5743,7 @@ const FOO$0: Tree = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5763,7 +5763,7 @@ const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5783,7 +5783,7 @@ const FOO$0: &str = "foo";
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5806,7 +5806,7 @@ const FOO$0: X = X {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5825,7 +5825,7 @@ const FOO$0: (&str, &str) = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5856,7 +5856,7 @@ fn test() {
             *FOO*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -5883,7 +5883,7 @@ fn foo() {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5912,7 +5912,7 @@ fn foo(e: E) {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5942,7 +5942,7 @@ pub fn the_function() -> AA {
             *CONST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5984,20 +5984,20 @@ mod foo$0;
 //! For the horde!
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod foo
-                ```
+            ```rust
+            mod foo
+            ```
 
-                ---
+            ---
 
-                For the horde!
-            "#]],
+            For the horde!
+        "#]],
     );
 }
 
@@ -6013,20 +6013,20 @@ mod foo {
 use foo::bar::{self$0};
 "#,
         expect![[r#"
-                *self*
+            *self*
 
-                ```rust
-                test::foo
-                ```
+            ```rust
+            ra_test_fixture::foo
+            ```
 
-                ```rust
-                mod bar
-                ```
+            ```rust
+            mod bar
+            ```
 
-                ---
+            ---
 
-                But this should appear
-            "#]],
+            But this should appear
+        "#]],
     )
 }
 
@@ -6166,7 +6166,7 @@ fn main() {
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6200,7 +6200,7 @@ pub fn gimme() -> theitem::TheItem {
             *[`TheItem`]*
 
             ```rust
-            test::theitem
+            ra_test_fixture::theitem
             ```
 
             ```rust
@@ -6248,7 +6248,7 @@ impl T1 for Foo {
             *Bar*
 
             ```rust
-            test::t2::T2
+            ra_test_fixture::t2::T2
             ```
 
             ```rust
@@ -6270,7 +6270,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6291,7 +6291,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6310,7 +6310,7 @@ trait A where
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6572,12 +6572,12 @@ fn hover_rename() {
 use self as foo$0;
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
     check(
         r#"
@@ -6585,16 +6585,16 @@ mod bar {}
 use bar::{self as foo$0};
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod bar
-                ```
-            "#]],
+            ```rust
+            mod bar
+            ```
+        "#]],
     );
     check(
         r#"
@@ -6603,24 +6603,24 @@ mod bar {
 }
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
     check(
         r#"
 use crate as foo$0;
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
 }
 
@@ -6645,7 +6645,7 @@ identity!{
             *Copy*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6669,7 +6669,7 @@ struct Foo;
             *Copy*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6691,7 +6691,7 @@ struct Foo;
             *Copy*
 
             ```rust
-            test::foo
+            ra_test_fixture::foo
             ```
 
             ```rust
@@ -6910,7 +6910,7 @@ fn foo() {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -7110,7 +7110,7 @@ foo_macro!(
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7119,7 +7119,7 @@ foo_macro!(
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7135,7 +7135,7 @@ pub struct Foo(i32);
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7144,7 +7144,7 @@ pub struct Foo(i32);
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7160,7 +7160,7 @@ pub struct Foo(T);
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7169,7 +7169,7 @@ pub struct Foo(T);
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7259,7 +7259,7 @@ enum Enum {
             *RecordV*
 
             ```rust
-            test::Enum
+            ra_test_fixture::Enum
             ```
 
             ```rust
@@ -7285,7 +7285,7 @@ enum Enum {
             *field*
 
             ```rust
-            test::RecordV
+            ra_test_fixture::RecordV
             ```
 
             ```rust
@@ -7315,7 +7315,7 @@ impl T for () {
             *func*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7341,7 +7341,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7360,7 +7360,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7383,7 +7383,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7406,7 +7406,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7433,7 +7433,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7460,7 +7460,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7529,7 +7529,7 @@ fn f() {
             ***
 
             ```rust
-            test::Struct
+            ra_test_fixture::Struct
             ```
 
             ```rust
@@ -7558,7 +7558,7 @@ fn main() { $0V; }
             *V*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7585,7 +7585,7 @@ fn main() { $0V; }
             *V*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7765,7 +7765,7 @@ fn test() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7794,7 +7794,7 @@ fn test() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7824,7 +7824,7 @@ mod m {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7854,7 +7854,7 @@ fn test() {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7883,7 +7883,7 @@ fn test() {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7913,7 +7913,7 @@ mod m {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7936,7 +7936,7 @@ fn test() {
             *f*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -8091,7 +8091,7 @@ fn main() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -8573,7 +8573,7 @@ impl Iterator for S {
             *S*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8595,7 +8595,7 @@ extern "C" {
             *STATIC*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8613,7 +8613,7 @@ extern "C" {
             *fun*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8631,7 +8631,7 @@ extern "C" {
             *Ty*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8731,7 +8731,7 @@ impl Iterator for S {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Notable",
+                            mod_path: "ra_test_fixture::Notable",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -8744,7 +8744,7 @@ impl Iterator for S {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -8775,7 +8775,7 @@ struct Pedro$0<'a> {
             *Pedro*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8962,7 +8962,7 @@ fn test_hover_function_with_pat_param() {
             *test_1*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8978,7 +8978,7 @@ fn test_hover_function_with_pat_param() {
             *test_2*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8994,7 +8994,7 @@ fn test_hover_function_with_pat_param() {
             *test_3*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9010,7 +9010,7 @@ fn test_hover_function_with_pat_param() {
             *test_4*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9026,7 +9026,7 @@ fn test_hover_function_with_pat_param() {
             *test_5*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9042,7 +9042,7 @@ fn test_hover_function_with_pat_param() {
             *test_6*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9058,7 +9058,7 @@ fn test_hover_function_with_pat_param() {
             *test_7*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9074,7 +9074,7 @@ fn test_hover_function_with_pat_param() {
             *test_8*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9090,7 +9090,7 @@ fn test_hover_function_with_pat_param() {
             *test_9*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9106,7 +9106,7 @@ fn test_hover_function_with_pat_param() {
             *test_10*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9122,7 +9122,7 @@ fn test_hover_function_with_pat_param() {
             *test_10*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9148,7 +9148,7 @@ mod m {
             *C*
 
             ```rust
-            test::m::m2
+            ra_test_fixture::m::m2
             ```
 
             ```rust
@@ -9173,17 +9173,17 @@ macro_rules! foo {
 foo!(BAR_$0);
 "#,
         expect![[r#"
-        *BAR_*
+            *BAR_*
 
-        ```rust
-        test
-        ```
+            ```rust
+            ra_test_fixture
+            ```
 
-        ```rust
-        pub static BAR_: {error} = Foo::new(||{
-            crate;
-        })
-        ```
+            ```rust
+            pub static BAR_: {error} = Foo::new(||{
+                crate;
+            })
+            ```
         "#]],
     );
 }
@@ -9202,7 +9202,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9235,7 +9235,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9269,7 +9269,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9301,7 +9301,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9362,7 +9362,7 @@ trait Compat$0 {}
             *Compat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9384,7 +9384,7 @@ trait UnCompat$0 {
             *UnCompat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9407,7 +9407,7 @@ fn f
             *UnCompat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 593e31c2fbb..889a7d10ada 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -236,7 +236,7 @@ impl ChangeFixture {
             crate_graph.add_crate_root(
                 crate_root,
                 Edition::CURRENT,
-                Some(CrateName::new("test").unwrap().into()),
+                Some(CrateName::new("ra_test_fixture").unwrap().into()),
                 None,
                 From::from(default_cfg.clone()),
                 Some(From::from(default_cfg)),
-- 
cgit 1.4.1-3-g733a5


From 770265d0578e5146092681bb252f29f0023d5028 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 11:42:51 +0100
Subject: Remove patch sysroot cfg-if hack

---
 .../rust-analyzer/crates/base-db/src/input.rs      | 23 -----------
 .../crates/project-model/src/workspace.rs          | 48 ++++++++--------------
 2 files changed, 18 insertions(+), 53 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 57522d69321..e86944eeb35 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -547,29 +547,6 @@ impl CrateGraph {
         None
     }
 
-    // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038.
-    // As hacky as it gets.
-    pub fn patch_cfg_if(&mut self) -> bool {
-        // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works
-        let cfg_if =
-            self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone());
-        let std = self.hacky_find_crate("std").next();
-        match (cfg_if, std) {
-            (Some(cfg_if), Some(std)) => {
-                self.arena[cfg_if].dependencies.clear();
-                self.arena[std]
-                    .dependencies
-                    .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if));
-                true
-            }
-            _ => false,
-        }
-    }
-
-    fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a {
-        self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name))
-    }
-
     /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies.
     /// Returns a mapping from old crate ids to new crate ids.
     pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index f5ba71fcd05..988eff9be44 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -747,17 +747,14 @@ impl ProjectWorkspace {
         let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered();
 
         let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
-        let ((mut crate_graph, proc_macros), sysroot) = match kind {
-            ProjectWorkspaceKind::Json(project) => (
-                project_json_to_crate_graph(
-                    rustc_cfg.clone(),
-                    load,
-                    project,
-                    sysroot,
-                    extra_env,
-                    cfg_overrides,
-                ),
+        let (crate_graph, proc_macros) = match kind {
+            ProjectWorkspaceKind::Json(project) => project_json_to_crate_graph(
+                rustc_cfg.clone(),
+                load,
+                project,
                 sysroot,
+                extra_env,
+                cfg_overrides,
             ),
             ProjectWorkspaceKind::Cargo {
                 cargo,
@@ -766,20 +763,17 @@ impl ProjectWorkspace {
                 cargo_config_extra_env: _,
                 error: _,
                 set_test,
-            } => (
-                cargo_to_crate_graph(
-                    load,
-                    rustc.as_ref().map(|a| a.as_ref()).ok(),
-                    cargo,
-                    sysroot,
-                    rustc_cfg.clone(),
-                    cfg_overrides,
-                    build_scripts,
-                    *set_test,
-                ),
+            } => cargo_to_crate_graph(
+                load,
+                rustc.as_ref().map(|a| a.as_ref()).ok(),
+                cargo,
                 sysroot,
+                rustc_cfg.clone(),
+                cfg_overrides,
+                build_scripts,
+                *set_test,
             ),
-            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => (
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => {
                 if let Some((cargo, build_scripts, _)) = cargo_script {
                     cargo_to_crate_graph(
                         &mut |path| load(path),
@@ -800,16 +794,10 @@ impl ProjectWorkspace {
                         cfg_overrides,
                         *set_test,
                     )
-                },
-                sysroot,
-            ),
+                }
+            }
         };
 
-        if matches!(sysroot.mode(), SysrootMode::Stitched(_)) && crate_graph.patch_cfg_if() {
-            debug!("Patched std to depend on cfg-if")
-        } else {
-            debug!("Did not patch std to depend on cfg-if")
-        }
         (crate_graph, proc_macros)
     }
 
-- 
cgit 1.4.1-3-g733a5


From a6c462863d0a73f0925aab2c9556db8b45a6e502 Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Tue, 3 Dec 2024 20:21:51 +0000
Subject: compiletest: `print{,ln}!` -> `eprint{,ln}!`

Co-authored-by: Jieyou Xu 
---
 src/tools/compiletest/src/compute_diff.rs          |  2 +-
 src/tools/compiletest/src/debuggers.rs             |  6 +--
 src/tools/compiletest/src/lib.rs                   | 10 ++---
 src/tools/compiletest/src/runtest.rs               | 52 +++++++++++-----------
 src/tools/compiletest/src/runtest/codegen_units.rs | 22 ++++-----
 src/tools/compiletest/src/runtest/debuginfo.rs     | 10 ++---
 src/tools/compiletest/src/runtest/incremental.rs   |  2 +-
 src/tools/compiletest/src/runtest/mir_opt.rs       |  2 +-
 src/tools/compiletest/src/runtest/rustdoc_json.rs  |  2 +-
 src/tools/compiletest/src/runtest/ui.rs            |  4 +-
 src/tools/compiletest/src/util.rs                  |  2 +-
 11 files changed, 57 insertions(+), 57 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs
index 92c80c27de0..3ace6c5b6d7 100644
--- a/src/tools/compiletest/src/compute_diff.rs
+++ b/src/tools/compiletest/src/compute_diff.rs
@@ -144,7 +144,7 @@ where
     }
 
     if !wrote_data {
-        println!("note: diff is identical to nightly rustdoc");
+        eprintln!("note: diff is identical to nightly rustdoc");
         assert!(diff_output.metadata().unwrap().len() == 0);
         return false;
     } else if verbose {
diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs
index b605bc813f1..e75c8a5993e 100644
--- a/src/tools/compiletest/src/debuggers.rs
+++ b/src/tools/compiletest/src/debuggers.rs
@@ -20,7 +20,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> {
     }
 
     if config.remote_test_client.is_some() && !config.target.contains("android") {
-        println!(
+        eprintln!(
             "WARNING: debuginfo tests are not available when \
              testing with remote"
         );
@@ -28,7 +28,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> {
     }
 
     if config.target.contains("android") {
-        println!(
+        eprintln!(
             "{} debug-info test uses tcp 5039 port.\
              please reserve it",
             config.target
@@ -50,7 +50,7 @@ pub(crate) fn configure_lldb(config: &Config) -> Option> {
     config.lldb_python_dir.as_ref()?;
 
     if let Some(350) = config.lldb_version {
-        println!(
+        eprintln!(
             "WARNING: The used version of LLDB (350) has a \
              known issue that breaks debuginfo tests. See \
              issue #32520 for more information. Skipping all \
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index a5a166af33b..9acb7d393b4 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -188,8 +188,8 @@ pub fn parse_config(args: Vec) -> Config {
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
+        eprintln!("{}", opts.usage(&message));
+        eprintln!();
         panic!()
     }
 
@@ -200,8 +200,8 @@ pub fn parse_config(args: Vec) -> Config {
 
     if matches.opt_present("h") || matches.opt_present("help") {
         let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
+        eprintln!("{}", opts.usage(&message));
+        eprintln!();
         panic!()
     }
 
@@ -508,7 +508,7 @@ pub fn run_tests(config: Arc) {
             // easy to miss which tests failed, and as such fail to reproduce
             // the failure locally.
 
-            println!(
+            eprintln!(
                 "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
                 config.suite,
                 config
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 7b11bf3b121..ca746ed8c55 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -131,7 +131,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) {
 
     if config.verbose {
         // We're going to be dumping a lot of info. Start on a new line.
-        print!("\n\n");
+        eprintln!("\n");
     }
     debug!("running {:?}", testpaths.file.display());
     let mut props = TestProps::from_file(&testpaths.file, revision, &config);
@@ -353,7 +353,7 @@ impl<'test> TestCx<'test> {
                 {
                     self.error(&format!("{} test did not emit an error", self.config.mode));
                     if self.config.mode == crate::common::Mode::Ui {
-                        println!("note: by default, ui tests are expected not to compile");
+                        eprintln!("note: by default, ui tests are expected not to compile");
                     }
                     proc_res.fatal(None, || ());
                 };
@@ -774,20 +774,20 @@ impl<'test> TestCx<'test> {
                 unexpected.len(),
                 not_found.len()
             ));
-            println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
+            eprintln!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
             if !unexpected.is_empty() {
-                println!("{}", "--- unexpected errors (from JSON output) ---".green());
+                eprintln!("{}", "--- unexpected errors (from JSON output) ---".green());
                 for error in &unexpected {
-                    println!("{}", error.render_for_expected());
+                    eprintln!("{}", error.render_for_expected());
                 }
-                println!("{}", "---".green());
+                eprintln!("{}", "---".green());
             }
             if !not_found.is_empty() {
-                println!("{}", "--- not found errors (from test file) ---".red());
+                eprintln!("{}", "--- not found errors (from test file) ---".red());
                 for error in ¬_found {
-                    println!("{}", error.render_for_expected());
+                    eprintln!("{}", error.render_for_expected());
                 }
-                println!("{}", "---\n".red());
+                eprintln!("{}", "---\n".red());
             }
             panic!("errors differ from expected");
         }
@@ -1876,18 +1876,18 @@ impl<'test> TestCx<'test> {
 
     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
         if self.config.verbose {
-            println!("------stdout------------------------------");
-            println!("{}", out);
-            println!("------stderr------------------------------");
-            println!("{}", err);
-            println!("------------------------------------------");
+            eprintln!("------stdout------------------------------");
+            eprintln!("{}", out);
+            eprintln!("------stderr------------------------------");
+            eprintln!("{}", err);
+            eprintln!("------------------------------------------");
         }
     }
 
     fn error(&self, err: &str) {
         match self.revision {
-            Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
-            None => println!("\nerror: {}", err),
+            Some(rev) => eprintln!("\nerror in revision `{}`: {}", rev, err),
+            None => eprintln!("\nerror: {}", err),
         }
     }
 
@@ -1972,7 +1972,7 @@ impl<'test> TestCx<'test> {
         if !self.config.has_html_tidy {
             return;
         }
-        println!("info: generating a diff against nightly rustdoc");
+        eprintln!("info: generating a diff against nightly rustdoc");
 
         let suffix =
             self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
@@ -2082,7 +2082,7 @@ impl<'test> TestCx<'test> {
                 .output()
                 .unwrap();
             assert!(output.status.success());
-            println!("{}", String::from_utf8_lossy(&output.stdout));
+            eprintln!("{}", String::from_utf8_lossy(&output.stdout));
             eprintln!("{}", String::from_utf8_lossy(&output.stderr));
         } else {
             use colored::Colorize;
@@ -2496,7 +2496,7 @@ impl<'test> TestCx<'test> {
                 )"#
             )
             .replace_all(&output, |caps: &Captures<'_>| {
-                println!("{}", &caps[0]);
+                eprintln!("{}", &caps[0]);
                 caps[0].replace(r"\", "/")
             })
             .replace("\r\n", "\n")
@@ -2601,14 +2601,14 @@ impl<'test> TestCx<'test> {
         if let Err(err) = fs::write(&actual_path, &actual) {
             self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
         }
-        println!("Saved the actual {stream} to {actual_path:?}");
+        eprintln!("Saved the actual {stream} to {actual_path:?}");
 
         let expected_path =
             expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
 
         if !self.config.bless {
             if expected.is_empty() {
-                println!("normalized {}:\n{}\n", stream, actual);
+                eprintln!("normalized {}:\n{}\n", stream, actual);
             } else {
                 self.show_diff(
                     stream,
@@ -2631,10 +2631,10 @@ impl<'test> TestCx<'test> {
             if let Err(err) = fs::write(&expected_path, &actual) {
                 self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
             }
-            println!("Blessing the {stream} of {test_name} in {expected_path:?}");
+            eprintln!("Blessing the {stream} of {test_name} in {expected_path:?}");
         }
 
-        println!("\nThe actual {0} differed from the expected {0}.", stream);
+        eprintln!("\nThe actual {0} differed from the expected {0}.", stream);
 
         if self.config.bless { 0 } else { 1 }
     }
@@ -2783,7 +2783,7 @@ impl<'test> TestCx<'test> {
         fs::create_dir_all(&incremental_dir).unwrap();
 
         if self.config.verbose {
-            println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+            eprintln!("init_incremental_test: incremental_dir={}", incremental_dir.display());
         }
     }
 
@@ -2841,7 +2841,7 @@ impl ProcRes {
             }
         }
 
-        println!(
+        eprintln!(
             "status: {}\ncommand: {}\n{}\n{}\n",
             self.status,
             self.cmdline,
@@ -2852,7 +2852,7 @@ impl ProcRes {
 
     pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
         if let Some(e) = err {
-            println!("\nerror: {}", e);
+            eprintln!("\nerror: {}", e);
         }
         self.print_info();
         on_failure();
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 6c866cbef21..6acd140183d 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -64,13 +64,13 @@ impl TestCx<'_> {
         if !missing.is_empty() {
             missing.sort();
 
-            println!("\nThese items should have been contained but were not:\n");
+            eprintln!("\nThese items should have been contained but were not:\n");
 
             for item in &missing {
-                println!("{}", item);
+                eprintln!("{}", item);
             }
 
-            println!("\n");
+            eprintln!("\n");
         }
 
         if !unexpected.is_empty() {
@@ -80,24 +80,24 @@ impl TestCx<'_> {
                 sorted
             };
 
-            println!("\nThese items were contained but should not have been:\n");
+            eprintln!("\nThese items were contained but should not have been:\n");
 
             for item in sorted {
-                println!("{}", item);
+                eprintln!("{}", item);
             }
 
-            println!("\n");
+            eprintln!("\n");
         }
 
         if !wrong_cgus.is_empty() {
             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
-            println!("\nThe following items were assigned to wrong codegen units:\n");
+            eprintln!("\nThe following items were assigned to wrong codegen units:\n");
 
             for &(ref expected_item, ref actual_item) in &wrong_cgus {
-                println!("{}", expected_item.name);
-                println!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
-                println!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
-                println!();
+                eprintln!("{}", expected_item.name);
+                eprintln!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
+                eprintln!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
+                eprintln!();
             }
         }
 
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index c621c22ac99..7322e730e53 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -260,7 +260,7 @@ impl TestCx<'_> {
                 cmdline,
             };
             if adb.kill().is_err() {
-                println!("Adb process is already finished.");
+                eprintln!("Adb process is already finished.");
             }
         } else {
             let rust_src_root =
@@ -275,7 +275,7 @@ impl TestCx<'_> {
 
             match self.config.gdb_version {
                 Some(version) => {
-                    println!("NOTE: compiletest thinks it is using GDB version {}", version);
+                    eprintln!("NOTE: compiletest thinks it is using GDB version {}", version);
 
                     if version > extract_gdb_version("7.4").unwrap() {
                         // Add the directory containing the pretty printers to
@@ -297,7 +297,7 @@ impl TestCx<'_> {
                     }
                 }
                 _ => {
-                    println!(
+                    eprintln!(
                         "NOTE: compiletest does not know which version of \
                          GDB it is using"
                     );
@@ -392,10 +392,10 @@ impl TestCx<'_> {
 
         match self.config.lldb_version {
             Some(ref version) => {
-                println!("NOTE: compiletest thinks it is using LLDB version {}", version);
+                eprintln!("NOTE: compiletest thinks it is using LLDB version {}", version);
             }
             _ => {
-                println!(
+                eprintln!(
                     "NOTE: compiletest does not know which version of \
                      LLDB it is using"
                 );
diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs
index 591aff0defe..4f26786129b 100644
--- a/src/tools/compiletest/src/runtest/incremental.rs
+++ b/src/tools/compiletest/src/runtest/incremental.rs
@@ -30,7 +30,7 @@ impl TestCx<'_> {
         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
 
         if self.config.verbose {
-            print!("revision={:?} props={:#?}", revision, self.props);
+            eprint!("revision={:?} props={:#?}", revision, self.props);
         }
 
         if revision.starts_with("cpass") {
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index d1ec0035744..64a2addaa28 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -89,7 +89,7 @@ impl TestCx<'_> {
                 }
                 let expected_string = fs::read_to_string(&expected_file).unwrap();
                 if dumped_string != expected_string {
-                    print!("{}", write_diff(&expected_string, &dumped_string, 3));
+                    eprint!("{}", write_diff(&expected_string, &dumped_string, 3));
                     panic!(
                         "Actual MIR output differs from expected MIR output {}",
                         expected_file.display()
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 31fdb0a5d13..84376d346af 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -29,7 +29,7 @@ impl TestCx<'_> {
 
         if !res.status.success() {
             self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| {
-                println!("Rustdoc Output:");
+                eprintln!("Rustdoc Output:");
                 proc_res.print_info();
             })
         }
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 172b1e32aad..bc860bf18c7 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -109,10 +109,10 @@ impl TestCx<'_> {
         }
 
         if errors > 0 {
-            println!("To update references, rerun the tests and pass the `--bless` flag");
+            eprintln!("To update references, rerun the tests and pass the `--bless` flag");
             let relative_path_to_file =
                 self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap());
-            println!(
+            eprintln!(
                 "To only update this specific test, also pass `--test-args {}`",
                 relative_path_to_file.display(),
             );
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index bff02f1db9f..7b50e62c29b 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -30,7 +30,7 @@ fn path_div() -> &'static str {
 pub fn logv(config: &Config, s: String) {
     debug!("{}", s);
     if config.verbose {
-        println!("{}", s);
+        eprintln!("{}", s);
     }
 }
 
-- 
cgit 1.4.1-3-g733a5


From 67c92878630657777039954b060d3410e5ef3d46 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 14:12:22 +0100
Subject: fix: Non-exhaustive structs may be empty

---
 .../src/diagnostics/match_check/pat_analysis.rs       |  6 +-----
 .../rust-analyzer/crates/hir-ty/src/inhabitedness.rs  |  8 +-------
 .../src/handlers/missing_match_arms.rs                | 19 +++++++++++++++++++
 3 files changed, 21 insertions(+), 12 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 58de19ba81e..5452f5c680d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -383,9 +383,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
                     } else {
                         let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
 
-                        // Whether we must not match the fields of this variant exhaustively.
-                        let is_non_exhaustive =
-                            LazyCell::new(|| self.is_foreign_non_exhaustive(adt));
                         let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
 
                         self.list_variant_fields(ty, variant)
@@ -396,8 +393,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
                                             .is_visible_from(self.db.upcast(), self.module)
                                 };
                                 let is_uninhabited = self.is_uninhabited(&ty);
-                                let private_uninhabited =
-                                    is_uninhabited && (!is_visible() || *is_non_exhaustive);
+                                let private_uninhabited = is_uninhabited && !is_visible();
                                 (ty, PrivateUninhabitedField(private_uninhabited))
                             })
                             .collect()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index c0a781b17ee..56b549436c7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -5,8 +5,7 @@ use chalk_ir::{
     visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
     DebruijnIndex,
 };
-use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId};
-use intern::sym;
+use hir_def::{visibility::Visibility, AdtId, EnumVariantId, ModuleId, VariantId};
 use rustc_hash::FxHashSet;
 
 use crate::{
@@ -118,11 +117,6 @@ impl UninhabitedFrom<'_> {
         variant: VariantId,
         subst: &Substitution,
     ) -> ControlFlow {
-        let is_local = variant.krate(self.db.upcast()) == self.target_mod.krate();
-        if !is_local && self.db.attrs(variant.into()).by_key(&sym::non_exhaustive).exists() {
-            return CONTINUE_OPAQUELY_INHABITED;
-        }
-
         let variant_data = self.db.variant_data(variant);
         let fields = variant_data.fields();
         if fields.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index f39738f2fb8..08e6e7dced9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -1114,6 +1114,25 @@ fn test(x: Option) {
         }
     }
 
+    #[test]
+    fn non_exhaustive_may_be_empty() {
+        check_diagnostics_no_bails(
+            r"
+//- /main.rs crate:main deps:dep
+// In a different crate
+fn empty_match_on_empty_struct(x: dep::UninhabitedStruct) -> T {
+    match x {}
+}
+//- /dep.rs crate:dep
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    pub never: !,
+    // other fields
+}
+",
+        );
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! prefer false negatives to false positives (ideally there would be no false positives). This
-- 
cgit 1.4.1-3-g733a5


From 73dc95dad19e2fa513ea8ac2b76231474398c8ec Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Mon, 9 Dec 2024 08:52:23 +0100
Subject: interpret: clean up deduplicating allocation functions

---
 compiler/rustc_const_eval/src/interpret/place.rs   | 44 ++++++--------
 .../rustc_const_eval/src/util/caller_location.rs   |  9 +--
 compiler/rustc_middle/src/ty/context.rs            |  2 +-
 src/tools/miri/src/shims/backtrace.rs              | 10 +---
 src/tools/miri/src/shims/panic.rs                  |  5 +-
 .../miri/tests/pass/backtrace/backtrace-api-v0.rs  | 69 ----------------------
 .../tests/pass/backtrace/backtrace-api-v0.stderr   | 18 ------
 .../tests/pass/backtrace/backtrace-api-v0.stdout   |  5 --
 8 files changed, 24 insertions(+), 138 deletions(-)
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout

(limited to 'src/tools')

diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index f54a932e1b6..810e9356b26 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -5,8 +5,7 @@
 use std::assert_matches::assert_matches;
 
 use either::{Either, Left, Right};
-use rustc_abi::{Align, BackendRepr, HasDataLayout, Size};
-use rustc_ast::Mutability;
+use rustc_abi::{BackendRepr, HasDataLayout, Size};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::{bug, mir, span_bug};
@@ -1018,40 +1017,31 @@ where
         self.allocate_dyn(layout, kind, MemPlaceMeta::None)
     }
 
-    /// Allocates a sequence of bytes in the interpreter's memory.
-    /// For immutable allocations, uses deduplication to reuse existing memory.
-    /// For mutable allocations, creates a new unique allocation.
-    pub fn allocate_bytes(
+    /// Allocates a sequence of bytes in the interpreter's memory with alignment 1.
+    /// This is allocated in immutable global memory and deduplicated.
+    pub fn allocate_bytes_dedup(
         &mut self,
         bytes: &[u8],
-        align: Align,
-        kind: MemoryKind,
-        mutbl: Mutability,
     ) -> InterpResult<'tcx, Pointer> {
-        // Use cache for immutable strings.
-        if mutbl.is_not() {
-            // Use dedup'd allocation function.
-            let salt = M::get_global_alloc_salt(self, None);
-            let id = self.tcx.allocate_bytes_dedup(bytes, salt);
-
-            // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
-            M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))
-        } else {
-            // Allocate new memory for mutable data.
-            self.allocate_bytes_ptr(bytes, align, kind, mutbl)
-        }
+        let salt = M::get_global_alloc_salt(self, None);
+        let id = self.tcx.allocate_bytes_dedup(bytes, salt);
+
+        // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
+        M::adjust_alloc_root_pointer(
+            &self,
+            Pointer::from(id),
+            M::GLOBAL_KIND.map(MemoryKind::Machine),
+        )
     }
 
-    /// Allocates a string in the interpreter's memory with metadata for length.
-    /// Uses `allocate_bytes` internally but adds string-specific metadata handling.
-    pub fn allocate_str(
+    /// Allocates a string in the interpreter's memory, returning it as a (wide) place.
+    /// This is allocated in immutable global memory and deduplicated.
+    pub fn allocate_str_dedup(
         &mut self,
         str: &str,
-        kind: MemoryKind,
-        mutbl: Mutability,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let bytes = str.as_bytes();
-        let ptr = self.allocate_bytes(bytes, Align::ONE, kind, mutbl)?;
+        let ptr = self.allocate_bytes_dedup(bytes)?;
 
         // Create length metadata for the string.
         let meta = Scalar::from_target_usize(u64::try_from(bytes.len()).unwrap(), self);
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 9bf16d4fe16..6593547cd23 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,7 +1,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Mutability};
+use rustc_middle::ty::{self};
 use rustc_middle::{bug, mir};
 use rustc_span::symbol::Symbol;
 use tracing::trace;
@@ -20,12 +20,9 @@ fn alloc_caller_location<'tcx>(
     // This can fail if rustc runs out of memory right here. Trying to emit an error would be
     // pointless, since that would require allocating more memory than these short strings.
     let file = if loc_details.file {
-        ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap()
+        ecx.allocate_str_dedup(filename.as_str()).unwrap()
     } else {
-        // FIXME: This creates a new allocation each time. It might be preferable to
-        // perform this allocation only once, and re-use the `MPlaceTy`.
-        // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
-        ecx.allocate_str("", MemoryKind::CallerLocation, Mutability::Not).unwrap()
+        ecx.allocate_str_dedup("").unwrap()
     };
     let file = file.map_provenance(CtfeProvenance::as_immutable);
     let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d4835bb07f6..2841470d248 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr))
     }
 
-    /// Allocates a read-only byte or string literal for `mir::interpret`.
+    /// Allocates a read-only byte or string literal for `mir::interpret` with alignment 1.
     /// Returns the same `AllocId` if called again with the same bytes.
     pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 64bd546458d..c7b399228bf 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,5 +1,4 @@
 use rustc_abi::{ExternAbi, Size};
-use rustc_ast::ast::Mutability;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
@@ -179,14 +178,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         match flags {
             0 => {
-                // These are "mutable" allocations as we consider them to be owned by the callee.
-                let name_alloc =
-                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
-                let filename_alloc =
-                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
-
-                this.write_immediate(name_alloc.to_ref(this), &this.project_field(dest, 0)?)?;
-                this.write_immediate(filename_alloc.to_ref(this), &this.project_field(dest, 1)?)?;
+                throw_unsup_format!("miri_resolve_frame: v0 is not supported any more");
             }
             1 => {
                 this.write_scalar(
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 722c3a2f0c5..93479540009 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -12,7 +12,6 @@
 //!   metadata we remembered when pushing said frame.
 
 use rustc_abi::ExternAbi;
-use rustc_ast::Mutability;
 use rustc_middle::{mir, ty};
 use rustc_target::spec::PanicStrategy;
 
@@ -161,7 +160,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
+        let msg = this.allocate_str_dedup(msg)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_fn().unwrap();
@@ -180,7 +179,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
+        let msg = this.allocate_str_dedup(msg)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_nounwind().unwrap();
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
deleted file mode 100644
index 3fff7921aff..00000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-//@normalize-stderr-test: "::<.*>" -> ""
-
-#[inline(never)]
-fn func_a() -> Box<[*mut ()]> {
-    func_b::()
-}
-#[inline(never)]
-fn func_b() -> Box<[*mut ()]> {
-    func_c()
-}
-
-macro_rules! invoke_func_d {
-    () => {
-        func_d()
-    };
-}
-
-#[inline(never)]
-fn func_c() -> Box<[*mut ()]> {
-    invoke_func_d!()
-}
-#[inline(never)]
-fn func_d() -> Box<[*mut ()]> {
-    unsafe { miri_get_backtrace(0) }
-}
-
-fn main() {
-    let mut seen_main = false;
-    let frames = func_a();
-    for frame in frames.iter() {
-        let miri_frame = unsafe { miri_resolve_frame(*frame, 0) };
-        let name = String::from_utf8(miri_frame.name.into()).unwrap();
-        let filename = String::from_utf8(miri_frame.filename.into()).unwrap();
-
-        if name == "func_a" {
-            assert_eq!(func_a as *mut (), miri_frame.fn_ptr);
-        }
-
-        // Print every frame to stderr.
-        let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name);
-        eprintln!("{}", out);
-        // Print the 'main' frame (and everything before it) to stdout, skipping
-        // the printing of internal (and possibly fragile) libstd frames.
-        // Stdout is less normalized so we see more, but it also means we can print less
-        // as platform differences would lead to test suite failures.
-        if !seen_main {
-            println!("{}", out);
-            seen_main = name == "main";
-        }
-    }
-}
-
-// This goes at the bottom of the file so that we can change it
-// without disturbing line numbers of the functions in the backtrace.
-
-extern "Rust" {
-    fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
-    fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
-}
-
-#[derive(Debug)]
-#[repr(C)]
-struct MiriFrame {
-    name: Box<[u8]>,
-    filename: Box<[u8]>,
-    lineno: u32,
-    colno: u32,
-    fn_ptr: *mut (),
-}
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
deleted file mode 100644
index 9849a1aa74e..00000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_d)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_c)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_b)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_a)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (main)
-RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn()))
-RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0})
-RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
-RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1})
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
-RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start)
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout
deleted file mode 100644
index 8c1bc5c353e..00000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout
+++ /dev/null
@@ -1,5 +0,0 @@
-tests/pass/backtrace/backtrace-api-v0.rs:24:14 (func_d)
-tests/pass/backtrace/backtrace-api-v0.rs:14:9 (func_c)
-tests/pass/backtrace/backtrace-api-v0.rs:9:5 (func_b::)
-tests/pass/backtrace/backtrace-api-v0.rs:5:5 (func_a)
-tests/pass/backtrace/backtrace-api-v0.rs:29:18 (main)
-- 
cgit 1.4.1-3-g733a5


From ed8ee39930a1bc0b436a67b7189b79466a514bae Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Sat, 7 Dec 2024 17:22:09 +0100
Subject: fix ICE on type error in promoted

---
 compiler/rustc_const_eval/src/const_eval/error.rs  |  2 +-
 .../src/const_eval/eval_queries.rs                 | 24 ++++-----
 .../rustc_const_eval/src/const_eval/machine.rs     |  3 +-
 .../rustc_const_eval/src/const_eval/valtrees.rs    |  4 +-
 .../rustc_const_eval/src/interpret/eval_context.rs |  6 ++-
 compiler/rustc_middle/src/mir/consts.rs            |  6 ++-
 compiler/rustc_middle/src/mir/interpret/error.rs   | 33 ++++++------
 compiler/rustc_middle/src/mir/interpret/queries.rs |  9 +++-
 .../clippy/clippy_lints/src/non_copy_const.rs      |  7 ++-
 .../unevaluated-const-ice-119731.stderr            | 14 -----
 tests/ui/consts/const-integer-bool-ops.stderr      | 60 ----------------------
 tests/ui/consts/const-mut-refs/issue-76510.stderr  |  6 ---
 tests/ui/consts/const-tup-index-span.stderr        |  6 ---
 tests/ui/consts/issue-54954.stderr                 | 18 -------
 tests/ui/consts/missing_assoc_const_type2.stderr   |  6 ---
 .../ui/consts/promoted-type-error-issue-133968.rs  |  7 +++
 .../consts/promoted-type-error-issue-133968.stderr | 16 ++++++
 tests/ui/enum-discriminant/issue-41394.stderr      |  6 ---
 .../layout/base-layout-is-sized-ice-123078.stderr  |  6 ---
 ...ms-from-outer-item-in-const-item.default.stderr | 14 -----
 ...r-item-in-const-item.generic_const_items.stderr | 14 -----
 tests/ui/resolve/issue-50599.stderr                |  6 ---
 .../avoid-invalid-mir.stderr                       |  6 ---
 .../arbitrary-self-from-method-substs-ice.stderr   |  6 ---
 .../ui/type/type-dependent-def-issue-49241.stderr  |  6 ---
 25 files changed, 78 insertions(+), 213 deletions(-)
 create mode 100644 tests/ui/consts/promoted-type-error-issue-133968.rs
 create mode 100644 tests/ui/consts/promoted-type-error-issue-133968.stderr

(limited to 'src/tools')

diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 3cb77d1dcb5..fee7287951d 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -170,7 +170,7 @@ where
             let reported = if allowed_in_infallible {
                 ReportedErrorInfo::allowed_in_infallible(g)
             } else {
-                ReportedErrorInfo::from(g)
+                ReportedErrorInfo::const_eval_error(g)
             };
             ErrorHandled::Reported(reported, span)
         }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 647d880e2bf..ce8eceebdf8 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -3,13 +3,13 @@ use std::sync::atomic::Ordering::Relaxed;
 use either::{Left, Right};
 use rustc_abi::{self as abi, BackendRepr};
 use rustc_hir::def::DefKind;
-use rustc_middle::bug;
-use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
+use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, throw_inval};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument, trace};
@@ -93,18 +93,18 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
     match intern_result {
         Ok(()) => {}
         Err(InternResult::FoundDanglingPointer) => {
-            return Err(ecx
-                .tcx
-                .dcx()
-                .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
-            .into();
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
+                ecx.tcx
+                    .dcx()
+                    .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
+            )));
         }
         Err(InternResult::FoundBadMutablePointer) => {
-            return Err(ecx
-                .tcx
-                .dcx()
-                .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
-            .into();
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
+                ecx.tcx
+                    .dcx()
+                    .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
+            )));
         }
     }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 11e0fac51d8..56325eaa1be 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
 use rustc_middle::mir::AssertMessage;
+use rustc_middle::mir::interpret::ReportedErrorInfo;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -563,7 +564,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                         .tcx
                         .dcx()
                         .span_delayed_bug(span, "The deny lint should have already errored");
-                    throw_inval!(AlreadyReported(guard.into()));
+                    throw_inval!(AlreadyReported(ReportedErrorInfo::allowed_in_infallible(guard)));
                 }
             } else if new_steps > start && new_steps.is_power_of_two() {
                 // Only report after a certain number of terminators have been evaluated and the
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 515028e6826..6f51b09323d 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{BackendRepr, VariantIdx};
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
+use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
@@ -261,7 +261,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
                 ValTreeCreationError::NodesOverflow => {
                     let handled =
                         tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
-                    Err(handled.into())
+                    Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
                 }
                 ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
             }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 241be5e175c..95a72d3cbc1 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -268,7 +268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         };
         // do not continue if typeck errors occurred (can only occur in local crate)
         if let Some(err) = body.tainted_by_errors {
-            throw_inval!(AlreadyReported(ReportedErrorInfo::from(err)));
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(err)));
         }
         interp_ok(body)
     }
@@ -317,7 +317,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Ok(None) => throw_inval!(TooGeneric),
 
             // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
-            Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())),
+            Err(error_guaranteed) => throw_inval!(AlreadyReported(
+                ReportedErrorInfo::non_const_eval_error(error_guaranteed)
+            )),
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 7983329b0f7..52009422d98 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -8,6 +8,7 @@ use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_type_ir::visit::TypeVisitableExt;
 
+use super::interpret::ReportedErrorInfo;
 use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
 use crate::mir::{Promoted, pretty_print_const_value};
 use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
@@ -331,7 +332,10 @@ impl<'tcx> Const<'tcx> {
                     ConstKind::Expr(_) => {
                         bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
                     }
-                    _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
+                    _ => Err(ReportedErrorInfo::non_const_eval_error(
+                        tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"),
+                    )
+                    .into()),
                 }
             }
             Const::Unevaluated(uneval, _) => {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index ad5d678178d..fbada6ec405 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -28,10 +28,10 @@ pub enum ErrorHandled {
     TooGeneric(Span),
 }
 
-impl From for ErrorHandled {
+impl From for ErrorHandled {
     #[inline]
-    fn from(error: ErrorGuaranteed) -> ErrorHandled {
-        ErrorHandled::Reported(error.into(), DUMMY_SP)
+    fn from(error: ReportedErrorInfo) -> ErrorHandled {
+        ErrorHandled::Reported(error, DUMMY_SP)
     }
 }
 
@@ -64,6 +64,20 @@ pub struct ReportedErrorInfo {
 }
 
 impl ReportedErrorInfo {
+    #[inline]
+    pub fn const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
+        ReportedErrorInfo { allowed_in_infallible: false, error }
+    }
+
+    /// Use this when the error that led to this is *not* a const-eval error
+    /// (e.g., a layout or type checking error).
+    #[inline]
+    pub fn non_const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
+        ReportedErrorInfo { allowed_in_infallible: true, error }
+    }
+
+    /// Use this when the error that led to this *is* a const-eval error, but
+    /// we do allow it to occur in infallible constants (e.g., resource exhaustion).
     #[inline]
     pub fn allowed_in_infallible(error: ErrorGuaranteed) -> ReportedErrorInfo {
         ReportedErrorInfo { allowed_in_infallible: true, error }
@@ -74,13 +88,6 @@ impl ReportedErrorInfo {
     }
 }
 
-impl From for ReportedErrorInfo {
-    #[inline]
-    fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
-        ReportedErrorInfo { allowed_in_infallible: false, error }
-    }
-}
-
 impl Into for ReportedErrorInfo {
     #[inline]
     fn into(self) -> ErrorGuaranteed {
@@ -180,12 +187,6 @@ fn print_backtrace(backtrace: &Backtrace) {
     eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}");
 }
 
-impl From for InterpErrorInfo<'_> {
-    fn from(err: ErrorGuaranteed) -> Self {
-        InterpErrorKind::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
-    }
-}
-
 impl From for InterpErrorInfo<'_> {
     fn from(err: ErrorHandled) -> Self {
         InterpErrorKind::InvalidProgram(match err {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index e540f0194ec..f7f38575bd0 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -6,6 +6,7 @@ use tracing::{debug, instrument};
 
 use super::{
     ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
+    ReportedErrorInfo,
 };
 use crate::mir;
 use crate::query::TyCtxtEnsure;
@@ -81,7 +82,9 @@ impl<'tcx> TyCtxt<'tcx> {
             // For errors during resolution, we deliberately do not point at the usage site of the constant,
             // since for these errors the place the constant is used shouldn't matter.
             Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
+            Err(err) => {
+                Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
+            }
         }
     }
 
@@ -138,7 +141,9 @@ impl<'tcx> TyCtxt<'tcx> {
             // For errors during resolution, we deliberately do not point at the usage site of the constant,
             // since for these errors the place the constant is used shouldn't matter.
             Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
+            Err(err) => {
+                Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 5f253b9e5d5..ebd301d5156 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -11,7 +11,7 @@ use rustc_hir::{
     BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
+use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo};
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
@@ -302,7 +302,10 @@ impl<'tcx> NonCopyConst<'tcx> {
                 tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
             },
             Ok(None) => Err(ErrorHandled::TooGeneric(span)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), span)),
+            Err(err) => Err(ErrorHandled::Reported(
+                ReportedErrorInfo::non_const_eval_error(err),
+                span,
+            )),
         }
     }
 }
diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
index 4eb374b2020..30a45ce377e 100644
--- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
@@ -72,20 +72,6 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
 LL + #![feature(adt_const_params)]
    |
 
-note: erroneous constant encountered
-  --> $DIR/unevaluated-const-ice-119731.rs:22:19
-   |
-LL |     impl v17<512, v0> {
-   |                   ^^
-
-note: erroneous constant encountered
-  --> $DIR/unevaluated-const-ice-119731.rs:22:19
-   |
-LL |     impl v17<512, v0> {
-   |                   ^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: maximum number of nodes exceeded in constant v20::v17::::{constant#0}
   --> $DIR/unevaluated-const-ice-119731.rs:28:37
    |
diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr
index d58a8e93ff6..4e503e5a5c0 100644
--- a/tests/ui/consts/const-integer-bool-ops.stderr
+++ b/tests/ui/consts/const-integer-bool-ops.stderr
@@ -16,12 +16,6 @@ error[E0308]: mismatched types
 LL | const X: usize = 42 && 39;
    |                  ^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:8:18
-   |
-LL | const ARR: [i32; X] = [99; 34];
-   |                  ^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:10:19
    |
@@ -40,12 +34,6 @@ error[E0308]: mismatched types
 LL | const X1: usize = 42 || 39;
    |                   ^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:17:19
-   |
-LL | const ARR1: [i32; X1] = [99; 47];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:19:19
    |
@@ -64,12 +52,6 @@ error[E0308]: mismatched types
 LL | const X2: usize = -42 || -39;
    |                   ^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:26:19
-   |
-LL | const ARR2: [i32; X2] = [99; 18446744073709551607];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:28:19
    |
@@ -88,84 +70,42 @@ error[E0308]: mismatched types
 LL | const X3: usize = -42 && -39;
    |                   ^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:35:19
-   |
-LL | const ARR3: [i32; X3] = [99; 6];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:37:18
    |
 LL | const Y: usize = 42.0 == 42.0;
    |                  ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:40:19
-   |
-LL | const ARRR: [i32; Y] = [99; 1];
-   |                   ^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:42:19
    |
 LL | const Y1: usize = 42.0 >= 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:45:20
-   |
-LL | const ARRR1: [i32; Y1] = [99; 1];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:47:19
    |
 LL | const Y2: usize = 42.0 <= 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:50:20
-   |
-LL | const ARRR2: [i32; Y2] = [99; 1];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:52:19
    |
 LL | const Y3: usize = 42.0 > 42.0;
    |                   ^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:55:20
-   |
-LL | const ARRR3: [i32; Y3] = [99; 0];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:57:19
    |
 LL | const Y4: usize = 42.0 < 42.0;
    |                   ^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:60:20
-   |
-LL | const ARRR4: [i32; Y4] = [99; 0];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:62:19
    |
 LL | const Y5: usize = 42.0 != 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:65:20
-   |
-LL | const ARRR5: [i32; Y5] = [99; 0];
-   |                    ^^
-
 error: aborting due to 18 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr
index a63be676fda..aff86e83578 100644
--- a/tests/ui/consts/const-mut-refs/issue-76510.stderr
+++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr
@@ -4,12 +4,6 @@ error[E0764]: mutable references are not allowed in the final value of constants
 LL | const S: &'static mut str = &mut " hello ";
    |                             ^^^^^^^^^^^^^^
 
-note: erroneous constant encountered
-  --> $DIR/issue-76510.rs:7:70
-   |
-LL |         let s = transmute::<(*const u8, usize), &ManuallyDrop>((S.as_ptr(), 3));
-   |                                                                      ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0764`.
diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr
index 2a3f0cfb06d..792e18aa8fd 100644
--- a/tests/ui/consts/const-tup-index-span.stderr
+++ b/tests/ui/consts/const-tup-index-span.stderr
@@ -11,12 +11,6 @@ help: use a trailing comma to create a tuple with one element
 LL | const TUP: (usize,) = (5usize << 64,);
    |                       +            ++
 
-note: erroneous constant encountered
-  --> $DIR/const-tup-index-span.rs:6:18
-   |
-LL | const ARR: [i32; TUP.0] = [];
-   |                  ^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr
index ed6aa9c44a3..b8c983eb7b8 100644
--- a/tests/ui/consts/issue-54954.stderr
+++ b/tests/ui/consts/issue-54954.stderr
@@ -19,24 +19,6 @@ LL | |         core::mem::size_of::()
 LL | |     }
    | |_____- `Tt::const_val` defined here
 
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:11:15
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |               ^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:11:34
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |                                  ^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:16:22
-   |
-LL |     let _ = f([1f32; ARR_LEN]);
-   |                      ^^^^^^^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0379, E0790.
diff --git a/tests/ui/consts/missing_assoc_const_type2.stderr b/tests/ui/consts/missing_assoc_const_type2.stderr
index 3279a077464..1255ca2d102 100644
--- a/tests/ui/consts/missing_assoc_const_type2.stderr
+++ b/tests/ui/consts/missing_assoc_const_type2.stderr
@@ -4,11 +4,5 @@ error: missing type for `const` item
 LL |     const FIRST:  = 10;
    |                 ^ help: provide a type for the associated constant: `u8`
 
-note: erroneous constant encountered
-  --> $DIR/missing_assoc_const_type2.rs:18:5
-   |
-LL |     TwoDigits::FIRST as usize
-   |     ^^^^^^^^^^^^^^^^
-
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/promoted-type-error-issue-133968.rs b/tests/ui/consts/promoted-type-error-issue-133968.rs
new file mode 100644
index 00000000000..52c0d48ab5b
--- /dev/null
+++ b/tests/ui/consts/promoted-type-error-issue-133968.rs
@@ -0,0 +1,7 @@
+struct B {
+    x: &'static T,
+}
+static STR: &'static [u8] = "a b"; //~ERROR: mismatched types
+static C: &B<[u8]> = &B { x: STR };
+
+fn main() {}
diff --git a/tests/ui/consts/promoted-type-error-issue-133968.stderr b/tests/ui/consts/promoted-type-error-issue-133968.stderr
new file mode 100644
index 00000000000..24f1268e4b6
--- /dev/null
+++ b/tests/ui/consts/promoted-type-error-issue-133968.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/promoted-type-error-issue-133968.rs:4:29
+   |
+LL | static STR: &'static [u8] = "a b";
+   |                             ^^^^^ expected `&[u8]`, found `&str`
+   |
+   = note: expected reference `&'static [u8]`
+              found reference `&'static str`
+help: consider adding a leading `b`
+   |
+LL | static STR: &'static [u8] = b"a b";
+   |                             +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/enum-discriminant/issue-41394.stderr b/tests/ui/enum-discriminant/issue-41394.stderr
index 9bf4fc79b1b..e81562df04f 100644
--- a/tests/ui/enum-discriminant/issue-41394.stderr
+++ b/tests/ui/enum-discriminant/issue-41394.stderr
@@ -6,12 +6,6 @@ LL |     A = "" + 1
    |         |
    |         &str
 
-note: erroneous constant encountered
-  --> $DIR/issue-41394.rs:7:9
-   |
-LL |     A = Foo::A as isize
-   |         ^^^^^^^^^^^^^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
index ee7f5162552..455bd2cbf8b 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
@@ -25,12 +25,6 @@ LL | const C: S = unsafe { std::mem::transmute(()) };
    = note: source type: `()` (0 bits)
    = note: target type: `S` (size can vary because of [u8])
 
-note: erroneous constant encountered
-  --> $DIR/base-layout-is-sized-ice-123078.rs:13:5
-   |
-LL |     C;
-   |     ^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0512.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
index c7e9df10d41..fbb9ede8aa1 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -29,20 +29,6 @@ LL |     const _: u32 = T::C;
    |
    = note: a `const` is a separate item from the item that contains it
 
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
index 64c436d3ceb..60aa94038c3 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -35,20 +35,6 @@ LL |     const _: u32 = T::C;
    |
    = note: a `const` is a separate item from the item that contains it
 
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr
index 427dc9f2049..24fb3d580b8 100644
--- a/tests/ui/resolve/issue-50599.stderr
+++ b/tests/ui/resolve/issue-50599.stderr
@@ -20,12 +20,6 @@ LL -     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
 LL +     const M: usize = (f64::from(N) * LOG10_2) as usize;
    |
 
-note: erroneous constant encountered
-  --> $DIR/issue-50599.rs:4:29
-   |
-LL |     let mut digits = [0u32; M];
-   |                             ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
index eab2604d4c0..606f808f093 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
@@ -6,11 +6,5 @@ LL |     !let y = 42;
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-note: erroneous constant encountered
-  --> $DIR/avoid-invalid-mir.rs:11:13
-   |
-LL |     x: [(); N]
-   |             ^
-
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index e4991823d28..cf4c219215e 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -17,12 +17,6 @@ LL |     const fn get>(self: R) -> u32 {
 LL |     }
    |     - value is dropped here
 
-note: erroneous constant encountered
-  --> $DIR/arbitrary-self-from-method-substs-ice.rs:24:5
-   |
-LL |     FOO;
-   |     ^^^
-
 error[E0801]: invalid generic `self` parameter type: `R`
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
    |
diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr
index 4e55618e5cb..cf372dc5968 100644
--- a/tests/ui/type/type-dependent-def-issue-49241.stderr
+++ b/tests/ui/type/type-dependent-def-issue-49241.stderr
@@ -9,12 +9,6 @@ help: consider using `let` instead of `const`
 LL |     let l: usize = v.count();
    |     ~~~
 
-note: erroneous constant encountered
-  --> $DIR/type-dependent-def-issue-49241.rs:4:18
-   |
-LL |     let s: [u32; l] = v.into_iter().collect();
-   |                  ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0435`.
-- 
cgit 1.4.1-3-g733a5


From 2ad6d7103cab511a72706c7fb2a06d8c4fe62c4e Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 15:52:04 +0100
Subject: Disable pipe on typing handler

---
 src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +-
 src/tools/rust-analyzer/docs/user/generated_config.adoc    | 2 +-
 src/tools/rust-analyzer/editors/code/package.json          | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index dd7351bcf26..fd4c8d0e687 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -309,7 +309,7 @@ config_data! {
         signatureInfo_documentation_enable: bool                       = true,
 
         /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
-        typing_excludeChars: Option = Some('<'.to_string()),
+        typing_excludeChars: Option = Some("|<".to_owned()),
 
 
         /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 715f8d43adc..1195a85cf70 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled.
 --
 Show documentation.
 --
-[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`)::
+[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`)::
 +
 --
 Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 70d26c97078..469c1b458d5 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2607,7 +2607,7 @@
                 "properties": {
                     "rust-analyzer.typing.excludeChars": {
                         "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.",
-                        "default": "<",
+                        "default": "|<",
                         "type": [
                             "null",
                             "string"
-- 
cgit 1.4.1-3-g733a5


From ab6382e4609a94c095b4df409a8ab1c0da953c1d Mon Sep 17 00:00:00 2001
From: roife 
Date: Tue, 10 Dec 2024 02:47:52 +0800
Subject: minor: enhance name suggestion for `Arc` and `Rc`

---
 .../ide-db/src/syntax_helpers/suggest_name.rs      | 28 +++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 2679cbef61b..b3ecc26cb22 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -29,7 +29,7 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
 /// # Examples
 /// `Option` -> `Name`
 /// `Result` -> `User`
-const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"];
+const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
 
 /// Prefixes to strip from methods names
 ///
@@ -858,6 +858,32 @@ fn foo() { $0(bar())$0; }
         );
     }
 
+    #[test]
+    fn arc_value() {
+        check(
+            r#"
+struct Arc(*const T);
+struct Seed;
+fn bar() -> Arc {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seed",
+        );
+    }
+
+    #[test]
+    fn rc_value() {
+        check(
+            r#"
+struct Rc(*const T);
+struct Seed;
+fn bar() -> Rc {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seed",
+        );
+    }
+
     #[test]
     fn ref_call() {
         check(
-- 
cgit 1.4.1-3-g733a5


From cbc006993957595db56432d0d0b43e944fd5e9d7 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Mon, 9 Dec 2024 19:53:30 +0200
Subject: Draft completion hashing

---
 src/tools/rust-analyzer/Cargo.lock                 |  8 ++
 .../crates/ide-completion/src/item.rs              |  3 +-
 .../rust-analyzer/crates/ide-completion/src/lib.rs |  1 +
 .../rust-analyzer/crates/rust-analyzer/Cargo.toml  | 16 ++--
 .../crates/rust-analyzer/src/handlers/request.rs   | 26 ++++---
 .../rust-analyzer/crates/rust-analyzer/src/lib.rs  | 89 ++++++++++++++++++++++
 .../crates/rust-analyzer/src/lsp/ext.rs            |  3 +-
 .../crates/rust-analyzer/src/lsp/to_proto.rs       | 18 ++++-
 src/tools/rust-analyzer/docs/dev/lsp-extensions.md |  2 +-
 9 files changed, 142 insertions(+), 24 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 5861833d53a..b6f2c6faf86 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1659,6 +1659,7 @@ dependencies = [
  "hir-def",
  "hir-ty",
  "ide",
+ "ide-completion",
  "ide-db",
  "ide-ssr",
  "intern",
@@ -1687,6 +1688,7 @@ dependencies = [
  "stdx",
  "syntax",
  "syntax-bridge",
+ "tenthash",
  "test-fixture",
  "test-utils",
  "tikv-jemallocator",
@@ -1990,6 +1992,12 @@ dependencies = [
  "tt",
 ]
 
+[[package]]
+name = "tenthash"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d67f9f3cf70e0852941d7bc3cb884b49b24b8ee956baf91ad0abae31f5ef11fb"
+
 [[package]]
 name = "test-fixture"
 version = "0.0.0"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 52f6bedaaa9..8878fbbea30 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -346,8 +346,7 @@ pub enum CompletionItemKind {
 impl_from!(SymbolKind for CompletionItemKind);
 
 impl CompletionItemKind {
-    #[cfg(test)]
-    pub(crate) fn tag(self) -> &'static str {
+    pub fn tag(self) -> &'static str {
         match self {
             CompletionItemKind::SymbolKind(kind) => match kind {
                 SymbolKind::Attribute => "at",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index cffdfa29f1a..14f42b40055 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -34,6 +34,7 @@ pub use crate::{
     config::{CallableSnippets, CompletionConfig},
     item::{
         CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
+        CompletionRelevanceReturnType, CompletionRelevanceTypeMatch,
     },
     snippet::{Snippet, SnippetScope},
 };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 2dd2f2242a0..022b0a0ecf1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -24,6 +24,7 @@ anyhow.workspace = true
 crossbeam-channel.workspace = true
 dirs = "5.0.1"
 dissimilar.workspace = true
+ide-completion.workspace = true
 itertools.workspace = true
 scip = "0.5.1"
 lsp-types = { version = "=0.95.0", features = ["proposed"] }
@@ -34,6 +35,7 @@ rayon.workspace = true
 rustc-hash.workspace = true
 serde_json = { workspace = true, features = ["preserve_order"] }
 serde.workspace = true
+tenthash = "0.4.0"
 num_cpus = "1.15.0"
 mimalloc = { version = "0.1.30", default-features = false, optional = true }
 lsp-server.workspace = true
@@ -90,13 +92,13 @@ jemalloc = ["jemallocator", "profile/jemalloc"]
 force-always-assert = ["always-assert/force"]
 sysroot-abi = []
 in-rust-tree = [
-  "sysroot-abi",
-  "syntax/in-rust-tree",
-  "parser/in-rust-tree",
-  "hir/in-rust-tree",
-  "hir-def/in-rust-tree",
-  "hir-ty/in-rust-tree",
-  "load-cargo/in-rust-tree",
+    "sysroot-abi",
+    "syntax/in-rust-tree",
+    "parser/in-rust-tree",
+    "hir/in-rust-tree",
+    "hir-def/in-rust-tree",
+    "hir-ty/in-rust-tree",
+    "load-cargo/in-rust-tree",
 ]
 
 [lints]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 0fadfa6c420..9dd6dc999b4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -36,6 +36,7 @@ use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
+    completion_item_hash,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diagnostics::convert_diagnostic,
     global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
@@ -1122,12 +1123,15 @@ pub(crate) fn handle_completion_resolve(
         return Ok(original_completion);
     };
     let source_root = snap.analysis.source_root_id(file_id)?;
+    let Some(completion_hash_for_resolve) = &resolve_data.completion_item_hash else {
+        return Ok(original_completion);
+    };
 
     let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
     forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
 
     let position = FilePosition { file_id, offset };
-    let Some(resolved_completions) = snap.analysis.completions(
+    let Some(completions) = snap.analysis.completions(
         &forced_resolve_completions_config,
         position,
         resolve_data.trigger_character,
@@ -1135,6 +1139,14 @@ pub(crate) fn handle_completion_resolve(
     else {
         return Ok(original_completion);
     };
+
+    let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
+        let hash = completion_item_hash(&completion_item, resolve_data.for_ref);
+        &hash == completion_hash_for_resolve
+    }) else {
+        return Ok(original_completion);
+    };
+
     let mut resolved_completions = to_proto::completion_items(
         &snap.config,
         &forced_resolve_completions_config.fields_to_resolve,
@@ -1142,15 +1154,11 @@ pub(crate) fn handle_completion_resolve(
         snap.file_version(position.file_id),
         resolve_data.position,
         resolve_data.trigger_character,
-        resolved_completions,
+        vec![corresponding_completion],
     );
-
-    let mut resolved_completion =
-        if resolved_completions.get(resolve_data.completion_item_index).is_some() {
-            resolved_completions.swap_remove(resolve_data.completion_item_index)
-        } else {
-            return Ok(original_completion);
-        };
+    let Some(mut resolved_completion) = resolved_completions.pop() else {
+        return Ok(original_completion);
+    };
 
     if !resolve_data.imports.is_empty() {
         let additional_edits = snap
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 234204695cb..8f74e75d3d3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,9 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
+use ide::{CompletionItem, CompletionRelevance, TextEdit, TextRange};
 use serde::de::DeserializeOwned;
+use tenthash::TentHasher;
 
 pub use crate::{
     lsp::capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph,
@@ -61,3 +63,90 @@ pub fn from_json(
     serde_json::from_value(json.clone())
         .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}"))
 }
+
+fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
+    fn hash_text_range(hasher: &mut TentHasher, text_range: &TextRange) {
+        hasher.update(u32::from(text_range.start()).to_le_bytes());
+        hasher.update(u32::from(text_range.end()).to_le_bytes());
+    }
+
+    fn hash_text_edit(hasher: &mut TentHasher, edit: &TextEdit) {
+        for indel in edit.iter() {
+            hasher.update(&indel.insert);
+            hash_text_range(hasher, &indel.delete);
+        }
+    }
+
+    fn has_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) {
+        use ide_completion::{
+            CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
+            CompletionRelevanceTypeMatch,
+        };
+
+        if let Some(type_match) = &relevance.type_match {
+            let label = match type_match {
+                CompletionRelevanceTypeMatch::CouldUnify => "could_unify",
+                CompletionRelevanceTypeMatch::Exact => "exact",
+            };
+            hasher.update(label);
+        }
+        hasher.update(&[u8::from(relevance.exact_name_match), u8::from(relevance.is_local)]);
+        if let Some(trait_) = &relevance.trait_ {
+            hasher.update(&[u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
+        }
+        hasher.update(&[
+            u8::from(relevance.is_name_already_imported),
+            u8::from(relevance.requires_import),
+            u8::from(relevance.is_private_editable),
+        ]);
+        if let Some(postfix_match) = &relevance.postfix_match {
+            let label = match postfix_match {
+                CompletionRelevancePostfixMatch::NonExact => "non_exact",
+                CompletionRelevancePostfixMatch::Exact => "exact",
+            };
+            hasher.update(label);
+        }
+        if let Some(function) = &relevance.function {
+            hasher.update(&[u8::from(function.has_params), u8::from(function.has_self_param)]);
+            let label = match function.return_type {
+                CompletionRelevanceReturnType::Other => "other",
+                CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
+                CompletionRelevanceReturnType::Constructor => "constructor",
+                CompletionRelevanceReturnType::Builder => "builder",
+            };
+            hasher.update(label);
+        }
+    }
+
+    let mut hasher = TentHasher::new();
+    hasher.update(&[
+        u8::from(is_ref_completion),
+        u8::from(item.is_snippet),
+        u8::from(item.deprecated),
+        u8::from(item.trigger_call_info),
+    ]);
+    hasher.update(&item.label);
+    if let Some(label_detail) = &item.label_detail {
+        hasher.update(label_detail);
+    }
+    hash_text_range(&mut hasher, &item.source_range);
+    hash_text_edit(&mut hasher, &item.text_edit);
+    hasher.update(item.kind.tag());
+    hasher.update(&item.lookup);
+    if let Some(detail) = &item.detail {
+        hasher.update(detail);
+    }
+    if let Some(documentation) = &item.documentation {
+        hasher.update(documentation.as_str());
+    }
+    has_completion_relevance(&mut hasher, &item.relevance);
+    if let Some((mutability, text_size)) = &item.ref_match {
+        hasher.update(mutability.as_keyword_for_ref());
+        hasher.update(u32::from(*text_size).to_le_bytes());
+    }
+    for (import_path, import_name) in &item.import_to_add {
+        hasher.update(import_path);
+        hasher.update(import_name);
+    }
+    hasher.finalize()
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index 6ddfe118d5e..7d60ae703b2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -826,7 +826,8 @@ pub struct CompletionResolveData {
     pub imports: Vec,
     pub version: Option,
     pub trigger_character: Option,
-    pub completion_item_index: usize,
+    pub for_ref: bool,
+    pub completion_item_hash: Option<[u8; 20]>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index d444f90a131..97caed8f08c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -21,6 +21,7 @@ use serde_json::to_value;
 use vfs::AbsPath;
 
 use crate::{
+    completion_item_hash,
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
@@ -274,6 +275,11 @@ fn completion_item(
     completion_trigger_character: Option,
     item: CompletionItem,
 ) {
+    let original_completion_item = if fields_to_resolve == &CompletionFieldsToResolve::empty() {
+        None
+    } else {
+        Some(item.clone())
+    };
     let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
     let ref_match = item.ref_match();
 
@@ -393,16 +399,17 @@ fn completion_item(
             Vec::new()
         };
     let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
-        let mut item_index = acc.len();
         let ref_resolve_data = if ref_match.is_some() {
             let ref_resolve_data = lsp_ext::CompletionResolveData {
                 position: tdpp.clone(),
                 imports: Vec::new(),
                 version,
                 trigger_character: completion_trigger_character,
-                completion_item_index: item_index,
+                for_ref: true,
+                completion_item_hash: original_completion_item
+                    .as_ref()
+                    .map(|item| completion_item_hash(item, true)),
             };
-            item_index += 1;
             Some(to_value(ref_resolve_data).unwrap())
         } else {
             None
@@ -412,7 +419,10 @@ fn completion_item(
             imports,
             version,
             trigger_character: completion_trigger_character,
-            completion_item_index: item_index,
+            for_ref: false,
+            completion_item_hash: original_completion_item
+                .as_ref()
+                .map(|item| completion_item_hash(item, false)),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index b7c536e0279..00863825170 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
  $DIR/struct_destructure_fail.rs:15:19
-   |
-LL |     Struct { a, .. };
-   |                   ^
-   |
-help: add a base expression here
-   |
-LL |     Struct { a, ../* expr */ };
-   |                   ++++++++++
-
 error[E0026]: struct `Struct` does not have a field named `c`
   --> $DIR/struct_destructure_fail.rs:10:20
    |
@@ -48,6 +37,17 @@ help: or always ignore missing fields here
 LL |     Struct { a, .. } = Struct { a: 1, b: 2 };
    |               ~~~~~~
 
+error[E0797]: base expression required after `..`
+  --> $DIR/struct_destructure_fail.rs:15:19
+   |
+LL |     Struct { a, .. };
+   |                   ^
+   |
+help: add a base expression here
+   |
+LL |     Struct { a, ../* expr */ };
+   |                   ++++++++++
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0026, E0027, E0797.
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs
new file mode 100644
index 00000000000..01441de67e0
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs
@@ -0,0 +1,106 @@
+#![feature(generic_const_exprs)]
+#![allow(unused_variables, dead_code, incomplete_features)]
+
+pub struct S;
+
+#[derive(Default)]
+pub struct Foo {
+    pub bar: S = S, //~ ERROR default values on `struct` fields aren't supported
+    pub baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+}
+
+#[derive(Default)]
+pub enum Bar {
+    #[default]
+    Foo { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+        bar: S = S, //~ ERROR default values on `struct` fields aren't supported
+        baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+    }
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Qux::::S, //~ ERROR default values on `struct` fields aren't supported
+    baz: i32 = foo(), //~ ERROR default values on `struct` fields aren't supported
+    bat: i32 =  as T>::K, //~ ERROR default values on `struct` fields aren't supported
+    bay: i32 = C, //~ ERROR default values on `struct` fields aren't supported
+    bak: Vec = Vec::new(), //~ ERROR default values on `struct` fields aren't supported
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+#[derive(Default)]
+pub struct Opt {
+    mandatory: Option<()>,
+    optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+}
+
+#[derive(Default)]
+pub enum OptEnum {
+    #[default]
+    Variant { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+        mandatory: Option<()>,
+        optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+    }
+}
+
+fn main () {
+    let x = Foo { .. }; //~ ERROR base expression required after `..`
+    let y = Foo::default();
+    let z = Foo { baz: 1, .. }; //~ ERROR base expression required after `..`
+
+    assert_eq!(45, x.baz);
+    assert_eq!(45, y.baz);
+    assert_eq!(1, z.baz);
+
+    let x = Bar::Foo { .. }; //~ ERROR base expression required after `..`
+    let y = Bar::default();
+    let z = Bar::Foo { baz: 1, .. }; //~ ERROR base expression required after `..`
+
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x));
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y));
+    assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z));
+
+    let x = Qux:: { .. }; //~ ERROR base expression required after `..`
+    assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
+    //~^ ERROR base expression required after `..`
+    assert!(x.bak.is_empty());
+    let y = Opt { mandatory: None, .. };
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt::default(), y));
+    let z = Opt::default();
+    assert!(matches!(Opt { mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { optional: (), .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    let y = OptEnum::Variant { mandatory: None, .. };
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::default(), y));
+    let z = OptEnum::default();
+    assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+}
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
new file mode 100644
index 00000000000..a24217c0727
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -0,0 +1,318 @@
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/feature-gate-default-field-values.rs:15:5
+   |
+LL |     Foo {
+   |     ^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/feature-gate-default-field-values.rs:55:5
+   |
+LL |     Variant {
+   |     ^^^^^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:8:15
+   |
+LL |     pub bar: S = S,
+   |               ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:9:17
+   |
+LL |     pub baz: i32 = 42 + 3,
+   |                 ^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:16:15
+   |
+LL |         bar: S = S,
+   |               ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:17:17
+   |
+LL |         baz: i32 = 42 + 3,
+   |                 ^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:23:11
+   |
+LL |     bar: S = Qux::::S,
+   |           ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:24:13
+   |
+LL |     baz: i32 = foo(),
+   |             ^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:25:13
+   |
+LL |     bat: i32 =  as T>::K,
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:26:13
+   |
+LL |     bay: i32 = C,
+   |             ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:27:16
+   |
+LL |     bak: Vec = Vec::new(),
+   |                ^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:49:17
+   |
+LL |     optional: () = (),
+   |                 ^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:57:21
+   |
+LL |         optional: () = (),
+   |                     ^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:62:21
+   |
+LL |     let x = Foo { .. };
+   |                     ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Foo { ../* expr */ };
+   |                     ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:64:29
+   |
+LL |     let z = Foo { baz: 1, .. };
+   |                             ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let z = Foo { baz: 1, ../* expr */ };
+   |                             ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:70:26
+   |
+LL |     let x = Bar::Foo { .. };
+   |                          ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Bar::Foo { ../* expr */ };
+   |                          ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:72:34
+   |
+LL |     let z = Bar::Foo { baz: 1, .. };
+   |                                  ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let z = Bar::Foo { baz: 1, ../* expr */ };
+   |                                  ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:78:31
+   |
+LL |     let x = Qux:: { .. };
+   |                               ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Qux:: { ../* expr */ };
+   |                               ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:79:73
+   |
+LL |     assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
+   |                                                                         ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, ../* expr */ }, x));
+   |                                                                         ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:82:38
+   |
+LL |     let y = Opt { mandatory: None, .. };
+   |                                      ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let y = Opt { mandatory: None, ../* expr */ };
+   |                                      ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:86:47
+   |
+LL |     assert!(matches!(Opt { mandatory: None, .. }, z));
+   |                                               ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
+   |                                               ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:88:30
+   |
+LL |     assert!(matches!(Opt { .. }, z));
+   |                              ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { ../* expr */ }, z));
+   |                              ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:90:44
+   |
+LL |     assert!(matches!(Opt { optional: (), .. }, z));
+   |                                            ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { optional: (), ../* expr */ }, z));
+   |                                            ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:92:61
+   |
+LL |     assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+   |                                                             ^
+   |
+help: remove the `..` as all the fields are already present
+   |
+LL -     assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+LL +     assert!(matches!(Opt { optional: (), mandatory: None,  }, z));
+   |
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:94:51
+   |
+LL |     let y = OptEnum::Variant { mandatory: None, .. };
+   |                                                   ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let y = OptEnum::Variant { mandatory: None, ../* expr */ };
+   |                                                   ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:98:60
+   |
+LL |     assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
+   |                                                            ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z));
+   |                                                            ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:100:43
+   |
+LL |     assert!(matches!(OptEnum::Variant { .. }, z));
+   |                                           ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
+   |                                           ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:102:57
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
+   |                                                         ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
+   |                                                         ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:104:74
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+   |                                                                          ^
+   |
+help: remove the `..` as all the fields are already present
+   |
+LL -     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+LL +     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None,  }, z));
+   |
+
+error: aborting due to 29 previous errors
+
+Some errors have detailed explanations: E0658, E0797.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed b/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed
deleted file mode 100644
index be6ed053c6e..00000000000
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed
+++ /dev/null
@@ -1,35 +0,0 @@
-//@ run-rustfix
-#![allow(dead_code)]
-
-enum E {
-    A,
-}
-
-struct S {
-    field1: i32, //~ ERROR default values on `struct` fields aren't supported
-    field2: E, //~ ERROR default values on `struct` fields aren't supported
-    field3: i32, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32, //~ ERROR default values on `struct` fields aren't supported
-    field5: E, //~ ERROR default values on `struct` fields aren't supported
-    field6: E, //~ ERROR default values on `struct` fields aren't supported
-}
-
-struct S1 {
-    field1: i32, //~ ERROR expected `,`, or `}`, found `field2`
-    field2: E, //~ ERROR expected `,`, or `}`, found `field3`
-    field3: i32, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32, //~ ERROR default values on `struct` fields aren't supported
-    field5: E, //~ ERROR default values on `struct` fields aren't supported
-    field6: E, //~ ERROR default values on `struct` fields aren't supported
-}
-
-struct S2 {
-    field1 : i32, //~ ERROR expected `:`, found `=`
-    field2: E, //~ ERROR expected `:`, found `;`
-}
-
-const fn foo(_: i32) -> E {
-    E::A
-}
-
-fn main() {}
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
index 7900d397a5d..8ecf042ad38 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
@@ -1,4 +1,3 @@
-//@ run-rustfix
 #![allow(dead_code)]
 
 enum E {
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
index 1fb57ab11f9..669147c5685 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
@@ -1,152 +1,133 @@
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16
+error: expected `,`, or `}`, found `field2`
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:17:16
    |
-LL |     field1: i32 = 42,
-   |                ^^^^^
+LL |     field1: i32
+   |                ^ help: try adding a comma: `,`
+
+error: expected `,`, or `}`, found `field3`
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:18:14
+   |
+LL |     field2: E
+   |              ^ help: try adding a comma: `,`
+
+error: expected `:`, found `=`
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:26:12
+   |
+LL |     field1 = i32,
+   |            ^
+   |            |
+   |            expected `:`
+   |            help: field names and their types are separated with `:`
+
+error: expected `:`, found `;`
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:27:11
    |
-help: remove this unsupported default value
+LL |     field2; E,
+   |           ^
+   |           |
+   |           expected `:`
+   |           help: field names and their types are separated with `:`
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:8:16
    |
-LL -     field1: i32 = 42,
-LL +     field1: i32,
+LL |     field1: i32 = 42,
+   |                ^^^^^
    |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:9:14
    |
 LL |     field2: E = E::A,
    |              ^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field2: E = E::A,
-LL +     field2: E,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:10:16
    |
 LL |     field3: i32 = 1 + 2,
    |                ^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field3: i32 = 1 + 2,
-LL +     field3: i32,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
    |
 LL |     field4: i32 = { 1 + 2 },
    |                ^^^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field4: i32 = { 1 + 2 },
-LL +     field4: i32,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:12:14
    |
 LL |     field5: E = foo(42),
    |              ^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field5: E = foo(42),
-LL +     field5: E,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
    |
 LL |     field6: E = { foo(42) },
    |              ^^^^^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field6: E = { foo(42) },
-LL +     field6: E,
-   |
-
-error: expected `,`, or `}`, found `field2`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16
-   |
-LL |     field1: i32
-   |                ^ help: try adding a comma: `,`
-
-error: expected `,`, or `}`, found `field3`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:19:14
-   |
-LL |     field2: E
-   |              ^ help: try adding a comma: `,`
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:19:16
    |
 LL |     field3: i32 = 1 + 2,
    |                ^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field3: i32 = 1 + 2,
-LL +     field3: i32,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
    |
 LL |     field4: i32 = { 1 + 2 },
    |                ^^^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field4: i32 = { 1 + 2 },
-LL +     field4: i32,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:21:14
    |
 LL |     field5: E = foo(42),
    |              ^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field5: E = foo(42),
-LL +     field5: E,
-   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
    |
 LL |     field6: E = { foo(42) },
    |              ^^^^^^^^^^^^^^
    |
-help: remove this unsupported default value
-   |
-LL -     field6: E = { foo(42) },
-LL +     field6: E,
-   |
-
-error: expected `:`, found `=`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12
-   |
-LL |     field1 = i32,
-   |            ^
-   |            |
-   |            expected `:`
-   |            help: field names and their types are separated with `:`
-
-error: expected `:`, found `;`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:28:11
-   |
-LL |     field2; E,
-   |           ^
-   |           |
-   |           expected `:`
-   |           help: field names and their types are separated with `:`
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 14 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 2adbcfab612..e3bc68a2134 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -20,8 +20,8 @@ ast-stats-1 Stmt                     160 ( 2.4%)             5            32
 ast-stats-1 - Let                       32 ( 0.5%)             1
 ast-stats-1 - MacCall                   32 ( 0.5%)             1
 ast-stats-1 - Expr                      96 ( 1.4%)             3
-ast-stats-1 FieldDef                 176 ( 2.6%)             2            88
 ast-stats-1 Block                    192 ( 2.9%)             6            32
+ast-stats-1 FieldDef                 208 ( 3.1%)             2           104
 ast-stats-1 Variant                  208 ( 3.1%)             2           104
 ast-stats-1 AssocItem                352 ( 5.3%)             4            88
 ast-stats-1 - Type                     176 ( 2.6%)             2
@@ -29,7 +29,7 @@ ast-stats-1 - Fn                       176 ( 2.6%)             2
 ast-stats-1 GenericBound             352 ( 5.3%)             4            88
 ast-stats-1 - Trait                    352 ( 5.3%)             4
 ast-stats-1 GenericParam             480 ( 7.2%)             5            96
-ast-stats-1 Pat                      504 ( 7.6%)             7            72
+ast-stats-1 Pat                      504 ( 7.5%)             7            72
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Wild                      72 ( 1.1%)             1
 ast-stats-1 - Ident                    360 ( 5.4%)             5
@@ -39,13 +39,13 @@ ast-stats-1 - Match                     72 ( 1.1%)             1
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Lit                      144 ( 2.2%)             2
 ast-stats-1 - Block                    216 ( 3.2%)             3
-ast-stats-1 PathSegment              744 (11.2%)            31            24
+ast-stats-1 PathSegment              744 (11.1%)            31            24
 ast-stats-1 Ty                       896 (13.4%)            14            64
 ast-stats-1 - Ref                       64 ( 1.0%)             1
 ast-stats-1 - Ptr                       64 ( 1.0%)             1
 ast-stats-1 - ImplicitSelf             128 ( 1.9%)             2
 ast-stats-1 - Path                     640 ( 9.6%)            10
-ast-stats-1 Item                   1_224 (18.4%)             9           136
+ast-stats-1 Item                   1_224 (18.3%)             9           136
 ast-stats-1 - ForeignMod               136 ( 2.0%)             1
 ast-stats-1 - Trait                    136 ( 2.0%)             1
 ast-stats-1 - Impl                     136 ( 2.0%)             1
@@ -53,7 +53,7 @@ ast-stats-1 - Enum                     136 ( 2.0%)             1
 ast-stats-1 - Fn                       272 ( 4.1%)             2
 ast-stats-1 - Use                      408 ( 6.1%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  6_664                   116
+ast-stats-1 Total                  6_696                   116
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -70,7 +70,7 @@ ast-stats-2 - Fn                        88 ( 1.2%)             1
 ast-stats-2 Arm                       96 ( 1.3%)             2            48
 ast-stats-2 FnDecl                   120 ( 1.6%)             5            24
 ast-stats-2 InlineAsm                120 ( 1.6%)             1           120
-ast-stats-2 Attribute                128 ( 1.8%)             4            32
+ast-stats-2 Attribute                128 ( 1.7%)             4            32
 ast-stats-2 - DocComment                32 ( 0.4%)             1
 ast-stats-2 - Normal                    96 ( 1.3%)             3
 ast-stats-2 Param                    160 ( 2.2%)             4            40
@@ -78,33 +78,33 @@ ast-stats-2 Stmt                     160 ( 2.2%)             5            32
 ast-stats-2 - Let                       32 ( 0.4%)             1
 ast-stats-2 - Semi                      32 ( 0.4%)             1
 ast-stats-2 - Expr                      96 ( 1.3%)             3
-ast-stats-2 FieldDef                 176 ( 2.4%)             2            88
 ast-stats-2 Block                    192 ( 2.6%)             6            32
+ast-stats-2 FieldDef                 208 ( 2.8%)             2           104
 ast-stats-2 Variant                  208 ( 2.8%)             2           104
 ast-stats-2 AssocItem                352 ( 4.8%)             4            88
 ast-stats-2 - Type                     176 ( 2.4%)             2
 ast-stats-2 - Fn                       176 ( 2.4%)             2
 ast-stats-2 GenericBound             352 ( 4.8%)             4            88
 ast-stats-2 - Trait                    352 ( 4.8%)             4
-ast-stats-2 GenericParam             480 ( 6.6%)             5            96
+ast-stats-2 GenericParam             480 ( 6.5%)             5            96
 ast-stats-2 Pat                      504 ( 6.9%)             7            72
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - Wild                      72 ( 1.0%)             1
 ast-stats-2 - Ident                    360 ( 4.9%)             5
-ast-stats-2 Expr                     648 ( 8.9%)             9            72
+ast-stats-2 Expr                     648 ( 8.8%)             9            72
 ast-stats-2 - Path                      72 ( 1.0%)             1
 ast-stats-2 - Match                     72 ( 1.0%)             1
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - InlineAsm                 72 ( 1.0%)             1
 ast-stats-2 - Lit                      144 ( 2.0%)             2
-ast-stats-2 - Block                    216 ( 3.0%)             3
+ast-stats-2 - Block                    216 ( 2.9%)             3
 ast-stats-2 PathSegment              864 (11.8%)            36            24
-ast-stats-2 Ty                       896 (12.3%)            14            64
+ast-stats-2 Ty                       896 (12.2%)            14            64
 ast-stats-2 - Ref                       64 ( 0.9%)             1
 ast-stats-2 - Ptr                       64 ( 0.9%)             1
-ast-stats-2 - ImplicitSelf             128 ( 1.8%)             2
-ast-stats-2 - Path                     640 ( 8.8%)            10
-ast-stats-2 Item                   1_496 (20.5%)            11           136
+ast-stats-2 - ImplicitSelf             128 ( 1.7%)             2
+ast-stats-2 - Path                     640 ( 8.7%)            10
+ast-stats-2 Item                   1_496 (20.4%)            11           136
 ast-stats-2 - Enum                     136 ( 1.9%)             1
 ast-stats-2 - Trait                    136 ( 1.9%)             1
 ast-stats-2 - Impl                     136 ( 1.9%)             1
@@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod               136 ( 1.9%)             1
 ast-stats-2 - Fn                       272 ( 3.7%)             2
 ast-stats-2 - Use                      544 ( 7.4%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  7_312                   127
+ast-stats-2 Total                  7_344                   127
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
@@ -138,9 +138,9 @@ hir-stats Stmt                      96 ( 1.1%)             3            32
 hir-stats - Let                       32 ( 0.4%)             1
 hir-stats - Semi                      32 ( 0.4%)             1
 hir-stats - Expr                      32 ( 0.4%)             1
-hir-stats FieldDef                 112 ( 1.3%)             2            56
 hir-stats FnDecl                   120 ( 1.3%)             3            40
 hir-stats Attribute                128 ( 1.4%)             4            32
+hir-stats FieldDef                 128 ( 1.4%)             2            64
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  144 ( 1.6%)             2            72
 hir-stats GenericBound             256 ( 2.9%)             4            64
@@ -163,7 +163,7 @@ hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.3%)             6
-hir-stats Item                     968 (10.9%)            11            88
+hir-stats Item                     968 (10.8%)            11            88
 hir-stats - Enum                      88 ( 1.0%)             1
 hir-stats - Trait                     88 ( 1.0%)             1
 hir-stats - Impl                      88 ( 1.0%)             1
@@ -174,5 +174,5 @@ hir-stats - Use                      352 ( 3.9%)             4
 hir-stats Path                   1_240 (13.9%)            31            40
 hir-stats PathSegment            1_920 (21.5%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_920                   180
+hir-stats Total                  8_936                   180
 hir-stats
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
new file mode 100644
index 00000000000..c4de4f5cdad
--- /dev/null
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -0,0 +1,49 @@
+#![feature(default_field_values)]
+
+#[derive(Debug)]
+pub struct S;
+
+#[derive(Debug, Default)]
+pub struct Foo {
+    pub bar: S = S,
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Debug, Default)]
+pub struct Bar {
+    pub bar: S, //~ ERROR the trait bound `S: Default` is not satisfied
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Self::S, //~ ERROR generic `Self` types are currently not permitted in anonymous constants
+    baz: i32 = foo(),
+    bat: i32 =  as T>::K, //~ ERROR generic parameters may not be used in const operations
+    bay: i32 = C,
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+fn main () {
+    let _ = Foo { .. }; // ok
+    let _ = Foo::default(); // ok
+    let _ = Bar { .. }; //~ ERROR mandatory field
+    let _ = Bar::default(); // silenced
+    let _ = Bar { bar: S, .. }; // ok
+    let _ = Qux::<4> { .. };
+}
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
new file mode 100644
index 00000000000..bd96777f865
--- /dev/null
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -0,0 +1,40 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/default-field-values-failures.rs:22:23
+   |
+LL |     bat: i32 =  as T>::K,
+   |                       ^ cannot perform const operation using `C`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `C`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error[E0277]: the trait bound `S: Default` is not satisfied
+  --> $DIR/default-field-values-failures.rs:14:5
+   |
+LL | #[derive(Debug, Default)]
+   |                 ------- in this derive macro expansion
+LL | pub struct Bar {
+LL |     pub bar: S,
+   |     ^^^^^^^^^^ the trait `Default` is not implemented for `S`
+   |
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `S` with `#[derive(Default)]`
+   |
+LL + #[derive(Default)]
+LL | pub struct S;
+   |
+
+error: missing mandatory field `bar`
+  --> $DIR/default-field-values-failures.rs:45:21
+   |
+LL |     let _ = Bar { .. };
+   |                     ^
+
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/default-field-values-failures.rs:20:14
+   |
+LL |     bar: S = Self::S,
+   |              ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/structs/default-field-values-invalid-const.rs b/tests/ui/structs/default-field-values-invalid-const.rs
new file mode 100644
index 00000000000..6838238064b
--- /dev/null
+++ b/tests/ui/structs/default-field-values-invalid-const.rs
@@ -0,0 +1,19 @@
+#![feature(default_field_values, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[warn(default_field_always_invalid_const)] //~ WARN lint `default_field_always_invalid_const` can't be warned on
+pub struct Bat {
+    pub bax: u8 = panic!("asdf"),
+    //~^ ERROR evaluation of constant value failed
+    //~| WARN default field fails const-evaluation
+}
+
+pub struct Baz {
+    pub bax: u8 = 130 + C, // ok
+    pub bat: u8 = 130 + 130,
+    //~^ ERROR evaluation of `Baz::::bat::{constant#0}` failed
+    //~| ERROR default field fails const-evaluation
+    pub bay: u8 = 1, // ok
+}
+
+fn main() {}
diff --git a/tests/ui/structs/default-field-values-invalid-const.stderr b/tests/ui/structs/default-field-values-invalid-const.stderr
new file mode 100644
index 00000000000..a0d84271f4b
--- /dev/null
+++ b/tests/ui/structs/default-field-values-invalid-const.stderr
@@ -0,0 +1,45 @@
+warning: lint `default_field_always_invalid_const` can't be warned on
+  --> $DIR/default-field-values-invalid-const.rs:4:8
+   |
+LL | #[warn(default_field_always_invalid_const)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ either `deny` or `allow`, no other lint level is supported for this lint
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/default-field-values-invalid-const.rs:6:19
+   |
+LL |     pub bax: u8 = panic!("asdf"),
+   |                   ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:6:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: default field fails const-evaluation
+  --> $DIR/default-field-values-invalid-const.rs:6:5
+   |
+LL |     pub bax: u8 = panic!("asdf"),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
+   |
+   = help: you can skip const-evaluation of default fields by enabling this lint
+note: the lint level is defined here
+  --> $DIR/default-field-values-invalid-const.rs:4:8
+   |
+LL | #[warn(default_field_always_invalid_const)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of `Baz::::bat::{constant#0}` failed
+  --> $DIR/default-field-values-invalid-const.rs:13:19
+   |
+LL |     pub bat: u8 = 130 + 130,
+   |                   ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow
+
+error: default field fails const-evaluation
+  --> $DIR/default-field-values-invalid-const.rs:13:5
+   |
+LL |     pub bat: u8 = 130 + 130,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
+   |
+   = help: you can skip const-evaluation of default fields by enabling this lint
+   = note: `#[deny(default_field_always_invalid_const)]` on by default
+
+error: aborting due to 3 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/structs/default-field-values-support.rs b/tests/ui/structs/default-field-values-support.rs
new file mode 100644
index 00000000000..bdf21e1272d
--- /dev/null
+++ b/tests/ui/structs/default-field-values-support.rs
@@ -0,0 +1,68 @@
+//@ run-pass
+#![feature(default_field_values, generic_const_exprs)]
+#![allow(unused_variables, dead_code, incomplete_features)]
+
+pub struct S;
+
+#[derive(Default)]
+pub struct Foo {
+    pub bar: S = S,
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Default)]
+pub enum Bar {
+    #[default]
+    Foo {
+        bar: S = S,
+        baz: i32 = 42 + 3,
+    }
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Qux::::S,
+    baz: i32 = foo(),
+    bat: i32 =  as T>::K,
+    baq: i32 = Self::K,
+    bay: i32 = C,
+    bak: Vec = Vec::new(),
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+fn main () {
+    let x = Foo { .. };
+    let y = Foo::default();
+    let z = Foo { baz: 1, .. };
+
+    assert_eq!(45, x.baz);
+    assert_eq!(45, y.baz);
+    assert_eq!(1, z.baz);
+
+    let x = Bar::Foo { .. };
+    let y = Bar::default();
+    let z = Bar::Foo { baz: 1, .. };
+
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x));
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y));
+    assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z));
+
+    let x = Qux:: { .. };
+    assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, baq: 2, bay: 4, .. }, x));
+    assert!(x.bak.is_empty());
+}
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index d56f15fb221..916f296ccfc 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -92,7 +92,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []
@@ -154,7 +154,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []
@@ -206,7 +206,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []
-- 
cgit 1.4.1-3-g733a5


From b203c73ccfb868c8d299aee34228ddc5b3545b9f Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 00:04:53 +0200
Subject: Avoid hashing completion-related ranges as those may change during
 /resolve query

---
 .../rust-analyzer/crates/rust-analyzer/src/lib.rs      | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 7cf88e60dba..aed84795895 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,7 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
-use ide::{CompletionItem, CompletionRelevance, TextEdit, TextRange};
+use ide::{CompletionItem, CompletionRelevance};
 use serde::de::DeserializeOwned;
 use tenthash::TentHasher;
 
@@ -65,18 +65,6 @@ pub fn from_json(
 }
 
 fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
-    fn hash_text_range(hasher: &mut TentHasher, text_range: &TextRange) {
-        hasher.update(u32::from(text_range.start()).to_le_bytes());
-        hasher.update(u32::from(text_range.end()).to_le_bytes());
-    }
-
-    fn hash_text_edit(hasher: &mut TentHasher, edit: &TextEdit) {
-        for indel in edit.iter() {
-            hasher.update(&indel.insert);
-            hash_text_range(hasher, &indel.delete);
-        }
-    }
-
     fn hash_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) {
         use ide_completion::{
             CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
@@ -130,8 +118,8 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     if let Some(label_detail) = &item.label_detail {
         hasher.update(label_detail);
     }
-    hash_text_range(&mut hasher, &item.source_range);
-    hash_text_edit(&mut hasher, &item.text_edit);
+    // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
+    // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
     hasher.update(item.kind.tag());
     hasher.update(&item.lookup);
     if let Some(detail) = &item.detail {
-- 
cgit 1.4.1-3-g733a5


From 61c0b269d8655e1db902238f987f642b558f3947 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 01:04:02 +0200
Subject: Clippy fixes

---
 .../rust-analyzer/crates/rust-analyzer/src/handlers/request.rs    | 2 +-
 src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs           | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 851341dfdf3..3f2ef7616be 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1138,7 +1138,7 @@ pub(crate) fn handle_completion_resolve(
     };
 
     let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
-        let hash = completion_item_hash(&completion_item, resolve_data.for_ref);
+        let hash = completion_item_hash(completion_item, resolve_data.for_ref);
         hash == resolve_data.hash
     }) else {
         return Ok(original_completion);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index aed84795895..8c8ac8de814 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -71,7 +71,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             CompletionRelevanceTypeMatch,
         };
 
-        hasher.update(&[
+        hasher.update([
             u8::from(relevance.exact_name_match),
             u8::from(relevance.is_local),
             u8::from(relevance.is_name_already_imported),
@@ -86,7 +86,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             hasher.update(label);
         }
         if let Some(trait_) = &relevance.trait_ {
-            hasher.update(&[u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
+            hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
         }
         if let Some(postfix_match) = &relevance.postfix_match {
             let label = match postfix_match {
@@ -96,7 +96,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             hasher.update(label);
         }
         if let Some(function) = &relevance.function {
-            hasher.update(&[u8::from(function.has_params), u8::from(function.has_self_param)]);
+            hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
             let label = match function.return_type {
                 CompletionRelevanceReturnType::Other => "other",
                 CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
@@ -108,7 +108,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     }
 
     let mut hasher = TentHasher::new();
-    hasher.update(&[
+    hasher.update([
         u8::from(is_ref_completion),
         u8::from(item.is_snippet),
         u8::from(item.deprecated),
-- 
cgit 1.4.1-3-g733a5


From 6058cdcccc4fcfa3c2ae2ce878cf229dae776041 Mon Sep 17 00:00:00 2001
From: Waffle Lapkin 
Date: Tue, 10 Dec 2024 00:09:40 +0100
Subject: remove instructions to git exclude files in
 `src/nix-dev-shell/envrc-*`

this is no longer needed as `.gitignore` contains both `/.envrc` and
`flake.lock` (and also `/.direnv/`)
---
 src/tools/nix-dev-shell/envrc-flake | 2 +-
 src/tools/nix-dev-shell/envrc-shell | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/nix-dev-shell/envrc-flake b/src/tools/nix-dev-shell/envrc-flake
index 9def420f05c..849ed1f4fc5 100644
--- a/src/tools/nix-dev-shell/envrc-flake
+++ b/src/tools/nix-dev-shell/envrc-flake
@@ -1,7 +1,7 @@
 # If you want to use this as an .envrc file to create a shell with necessery components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
-# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell && echo .envrc >> .git/info/exclude
+# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell
 
 if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then
   use flake path:./src/tools/nix-dev-shell
diff --git a/src/tools/nix-dev-shell/envrc-shell b/src/tools/nix-dev-shell/envrc-shell
index fb7231a6c30..d8f900fe86a 100644
--- a/src/tools/nix-dev-shell/envrc-shell
+++ b/src/tools/nix-dev-shell/envrc-shell
@@ -1,7 +1,7 @@
 # If you want to use this as an .envrc file to create a shell with necessery components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
-# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc && echo .envrc >> .git/info/exclude
+# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc
 
 use nix ./src/tools/nix-dev-shell/shell.nix
   
-- 
cgit 1.4.1-3-g733a5


From 05d83185c3faac682a8a1d8a674a58afa180f292 Mon Sep 17 00:00:00 2001
From: Waffle Lapkin 
Date: Tue, 10 Dec 2024 00:19:29 +0100
Subject: provide `libz.so.1` in the `nix-dev-shell`

`libz.so.1` is needed for some (?) things...

i personally found myself in need of it when running `x t linkchecker`,
which failed when running cargo build script or something.

although there are also mentions of rustc itself needing it:

---
 src/tools/nix-dev-shell/flake.nix | 5 ++---
 src/tools/nix-dev-shell/shell.nix | 5 ++---
 2 files changed, 4 insertions(+), 6 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/nix-dev-shell/flake.nix b/src/tools/nix-dev-shell/flake.nix
index 8ab5e097427..1b838bd2f7b 100644
--- a/src/tools/nix-dev-shell/flake.nix
+++ b/src/tools/nix-dev-shell/flake.nix
@@ -24,9 +24,8 @@
           # Avoid creating text files for ICEs.
           RUSTC_ICE = "0";
           # Provide `libstdc++.so.6` for the self-contained lld.
-          LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [
-            stdenv.cc.cc.lib
-          ]}";
+          # Provide `libz.so.1`.
+          LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
         };
       }
     );
diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix
index 8a5cbb7c89e..a3f5969bd81 100644
--- a/src/tools/nix-dev-shell/shell.nix
+++ b/src/tools/nix-dev-shell/shell.nix
@@ -13,7 +13,6 @@ pkgs.mkShell {
   # Avoid creating text files for ICEs.
   RUSTC_ICE = "0";
   # Provide `libstdc++.so.6` for the self-contained lld.
-  LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [
-    stdenv.cc.cc.lib
-  ]}";
+  # Provide `libz.so.1`
+  LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
 }
-- 
cgit 1.4.1-3-g733a5


From a73a6a00583db23af2f47eff6965dee1ccac8167 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Fri, 1 Nov 2024 10:40:19 -0400
Subject: Add diagnostic fix to remove unnecessary wrapper in type mismatch

I also reorganized the tests in a more logical order, and removed the redundant `test_` prefix from their names.
---
 .../ide-diagnostics/src/handlers/type_mismatch.rs  | 437 ++++++++++++++++++---
 1 file changed, 375 insertions(+), 62 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 93fe9374a3e..8994ab50e67 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,14 +1,17 @@
 use either::Either;
-use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
-use ide_db::text_edit::TextEdit;
-use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
+use hir::{db::ExpandDatabase, CallableKind, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use ide_db::{
+    famous_defs::FamousDefs,
+    source_change::{SourceChange, SourceChangeBuilder},
+    text_edit::TextEdit,
+};
 use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        BlockExpr, Expr, ExprStmt,
+        make, BlockExpr, Expr, ExprStmt, HasArgList,
     },
-    AstNode, AstPtr, TextSize,
+    ted, AstNode, AstPtr, TextSize,
 };
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -63,6 +66,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option,
+    d: &hir::TypeMismatch,
+    expr_ptr: &InFile>,
+    acc: &mut Vec,
+) -> Option<()> {
+    let db = ctx.sema.db;
+    let root = db.parse_or_expand(expr_ptr.file_id);
+    let expr = expr_ptr.value.to_node(&root);
+    let expr = ctx.sema.original_ast_node(expr.clone())?;
+
+    let Expr::CallExpr(call_expr) = expr else {
+        return None;
+    };
+
+    let callable = ctx.sema.resolve_expr_as_callable(&call_expr.expr()?)?;
+    let CallableKind::TupleEnumVariant(variant) = callable.kind() else {
+        return None;
+    };
+
+    let actual_enum = d.actual.as_adt()?.as_enum()?;
+    let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(call_expr.syntax())?.krate());
+    let core_option = famous_defs.core_option_Option();
+    let core_result = famous_defs.core_result_Result();
+    if Some(actual_enum) != core_option && Some(actual_enum) != core_result {
+        return None;
+    }
+
+    let inner_type = variant.fields(db).first()?.ty_with_args(db, d.actual.type_arguments());
+    if !d.expected.could_unify_with(db, &inner_type) {
+        return None;
+    }
+
+    let inner_arg = call_expr.arg_list()?.args().next()?;
+
+    let mut builder = SourceChangeBuilder::new(expr_ptr.file_id.original_file(ctx.sema.db));
+
+    match inner_arg {
+        // We're returning `()`
+        Expr::TupleExpr(tup) if tup.fields().next().is_none() => {
+            let parent = call_expr
+                .syntax()
+                .parent()
+                .and_then(Either::::cast)?;
+
+            match parent {
+                Either::Left(ret_expr) => {
+                    let old = builder.make_mut(ret_expr);
+                    let new = make::expr_return(None).clone_for_update();
+
+                    ted::replace(old.syntax(), new.syntax());
+                }
+                Either::Right(stmt_list) => {
+                    if stmt_list.statements().count() == 0 {
+                        let block = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)?;
+                        let old = builder.make_mut(block);
+                        let new = make::expr_empty_block().clone_for_update();
+
+                        ted::replace(old.syntax(), new.syntax());
+                    } else {
+                        let old = builder.make_syntax_mut(stmt_list.syntax().parent()?);
+                        let new = make::block_expr(stmt_list.statements(), None).clone_for_update();
+
+                        ted::replace(old, new.syntax());
+                    }
+                }
+            }
+        }
+        _ => {
+            let call_mut = builder.make_mut(call_expr.clone());
+            ted::replace(call_mut.syntax(), inner_arg.clone_for_update().syntax());
+        }
+    }
+
+    let name = format!("Remove unnecessary {}() wrapper", variant.name(db).as_str());
+    acc.push(fix(
+        "remove_unnecessary_wrapper",
+        &name,
+        builder.finish(),
+        call_expr.syntax().text_range(),
+    ));
+    Some(())
+}
+
 fn remove_semicolon(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::TypeMismatch,
@@ -243,7 +331,7 @@ fn str_ref_to_owned(
 #[cfg(test)]
 mod tests {
     use crate::tests::{
-        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_no_fix,
+        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_has_fix, check_no_fix,
     };
 
     #[test]
@@ -260,7 +348,7 @@ fn test(_arg: &i32) {}
     }
 
     #[test]
-    fn test_add_reference_to_int() {
+    fn add_reference_to_int() {
         check_fix(
             r#"
 fn main() {
@@ -278,7 +366,7 @@ fn test(_arg: &i32) {}
     }
 
     #[test]
-    fn test_add_mutable_reference_to_int() {
+    fn add_mutable_reference_to_int() {
         check_fix(
             r#"
 fn main() {
@@ -296,7 +384,7 @@ fn test(_arg: &mut i32) {}
     }
 
     #[test]
-    fn test_add_reference_to_array() {
+    fn add_reference_to_array() {
         check_fix(
             r#"
 //- minicore: coerce_unsized
@@ -315,7 +403,7 @@ fn test(_arg: &[i32]) {}
     }
 
     #[test]
-    fn test_add_reference_with_autoderef() {
+    fn add_reference_with_autoderef() {
         check_fix(
             r#"
 //- minicore: coerce_unsized, deref
@@ -348,7 +436,7 @@ fn test(_arg: &Bar) {}
     }
 
     #[test]
-    fn test_add_reference_to_method_call() {
+    fn add_reference_to_method_call() {
         check_fix(
             r#"
 fn main() {
@@ -372,7 +460,7 @@ impl Test {
     }
 
     #[test]
-    fn test_add_reference_to_let_stmt() {
+    fn add_reference_to_let_stmt() {
         check_fix(
             r#"
 fn main() {
@@ -388,7 +476,7 @@ fn main() {
     }
 
     #[test]
-    fn test_add_reference_to_macro_call() {
+    fn add_reference_to_macro_call() {
         check_fix(
             r#"
 macro_rules! thousand {
@@ -416,7 +504,7 @@ fn main() {
     }
 
     #[test]
-    fn test_add_mutable_reference_to_let_stmt() {
+    fn add_mutable_reference_to_let_stmt() {
         check_fix(
             r#"
 fn main() {
@@ -431,29 +519,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn test_wrap_return_type_option() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Option {
-    if y == 0 {
-        return None;
-    }
-    x / y$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Option {
-    if y == 0 {
-        return None;
-    }
-    Some(x / y)
-}
-"#,
-        );
-    }
-
     #[test]
     fn const_generic_type_mismatch() {
         check_diagnostics(
@@ -487,59 +552,82 @@ fn div(x: i32, y: i32) -> Option {
     }
 
     #[test]
-    fn test_wrap_return_type_option_tails() {
+    fn wrap_return_type() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Result {
+    if y == 0 {
+        return Err(());
+    }
+    x / y$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Result {
+    if y == 0 {
+        return Err(());
+    }
+    Ok(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn wrap_return_type_option() {
         check_fix(
             r#"
 //- minicore: option, result
 fn div(x: i32, y: i32) -> Option {
     if y == 0 {
-        Some(0)
-    } else if true {
-        100$0
-    } else {
-        None
+        return None;
     }
+    x / y$0
 }
 "#,
             r#"
 fn div(x: i32, y: i32) -> Option {
     if y == 0 {
-        Some(0)
-    } else if true {
-        Some(100)
-    } else {
-        None
+        return None;
     }
+    Some(x / y)
 }
 "#,
         );
     }
 
     #[test]
-    fn test_wrap_return_type() {
+    fn wrap_return_type_option_tails() {
         check_fix(
             r#"
 //- minicore: option, result
-fn div(x: i32, y: i32) -> Result {
+fn div(x: i32, y: i32) -> Option {
     if y == 0 {
-        return Err(());
+        Some(0)
+    } else if true {
+        100$0
+    } else {
+        None
     }
-    x / y$0
 }
 "#,
             r#"
-fn div(x: i32, y: i32) -> Result {
+fn div(x: i32, y: i32) -> Option {
     if y == 0 {
-        return Err(());
+        Some(0)
+    } else if true {
+        Some(100)
+    } else {
+        None
     }
-    Ok(x / y)
 }
 "#,
         );
     }
 
     #[test]
-    fn test_wrap_return_type_handles_generic_functions() {
+    fn wrap_return_type_handles_generic_functions() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -562,7 +650,7 @@ fn div(x: T) -> Result {
     }
 
     #[test]
-    fn test_wrap_return_type_handles_type_aliases() {
+    fn wrap_return_type_handles_type_aliases() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -589,7 +677,7 @@ fn div(x: i32, y: i32) -> MyResult {
     }
 
     #[test]
-    fn test_wrapped_unit_as_block_tail_expr() {
+    fn wrapped_unit_as_block_tail_expr() {
         check_fix(
             r#"
 //- minicore: result
@@ -619,7 +707,7 @@ fn foo() -> Result<(), ()> {
     }
 
     #[test]
-    fn test_wrapped_unit_as_return_expr() {
+    fn wrapped_unit_as_return_expr() {
         check_fix(
             r#"
 //- minicore: result
@@ -642,7 +730,7 @@ fn foo(b: bool) -> Result<(), String> {
     }
 
     #[test]
-    fn test_in_const_and_static() {
+    fn wrap_in_const_and_static() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -664,7 +752,7 @@ const _: Option<()> = {Some(())};
     }
 
     #[test]
-    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
+    fn wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
         check_no_fix(
             r#"
 //- minicore: option, result
@@ -674,7 +762,7 @@ fn foo() -> Result<(), i32> { 0$0 }
     }
 
     #[test]
-    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
+    fn wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
         check_no_fix(
             r#"
 //- minicore: option, result
@@ -685,6 +773,231 @@ fn foo() -> SomeOtherEnum { 0$0 }
         );
     }
 
+    #[test]
+    fn unwrap_return_type() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    Ok(x / y)$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_option() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    Some(x / y)$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_option_tails() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        42
+    } else if true {
+        Some(100)$0
+    } else {
+        0
+    }
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        42
+    } else if true {
+        100
+    } else {
+        0
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_handles_generic_functions() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: T) -> T {
+    if x == 0 {
+        panic!();
+    }
+    $0Ok(x)
+}
+"#,
+            r#"
+fn div(x: T) -> T {
+    if x == 0 {
+        panic!();
+    }
+    x
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_handles_type_aliases() {
+        check_fix(
+            r#"
+//- minicore: option, result
+type MyResult = T;
+
+fn div(x: i32, y: i32) -> MyResult {
+    if y == 0 {
+        panic!();
+    }
+    Ok(x $0/ y)
+}
+"#,
+            r#"
+type MyResult = T;
+
+fn div(x: i32, y: i32) -> MyResult {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_tail_expr() {
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> () {
+    println!("Hello, world!");
+    Ok(())$0
+}
+            "#,
+            r#"
+fn foo() -> () {
+    println!("Hello, world!");
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_to_empty_block() {
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> () {
+    Ok(())$0
+}
+            "#,
+            r#"
+fn foo() -> () {}
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_to_return_expr() {
+        check_has_fix(
+            r#"
+//- minicore: result
+fn foo(b: bool) -> () {
+    if b {
+        return $0Ok(());
+    }
+
+    panic!("oh dear");
+}"#,
+            r#"
+fn foo(b: bool) -> () {
+    if b {
+        return;
+    }
+
+    panic!("oh dear");
+}"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_in_const_and_static() {
+        check_fix(
+            r#"
+//- minicore: option, result
+static A: () = {Some(($0))};
+            "#,
+            r#"
+static A: () = {};
+            "#,
+        );
+        check_fix(
+            r#"
+//- minicore: option, result
+const _: () = {Some(($0))};
+            "#,
+            r#"
+const _: () = {};
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_not_applicable_when_inner_type_does_not_match_return_type() {
+        check_no_fix(
+            r#"
+//- minicore: result
+fn foo() -> i32 { $0Ok(()) }
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_not_applicable_when_wrapper_type_is_not_result_or_option() {
+        check_no_fix(
+            r#"
+//- minicore: option, result
+enum SomeOtherEnum { Ok(i32), Err(String) }
+
+fn foo() -> i32 { SomeOtherEnum::Ok($042) }
+"#,
+        );
+    }
+
     #[test]
     fn remove_semicolon() {
         check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
-- 
cgit 1.4.1-3-g733a5


From 4898f3f5919824c955510a60e09b3353e69f2e2b Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Thu, 14 Nov 2024 15:57:58 -0500
Subject: fix: Handle the final statement in `SyntaxFactory::block_expr`
 properly

This caused a bug that was rather tricky to hunt down!
---
 .../syntax/src/ast/syntax_factory/constructors.rs   | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 54f17bd721d..44f67d83dc6 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -58,22 +58,31 @@ impl SyntaxFactory {
         tail_expr: Option,
     ) -> ast::BlockExpr {
         let stmts = stmts.into_iter().collect_vec();
-        let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec();
+        let mut input = stmts.iter().map(|it| it.syntax().clone()).collect_vec();
 
         let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update();
 
-        if let Some((mut mapping, stmt_list)) = self.mappings().zip(ast.stmt_list()) {
+        if let Some(mut mapping) = self.mappings() {
+            let stmt_list = ast.stmt_list().unwrap();
             let mut builder = SyntaxMappingBuilder::new(stmt_list.syntax().clone());
 
+            if let Some(input) = tail_expr {
+                builder.map_node(
+                    input.syntax().clone(),
+                    stmt_list.tail_expr().unwrap().syntax().clone(),
+                );
+            } else if let Some(ast_tail) = stmt_list.tail_expr() {
+                // The parser interpreted the last statement (probably a statement with a block) as an Expr
+                let last_stmt = input.pop().unwrap();
+
+                builder.map_node(last_stmt, ast_tail.syntax().clone());
+            }
+
             builder.map_children(
                 input.into_iter(),
                 stmt_list.statements().map(|it| it.syntax().clone()),
             );
 
-            if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) {
-                builder.map_node(input.syntax().clone(), output.syntax().clone());
-            }
-
             builder.finish(&mut mapping);
         }
 
-- 
cgit 1.4.1-3-g733a5


From b76734f20e05df0c698b3a00f51f20968a411f59 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Thu, 14 Nov 2024 21:15:50 -0500
Subject: minor: Migrate `remove_unnecessary_wrapper` to `SyntaxEditor`

---
 .../ide-diagnostics/src/handlers/type_mismatch.rs  | 63 +++++++++++++++-------
 .../syntax/src/ast/syntax_factory/constructors.rs  | 20 +++++++
 2 files changed, 63 insertions(+), 20 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 8994ab50e67..bfdda537405 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -9,9 +9,10 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, BlockExpr, Expr, ExprStmt, HasArgList,
+        syntax_factory::SyntaxFactory,
+        BlockExpr, Expr, ExprStmt, HasArgList,
     },
-    ted, AstNode, AstPtr, TextSize,
+    AstNode, AstPtr, TextSize,
 };
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -223,8 +224,9 @@ fn remove_unnecessary_wrapper(
 
     let inner_arg = call_expr.arg_list()?.args().next()?;
 
-    let mut builder = SourceChangeBuilder::new(expr_ptr.file_id.original_file(ctx.sema.db));
-
+    let file_id = expr_ptr.file_id.original_file(db);
+    let mut builder = SourceChangeBuilder::new(file_id);
+    let mut editor;
     match inner_arg {
         // We're returning `()`
         Expr::TupleExpr(tup) if tup.fields().next().is_none() => {
@@ -233,35 +235,33 @@ fn remove_unnecessary_wrapper(
                 .parent()
                 .and_then(Either::::cast)?;
 
+            editor = builder.make_editor(parent.syntax());
+            let make = SyntaxFactory::new();
+
             match parent {
                 Either::Left(ret_expr) => {
-                    let old = builder.make_mut(ret_expr);
-                    let new = make::expr_return(None).clone_for_update();
-
-                    ted::replace(old.syntax(), new.syntax());
+                    editor.replace(ret_expr.syntax(), make.expr_return(None).syntax());
                 }
                 Either::Right(stmt_list) => {
-                    if stmt_list.statements().count() == 0 {
-                        let block = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)?;
-                        let old = builder.make_mut(block);
-                        let new = make::expr_empty_block().clone_for_update();
-
-                        ted::replace(old.syntax(), new.syntax());
+                    let new_block = if stmt_list.statements().next().is_none() {
+                        make.expr_empty_block()
                     } else {
-                        let old = builder.make_syntax_mut(stmt_list.syntax().parent()?);
-                        let new = make::block_expr(stmt_list.statements(), None).clone_for_update();
+                        make.block_expr(stmt_list.statements(), None)
+                    };
 
-                        ted::replace(old, new.syntax());
-                    }
+                    editor.replace(stmt_list.syntax().parent()?, new_block.syntax());
                 }
             }
+
+            editor.add_mappings(make.finish_with_mappings());
         }
         _ => {
-            let call_mut = builder.make_mut(call_expr.clone());
-            ted::replace(call_mut.syntax(), inner_arg.clone_for_update().syntax());
+            editor = builder.make_editor(call_expr.syntax());
+            editor.replace(call_expr.syntax(), inner_arg.syntax());
         }
     }
 
+    builder.add_file_edits(file_id, editor);
     let name = format!("Remove unnecessary {}() wrapper", variant.name(db).as_str());
     acc.push(fix(
         "remove_unnecessary_wrapper",
@@ -848,6 +848,29 @@ fn div(x: i32, y: i32) -> i32 {
         );
     }
 
+    #[test]
+    fn unwrap_return_type_option_tail_unit() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) {
+    if y == 0 {
+        panic!();
+    }
+
+    Ok(())$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) {
+    if y == 0 {
+        panic!();
+    }
+}
+"#,
+        );
+    }
+
     #[test]
     fn unwrap_return_type_handles_generic_functions() {
         check_fix(
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 44f67d83dc6..f6ec18ef306 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -89,6 +89,10 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_empty_block(&self) -> ast::BlockExpr {
+        ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
+    }
+
     pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
         let ast::Expr::BinExpr(ast) =
             make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
@@ -135,6 +139,22 @@ impl SyntaxFactory {
         ast.into()
     }
 
+    pub fn expr_return(&self, expr: Option) -> ast::ReturnExpr {
+        let ast::Expr::ReturnExpr(ast) = make::expr_return(expr.clone()).clone_for_update() else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            if let Some(input) = expr {
+                builder.map_node(input.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn let_stmt(
         &self,
         pattern: ast::Pat,
-- 
cgit 1.4.1-3-g733a5


From 9a6deba8af18e3d69b6c824a989f8647955fd3a1 Mon Sep 17 00:00:00 2001
From: jyn 
Date: Tue, 10 Dec 2024 04:35:20 -0500
Subject: run-make: Fix `assert_stderr_not_contains_regex`

It asserted on **stdout**, not stderr.
---
 src/tools/run-make-support/src/command.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/tools')

diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 9e09527d6d0..e73413085fa 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -329,7 +329,7 @@ impl CompletedProcess {
     /// Checks that `stderr` does not contain the regex pattern `unexpected`.
     #[track_caller]
     pub fn assert_stderr_not_contains_regex>(&self, unexpected: S) -> &Self {
-        assert_not_contains_regex(&self.stdout_utf8(), unexpected);
+        assert_not_contains_regex(&self.stderr_utf8(), unexpected);
         self
     }
 
-- 
cgit 1.4.1-3-g733a5


From f94953d7320b2a4d2c7341136e7e63d4c118db0f Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 12:33:13 +0200
Subject: Address the feedback from Veykril

* Exclude documentation field from hashing
* Do less cloning during initial completion list generation
---
 src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs    |  6 +++---
 .../rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs | 14 +++++++-------
 2 files changed, 10 insertions(+), 10 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 8c8ac8de814..15d60c873fb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -120,14 +120,14 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     }
     // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
     // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
+    //
+    // Documentation hashing is skipped too, as it's a large blob to process,
+    // while not really making completion properties more unique as they are already.
     hasher.update(item.kind.tag());
     hasher.update(&item.lookup);
     if let Some(detail) = &item.detail {
         hasher.update(detail);
     }
-    if let Some(documentation) = &item.documentation {
-        hasher.update(documentation.as_str());
-    }
     hash_completion_relevance(&mut hasher, &item.relevance);
     if let Some((mutability, text_size)) = &item.ref_match {
         hasher.update(mutability.as_keyword_for_ref());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index f70968d6942..a64e1a86210 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -275,7 +275,6 @@ fn completion_item(
     completion_trigger_character: Option,
     item: CompletionItem,
 ) {
-    let original_completion_item = item.clone();
     let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
     let ref_match = item.ref_match();
 
@@ -297,7 +296,7 @@ fn completion_item(
         // non-trivial mapping here.
         let mut text_edit = None;
         let source_range = item.source_range;
-        for indel in item.text_edit {
+        for indel in &item.text_edit {
             if indel.delete.contains_range(source_range) {
                 // Extract this indel as the main edit
                 text_edit = Some(if indel.delete == source_range {
@@ -349,7 +348,7 @@ fn completion_item(
         something_to_resolve |= item.documentation.is_some();
         None
     } else {
-        item.documentation.map(documentation)
+        item.documentation.clone().map(documentation)
     };
 
     let mut lsp_item = lsp_types::CompletionItem {
@@ -373,10 +372,10 @@ fn completion_item(
         } else {
             lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
                 detail: item.label_detail.as_ref().map(ToString::to_string),
-                description: item.detail,
+                description: item.detail.clone(),
             });
         }
-    } else if let Some(label_detail) = item.label_detail {
+    } else if let Some(label_detail) = &item.label_detail {
         lsp_item.label.push_str(label_detail.as_str());
     }
 
@@ -385,6 +384,7 @@ fn completion_item(
     let imports =
         if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
             item.import_to_add
+                .clone()
                 .into_iter()
                 .map(|(import_path, import_name)| lsp_ext::CompletionImport {
                     full_import_path: import_path,
@@ -402,7 +402,7 @@ fn completion_item(
                 version,
                 trigger_character: completion_trigger_character,
                 for_ref: true,
-                hash: completion_item_hash(&original_completion_item, true),
+                hash: completion_item_hash(&item, true),
             };
             Some(to_value(ref_resolve_data).unwrap())
         } else {
@@ -414,7 +414,7 @@ fn completion_item(
             version,
             trigger_character: completion_trigger_character,
             for_ref: false,
-            hash: completion_item_hash(&original_completion_item, false),
+            hash: completion_item_hash(&item, false),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {
-- 
cgit 1.4.1-3-g733a5


From 1ce15606f2157b955e87608a20492160f4a74ae1 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 13:01:23 +0200
Subject: Address the feedback from pascalkuthe

* Use Base64 to minify the hash representation in the JSON data
* Do hash checks only for items with similar labels
---
 src/tools/rust-analyzer/Cargo.lock                             |  7 +++++++
 src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml        |  1 +
 .../rust-analyzer/crates/rust-analyzer/src/handlers/request.rs | 10 ++++++++--
 src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs    |  2 +-
 .../rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs     |  5 +++--
 src/tools/rust-analyzer/docs/dev/lsp-extensions.md             |  2 +-
 6 files changed, 21 insertions(+), 6 deletions(-)

(limited to 'src/tools')

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index b6f2c6faf86..8b156a54013 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -84,6 +84,12 @@ dependencies = [
  "vfs",
 ]
 
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -1649,6 +1655,7 @@ version = "0.0.0"
 dependencies = [
  "always-assert",
  "anyhow",
+ "base64",
  "cargo_metadata",
  "cfg",
  "crossbeam-channel",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 58d871270d9..7c8610280b3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -21,6 +21,7 @@ path = "src/bin/main.rs"
 
 [dependencies]
 anyhow.workspace = true
+base64 = "0.22"
 crossbeam-channel.workspace = true
 dirs = "5.0.1"
 dissimilar.workspace = true
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 3f2ef7616be..e51b14f6118 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -10,6 +10,7 @@ use std::{
 
 use anyhow::Context;
 
+use base64::{prelude::BASE64_STANDARD, Engine};
 use ide::{
     AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
     FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
@@ -1136,10 +1137,15 @@ pub(crate) fn handle_completion_resolve(
     else {
         return Ok(original_completion);
     };
+    let Ok(resolve_data_hash) = BASE64_STANDARD.decode(resolve_data.hash) else {
+        return Ok(original_completion);
+    };
 
     let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
-        let hash = completion_item_hash(completion_item, resolve_data.for_ref);
-        hash == resolve_data.hash
+        // Avoid computing hashes for items that obviously do not match
+        // r-a might append a detail-based suffix to the label, so we cannot check for equality
+        original_completion.label.starts_with(completion_item.label.as_str())
+            && resolve_data_hash == completion_item_hash(completion_item, resolve_data.for_ref)
     }) else {
         return Ok(original_completion);
     };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index afb9c909c68..df06270a8b1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -827,7 +827,7 @@ pub struct CompletionResolveData {
     pub version: Option,
     pub trigger_character: Option,
     pub for_ref: bool,
-    pub hash: [u8; 20],
+    pub hash: String,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index a64e1a86210..612cb547b41 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -5,6 +5,7 @@ use std::{
     sync::atomic::{AtomicU32, Ordering},
 };
 
+use base64::{prelude::BASE64_STANDARD, Engine};
 use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
     CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
@@ -402,7 +403,7 @@ fn completion_item(
                 version,
                 trigger_character: completion_trigger_character,
                 for_ref: true,
-                hash: completion_item_hash(&item, true),
+                hash: BASE64_STANDARD.encode(completion_item_hash(&item, true)),
             };
             Some(to_value(ref_resolve_data).unwrap())
         } else {
@@ -414,7 +415,7 @@ fn completion_item(
             version,
             trigger_character: completion_trigger_character,
             for_ref: false,
-            hash: completion_item_hash(&item, false),
+            hash: BASE64_STANDARD.encode(completion_item_hash(&item, false)),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 80b35d453a3..2aad2cfa361 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@