From e45a250f8c26e94a2a3ff8b50305530f75718239 Mon Sep 17 00:00:00 2001
From: Zachary S <zasample18+github@gmail.com>
Date: Mon, 25 Jul 2022 15:43:25 -0500
Subject: [PATCH 01/28] fix: Insert spaces when inlining a function defined in
 a macro.

---
 .../ide-assists/src/handlers/inline_call.rs   | 50 ++++++++++++++++++-
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 658a1aadf53ec..8b2f6ac75a28e 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -7,7 +7,7 @@ use ide_db::{
     imports::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    syntax_helpers::node_ext::expr_as_name_ref,
+    syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
     RootDatabase,
 };
 use itertools::{izip, Itertools};
@@ -301,7 +301,18 @@ fn inline(
     params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
     CallInfo { node, arguments, generic_arg_list }: &CallInfo,
 ) -> ast::Expr {
-    let body = fn_body.clone_for_update();
+    let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
+        cov_mark::hit!(inline_call_defined_in_macro);
+        if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
+            body
+        } else {
+            // FIXME(zachs18): I believe this should be unreachable,
+            // since insert_ws_into shouldn't change the kind of the SyntaxNode.
+            fn_body.clone_for_update()
+        }
+    } else {
+        fn_body.clone_for_update()
+    };
     let usages_for_locals = |local| {
         Definition::Local(local)
             .usages(sema)
@@ -1144,6 +1155,41 @@ fn bar() -> u32 {
         x
     }) + foo()
 }
+"#,
+        )
+    }
+
+    #[test]
+    fn inline_call_defined_in_macro() {
+        cov_mark::check!(inline_call_defined_in_macro);
+        check_assist(
+            inline_call,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    foo$0()
+}
+"#,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    {
+      let x = 0;
+      x
+    }
+}
 "#,
         )
     }

From b1e3daf14b14404945a14346d7b478feee7c5508 Mon Sep 17 00:00:00 2001
From: Amos Wenger <amoswenger@gmail.com>
Date: Tue, 26 Jul 2022 11:30:41 +0200
Subject: [PATCH 02/28] Find standalone proc-macro-srv on windows too

---
 crates/rust-analyzer/src/reload.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 9ae361b034e28..b9aa13ec5b33b 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -303,6 +303,9 @@ impl GlobalState {
         let files_config = self.config.files();
         let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 
+        let standalone_server_name =
+            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+
         if self.proc_macro_clients.is_empty() {
             if let Some((path, args)) = self.config.proc_macro_srv() {
                 self.proc_macro_clients = self
@@ -316,10 +319,8 @@ impl GlobalState {
                             tracing::info!("Found a cargo workspace...");
                             if let Some(sysroot) = sysroot.as_ref() {
                                 tracing::info!("Found a cargo workspace with a sysroot...");
-                                let server_path = sysroot
-                                    .root()
-                                    .join("libexec")
-                                    .join("rust-analyzer-proc-macro-srv");
+                                let server_path =
+                                    sysroot.root().join("libexec").join(&standalone_server_name);
                                 if std::fs::metadata(&server_path).is_ok() {
                                     tracing::info!(
                                         "And the server exists at {}",

From c8ff70e924efe3adba39ac5dc2a93dbd94bde5a4 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Tue, 26 Jul 2022 16:30:45 +0200
Subject: [PATCH 03/28] fix: Fix server panicking on project loading when
 proc-macros are disabled

---
 crates/rust-analyzer/src/cli/load_cargo.rs | 4 +++-
 crates/rust-analyzer/src/reload.rs         | 7 +++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 0ada4b73e842d..5d1c013c3275b 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -66,7 +66,9 @@ pub fn load_workspace(
     };
 
     let crate_graph = ws.to_crate_graph(
-        &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
+        &mut |_, path: &AbsPath| {
+            load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
+        },
         &mut |path: &AbsPath| {
             let contents = loader.load_sync(path);
             let path = vfs::VfsPath::from(path.to_path_buf());
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index b9aa13ec5b33b..eaab275bc68a4 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -390,7 +390,10 @@ impl GlobalState {
 
             let mut crate_graph = CrateGraph::default();
             for (idx, ws) in self.workspaces.iter().enumerate() {
-                let proc_macro_client = self.proc_macro_clients[idx].as_ref();
+                let proc_macro_client = match self.proc_macro_clients.get(idx) {
+                    Some(res) => res.as_ref().map_err(|e| &**e),
+                    None => Err("Proc macros are disabled"),
+                };
                 let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
                     load_proc_macro(
                         proc_macro_client,
@@ -574,7 +577,7 @@ impl SourceRootConfig {
 /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 /// with an identity dummy expander.
 pub(crate) fn load_proc_macro(
-    server: Result<&ProcMacroServer, &String>,
+    server: Result<&ProcMacroServer, &str>,
     path: &AbsPath,
     dummy_replace: &[Box<str>],
 ) -> ProcMacroLoadResult {

From add33b65dda4b59b46b5192f3a88a83b771af844 Mon Sep 17 00:00:00 2001
From: Zachary S <zasample18+github@gmail.com>
Date: Tue, 26 Jul 2022 10:59:19 -0500
Subject: [PATCH 04/28] Remove FIXME comment for unreachable fallback.

---
 crates/ide-assists/src/handlers/inline_call.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 8b2f6ac75a28e..80d3b92559367 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -306,8 +306,6 @@ fn inline(
         if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
             body
         } else {
-            // FIXME(zachs18): I believe this should be unreachable,
-            // since insert_ws_into shouldn't change the kind of the SyntaxNode.
             fn_body.clone_for_update()
         }
     } else {

From 6c379b9f4bb9774758e018944a33db5eb29622fb Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Wed, 27 Jul 2022 12:45:29 +0200
Subject: [PATCH 05/28] fix: Fix Semantics::original_ast_node not caching the
 resulting file

---
 crates/hir/src/semantics.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index fc8f23f19ab91..a75e5cafd0bd1 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -924,7 +924,12 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
+        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
+            |InFile { file_id, value }| {
+                self.cache(find_root(value.syntax()), file_id);
+                value
+            },
+        )
     }
 
     fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {

From 1f8daa180fdfb847f5f82b8ac9870aebb17c9494 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Wed, 27 Jul 2022 13:48:26 +0200
Subject: [PATCH 06/28] fix: Honor ref expressions for compute_ref_match
 completions

---
 crates/hir-ty/src/chalk_ext.rs                |  5 ++
 crates/hir/src/lib.rs                         |  4 ++
 crates/ide-completion/src/context/analysis.rs | 69 ++++++++++++-------
 crates/ide-completion/src/context/tests.rs    | 20 ++++++
 4 files changed, 75 insertions(+), 23 deletions(-)

diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index b0885ab003f71..a9c124b42dc2c 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -34,6 +34,7 @@ pub trait TyExt {
     fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
 
     fn strip_references(&self) -> &Ty;
+    fn strip_reference(&self) -> &Ty;
 
     /// If this is a `dyn Trait`, returns that trait.
     fn dyn_trait(&self) -> Option<TraitId>;
@@ -182,6 +183,10 @@ impl TyExt for Ty {
         t
     }
 
+    fn strip_reference(&self) -> &Ty {
+        self.as_reference().map_or(self, |(ty, _, _)| ty)
+    }
+
     fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
         match self.kind(Interner) {
             TyKind::OpaqueType(opaque_ty_id, subst) => {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d4925455d7bd2..8f984210e1176 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2769,6 +2769,10 @@ impl Type {
         self.derived(self.ty.strip_references().clone())
     }
 
+    pub fn strip_reference(&self) -> Type {
+        self.derived(self.ty.strip_reference().clone())
+    }
+
     pub fn is_unknown(&self) -> bool {
         self.ty.is_unknown()
     }
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index c71ffa0ed86fd..09a1a99eb64ca 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -162,11 +162,52 @@ impl<'a> CompletionContext<'a> {
     }
 
     /// Calculate the expected type and name of the cursor position.
-    fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
+    fn expected_type_and_name(
+        &self,
+        name_like: &ast::NameLike,
+    ) -> (Option<Type>, Option<NameOrNameRef>) {
         let mut node = match self.token.parent() {
             Some(it) => it,
             None => return (None, None),
         };
+
+        let strip_refs = |mut ty: Type| match name_like {
+            ast::NameLike::NameRef(n) => {
+                let p = match n.syntax().parent() {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                let top_syn = match_ast! {
+                    match p {
+                        ast::FieldExpr(e) => e
+                            .syntax()
+                            .ancestors()
+                            .map_while(ast::FieldExpr::cast)
+                            .last()
+                            .map(|it| it.syntax().clone()),
+                        ast::PathSegment(e) => e
+                            .syntax()
+                            .ancestors()
+                            .skip(1)
+                            .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
+                            .find_map(ast::PathExpr::cast)
+                            .map(|it| it.syntax().clone()),
+                        _ => None
+                    }
+                };
+                let top_syn = match top_syn {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
+                    cov_mark::hit!(expected_type_fn_param_ref);
+                    ty = ty.strip_reference();
+                }
+                ty
+            }
+            _ => ty,
+        };
+
         loop {
             break match_ast! {
                 match node {
@@ -199,13 +240,9 @@ impl<'a> CompletionContext<'a> {
                             self.token.clone(),
                         ).map(|ap| {
                             let name = ap.ident().map(NameOrNameRef::Name);
-                            let ty = if has_ref(&self.token) {
-                                cov_mark::hit!(expected_type_fn_param_ref);
-                                ap.ty.remove_ref()
-                            } else {
-                                Some(ap.ty)
-                            };
-                            (ty, name)
+
+                            let ty = strip_refs(ap.ty);
+                            (Some(ty), name)
                         })
                         .unwrap_or((None, None))
                     },
@@ -330,8 +367,6 @@ impl<'a> CompletionContext<'a> {
             return None;
         }
 
-        (self.expected_type, self.expected_name) = self.expected_type_and_name();
-
         // Overwrite the path kind for derives
         if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
             if let Some(ast::NameLike::NameRef(name_ref)) =
@@ -389,6 +424,7 @@ impl<'a> CompletionContext<'a> {
                 return Some(analysis);
             }
         };
+        (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
         let analysis = match name_like {
             ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
                 Self::classify_lifetime(&self.sema, original_file, lifetime)?,
@@ -1141,19 +1177,6 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
     Some((use_tree.path()?, true))
 }
 
-fn has_ref(token: &SyntaxToken) -> bool {
-    let mut token = token.clone();
-    for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] {
-        if token.kind() == skip {
-            token = match token.prev_token() {
-                Some(it) => it,
-                None => return false,
-            }
-        }
-    }
-    token.kind() == T![&]
-}
-
 pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
     // oh my ...
     (|| {
diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs
index c5557bdafb339..50845b3881f43 100644
--- a/crates/ide-completion/src/context/tests.rs
+++ b/crates/ide-completion/src/context/tests.rs
@@ -391,3 +391,23 @@ fn foo($0: Foo) {}
         expect![[r#"ty: ?, name: ?"#]],
     );
 }
+
+#[test]
+fn expected_type_ref_prefix_on_field() {
+    check_expected_type_and_name(
+        r#"
+fn foo(_: &mut i32) {}
+struct S {
+    field: i32,
+}
+
+fn main() {
+    let s = S {
+        field: 100,
+    };
+    foo(&mut s.f$0);
+}
+"#,
+        expect!["ty: i32, name: ?"],
+    );
+}

From 349dfc7e95c7b384a3e520db3cc26645918857d2 Mon Sep 17 00:00:00 2001
From: hi-rustin <rustin.liu@gmail.com>
Date: Wed, 27 Jul 2022 20:18:00 +0800
Subject: [PATCH 07/28] Find original ast node before compute ref match in fn
 render

Signed-off-by: hi-rustin <rustin.liu@gmail.com>
---
 crates/ide-completion/src/render/function.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 241de0a1834a0..4b5535718c5df 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -85,7 +85,9 @@ fn render(
                 item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
             }
             FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
-                item.ref_match(ref_match, receiver.syntax().text_range().start());
+                if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+                    item.ref_match(ref_match, original_expr.syntax().text_range().start());
+                }
             }
             _ => (),
         }

From bf893d59b54eb3b0dd3bcf34a66f9f0703753ffb Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Wed, 27 Jul 2022 17:14:50 +0200
Subject: [PATCH 08/28] internal: Assume condition/iterable is missing if there
 is only a BlockExpr

---
 crates/syntax/src/ast/generated/nodes.rs |  4 ---
 crates/syntax/src/ast/node_ext.rs        | 38 ++++++++++++++++++++++++
 crates/syntax/src/tests/sourcegen_ast.rs |  2 ++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index cf90ba64cff1a..63309a155219e 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -880,7 +880,6 @@ impl ForExpr {
     pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
-    pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -890,7 +889,6 @@ pub struct IfExpr {
 impl ast::HasAttrs for IfExpr {}
 impl IfExpr {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 }
 
@@ -1051,7 +1049,6 @@ pub struct WhileExpr {
 impl ast::HasAttrs for WhileExpr {}
 impl WhileExpr {
     pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1170,7 +1167,6 @@ pub struct MatchGuard {
 }
 impl MatchGuard {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index b143df1f83f2a..bb92c51e9a90e 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -806,6 +806,19 @@ impl ast::GenericParamList {
     }
 }
 
+impl ast::ForExpr {
+    pub fn iterable(&self) -> Option<ast::Expr> {
+        // If the iterable is a BlockExpr, check if the body is missing.
+        // If it is assume the iterable is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::ForExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -815,6 +828,19 @@ impl ast::HasLoopBody for ast::ForExpr {
     }
 }
 
+impl ast::WhileExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        // If the condition is a BlockExpr, check if the body is missing.
+        // If it is assume the condition is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::WhileExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -835,3 +861,15 @@ impl From<ast::Adt> for ast::Item {
         }
     }
 }
+
+impl ast::IfExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
+
+impl ast::MatchGuard {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 4cfb8075cb155..6d2766225103f 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -682,6 +682,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
                     | "value"
                     | "trait"
                     | "self_ty"
+                    | "iterable"
+                    | "condition"
             );
             if manually_implemented {
                 return;

From f83738e1d993d84c1607fcabdf9f41ab00f83d55 Mon Sep 17 00:00:00 2001
From: Brennan Vincent <brennan@umanwizard.com>
Date: Wed, 27 Jul 2022 14:34:46 -0400
Subject: [PATCH 09/28] Use large stack on expander thread

---
 crates/proc-macro-srv/src/lib.rs | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index 4b1858b8ed89e..4c205b9cadac3 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -39,6 +39,8 @@ pub(crate) struct ProcMacroSrv {
     expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
 }
 
+const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
+
 impl ProcMacroSrv {
     pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
         let expander = self.expander(task.lib.as_ref()).map_err(|err| {
@@ -66,13 +68,18 @@ impl ProcMacroSrv {
         // FIXME: replace this with std's scoped threads once they stabilize
         // (then remove dependency on crossbeam)
         let result = crossbeam::scope(|s| {
-            let res = s
+            let res = match s
+                .builder()
+                .stack_size(EXPANDER_STACK_SIZE)
+                .name(task.macro_name.clone())
                 .spawn(|_| {
                     expander
                         .expand(&task.macro_name, &macro_body, attributes.as_ref())
                         .map(|it| FlatTree::new(&it))
-                })
-                .join();
+                }) {
+                Ok(handle) => handle.join(),
+                Err(e) => std::panic::resume_unwind(Box::new(e)),
+            };
 
             match res {
                 Ok(res) => res,

From e782e59d3de3d4a58cbc8005fd9521502b8d9a61 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Thu, 28 Jul 2022 10:05:21 +0200
Subject: [PATCH 10/28] fix: Calculate completions after type anchors

---
 crates/hir/src/semantics.rs                   | 18 ++++++
 .../src/completions/attribute.rs              |  2 +-
 .../src/completions/attribute/derive.rs       |  2 +-
 crates/ide-completion/src/completions/expr.rs | 23 +++++++-
 .../src/completions/item_list.rs              |  2 +-
 .../ide-completion/src/completions/pattern.rs |  2 +-
 crates/ide-completion/src/completions/type.rs | 18 +++++-
 crates/ide-completion/src/completions/use_.rs |  2 +-
 crates/ide-completion/src/completions/vis.rs  |  2 +-
 crates/ide-completion/src/context.rs          |  5 +-
 crates/ide-completion/src/context/analysis.rs | 56 ++++++++++---------
 crates/ide-completion/src/tests/special.rs    | 55 +++++++++++++++++-
 12 files changed, 151 insertions(+), 36 deletions(-)

diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index a75e5cafd0bd1..c84318b2fb877 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -324,6 +324,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_type(ty)
     }
 
+    pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
+        self.imp.resolve_trait(trait_)
+    }
+
     // FIXME: Figure out a nice interface to inspect adjustments
     pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.imp.is_implicit_reborrow(expr)
@@ -1014,6 +1018,20 @@ impl<'db> SemanticsImpl<'db> {
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
+    fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
+        let analyze = self.analyze(path.syntax())?;
+        let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
+        let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
+        let hir_path = Path::from_src(path.clone(), &ctx)?;
+        match analyze
+            .resolver
+            .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
+        {
+            TypeNs::TraitId(id) => Some(Trait { id }),
+            _ => None,
+        }
+    }
+
     fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
     }
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index 1d8a8c5f20db3..d9fe94cb44ee1 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -115,7 +115,7 @@ pub(crate) fn complete_attribute_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 
     let attributes = annotated_item_kind.and_then(|kind| {
diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs
index 14538fef6072c..793c22630bf89 100644
--- a/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/crates/ide-completion/src/completions/attribute/derive.rs
@@ -97,7 +97,7 @@ pub(crate) fn complete_derive_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
 
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index bdf6e64f09696..d4f2766602fbf 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -46,11 +46,32 @@ pub(crate) fn complete_expr_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                cov_mark::hit!(completes_variant_through_alias);
+                acc.add_enum_variants(ctx, path_ctx, e);
+            }
+
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 4e4c9fba6cc57..60d05ae46b916 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -66,7 +66,7 @@ pub(crate) fn complete_item_list(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
     }
 }
 
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 17dfe432b3529..af8a0853313b4 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -180,6 +180,6 @@ pub(crate) fn complete_pattern_path(
 
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 87a998dfcce6b..8f9db2f94c204 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -49,11 +49,27 @@ pub(crate) fn complete_type_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index bb2ecc9fdde76..2555c34aa7477 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -115,6 +115,6 @@ pub(crate) fn complete_use_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { resolution: None, .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
     }
 }
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index ca8303906a800..5e6cf4bf9a521 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -29,7 +29,7 @@ pub(crate) fn complete_vis_path(
 
             acc.add_super_keyword(ctx, *super_chain_len);
         }
-        Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 93b6ad5d145df..e35f79d2b6951 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -193,7 +193,10 @@ pub(super) enum Qualified {
         super_chain_len: Option<usize>,
     },
     /// <_>::
-    Infer,
+    TypeAnchor {
+        ty: Option<hir::Type>,
+        trait_: Option<hir::Trait>,
+    },
     /// Whether the path is an absolute path
     Absolute,
 }
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 09a1a99eb64ca..3e7e637dd9ed5 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -920,49 +920,53 @@ impl<'a> CompletionContext<'a> {
         path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
         // calculate the qualifier context
-        if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
+        if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
             path_ctx.use_tree_parent = use_tree_parent;
             if !use_tree_parent && segment.coloncolon_token().is_some() {
                 path_ctx.qualified = Qualified::Absolute;
             } else {
-                let path = path
+                let qualifier = qualifier
                     .segment()
                     .and_then(|it| find_node_in_file(original_file, &it))
                     .map(|it| it.parent_path());
-                if let Some(path) = path {
-                    // `<_>::$0`
-                    let is_infer_qualifier = path.qualifier().is_none()
-                        && matches!(
-                            path.segment().and_then(|it| it.kind()),
-                            Some(ast::PathSegmentKind::Type {
-                                type_ref: Some(ast::Type::InferType(_)),
-                                trait_ref: None,
-                            })
-                        );
+                if let Some(qualifier) = qualifier {
+                    let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
+                        Some(ast::PathSegmentKind::Type {
+                            type_ref: Some(type_ref),
+                            trait_ref,
+                        }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
+                        _ => None,
+                    };
 
-                    path_ctx.qualified = if is_infer_qualifier {
-                        Qualified::Infer
+                    path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
+                        let ty = match ty {
+                            ast::Type::InferType(_) => None,
+                            ty => sema.resolve_type(&ty),
+                        };
+                        let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
+                        Qualified::TypeAnchor { ty, trait_ }
                     } else {
-                        let res = sema.resolve_path(&path);
+                        let res = sema.resolve_path(&qualifier);
 
                         // For understanding how and why super_chain_len is calculated the way it
                         // is check the documentation at it's definition
                         let mut segment_count = 0;
-                        let super_count = iter::successors(Some(path.clone()), |p| p.qualifier())
-                            .take_while(|p| {
-                                p.segment()
-                                    .and_then(|s| {
-                                        segment_count += 1;
-                                        s.super_token()
-                                    })
-                                    .is_some()
-                            })
-                            .count();
+                        let super_count =
+                            iter::successors(Some(qualifier.clone()), |p| p.qualifier())
+                                .take_while(|p| {
+                                    p.segment()
+                                        .and_then(|s| {
+                                            segment_count += 1;
+                                            s.super_token()
+                                        })
+                                        .is_some()
+                                })
+                                .count();
 
                         let super_chain_len =
                             if segment_count > super_count { None } else { Some(super_count) };
 
-                        Qualified::With { path, resolution: res, super_chain_len }
+                        Qualified::With { path: qualifier, resolution: res, super_chain_len }
                     }
                 };
             }
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index ca779c2fc713e..033dc99c26cf0 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -674,7 +674,60 @@ fn bar() -> Bar {
         expect![[r#"
                 fn foo() (as Foo) fn() -> Self
             "#]],
-    )
+    );
+}
+
+#[test]
+fn type_anchor_type() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar>::$0
+}
+"#,
+        expect![[r#"
+            fn bar()          fn()
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
+}
+
+#[test]
+fn type_anchor_type_trait() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar as Foo>::$0
+}
+"#,
+        expect![[r#"
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
 }
 
 #[test]

From 7c59d7c75c1aed160bf1aa67047ba6063ae21ba0 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Thu, 28 Jul 2022 15:47:46 +0200
Subject: [PATCH 11/28] fix: Fix pattern completions adding unnecessary braces

---
 crates/ide-completion/src/completions.rs      | 13 +++++++++--
 .../ide-completion/src/completions/pattern.rs |  2 +-
 crates/ide-completion/src/render/pattern.rs   | 23 +++++++++++++++----
 crates/ide-completion/src/tests/pattern.rs    |  4 ++--
 4 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 149afcac9d478..72579e6026aee 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -400,7 +400,7 @@ impl Completions {
     ) {
         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
             cov_mark::hit!(enum_variant_pattern_path);
-            self.add_variant_pat(ctx, pat_ctx, variant, local_name);
+            self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
             return;
         }
 
@@ -484,12 +484,14 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext<'_>,
         pattern_ctx: &PatternContext,
+        path_ctx: Option<&PathCompletionCtx>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
         self.add_opt(render_variant_pat(
             RenderContext::new(ctx),
             pattern_ctx,
+            path_ctx,
             variant,
             local_name.clone(),
             None,
@@ -504,7 +506,14 @@ impl Completions {
         path: hir::ModPath,
     ) {
         let path = Some(&path);
-        self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
+        self.add_opt(render_variant_pat(
+            RenderContext::new(ctx),
+            pattern_ctx,
+            None,
+            variant,
+            None,
+            path,
+        ));
     }
 
     pub(crate) fn add_struct_pat(
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index af8a0853313b4..71d2d9d434b44 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -74,7 +74,7 @@ pub(crate) fn complete_pattern(
                 hir::ModuleDef::Variant(variant)
                     if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
                 {
-                    acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
+                    acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
                     true
                 }
                 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs
index 03db08a911e92..34a384f2f7ae8 100644
--- a/crates/ide-completion/src/render/pattern.rs
+++ b/crates/ide-completion/src/render/pattern.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 use syntax::SmolStr;
 
 use crate::{
-    context::{ParamContext, ParamKind, PatternContext},
+    context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
     render::{
         variant::{format_literal_label, visible_fields},
         RenderContext,
@@ -42,6 +42,7 @@ pub(crate) fn render_struct_pat(
 pub(crate) fn render_variant_pat(
     ctx: RenderContext<'_>,
     pattern_ctx: &PatternContext,
+    path_ctx: Option<&PathCompletionCtx>,
     variant: hir::Variant,
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
@@ -58,9 +59,23 @@ pub(crate) fn render_variant_pat(
             (name.to_smol_str(), name.escaped().to_smol_str())
         }
     };
-    let kind = variant.kind(ctx.db());
-    let label = format_literal_label(name.as_str(), kind);
-    let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
+
+    let (label, pat) = match path_ctx {
+        Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
+        _ => {
+            let kind = variant.kind(ctx.db());
+            let label = format_literal_label(name.as_str(), kind);
+            let pat = render_pat(
+                &ctx,
+                pattern_ctx,
+                &escaped_name,
+                kind,
+                &visible_fields,
+                fields_omitted,
+            )?;
+            (label, pat)
+        }
+    };
 
     Some(build_completion(ctx, label, pat, variant))
 }
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index 877b5f2164331..30ddbe2dc6f60 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -443,7 +443,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn TupleVariant(…) TupleVariant($1)$0
+            bn TupleVariant TupleVariant
         "#]],
     );
     check_empty(
@@ -458,7 +458,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn RecordVariant {…} RecordVariant { field$1 }$0
+            bn RecordVariant RecordVariant
         "#]],
     );
 }

From 74abd44a265d6daded813ccb48ed599d835ea532 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Thu, 28 Jul 2022 17:09:31 +0200
Subject: [PATCH 12/28] fix: Do completions in path qualifier position

---
 crates/ide-completion/src/completions/expr.rs |  16 +-
 crates/ide-completion/src/context/analysis.rs | 187 ++++++++++--------
 2 files changed, 118 insertions(+), 85 deletions(-)

diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index d4f2766602fbf..bafaeb502ad75 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    &ExprCtx {
+    expr_ctx: &ExprCtx,
+) {
+    let _p = profile::span("complete_expr_path");
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+
+    let &ExprCtx {
         in_block_expr,
         in_loop_body,
         after_if_expr,
@@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path(
         ref impl_,
         in_match_guard,
         ..
-    }: &ExprCtx,
-) {
-    let _p = profile::span("complete_expr_path");
-    if !ctx.qualifier_ctx.none() {
-        return;
-    }
+    } = expr_ctx;
 
     let wants_mut_token =
         ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 3e7e637dd9ed5..76fc74c01d22c 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -592,7 +592,7 @@ impl<'a> CompletionContext<'a> {
             has_call_parens: false,
             has_macro_bang: false,
             qualified: Qualified::No,
-            parent: path.parent_path(),
+            parent: None,
             path: path.clone(),
             kind: PathKind::Item { kind: ItemListKind::SourceFile },
             has_type_args: false,
@@ -827,92 +827,123 @@ impl<'a> CompletionContext<'a> {
             PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
         };
 
+        let mut kind_macro_call = |it: ast::MacroCall| {
+            path_ctx.has_macro_bang = it.excl_token().is_some();
+            let parent = it.syntax().parent()?;
+            // Any path in an item list will be treated as a macro call by the parser
+            let kind = match_ast! {
+                match parent {
+                    ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
+                    ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
+                    ast::MacroType(ty) => make_path_kind_type(ty.into()),
+                    ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
+                    ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
+                        Some(it) => match_ast! {
+                            match it {
+                                ast::Trait(_) => ItemListKind::Trait,
+                                ast::Impl(it) => if it.trait_().is_some() {
+                                    ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
+                                } else {
+                                    ItemListKind::Impl
+                                },
+                                _ => return None
+                            }
+                        },
+                        None => return None,
+                    } },
+                    ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
+                    ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
+                    _ => return None,
+                }
+            };
+            Some(kind)
+        };
+        let make_path_kind_attr = |meta: ast::Meta| {
+            let attr = meta.parent_attr()?;
+            let kind = attr.kind();
+            let attached = attr.syntax().parent()?;
+            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 } })
+        };
+
         // Infer the path kind
         let parent = path.syntax().parent()?;
         let kind = match_ast! {
-                match parent {
-                    ast::PathType(it) => make_path_kind_type(it.into()),
-                    ast::PathExpr(it) => {
-                        if let Some(p) = it.syntax().parent() {
-                            if ast::ExprStmt::can_cast(p.kind()) {
-                                if let Some(kind) = inbetween_body_and_decl_check(p) {
-                                    return Some(make_res(NameRefKind::Keyword(kind)));
-                                }
+            match parent {
+                ast::PathType(it) => make_path_kind_type(it.into()),
+                ast::PathExpr(it) => {
+                    if let Some(p) = it.syntax().parent() {
+                        if ast::ExprStmt::can_cast(p.kind()) {
+                            if let Some(kind) = inbetween_body_and_decl_check(p) {
+                                return Some(make_res(NameRefKind::Keyword(kind)));
                             }
                         }
+                    }
 
-                        path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+                    path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
 
-                        make_path_kind_expr(it.into())
-                    },
-                    ast::TupleStructPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::RecordPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::PathPat(it) => {
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::MacroCall(it) => {
-                        // A macro call in this position is usually a result of parsing recovery, so check that
-                        if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
-                            return Some(make_res(NameRefKind::Keyword(kind)));
-                        }
+                    make_path_kind_expr(it.into())
+                },
+                ast::TupleStructPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::RecordPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::PathPat(it) => {
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                },
+                ast::MacroCall(it) => {
+                    // A macro call in this position is usually a result of parsing recovery, so check that
+                    if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+                        return Some(make_res(NameRefKind::Keyword(kind)));
+                    }
 
-                        path_ctx.has_macro_bang = it.excl_token().is_some();
-                        let parent = it.syntax().parent()?;
-                        // Any path in an item list will be treated as a macro call by the parser
-                        match_ast! {
-                            match parent {
-                                ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
-                                ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
-                                ast::MacroType(ty) => make_path_kind_type(ty.into()),
-                                ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
-                                ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
-                                    Some(it) => match_ast! {
-                                        match it {
-                                            ast::Trait(_) => ItemListKind::Trait,
-                                            ast::Impl(it) => if it.trait_().is_some() {
-                                                ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
-                                            } else {
-                                                ItemListKind::Impl
-                                            },
-                                            _ => return None
-                                        }
-                                    },
-                                    None => return None,
-                                } },
-                                ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
-                                ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
-                                _ => return None,
-                            }
-                        }
-                    },
-                    ast::Meta(meta) => {
-                        let attr = meta.parent_attr()?;
-                        let kind = attr.kind();
-                        let attached = attr.syntax().parent()?;
-                        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())
-                        };
-                        PathKind::Attr {
-                            attr_ctx: AttrCtx {
-                                kind,
-                                annotated_item_kind,
-                            }
+                    kind_macro_call(it)?
+                },
+                ast::Meta(meta) => make_path_kind_attr(meta)?,
+                ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                ast::UseTree(_) => PathKind::Use,
+                // completing inside a qualifier
+                ast::Path(parent) => {
+                    path_ctx.parent = Some(parent.clone());
+                    let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
+                    match_ast! {
+                        match parent {
+                            ast::PathType(it) => make_path_kind_type(it.into()),
+                            ast::PathExpr(it) => {
+                                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+                                make_path_kind_expr(it.into())
+                            },
+                            ast::TupleStructPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::RecordPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::PathPat(it) => {
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                            },
+                            ast::MacroCall(it) => {
+                                kind_macro_call(it)?
+                            },
+                            ast::Meta(meta) => make_path_kind_attr(meta)?,
+                            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                            ast::UseTree(_) => PathKind::Use,
+                            _ => return None,
                         }
-                    },
-                    ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                    ast::UseTree(_) => PathKind::Use,
-                    _ => return None,
-
+                    }
+                },
+                _ => return None,
             }
         };
 

From 8658425a672e5e56ac5e02db8423ca56c81c2c31 Mon Sep 17 00:00:00 2001
From: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
Date: Thu, 28 Jul 2022 16:21:14 +0100
Subject: [PATCH 13/28] publish: Use cargo ws rename to rename crates

---
 .github/workflows/publish.yml | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 927996c1bef21..a4497f49e3c2f 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -34,8 +34,21 @@ jobs:
           git config --global user.email "runner@gha.local"
           git config --global user.name "Github Action"
           rm Cargo.lock
+          # Fix names for crates that were published before switch to kebab-case.
+          cargo workspaces rename --from base-db base_db
+          cargo workspaces rename --from hir-def hir_def
+          cargo workspaces rename --from hir-expand hir_expand
+          cargo workspaces rename --from hir-ty hir_ty
+          cargo workspaces rename --from ide-assists ide_assists
+          cargo workspaces rename --from ide-completion ide_completion
+          cargo workspaces rename --from ide-db ide_db
+          cargo workspaces rename --from ide-diagnostics ide_diagnostics
+          cargo workspaces rename --from ide-ssr ide_ssr
+          cargo workspaces rename --from proc-macro-api proc_macro_api
+          cargo workspaces rename --from proc-macro-srv proc_macro_srv
+          cargo workspaces rename --from project-model project_model
+          cargo workspaces rename --from test-utils test_utils
+          cargo workspaces rename --from text-edit text_edit
           cargo workspaces rename ra_ap_%n
           find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
-          # Fix names for crates that were published before switch to kebab-case.
-          find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} +
           cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH

From ce7541260d6a5c76633b4c0e2e1639730018773d Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Thu, 28 Jul 2022 17:49:23 +0200
Subject: [PATCH 14/28] fix: Don't complete marker traits in expression
 position

---
 crates/ide-completion/src/completions/expr.rs | 17 ++++++++++++++---
 crates/ide-completion/src/render.rs           |  3 ---
 crates/ide-completion/src/tests/expression.rs |  2 --
 crates/ide-completion/src/tests/record.rs     |  1 -
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index bafaeb502ad75..5d0ddaaf2a228 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -202,10 +202,21 @@ pub(crate) fn complete_expr_path(
                     }
                 }
             }
-            ctx.process_all_names(&mut |name, def| {
-                if scope_def_applicable(def) {
-                    acc.add_path_resolution(ctx, path_ctx, name, def);
+            ctx.process_all_names(&mut |name, def| match def {
+                ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
+                    let assocs = t.items_with_supertraits(ctx.db);
+                    match &*assocs {
+                        // traits with no assoc items are unusable as expressions since
+                        // there is no associated item path that can be constructed with them
+                        [] => (),
+                        // FIXME: Render the assoc item with the trait qualified
+                        &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                        // FIXME: Append `::` to the thing here, since a trait on its own won't work
+                        [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                    }
                 }
+                _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
+                _ => (),
             });
 
             if is_func_update.is_none() {
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 9b25964a6086e..39cf957137937 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -1347,7 +1347,6 @@ fn main() {
                 fn main() []
                 fn foo(…) []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1394,7 +1393,6 @@ fn main() {
                 fn main() []
                 fn foo(…) []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1492,7 +1490,6 @@ fn main() {
                 fn &bar() [type]
                 fn foo(…) []
                 md core []
-                tt Sized []
             "#]],
         )
     }
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index ce9d01d337bae..ce7a543d9f300 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -44,7 +44,6 @@ fn baz() {
             st Record
             st Tuple
             st Unit
-            tt Trait
             un Union
             ev TupleV(…)     TupleV(u32)
             bt u32
@@ -137,7 +136,6 @@ impl Unit {
             st Record
             st Tuple
             st Unit
-            tt Trait
             tp TypeParam
             un Union
             ev TupleV(…)    TupleV(u32)
diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs
index ec32602fa3c2f..f6accc68e5e80 100644
--- a/crates/ide-completion/src/tests/record.rs
+++ b/crates/ide-completion/src/tests/record.rs
@@ -167,7 +167,6 @@ fn main() {
             st Foo
             st Foo {…}              Foo { foo1: u32, foo2: u32 }
             tt Default
-            tt Sized
             bt u32
             kw crate::
             kw self::

From f867ddc6217438ad514980fcbd5f59e2d99c3d55 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Thu, 28 Jul 2022 18:49:31 +0200
Subject: [PATCH 15/28] fix: Order ItemScope::entries results

---
 crates/hir-def/src/item_scope.rs              | 10 ++++-----
 .../src/handlers/expand_glob_import.rs        | 10 ++++-----
 crates/ide-assists/src/tests/generated.rs     |  2 +-
 crates/ide-completion/src/render.rs           | 22 +++++++++----------
 4 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 579f803ea193a..a11a92204c15c 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -5,6 +5,7 @@ use std::collections::hash_map::Entry;
 
 use base_db::CrateId;
 use hir_expand::{name::Name, AstId, MacroCallId};
+use itertools::Itertools;
 use once_cell::sync::Lazy;
 use profile::Count;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -97,15 +98,14 @@ pub(crate) enum BuiltinShadowMode {
 impl ItemScope {
     pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
         // FIXME: shadowing
-        let keys: FxHashSet<_> = self
-            .types
+        self.types
             .keys()
             .chain(self.values.keys())
             .chain(self.macros.keys())
             .chain(self.unresolved.iter())
-            .collect();
-
-        keys.into_iter().map(move |name| (name, self.get(name)))
+            .sorted()
+            .unique()
+            .map(move |name| (name, self.get(name)))
     }
 
     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
diff --git a/crates/ide-assists/src/handlers/expand_glob_import.rs b/crates/ide-assists/src/handlers/expand_glob_import.rs
index 943c1d90e6365..87f5018fb6958 100644
--- a/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -36,7 +36,7 @@ use crate::{
 //     pub struct Baz;
 // }
 //
-// use foo::{Baz, Bar};
+// use foo::{Bar, Baz};
 //
 // fn qux(bar: Bar, baz: Baz) {}
 // ```
@@ -281,7 +281,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -351,7 +351,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -440,7 +440,7 @@ mod foo {
     }
 }
 
-use foo::{bar::{Baz, Bar, f}, baz::*};
+use foo::{bar::{Bar, Baz, f}, baz::*};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -561,7 +561,7 @@ mod foo {
 
 use foo::{
     bar::{*, f},
-    baz::{g, qux::{q, h}}
+    baz::{g, qux::{h, q}}
 };
 
 fn qux(bar: Bar, baz: Baz) {
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index e8d48607be0e9..6eaab48a32ba5 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -535,7 +535,7 @@ mod foo {
     pub struct Baz;
 }
 
-use foo::{Baz, Bar};
+use foo::{Bar, Baz};
 
 fn qux(bar: Bar, baz: Baz) {}
 "#####,
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 39cf957137937..946134b0ff95d 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -1271,8 +1271,8 @@ fn main() {
                 st S []
                 st &mut S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1288,8 +1288,8 @@ fn main() {
                 lc s [type+name+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1305,8 +1305,8 @@ fn main() {
                 lc ssss [type+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
     }
@@ -1342,10 +1342,10 @@ fn main() {
                 lc &t [type+local]
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
             "#]],
         )
@@ -1388,10 +1388,10 @@ fn main() {
                 lc &mut t [type+local]
                 st S []
                 st &mut S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
             "#]],
         )
@@ -1483,12 +1483,12 @@ fn main() {
             expect![[r#"
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn bar() []
                 fn &bar() [type]
                 fn foo(…) []
+                fn main() []
                 md core []
             "#]],
         )
@@ -1633,8 +1633,8 @@ fn foo() {
                 ev Foo::B [type_could_unify]
                 fn foo() []
                 en Foo []
-                fn baz() []
                 fn bar() []
+                fn baz() []
             "#]],
         );
     }
@@ -1724,9 +1724,9 @@ fn f() {
 }
 "#,
             expect![[r#"
-                md std []
                 st Buffer []
                 fn f() []
+                md std []
                 tt BufRead (use std::io::BufRead) [requires_import]
                 st BufReader (use std::io::BufReader) [requires_import]
                 st BufWriter (use std::io::BufWriter) [requires_import]

From 948c9afc73786d5b4895fa4ea9041992601a59c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= <lnicola@dend.ro>
Date: Thu, 28 Jul 2022 21:02:36 +0300
Subject: [PATCH 16/28] Only run rainbow highlighting test on 64-bit Unix

---
 crates/ide/src/syntax_highlighting/tests.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 6ba6153178da9..d21bfc938514c 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -915,6 +915,10 @@ fn main() {
 }
 
 #[test]
+#[cfg_attr(
+    all(unix, not(target_pointer_width = "64")),
+    ignore = "depends on `DefaultHasher` outputs"
+)]
 fn test_rainbow_highlighting() {
     check_highlighting(
         r#"

From 11ef494b3764811b8ea5178d6c9bd67b287f104a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= <lnicola@dend.ro>
Date: Thu, 28 Jul 2022 21:45:47 +0300
Subject: [PATCH 17/28] Be more explicit when filtering built-in completions

---
 crates/ide-completion/src/tests.rs | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index 4be6acbe8461e..cf826648dcf7b 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -23,8 +23,6 @@ mod type_pos;
 mod use_tree;
 mod visibility;
 
-use std::mem;
-
 use hir::{db::DefDatabase, PrefixKind, Semantics};
 use ide_db::{
     base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
@@ -107,12 +105,9 @@ fn completion_list_with_config(
 ) -> String {
     // filter out all but one builtintype completion for smaller test outputs
     let items = get_all_items(config, ra_fixture, trigger_character);
-    let mut bt_seen = false;
     let items = items
         .into_iter()
-        .filter(|it| {
-            it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
-        })
+        .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
         .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))

From 902fd6ddcdd4e3ad03c7a9099f0b3b1d7e6a95e8 Mon Sep 17 00:00:00 2001
From: cynecx <me@cynecx.net>
Date: Fri, 29 Jul 2022 02:27:16 +0200
Subject: [PATCH 18/28] fix: complete path of existing record expr

---
 crates/ide-completion/src/context/analysis.rs |  2 ++
 crates/ide-completion/src/tests/expression.rs | 19 +++++++++++++++++++
 crates/parser/src/grammar/paths.rs            |  2 +-
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 76fc74c01d22c..22ec7cead4988 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -939,10 +939,12 @@ impl<'a> CompletionContext<'a> {
                             ast::Meta(meta) => make_path_kind_attr(meta)?,
                             ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
                             ast::UseTree(_) => PathKind::Use,
+                            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
                             _ => return None,
                         }
                     }
                 },
+                ast::RecordExpr(it) => make_path_kind_expr(it.into()),
                 _ => return None,
             }
         };
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index ce7a543d9f300..925081ebf6602 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -651,3 +651,22 @@ fn main() {
         "]],
     );
 }
+
+#[test]
+fn complete_record_expr_path() {
+    check(
+        r#"
+struct Zulu;
+impl Zulu {
+    fn test() -> Self { }
+}
+fn boi(val: Zulu) { }
+fn main() {
+    boi(Zulu:: $0 {});
+}
+"#,
+        expect![[r#"
+            fn test() fn() -> Zulu
+        "#]],
+    );
+}
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index f9efcef92a610..8de5d33a1936d 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -54,7 +54,7 @@ fn path_for_qualifier(
     mut qual: CompletedMarker,
 ) -> CompletedMarker {
     loop {
-        let use_tree = matches!(p.nth(2), T![*] | T!['{']);
+        let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
         if p.at(T![::]) && !use_tree {
             let path = qual.precede(p);
             p.bump(T![::]);

From 5b0ec1ebe4da106c18ce1ceec76e4adc627bddd1 Mon Sep 17 00:00:00 2001
From: Alex Gaynor <alex.gaynor@gmail.com>
Date: Fri, 29 Jul 2022 23:26:00 -0400
Subject: [PATCH 19/28] parallelize HTML checking tool

---
 Cargo.lock                        |  1 +
 src/tools/html-checker/Cargo.toml |  1 +
 src/tools/html-checker/main.rs    | 46 +++++++++++++++++--------------
 3 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 58c3982de2333..ccffbb01518dd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1788,6 +1788,7 @@ dependencies = [
 name = "html-checker"
 version = "0.1.0"
 dependencies = [
+ "rayon",
  "walkdir",
 ]
 
diff --git a/src/tools/html-checker/Cargo.toml b/src/tools/html-checker/Cargo.toml
index 34d3954db28dc..72d61d9bd2638 100644
--- a/src/tools/html-checker/Cargo.toml
+++ b/src/tools/html-checker/Cargo.toml
@@ -9,3 +9,4 @@ path = "main.rs"
 
 [dependencies]
 walkdir = "2"
+rayon = "1.5"
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index f52fbdfe2d7dc..9b4d2c5259806 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -1,3 +1,4 @@
+use rayon::iter::{ParallelBridge, ParallelIterator};
 use std::env;
 use std::path::Path;
 use std::process::{Command, Output};
@@ -56,27 +57,30 @@ const DOCS_TO_CHECK: &[&str] =
 
 // Returns the number of files read and the number of errors.
 fn find_all_html_files(dir: &Path) -> (usize, usize) {
-    let mut files_read = 0;
-    let mut errors = 0;
-
-    for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
-        e.depth() != 1
-            || e.file_name()
-                .to_str()
-                .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
-                .unwrap_or(false)
-    }) {
-        let entry = entry.expect("failed to read file");
-        if !entry.file_type().is_file() {
-            continue;
-        }
-        let entry = entry.path();
-        if entry.extension().and_then(|s| s.to_str()) == Some("html") {
-            errors += check_html_file(&entry);
-            files_read += 1;
-        }
-    }
-    (files_read, errors)
+    walkdir::WalkDir::new(dir)
+        .into_iter()
+        .filter_entry(|e| {
+            e.depth() != 1
+                || e.file_name()
+                    .to_str()
+                    .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
+                    .unwrap_or(false)
+        })
+        .par_bridge()
+        .map(|entry| {
+            let entry = entry.expect("failed to read file");
+            if !entry.file_type().is_file() {
+                return (0, 0);
+            }
+            let entry = entry.path();
+            // (Number of files processed, number of errors)
+            if entry.extension().and_then(|s| s.to_str()) == Some("html") {
+                (1, check_html_file(&entry))
+            } else {
+                (0, 0)
+            }
+        })
+        .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
 }
 
 /// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.

From 618cfd792ca2b3da5cd027bad20a7769f5d9f973 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Sat, 30 Jul 2022 09:43:30 +0200
Subject: [PATCH 20/28] fix: Fix ast-id up when merging raw attributes

---
 crates/hir-def/src/attr.rs                    | 21 ++++++--
 crates/ide/src/syntax_highlighting.rs         |  4 +-
 crates/ide/src/syntax_highlighting/inject.rs  |  9 ++--
 .../highlight_module_docs_inline.html         | 51 +++++++++++++++++++
 .../highlight_module_docs_outline.html        | 50 ++++++++++++++++++
 crates/ide/src/syntax_highlighting/tests.rs   | 42 +++++++++++++++
 6 files changed, 167 insertions(+), 10 deletions(-)
 create mode 100644 crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
 create mode 100644 crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html

diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index 8a6b6f3effd2e..2b39c6f8da86b 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -124,13 +124,24 @@ impl RawAttrs {
 
     pub(crate) fn merge(&self, other: Self) -> Self {
         // FIXME: This needs to fixup `AttrId`s
-        match (&self.entries, &other.entries) {
+        match (&self.entries, other.entries) {
             (None, None) => Self::EMPTY,
-            (Some(entries), None) | (None, Some(entries)) => {
-                Self { entries: Some(entries.clone()) }
-            }
+            (None, entries @ Some(_)) => Self { entries },
+            (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
+                let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
+                Self {
+                    entries: Some(
+                        a.iter()
+                            .cloned()
+                            .chain(b.iter().map(|it| {
+                                let mut it = it.clone();
+                                it.id.ast_index += last_ast_index;
+                                it
+                            }))
+                            .collect(),
+                    ),
+                }
             }
         }
     }
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index d013d6f4b19ff..3fb49b45d9888 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -13,7 +13,7 @@ mod html;
 #[cfg(test)]
 mod tests;
 
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
 use ide_db::{FxHashMap, RootDatabase};
 use syntax::{
     ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
@@ -325,7 +325,7 @@ fn traverse(
             Leave(NodeOrToken::Node(node)) => {
                 // Doc comment highlighting injection, we do this when leaving the node
                 // so that we overwrite the highlighting of the doc comment itself.
-                inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
+                inject::doc_comment(hl, sema, file_id, &node);
                 continue;
             }
         };
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index f779a985a99ae..f376f9fda7a57 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -5,7 +5,8 @@ use std::mem;
 use either::Either;
 use hir::{InFile, Semantics};
 use ide_db::{
-    active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
+    active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
+    SymbolKind,
 };
 use syntax::{
     ast::{self, AstNode, IsString, QuoteOffsets},
@@ -81,16 +82,18 @@ pub(super) fn ra_fixture(
 const RUSTDOC_FENCE_LENGTH: usize = 3;
 const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
 
-/// Injection of syntax highlighting of doctests.
+/// Injection of syntax highlighting of doctests and intra doc links.
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
+    src_file_id: FileId,
+    node: &SyntaxNode,
 ) {
     let (attributes, def) = match doc_attributes(sema, node) {
         Some(it) => it,
         None => return,
     };
+    let src_file_id = src_file_id.into();
 
     // Extract intra-doc links and emit highlights for them.
     if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
new file mode 100644
index 0000000000000..8a1d69816e688
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -0,0 +1,51 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+
+<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
new file mode 100644
index 0000000000000..c4c3e3dc2606e
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -0,0 +1,50 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="keyword">mod</span> <span class="module declaration">foo</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index d21bfc938514c..99be7c6648687 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -914,6 +914,48 @@ fn main() {
     );
 }
 
+#[test]
+fn test_mod_hl_injection() {
+    check_highlighting(
+        r##"
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+"##,
+        expect_file!["./test_data/highlight_module_docs_inline.html"],
+        false,
+    );
+    check_highlighting(
+        r##"
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+"##,
+        expect_file!["./test_data/highlight_module_docs_outline.html"],
+        false,
+    );
+}
+
 #[test]
 #[cfg_attr(
     all(unix, not(target_pointer_width = "64")),

From 58c3a5634fec30705be19f21971e016c730f305c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= <lnicola@dend.ro>
Date: Sun, 31 Jul 2022 20:26:35 +0300
Subject: [PATCH 21/28] Update xtask promote and release instructions

---
 docs/dev/README.md   |  7 ++++---
 xtask/src/release.rs | 10 ++--------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/docs/dev/README.md b/docs/dev/README.md
index 468f2b9e981fe..76bbd1e91889e 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -210,7 +210,8 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release`
 ./rust-rust-analyzer  # Note the name!
 ```
 
-Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork).
+The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork).
+In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub.
 
 `release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog.
 This step uses the `curl` and `jq` applications, which need to be available in `PATH`.
@@ -225,13 +226,13 @@ Release steps:
    * push it to `upstream`. This triggers GitHub Actions which:
      * runs `cargo xtask dist` to package binaries and VS Code extension
      * makes a GitHub release
-     * pushes VS Code extension to the marketplace
+     * publishes the VS Code extension to the marketplace
    * call the GitHub API for PR details
    * create a new changelog in `rust-analyzer.github.io`
 3. While the release is in progress, fill in the changelog
 4. Commit & push the changelog
 5. Tweet
-6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule.
+6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
    Self-approve the PR.
 
 If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index 1c5fc64c2417e..17ada5156407e 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -77,18 +77,12 @@ impl flags::Promote {
         cmd!(sh, "git switch master").run()?;
         cmd!(sh, "git fetch upstream").run()?;
         cmd!(sh, "git reset --hard upstream/master").run()?;
-        cmd!(sh, "git submodule update --recursive").run()?;
 
         let date = date_iso(sh)?;
         let branch = format!("rust-analyzer-{date}");
         cmd!(sh, "git switch -c {branch}").run()?;
-        {
-            let _dir = sh.push_dir("src/tools/rust-analyzer");
-            cmd!(sh, "git fetch origin").run()?;
-            cmd!(sh, "git reset --hard origin/release").run()?;
-        }
-        cmd!(sh, "git add src/tools/rust-analyzer").run()?;
-        cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
+        cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?;
+
         if !self.dry_run {
             cmd!(sh, "git push -u origin {branch}").run()?;
             cmd!(

From d31f3605cea39530cb6b5b1c89934b174c886f49 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Sun, 31 Jul 2022 19:27:20 +0200
Subject: [PATCH 22/28] Properly cfg the `max` field of Limit

---
 crates/limit/src/lib.rs | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs
index 3c1da80edb98b..d6a706a7cd73a 100644
--- a/crates/limit/src/lib.rs
+++ b/crates/limit/src/lib.rs
@@ -2,12 +2,13 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 
+#[cfg(feature = "tracking")]
 use std::sync::atomic::AtomicUsize;
 
 /// Represents a struct used to enforce a numerical limit.
 pub struct Limit {
     upper_bound: usize,
-    #[allow(unused)]
+    #[cfg(feature = "tracking")]
     max: AtomicUsize,
 }
 
@@ -15,14 +16,22 @@ impl Limit {
     /// Creates a new limit.
     #[inline]
     pub const fn new(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(0) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(0),
+        }
     }
 
     /// Creates a new limit.
     #[inline]
     #[cfg(feature = "tracking")]
     pub const fn new_tracking(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(1) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(1),
+        }
     }
 
     /// Gets the underlying numeric limit.

From 3b2ecf44a0ee8437f8eb0e5b607312de6af7312a Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Sun, 31 Jul 2022 19:27:34 +0200
Subject: [PATCH 23/28] Give variables more descriptive names

---
 crates/hir-def/src/nameres/collector.rs | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index f394c541719f3..8a6bb929c3df7 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -1055,7 +1055,7 @@ impl DefCollector<'_> {
         };
         let mut res = ReachedFixedPoint::Yes;
         macros.retain(|directive| {
-            let resolver2 = |path| {
+            let resolver = |path| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
                     self.db,
                     ResolveMode::Other,
@@ -1068,7 +1068,7 @@ impl DefCollector<'_> {
                     .take_macros()
                     .map(|it| (it, macro_id_to_def_id(self.db, it)))
             };
-            let resolver = |path| resolver2(path).map(|(_, it)| it);
+            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 
             match &directive.kind {
                 MacroDirectiveKind::FnLike { ast_id, expand_to } => {
@@ -1077,7 +1077,7 @@ impl DefCollector<'_> {
                         ast_id,
                         *expand_to,
                         self.def_map.krate,
-                        &resolver,
+                        &resolver_def_id,
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
@@ -1093,7 +1093,7 @@ impl DefCollector<'_> {
                         *derive_attr,
                         *derive_pos as u32,
                         self.def_map.krate,
-                        &resolver2,
+                        &resolver,
                     );
 
                     if let Ok((macro_id, def_id, call_id)) = id {
@@ -1158,7 +1158,7 @@ impl DefCollector<'_> {
                         }
                     }
 
-                    let def = match resolver(path.clone()) {
+                    let def = match resolver_def_id(path.clone()) {
                         Some(def) if def.is_attribute() => def,
                         _ => return true,
                     };
@@ -1292,7 +1292,8 @@ impl DefCollector<'_> {
             true
         });
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
-        self.unresolved_macros.extend(macros);
+        macros.extend(mem::take(&mut self.unresolved_macros));
+        self.unresolved_macros = macros;
 
         for (module_id, depth, container, macro_call_id) in resolved {
             self.collect_macro_expansion(module_id, macro_call_id, depth, container);

From f2164c324cedfed8e655342b26b2831bdb39c5f2 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jnelson@cloudflare.com>
Date: Sun, 31 Jul 2022 20:18:15 -0500
Subject: [PATCH 24/28] Update all pre-cloned submodules on startup

Fixes https://github.com/rust-lang/rust/issues/99083
---
 src/bootstrap/lib.rs | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index cd421c249d8da..f84de73297acb 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -624,20 +624,6 @@ impl Build {
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
     pub fn maybe_update_submodules(&self) {
-        // WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
-        let mut bootstrap_submodules: Vec<&str> = vec![
-            "src/tools/rust-installer",
-            "src/tools/cargo",
-            "src/tools/rls",
-            "src/tools/miri",
-            "library/backtrace",
-            "library/stdarch",
-        ];
-        // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
-        // `config.toml`.
-        if self.config.vendor {
-            bootstrap_submodules.push("src/tools/rust-analyzer");
-        }
         // Avoid running git when there isn't a git checkout.
         if !self.config.submodules(&self.rust_info) {
             return;
@@ -653,10 +639,8 @@ impl Build {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
             let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
-            // avoid updating submodules twice
-            if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
-                && channel::GitInfo::new(false, submodule).is_git()
-            {
+            // Don't update the submodule unless it's already been cloned.
+            if channel::GitInfo::new(false, submodule).is_git() {
                 self.update_submodule(submodule);
             }
         }

From d0ea440dfe8659debd01246b5f2b8448abfb1e8b Mon Sep 17 00:00:00 2001
From: Preston From <prestonfrom@gmail.com>
Date: Fri, 29 Jul 2022 22:52:46 -0600
Subject: [PATCH 25/28] Improve position named arguments lint underline and
 formatting names

For named arguments used as implicit position arguments, underline both
the opening curly brace and either:
* if there is formatting, the next character (which will either be the
  closing curl brace or the `:` denoting the start of formatting args)
* if there is no formatting, the entire arg span (important if there is
  whitespace like `{  }`)

This should make it more obvious where the named argument should be.

Additionally, in the lint message, emit the formatting argument names
without a dollar sign to avoid potentially confusion.

Fixes #99907
---
 compiler/rustc_builtin_macros/src/format.rs |  86 +++++++---
 compiler/rustc_lint/src/context.rs          |  17 +-
 compiler/rustc_lint_defs/src/lib.rs         |  14 +-
 src/test/ui/macros/issue-98466.stderr       |  36 ++--
 src/test/ui/macros/issue-99265.stderr       | 172 ++++++++++----------
 src/test/ui/macros/issue-99907.fixed        |  24 +++
 src/test/ui/macros/issue-99907.rs           |  24 +++
 src/test/ui/macros/issue-99907.stderr       |  68 ++++++++
 8 files changed, 305 insertions(+), 136 deletions(-)
 create mode 100644 src/test/ui/macros/issue-99907.fixed
 create mode 100644 src/test/ui/macros/issue-99907.rs
 create mode 100644 src/test/ui/macros/issue-99907.stderr

diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 082c78934262b..e6d514e76d2e5 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -16,6 +16,7 @@ use smallvec::SmallVec;
 
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_parse_format::Count;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -57,26 +58,47 @@ struct PositionalNamedArg {
     replacement: Symbol,
     /// The span for the positional named argument (so the lint can point a message to it)
     positional_named_arg_span: Span,
+    has_formatting: bool,
 }
 
 impl PositionalNamedArg {
-    /// Determines what span to replace with the name of the named argument
-    fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
+    /// Determines:
+    /// 1) span to be replaced with the name of the named argument and
+    /// 2) span to be underlined for error messages
+    fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
         if let Some(inner_span) = &self.inner_span_to_replace {
-            return Some(
-                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
-            );
+            let span =
+                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
+            (Some(span), Some(span))
         } else if self.ty == PositionalNamedArgType::Arg {
-            // In the case of a named argument whose position is implicit, there will not be a span
-            // to replace. Instead, we insert the name after the `{`, which is the first character
-            // of arg_span.
-            return cx
-                .arg_spans
-                .get(self.cur_piece)
-                .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
+            // In the case of a named argument whose position is implicit, if the argument *has*
+            // formatting, there will not be a span to replace. Instead, we insert the name after
+            // the `{`, which will be the first character of arg_span. If the argument does *not*
+            // have formatting, there may or may not be a span to replace. This is because
+            // whitespace is allowed in arguments without formatting (such as `format!("{  }", 1);`)
+            // but is not allowed in arguments with formatting (an error will be generated in cases
+            // like `format!("{ :1.1}", 1.0f32);`.
+            // For the message span, if there is formatting, we want to use the opening `{` and the
+            // next character, which will the `:` indicating the start of formatting. If there is
+            // not any formatting, we want to underline the entire span.
+            if self.has_formatting {
+                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                    (
+                        Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
+                        Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
+                    )
+                })
+            } else {
+                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                    let replace_start = arg_span.lo() + BytePos(1);
+                    let replace_end = arg_span.hi() - BytePos(1);
+                    let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
+                    (Some(to_replace), Some(*arg_span))
+                })
+            }
+        } else {
+            (None, None)
         }
-
-        None
     }
 }
 
@@ -117,10 +139,18 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let start_of_named_args = total_args_length - names.len();
         if current_positional_arg >= start_of_named_args {
-            self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
+            self.maybe_push(
+                format_argument_index,
+                ty,
+                cur_piece,
+                inner_span_to_replace,
+                names,
+                has_formatting,
+            )
         }
     }
 
@@ -134,6 +164,7 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let named_arg = names
             .iter()
@@ -156,6 +187,7 @@ impl PositionalNamedArgsLint {
                 inner_span_to_replace,
                 replacement,
                 positional_named_arg_span,
+                has_formatting,
             });
         }
     }
@@ -414,6 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
                     PositionalNamedArgType::Precision,
                 );
 
+                let has_precision = arg.format.precision != Count::CountImplied;
+                let has_width = arg.format.width != Count::CountImplied;
+
                 // argument second, if it's an implicit positional parameter
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
@@ -426,6 +461,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             self.curpiece,
                             arg_end,
                             &self.names,
+                            has_precision || has_width,
                         );
 
                         Exact(i)
@@ -439,6 +475,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             self.curpiece,
                             None,
                             &self.names,
+                            has_precision || has_width,
                         );
                         Exact(i)
                     }
@@ -529,6 +566,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     self.curpiece,
                     *inner_span,
                     &self.names,
+                    true,
                 );
                 self.verify_arg_type(Exact(i), Count);
             }
@@ -1150,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
 
 fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
     for named_arg in &cx.unused_names_lint.positional_named_args {
-        let arg_span = named_arg.get_span_to_replace(cx);
+        let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
 
         let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
-        let replacement = match named_arg.ty {
-            PositionalNamedArgType::Arg => named_arg.replacement.to_string(),
-            _ => named_arg.replacement.to_string() + "$",
-        };
 
         cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
             span: MultiSpan::from_span(named_arg.positional_named_arg_span),
             msg: msg.clone(),
             node_id: ast::CRATE_NODE_ID,
             lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
-            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
-                arg_span,
-                named_arg.positional_named_arg_span,
-                replacement,
-            ),
+            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                position_sp_to_replace,
+                position_sp_for_msg,
+                named_arg_sp: named_arg.positional_named_arg_span,
+                named_arg_name: named_arg.replacement.to_string(),
+                is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
+            },
         });
     }
 }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 04ac50f1d4806..b95fc341db656 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -856,13 +856,18 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 },
-                BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
-                    db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
-                    if let Some(positional_arg) = positional_arg {
-                        let msg = format!("this formatting argument uses named argument `{}` by position", name);
-                        db.span_label(positional_arg, msg);
+                BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
+                    db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
+                    if let Some(positional_arg_for_msg) = position_sp_for_msg {
+                        let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
+                        db.span_label(positional_arg_for_msg, msg);
+                    }
+
+                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
+                        let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+
                         db.span_suggestion_verbose(
-                            positional_arg,
+                            positional_arg_to_replace,
                             "use the named argument by name to avoid ambiguity",
                             name,
                             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4fd57ed853379..6acbe97a7a118 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,7 +467,19 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally {
+        /// Span where the named argument is used by position and will be replaced with the named
+        /// argument name
+        position_sp_to_replace: Option<Span>,
+        /// Span where the named argument is used by position and is used for lint messages
+        position_sp_for_msg: Option<Span>,
+        /// Span where the named argument's name is (so we know where to put the warning message)
+        named_arg_sp: Span,
+        /// String containing the named arguments name
+        named_arg_name: String,
+        /// Indicates if the named argument is used as a width/precision for formatting
+        is_formatting_arg: bool,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr
index 4a39dd1440b1f..c93451c761ae4 100644
--- a/src/test/ui/macros/issue-98466.stderr
+++ b/src/test/ui/macros/issue-98466.stderr
@@ -2,9 +2,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:7:26
    |
 LL |     println!("_x is {}", _x = 5);
-   |                      -   ^^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `_x` by position
+   |                     --   ^^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `_x` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:10:26
    |
 LL |     println!("_x is {}", y = _x);
-   |                      -   ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `y` by position
+   |                     --   ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:13:83
    |
 LL |     println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                         -         ^ this named argument is only referred to by position in formatting string
-   |                                                                         |
-   |                                                                         this formatting argument uses named argument `y` by position
+   |                                                                        --         ^ this named argument is referred to by position in formatting string
+   |                                                                        |
+   |                                                                        this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:19:34
    |
 LL |     let _f = format!("_x is {}", _x = 5);
-   |                              -   ^^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `_x` by position
+   |                             --   ^^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `_x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:22:34
    |
 LL |     let _f = format!("_x is {}", y = _x);
-   |                              -   ^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `y` by position
+   |                             --   ^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:25:91
    |
 LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                                 -         ^ this named argument is only referred to by position in formatting string
-   |                                                                                 |
-   |                                                                                 this formatting argument uses named argument `y` by position
+   |                                                                                --         ^ this named argument is referred to by position in formatting string
+   |                                                                                |
+   |                                                                                this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr
index 0798ad8dc517c..2bfeedd7d0737 100644
--- a/src/test/ui/macros/issue-99265.stderr
+++ b/src/test/ui/macros/issue-99265.stderr
@@ -2,9 +2,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:5:24
    |
 LL |     println!("{b} {}", a=1, b=2);
-   |                    -   ^ this named argument is only referred to by position in formatting string
-   |                    |
-   |                    this formatting argument uses named argument `a` by position
+   |                   --   ^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `a` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:9:35
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                   -               ^ this named argument is only referred to by position in formatting string
-   |                   |
-   |                   this formatting argument uses named argument `a` by position
+   |                  --               ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:9:40
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                      -                 ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `b` by position
+   |                     --                 ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `b` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:9:45
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                         -                   ^ this named argument is only referred to by position in formatting string
-   |                         |
-   |                         this formatting argument uses named argument `c` by position
+   |                        --                   ^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `c` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `d` is not used by name
   --> $DIR/issue-99265.rs:9:50
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                            -                     ^ this named argument is only referred to by position in formatting string
-   |                            |
-   |                            this formatting argument uses named argument `d` by position
+   |                           --                     ^ this named argument is referred to by position in formatting string
+   |                           |
+   |                           this formatting argument uses named argument `d` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:19:35
    |
 LL |     println!("Hello {:1$}!", "x", width = 5);
-   |                       --          ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --          ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -81,9 +81,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:23:46
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                       --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -94,9 +94,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:23:57
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                          --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                          --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                          |
-   |                          this formatting argument uses named argument `precision$` by position
+   |                          this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -107,9 +107,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:23:33
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -          ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --          ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -120,9 +120,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:31:47
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                        --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
    |                        |
-   |                        this formatting argument uses named argument `width$` by position
+   |                        this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -133,9 +133,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:31:58
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                           --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                           --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                           |
-   |                           this formatting argument uses named argument `precision$` by position
+   |                           this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -146,7 +146,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:31:34
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -           ^ this named argument is only referred to by position in formatting string
+   |                      -           ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -159,10 +159,10 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:52:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                       -- this formatting argument uses named argument `width$` by position
+   |                       -- this formatting argument uses named argument `width` by position
 ...
 LL |         width = 5,
-   |         ^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -173,10 +173,10 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:54:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                          -- this formatting argument uses named argument `precision$` by position
+   |                          -- this formatting argument uses named argument `precision` by position
 ...
 LL |         precision = 2,
-   |         ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -190,7 +190,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                     - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -201,10 +201,10 @@ warning: named argument `width2` is not used by name
   --> $DIR/issue-99265.rs:58:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                 -- this formatting argument uses named argument `width2$` by position
+   |                                 -- this formatting argument uses named argument `width2` by position
 ...
 LL |         width2 = 5,
-   |         ^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -215,10 +215,10 @@ warning: named argument `precision2` is not used by name
   --> $DIR/issue-99265.rs:60:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                    -- this formatting argument uses named argument `precision2$` by position
+   |                                    -- this formatting argument uses named argument `precision2` by position
 ...
 LL |         precision2 = 2
-   |         ^^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -232,7 +232,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                               - this formatting argument uses named argument `g` by position
 ...
 LL |         g = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -246,7 +246,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                                          - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -257,9 +257,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:64:31
    |
 LL |     println!("Hello {:0.1}!", f = 0.02f32);
-   |                      -        ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -270,7 +270,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:68:32
    |
 LL |     println!("Hello {0:0.1}!", f = 0.02f32);
-   |                      -         ^ this named argument is only referred to by position in formatting string
+   |                      -         ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -283,9 +283,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                 --    ^ this named argument is only referred to by position in formatting string
+   |                 --    ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -296,9 +296,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                -      ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --      ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -309,9 +309,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                  --    ^ this named argument is only referred to by position in formatting string
+   |                  --    ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -322,7 +322,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                -       ^ this named argument is only referred to by position in formatting string
+   |                -       ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -335,9 +335,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                 --       ^ this named argument is only referred to by position in formatting string
+   |                 --       ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -348,9 +348,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                    --    ^ this named argument is only referred to by position in formatting string
+   |                    --    ^ this named argument is referred to by position in formatting string
    |                    |
-   |                    this formatting argument uses named argument `v$` by position
+   |                    this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -361,9 +361,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                -         ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --         ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -374,9 +374,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                  --       ^ this named argument is only referred to by position in formatting string
+   |                  --       ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -387,9 +387,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                     --    ^ this named argument is only referred to by position in formatting string
+   |                     --    ^ this named argument is referred to by position in formatting string
    |                     |
-   |                     this formatting argument uses named argument `v$` by position
+   |                     this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -400,7 +400,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                -          ^ this named argument is only referred to by position in formatting string
+   |                -          ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -413,9 +413,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                -           ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `a` by position
+   |               --           ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -426,7 +426,7 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                       -    ^ this named argument is only referred to by position in formatting string
+   |                       -    ^ this named argument is referred to by position in formatting string
    |                       |
    |                       this formatting argument uses named argument `a` by position
    |
@@ -439,10 +439,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:115:23
    |
 LL |                 {:1$.2$}",
-   |                   -- this formatting argument uses named argument `b$` by position
+   |                   -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -453,10 +453,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:115:30
    |
 LL |                 {:1$.2$}",
-   |                      -- this formatting argument uses named argument `c$` by position
+   |                      -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -467,10 +467,10 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:115:14
    |
 LL |                 {:1$.2$}",
-   |                  - this formatting argument uses named argument `a` by position
+   |                 -- this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -481,10 +481,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:126:23
    |
 LL |                 {0:1$.2$}",
-   |                    -- this formatting argument uses named argument `b$` by position
+   |                    -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -495,10 +495,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:126:30
    |
 LL |                 {0:1$.2$}",
-   |                       -- this formatting argument uses named argument `c$` by position
+   |                       -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -512,7 +512,7 @@ LL |                 {0:1$.2$}",
    |                  - this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -523,9 +523,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:132:39
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                   --                  ^^^^^ this named argument is only referred to by position in formatting string
+   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
    |                   |
-   |                   this formatting argument uses named argument `width$` by position
+   |                   this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -536,9 +536,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:132:50
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                      --                          ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                      --                          ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                      |
-   |                      this formatting argument uses named argument `precision$` by position
+   |                      this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -549,9 +549,9 @@ warning: named argument `x` is not used by name
   --> $DIR/issue-99265.rs:132:30
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                  -           ^ this named argument is only referred to by position in formatting string
-   |                  |
-   |                  this formatting argument uses named argument `x` by position
+   |                 --           ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
diff --git a/src/test/ui/macros/issue-99907.fixed b/src/test/ui/macros/issue-99907.fixed
new file mode 100644
index 0000000000000..9e0e1b80ee59f
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.fixed
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {f:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.rs b/src/test/ui/macros/issue-99907.rs
new file mode 100644
index 0000000000000..eebcfc2efecc9
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.rs
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello { }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {  }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr
new file mode 100644
index 0000000000000..4786ce003b4c2
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.stderr
@@ -0,0 +1,68 @@
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:5:30
+   |
+LL |     println!("Hello {:.1}!", f = 0.02f32);
+   |                     --       ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:9:31
+   |
+LL |     println!("Hello {:1.1}!", f = 0.02f32);
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:13:27
+   |
+LL |     println!("Hello {}!", f = 0.02f32);
+   |                     --    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:17:28
+   |
+LL |     println!("Hello { }!", f = 0.02f32);
+   |                     ---    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:21:29
+   |
+LL |     println!("Hello {  }!", f = 0.02f32);
+   |                     ----    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: 5 warnings emitted
+

From 298acef30730ee676fdbc9e731370cd7ccedd431 Mon Sep 17 00:00:00 2001
From: Preston From <prestonfrom@gmail.com>
Date: Tue, 2 Aug 2022 00:20:12 -0600
Subject: [PATCH 26/28] Move if-block into closure to reduce duplicate code

---
 compiler/rustc_builtin_macros/src/format.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index e6d514e76d2e5..4f3cda16f037d 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -81,21 +81,19 @@ impl PositionalNamedArg {
             // For the message span, if there is formatting, we want to use the opening `{` and the
             // next character, which will the `:` indicating the start of formatting. If there is
             // not any formatting, we want to underline the entire span.
-            if self.has_formatting {
-                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+            cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                if self.has_formatting {
                     (
                         Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
                         Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
                     )
-                })
-            } else {
-                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                } else {
                     let replace_start = arg_span.lo() + BytePos(1);
                     let replace_end = arg_span.hi() - BytePos(1);
                     let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
                     (Some(to_replace), Some(*arg_span))
-                })
-            }
+                }
+            })
         } else {
             (None, None)
         }

From 63e04eeb6d9a92084d283c57709dc1cc5031995e Mon Sep 17 00:00:00 2001
From: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
Date: Tue, 2 Aug 2022 12:50:06 -0500
Subject: [PATCH 27/28] Clarify Cargo.toml comments

Existing comments were left in an incoherent state after #99768.
---
 src/tools/rustc-workspace-hack/Cargo.toml | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index 00281bf8f014a..b1d8b86496ad0 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -79,11 +79,10 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] }
 libc = { version = "0.2.79", features = ["align"] }
 # Ensure default features of libz-sys, which are disabled in some scenarios.
 libz-sys = { version = "1.1.2" }
-
-# looks like the only user of deprecated `use_std` feature is `combine`, so this
-# can be removed if/when https://github.com/Marwes/combine/pull/348 be merged and released.
+# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
+# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
 memchr = { version = "2.5", features = ["std", "use_std"] }
-# same for regex
+# Ensure default features of regex, which are disabled in some scenarios.
 regex = { version = "1.5.6" }
 proc-macro2 = { version = "1", features = ["default"] }
 quote = { version = "1", features = ["default"] }

From 2bbdc4158e57c7839f381bff32ff294106e8e66b Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 2 Aug 2022 22:29:29 +0300
Subject: [PATCH 28/28] rustc-docs: Be less specific about the representation
 of `+bundle`

---
 src/doc/rustc/src/command-line-arguments.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index bc04dfd4433f6..f05ff3f1b6b4e 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -89,9 +89,9 @@ but it is not guaranteed. If you need whole archive semantics use `+whole-archiv
 This modifier is only compatible with the `static` linking kind.
 Using any other kind will result in a compiler error.
 
-When building a rlib or staticlib `+bundle` means that all object files from the native static
-library will be added to the rlib or staticlib archive, and then used from it during linking of
-the final binary.
+When building a rlib or staticlib `+bundle` means that the native static library
+will be packed into the rlib or staticlib archive, and then retrieved from there
+during linking of the final binary.
 
 When building a rlib `-bundle` means that the native static library is registered as a dependency
 of that rlib "by name", and object files from it are included only during linking of the final