Repository: rust-lang/rust-analyzer
Pull request #13025 (2022-08-15 14:17:10)

Simplify

Veykril: @bors r+
bors: :pushpin: Commit 65d86eab2eabb4fdb47b8a872875f1d829bc078a has been approved by `Veykril`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust-analyzer) for this repository.

<!-- @bors r=Veykril 65d86eab2eabb4fdb47b8a872875f1d829bc078a -->
<!-- homu: {"type":"Approved","sha":"65d86eab2eabb4fdb47b8a872875f1d829bc078a","approver":"Veykril","queue":"https://bors.rust-lang.org/homu/queue/rust-analyzer"} -->
bors: :hourglass: Testing commit 65d86eab2eabb4fdb47b8a872875f1d829bc078a with merge 59152c4e19c0d076762a1fa86c0d02a09499a1ee...
<!-- homu: {"type":"BuildStarted","head_sha":"65d86eab2eabb4fdb47b8a872875f1d829bc078a","merge_sha":"59152c4e19c0d076762a1fa86c0d02a09499a1ee"} -->
bors: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang/rust-analyzer/runs/7839708023?check_suite_focus=true)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang/rust-analyzer/runs/7839708023?check_suite_focus=true","builder_name":"checks-actions"} -->

Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 3c36c4fb84..d5d8df2345 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -253,9 +253,9 @@ jobs:
       - name: Publish Extension (Code Marketplace, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release
 
       - name: Publish Extension (OpenVSX, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 1e21214ffc..021b8f048c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -78,7 +78,7 @@
       "request": "launch",
       "runtimeExecutable": "${execPath}",
       "args": [
-        "--disable-extension", "rust-lang.rust-analyzer",
+        "--disable-extension", "matklad.rust-analyzer",
         "--extensionDevelopmentPath=${workspaceFolder}/editors/code"
       ],
       "outFiles": [
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index 1d818d9626..080a307b1f 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -4,7 +4,6 @@ mod lower;
 #[cfg(test)]
 mod tests;
 pub mod scope;
-mod pretty;
 
 use std::{ops::Index, sync::Arc};
 
@@ -353,10 +352,6 @@ impl Body {
         }
     }
 
-    pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String {
-        pretty::print_body_hir(db, self, owner)
-    }
-
     fn new(
         db: &dyn DefDatabase,
         expander: Expander,
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
deleted file mode 100644
index ddd476efe5..0000000000
--- a/crates/hir-def/src/body/pretty.rs
+++ /dev/null
@@ -1,621 +0,0 @@
-//! A pretty-printer for HIR.
-
-use std::fmt::{self, Write};
-
-use crate::{
-    expr::{Array, BindingAnnotation, Literal, Statement},
-    pretty::{print_generic_args, print_path, print_type_ref},
-    type_ref::TypeRef,
-};
-
-use super::*;
-
-pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
-    let needs_semi;
-    let header = match owner {
-        DefWithBodyId::FunctionId(it) => {
-            needs_semi = false;
-            let item_tree_id = it.lookup(db).id;
-            format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
-        }
-        DefWithBodyId::StaticId(it) => {
-            needs_semi = true;
-            let item_tree_id = it.lookup(db).id;
-            format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
-        }
-        DefWithBodyId::ConstId(it) => {
-            needs_semi = true;
-            let item_tree_id = it.lookup(db).id;
-            let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
-                Some(name) => name.to_string(),
-                None => "_".to_string(),
-            };
-            format!("const {} = ", name)
-        }
-    };
-
-    let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
-    p.print_expr(body.body_expr);
-    if needs_semi {
-        p.buf.push(';');
-    }
-    p.buf
-}
-
-macro_rules! w {
-    ($dst:expr, $($arg:tt)*) => {
-        { let _ = write!($dst, $($arg)*); }
-    };
-}
-
-macro_rules! wln {
-    ($dst:expr) => {
-        { let _ = writeln!($dst); }
-    };
-    ($dst:expr, $($arg:tt)*) => {
-        { let _ = writeln!($dst, $($arg)*); }
-    };
-}
-
-struct Printer<'a> {
-    body: &'a Body,
-    buf: String,
-    indent_level: usize,
-    needs_indent: bool,
-}
-
-impl<'a> Write for Printer<'a> {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        for line in s.split_inclusive('\n') {
-            if self.needs_indent {
-                match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
-                    Some('\n') | None => {}
-                    _ => self.buf.push('\n'),
-                }
-                self.buf.push_str(&"    ".repeat(self.indent_level));
-                self.needs_indent = false;
-            }
-
-            self.buf.push_str(line);
-            self.needs_indent = line.ends_with('\n');
-        }
-
-        Ok(())
-    }
-}
-
-impl<'a> Printer<'a> {
-    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
-        self.indent_level += 1;
-        wln!(self);
-        f(self);
-        self.indent_level -= 1;
-        self.buf = self.buf.trim_end_matches('\n').to_string();
-    }
-
-    fn whitespace(&mut self) {
-        match self.buf.chars().next_back() {
-            None | Some('\n' | ' ') => {}
-            _ => self.buf.push(' '),
-        }
-    }
-
-    fn newline(&mut self) {
-        match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
-            Some('\n') | None => {}
-            _ => writeln!(self).unwrap(),
-        }
-    }
-
-    fn print_expr(&mut self, expr: ExprId) {
-        let expr = &self.body[expr];
-
-        match expr {
-            Expr::Missing => w!(self, "�"),
-            Expr::Underscore => w!(self, "_"),
-            Expr::Path(path) => self.print_path(path),
-            Expr::If { condition, then_branch, else_branch } => {
-                w!(self, "if ");
-                self.print_expr(*condition);
-                w!(self, " ");
-                self.print_expr(*then_branch);
-                if let Some(els) = *else_branch {
-                    w!(self, " else ");
-                    self.print_expr(els);
-                }
-            }
-            Expr::Let { pat, expr } => {
-                w!(self, "let ");
-                self.print_pat(*pat);
-                w!(self, " = ");
-                self.print_expr(*expr);
-            }
-            Expr::Loop { body, label } => {
-                if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name);
-                }
-                w!(self, "loop ");
-                self.print_expr(*body);
-            }
-            Expr::While { condition, body, label } => {
-                if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name);
-                }
-                w!(self, "while ");
-                self.print_expr(*condition);
-                self.print_expr(*body);
-            }
-            Expr::For { iterable, pat, body, label } => {
-                if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name);
-                }
-                w!(self, "for ");
-                self.print_pat(*pat);
-                w!(self, " in ");
-                self.print_expr(*iterable);
-                self.print_expr(*body);
-            }
-            Expr::Call { callee, args, is_assignee_expr: _ } => {
-                self.print_expr(*callee);
-                w!(self, "(");
-                if !args.is_empty() {
-                    self.indented(|p| {
-                        for arg in &**args {
-                            p.print_expr(*arg);
-                            wln!(p, ",");
-                        }
-                    });
-                }
-                w!(self, ")");
-            }
-            Expr::MethodCall { receiver, method_name, args, generic_args } => {
-                self.print_expr(*receiver);
-                w!(self, ".{}", method_name);
-                if let Some(args) = generic_args {
-                    w!(self, "::<");
-                    print_generic_args(args, self).unwrap();
-                    w!(self, ">");
-                }
-                w!(self, "(");
-                if !args.is_empty() {
-                    self.indented(|p| {
-                        for arg in &**args {
-                            p.print_expr(*arg);
-                            wln!(p, ",");
-                        }
-                    });
-                }
-                w!(self, ")");
-            }
-            Expr::Match { expr, arms } => {
-                w!(self, "match ");
-                self.print_expr(*expr);
-                w!(self, " {{");
-                self.indented(|p| {
-                    for arm in &**arms {
-                        p.print_pat(arm.pat);
-                        if let Some(guard) = arm.guard {
-                            w!(p, " if ");
-                            p.print_expr(guard);
-                        }
-                        w!(p, " => ");
-                        p.print_expr(arm.expr);
-                        wln!(p, ",");
-                    }
-                });
-                wln!(self, "}}");
-            }
-            Expr::Continue { label } => {
-                w!(self, "continue");
-                if let Some(label) = label {
-                    w!(self, " {}", label);
-                }
-            }
-            Expr::Break { expr, label } => {
-                w!(self, "break");
-                if let Some(label) = label {
-                    w!(self, " {}", label);
-                }
-                if let Some(expr) = expr {
-                    self.whitespace();
-                    self.print_expr(*expr);
-                }
-            }
-            Expr::Return { expr } => {
-                w!(self, "return");
-                if let Some(expr) = expr {
-                    self.whitespace();
-                    self.print_expr(*expr);
-                }
-            }
-            Expr::Yield { expr } => {
-                w!(self, "yield");
-                if let Some(expr) = expr {
-                    self.whitespace();
-                    self.print_expr(*expr);
-                }
-            }
-            Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
-                match path {
-                    Some(path) => self.print_path(path),
-                    None => w!(self, "�"),
-                }
-
-                w!(self, "{{");
-                self.indented(|p| {
-                    for field in &**fields {
-                        w!(p, "{}: ", field.name);
-                        p.print_expr(field.expr);
-                        wln!(p, ",");
-                    }
-                    if let Some(spread) = spread {
-                        w!(p, "..");
-                        p.print_expr(*spread);
-                        wln!(p);
-                    }
-                    if *ellipsis {
-                        wln!(p, "..");
-                    }
-                });
-                w!(self, "}}");
-            }
-            Expr::Field { expr, name } => {
-                self.print_expr(*expr);
-                w!(self, ".{}", name);
-            }
-            Expr::Await { expr } => {
-                self.print_expr(*expr);
-                w!(self, ".await");
-            }
-            Expr::Try { expr } => {
-                self.print_expr(*expr);
-                w!(self, "?");
-            }
-            Expr::TryBlock { body } => {
-                w!(self, "try ");
-                self.print_expr(*body);
-            }
-            Expr::Async { body } => {
-                w!(self, "async ");
-                self.print_expr(*body);
-            }
-            Expr::Const { body } => {
-                w!(self, "const ");
-                self.print_expr(*body);
-            }
-            Expr::Cast { expr, type_ref } => {
-                self.print_expr(*expr);
-                w!(self, " as ");
-                self.print_type_ref(type_ref);
-            }
-            Expr::Ref { expr, rawness, mutability } => {
-                w!(self, "&");
-                if rawness.is_raw() {
-                    w!(self, "raw ");
-                }
-                if mutability.is_mut() {
-                    w!(self, "mut ");
-                }
-                self.print_expr(*expr);
-            }
-            Expr::Box { expr } => {
-                w!(self, "box ");
-                self.print_expr(*expr);
-            }
-            Expr::UnaryOp { expr, op } => {
-                let op = match op {
-                    ast::UnaryOp::Deref => "*",
-                    ast::UnaryOp::Not => "!",
-                    ast::UnaryOp::Neg => "-",
-                };
-                w!(self, "{}", op);
-                self.print_expr(*expr);
-            }
-            Expr::BinaryOp { lhs, rhs, op } => {
-                let (bra, ket) = match op {
-                    None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
-                    _ => ("(", ")"),
-                };
-                w!(self, "{}", bra);
-                self.print_expr(*lhs);
-                w!(self, "{} ", ket);
-                match op {
-                    Some(op) => w!(self, "{}", op),
-                    None => w!(self, "�"), // :)
-                }
-                w!(self, " {}", bra);
-                self.print_expr(*rhs);
-                w!(self, "{}", ket);
-            }
-            Expr::Range { lhs, rhs, range_type } => {
-                if let Some(lhs) = lhs {
-                    w!(self, "(");
-                    self.print_expr(*lhs);
-                    w!(self, ") ");
-                }
-                let range = match range_type {
-                    ast::RangeOp::Exclusive => "..",
-                    ast::RangeOp::Inclusive => "..=",
-                };
-                w!(self, "{}", range);
-                if let Some(rhs) = rhs {
-                    w!(self, "(");
-                    self.print_expr(*rhs);
-                    w!(self, ") ");
-                }
-            }
-            Expr::Index { base, index } => {
-                self.print_expr(*base);
-                w!(self, "[");
-                self.print_expr(*index);
-                w!(self, "]");
-            }
-            Expr::Closure { args, arg_types, ret_type, body } => {
-                w!(self, "|");
-                for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
-                    if i != 0 {
-                        w!(self, ", ");
-                    }
-                    self.print_pat(*pat);
-                    if let Some(ty) = ty {
-                        w!(self, ": ");
-                        self.print_type_ref(ty);
-                    }
-                }
-                w!(self, "|");
-                if let Some(ret_ty) = ret_type {
-                    w!(self, " -> ");
-                    self.print_type_ref(ret_ty);
-                }
-                self.whitespace();
-                self.print_expr(*body);
-            }
-            Expr::Tuple { exprs, is_assignee_expr: _ } => {
-                w!(self, "(");
-                for expr in exprs.iter() {
-                    self.print_expr(*expr);
-                    w!(self, ", ");
-                }
-                w!(self, ")");
-            }
-            Expr::Unsafe { body } => {
-                w!(self, "unsafe ");
-                self.print_expr(*body);
-            }
-            Expr::Array(arr) => {
-                w!(self, "[");
-                if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
-                    self.indented(|p| match arr {
-                        Array::ElementList { elements, is_assignee_expr: _ } => {
-                            for elem in elements.iter() {
-                                p.print_expr(*elem);
-                                w!(p, ", ");
-                            }
-                        }
-                        Array::Repeat { initializer, repeat } => {
-                            p.print_expr(*initializer);
-                            w!(p, "; ");
-                            p.print_expr(*repeat);
-                        }
-                    });
-                    self.newline();
-                }
-                w!(self, "]");
-            }
-            Expr::Literal(lit) => self.print_literal(lit),
-            Expr::Block { id: _, statements, tail, label } => {
-                self.whitespace();
-                if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name);
-                }
-                w!(self, "{{");
-                if !statements.is_empty() || tail.is_some() {
-                    self.indented(|p| {
-                        for stmt in &**statements {
-                            p.print_stmt(stmt);
-                        }
-                        if let Some(tail) = tail {
-                            p.print_expr(*tail);
-                        }
-                        p.newline();
-                    });
-                }
-                w!(self, "}}");
-            }
-            Expr::MacroStmts { statements, tail } => {
-                w!(self, "{{ // macro statements");
-                self.indented(|p| {
-                    for stmt in statements.iter() {
-                        p.print_stmt(stmt);
-                    }
-                    if let Some(tail) = tail {
-                        p.print_expr(*tail);
-                    }
-                });
-                self.newline();
-                w!(self, "}}");
-            }
-        }
-    }
-
-    fn print_pat(&mut self, pat: PatId) {
-        let pat = &self.body[pat];
-
-        match pat {
-            Pat::Missing => w!(self, "�"),
-            Pat::Wild => w!(self, "_"),
-            Pat::Tuple { args, ellipsis } => {
-                w!(self, "(");
-                for (i, pat) in args.iter().enumerate() {
-                    if i != 0 {
-                        w!(self, ", ");
-                    }
-                    if *ellipsis == Some(i) {
-                        w!(self, ".., ");
-                    }
-                    self.print_pat(*pat);
-                }
-                w!(self, ")");
-            }
-            Pat::Or(pats) => {
-                for (i, pat) in pats.iter().enumerate() {
-                    if i != 0 {
-                        w!(self, " | ");
-                    }
-                    self.print_pat(*pat);
-                }
-            }
-            Pat::Record { path, args, ellipsis } => {
-                match path {
-                    Some(path) => self.print_path(path),
-                    None => w!(self, "�"),
-                }
-
-                w!(self, " {{");
-                self.indented(|p| {
-                    for arg in args.iter() {
-                        w!(p, "{}: ", arg.name);
-                        p.print_pat(arg.pat);
-                        wln!(p, ",");
-                    }
-                    if *ellipsis {
-                        wln!(p, "..");
-                    }
-                });
-                w!(self, "}}");
-            }
-            Pat::Range { start, end } => {
-                self.print_expr(*start);
-                w!(self, "...");
-                self.print_expr(*end);
-            }
-            Pat::Slice { prefix, slice, suffix } => {
-                w!(self, "[");
-                for pat in prefix.iter() {
-                    self.print_pat(*pat);
-                    w!(self, ", ");
-                }
-                if let Some(pat) = slice {
-                    self.print_pat(*pat);
-                    w!(self, ", ");
-                }
-                for pat in suffix.iter() {
-                    self.print_pat(*pat);
-                    w!(self, ", ");
-                }
-                w!(self, "]");
-            }
-            Pat::Path(path) => self.print_path(path),
-            Pat::Lit(expr) => self.print_expr(*expr),
-            Pat::Bind { mode, name, subpat } => {
-                let mode = match mode {
-                    BindingAnnotation::Unannotated => "",
-                    BindingAnnotation::Mutable => "mut ",
-                    BindingAnnotation::Ref => "ref ",
-                    BindingAnnotation::RefMut => "ref mut ",
-                };
-                w!(self, "{}{}", mode, name);
-                if let Some(pat) = subpat {
-                    self.whitespace();
-                    self.print_pat(*pat);
-                }
-            }
-            Pat::TupleStruct { path, args, ellipsis } => {
-                match path {
-                    Some(path) => self.print_path(path),
-                    None => w!(self, "�"),
-                }
-                w!(self, "(");
-                for (i, arg) in args.iter().enumerate() {
-                    if i != 0 {
-                        w!(self, ", ");
-                    }
-                    if *ellipsis == Some(i) {
-                        w!(self, ", ..");
-                    }
-                    self.print_pat(*arg);
-                }
-                w!(self, ")");
-            }
-            Pat::Ref { pat, mutability } => {
-                w!(self, "&");
-                if mutability.is_mut() {
-                    w!(self, "mut ");
-                }
-                self.print_pat(*pat);
-            }
-            Pat::Box { inner } => {
-                w!(self, "box ");
-                self.print_pat(*inner);
-            }
-            Pat::ConstBlock(c) => {
-                w!(self, "const ");
-                self.print_expr(*c);
-            }
-        }
-    }
-
-    fn print_stmt(&mut self, stmt: &Statement) {
-        match stmt {
-            Statement::Let { pat, type_ref, initializer, else_branch } => {
-                w!(self, "let ");
-                self.print_pat(*pat);
-                if let Some(ty) = type_ref {
-                    w!(self, ": ");
-                    self.print_type_ref(ty);
-                }
-                if let Some(init) = initializer {
-                    w!(self, " = ");
-                    self.print_expr(*init);
-                }
-                if let Some(els) = else_branch {
-                    w!(self, " else ");
-                    self.print_expr(*els);
-                }
-                wln!(self, ";");
-            }
-            Statement::Expr { expr, has_semi } => {
-                self.print_expr(*expr);
-                if *has_semi {
-                    w!(self, ";");
-                }
-                wln!(self);
-            }
-        }
-    }
-
-    fn print_literal(&mut self, literal: &Literal) {
-        match literal {
-            Literal::String(it) => w!(self, "{:?}", it),
-            Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
-            Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
-            Literal::Bool(it) => w!(self, "{}", it),
-            Literal::Int(i, suffix) => {
-                w!(self, "{}", i);
-                if let Some(suffix) = suffix {
-                    w!(self, "{}", suffix);
-                }
-            }
-            Literal::Uint(i, suffix) => {
-                w!(self, "{}", i);
-                if let Some(suffix) = suffix {
-                    w!(self, "{}", suffix);
-                }
-            }
-            Literal::Float(f, suffix) => {
-                w!(self, "{}", f);
-                if let Some(suffix) = suffix {
-                    w!(self, "{}", suffix);
-                }
-            }
-        }
-    }
-
-    fn print_type_ref(&mut self, ty: &TypeRef) {
-        print_type_ref(ty, self).unwrap();
-    }
-
-    fn print_path(&mut self, path: &Path) {
-        print_path(path, self).unwrap();
-    }
-}
diff --git a/crates/hir-def/src/builtin_type.rs b/crates/hir-def/src/builtin_type.rs
index dd69c3ab47..25a408036f 100644
--- a/crates/hir-def/src/builtin_type.rs
+++ b/crates/hir-def/src/builtin_type.rs
@@ -156,38 +156,3 @@ impl BuiltinFloat {
         Some(res)
     }
 }
-
-impl fmt::Display for BuiltinInt {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            BuiltinInt::Isize => "isize",
-            BuiltinInt::I8 => "i8",
-            BuiltinInt::I16 => "i16",
-            BuiltinInt::I32 => "i32",
-            BuiltinInt::I64 => "i64",
-            BuiltinInt::I128 => "i128",
-        })
-    }
-}
-
-impl fmt::Display for BuiltinUint {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            BuiltinUint::Usize => "usize",
-            BuiltinUint::U8 => "u8",
-            BuiltinUint::U16 => "u16",
-            BuiltinUint::U32 => "u32",
-            BuiltinUint::U64 => "u64",
-            BuiltinUint::U128 => "u128",
-        })
-    }
-}
-
-impl fmt::Display for BuiltinFloat {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            BuiltinFloat::F32 => "f32",
-            BuiltinFloat::F64 => "f64",
-        })
-    }
-}
diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs
index 4381b43c25..c1b3788acb 100644
--- a/crates/hir-def/src/expr.rs
+++ b/crates/hir-def/src/expr.rs
@@ -12,8 +12,6 @@
 //!
 //! See also a neighboring `body` module.
 
-use std::fmt;
-
 use hir_expand::name::Name;
 use la_arena::{Idx, RawIdx};
 
@@ -54,8 +52,8 @@ impl FloatTypeWrapper {
     }
 }
 
-impl fmt::Display for FloatTypeWrapper {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl std::fmt::Display for FloatTypeWrapper {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}", f64::from_bits(self.0))
     }
 }
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index 34dd817fd1..f12d9a1273 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -2,10 +2,13 @@
 
 use std::fmt::{self, Write};
 
+use itertools::Itertools;
+
 use crate::{
     attr::RawAttrs,
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
-    pretty::{print_path, print_type_bounds, print_type_ref},
+    path::GenericArg,
+    type_ref::TraitBoundModifier,
     visibility::RawVisibility,
 };
 
@@ -461,15 +464,183 @@ impl<'a> Printer<'a> {
     }
 
     fn print_type_ref(&mut self, type_ref: &TypeRef) {
-        print_type_ref(type_ref, self).unwrap();
+        // FIXME: deduplicate with `HirDisplay` impl
+        match type_ref {
+            TypeRef::Never => w!(self, "!"),
+            TypeRef::Placeholder => w!(self, "_"),
+            TypeRef::Tuple(fields) => {
+                w!(self, "(");
+                for (i, field) in fields.iter().enumerate() {
+                    if i != 0 {
+                        w!(self, ", ");
+                    }
+                    self.print_type_ref(field);
+                }
+                w!(self, ")");
+            }
+            TypeRef::Path(path) => self.print_path(path),
+            TypeRef::RawPtr(pointee, mtbl) => {
+                let mtbl = match mtbl {
+                    Mutability::Shared => "*const",
+                    Mutability::Mut => "*mut",
+                };
+                w!(self, "{} ", mtbl);
+                self.print_type_ref(pointee);
+            }
+            TypeRef::Reference(pointee, lt, mtbl) => {
+                let mtbl = match mtbl {
+                    Mutability::Shared => "",
+                    Mutability::Mut => "mut ",
+                };
+                w!(self, "&");
+                if let Some(lt) = lt {
+                    w!(self, "{} ", lt.name);
+                }
+                w!(self, "{}", mtbl);
+                self.print_type_ref(pointee);
+            }
+            TypeRef::Array(elem, len) => {
+                w!(self, "[");
+                self.print_type_ref(elem);
+                w!(self, "; {}]", len);
+            }
+            TypeRef::Slice(elem) => {
+                w!(self, "[");
+                self.print_type_ref(elem);
+                w!(self, "]");
+            }
+            TypeRef::Fn(args_and_ret, varargs) => {
+                let ((_, return_type), args) =
+                    args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
+                w!(self, "fn(");
+                for (i, (_, typeref)) in args.iter().enumerate() {
+                    if i != 0 {
+                        w!(self, ", ");
+                    }
+                    self.print_type_ref(typeref);
+                }
+                if *varargs {
+                    if !args.is_empty() {
+                        w!(self, ", ");
+                    }
+                    w!(self, "...");
+                }
+                w!(self, ") -> ");
+                self.print_type_ref(return_type);
+            }
+            TypeRef::Macro(_ast_id) => {
+                w!(self, "<macro>");
+            }
+            TypeRef::Error => w!(self, "{{unknown}}"),
+            TypeRef::ImplTrait(bounds) => {
+                w!(self, "impl ");
+                self.print_type_bounds(bounds);
+            }
+            TypeRef::DynTrait(bounds) => {
+                w!(self, "dyn ");
+                self.print_type_bounds(bounds);
+            }
+        }
     }
 
     fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
-        print_type_bounds(bounds, self).unwrap();
+        for (i, bound) in bounds.iter().enumerate() {
+            if i != 0 {
+                w!(self, " + ");
+            }
+
+            match bound.as_ref() {
+                TypeBound::Path(path, modifier) => {
+                    match modifier {
+                        TraitBoundModifier::None => (),
+                        TraitBoundModifier::Maybe => w!(self, "?"),
+                    }
+                    self.print_path(path)
+                }
+                TypeBound::ForLifetime(lifetimes, path) => {
+                    w!(self, "for<{}> ", lifetimes.iter().format(", "));
+                    self.print_path(path);
+                }
+                TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
+                TypeBound::Error => w!(self, "{{unknown}}"),
+            }
+        }
     }
 
     fn print_path(&mut self, path: &Path) {
-        print_path(path, self).unwrap();
+        match path.type_anchor() {
+            Some(anchor) => {
+                w!(self, "<");
+                self.print_type_ref(anchor);
+                w!(self, ">::");
+            }
+            None => match path.kind() {
+                PathKind::Plain => {}
+                PathKind::Super(0) => w!(self, "self::"),
+                PathKind::Super(n) => {
+                    for _ in 0..*n {
+                        w!(self, "super::");
+                    }
+                }
+                PathKind::Crate => w!(self, "crate::"),
+                PathKind::Abs => w!(self, "::"),
+                PathKind::DollarCrate(_) => w!(self, "$crate::"),
+            },
+        }
+
+        for (i, segment) in path.segments().iter().enumerate() {
+            if i != 0 {
+                w!(self, "::");
+            }
+
+            w!(self, "{}", segment.name);
+            if let Some(generics) = segment.args_and_bindings {
+                // NB: these are all in type position, so `::<` turbofish syntax is not necessary
+                w!(self, "<");
+                let mut first = true;
+                let args = if generics.has_self_type {
+                    let (self_ty, args) = generics.args.split_first().unwrap();
+                    w!(self, "Self=");
+                    self.print_generic_arg(self_ty);
+                    first = false;
+                    args
+                } else {
+                    &generics.args
+                };
+                for arg in args {
+                    if !first {
+                        w!(self, ", ");
+                    }
+                    first = false;
+                    self.print_generic_arg(arg);
+                }
+                for binding in &generics.bindings {
+                    if !first {
+                        w!(self, ", ");
+                    }
+                    first = false;
+                    w!(self, "{}", binding.name);
+                    if !binding.bounds.is_empty() {
+                        w!(self, ": ");
+                        self.print_type_bounds(&binding.bounds);
+                    }
+                    if let Some(ty) = &binding.type_ref {
+                        w!(self, " = ");
+                        self.print_type_ref(ty);
+                    }
+                }
+
+                w!(self, ">");
+            }
+        }
+    }
+
+    fn print_generic_arg(&mut self, arg: &GenericArg) {
+        match arg {
+            GenericArg::Type(ty) => self.print_type_ref(ty),
+            GenericArg::Const(c) => w!(self, "{}", c),
+            GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
+        }
     }
 
     fn print_generic_params(&mut self, params: &GenericParams) {
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 32ebfda4fd..56603f4b15 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -53,7 +53,6 @@ pub mod import_map;
 mod test_db;
 #[cfg(test)]
 mod macro_expansion_tests;
-mod pretty;
 
 use std::{
     hash::{Hash, Hasher},
diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs
deleted file mode 100644
index 6636c8a23c..0000000000
--- a/crates/hir-def/src/pretty.rs
+++ /dev/null
@@ -1,209 +0,0 @@
-//! Display and pretty printing routines.
-
-use std::fmt::{self, Write};
-
-use hir_expand::mod_path::PathKind;
-use itertools::Itertools;
-
-use crate::{
-    intern::Interned,
-    path::{GenericArg, GenericArgs, Path},
-    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
-};
-
-pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result {
-    match path.type_anchor() {
-        Some(anchor) => {
-            write!(buf, "<")?;
-            print_type_ref(anchor, buf)?;
-            write!(buf, ">::")?;
-        }
-        None => match path.kind() {
-            PathKind::Plain => {}
-            PathKind::Super(0) => write!(buf, "self")?,
-            PathKind::Super(n) => {
-                for i in 0..*n {
-                    if i == 0 {
-                        buf.write_str("super")?;
-                    } else {
-                        buf.write_str("::super")?;
-                    }
-                }
-            }
-            PathKind::Crate => write!(buf, "crate")?,
-            PathKind::Abs => {}
-            PathKind::DollarCrate(_) => write!(buf, "$crate")?,
-        },
-    }
-
-    for (i, segment) in path.segments().iter().enumerate() {
-        if i != 0 || !matches!(path.kind(), PathKind::Plain) {
-            write!(buf, "::")?;
-        }
-
-        write!(buf, "{}", segment.name)?;
-        if let Some(generics) = segment.args_and_bindings {
-            write!(buf, "::<")?;
-            print_generic_args(generics, buf)?;
-
-            write!(buf, ">")?;
-        }
-    }
-
-    Ok(())
-}
-
-pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result {
-    let mut first = true;
-    let args = if generics.has_self_type {
-        let (self_ty, args) = generics.args.split_first().unwrap();
-        write!(buf, "Self=")?;
-        print_generic_arg(self_ty, buf)?;
-        first = false;
-        args
-    } else {
-        &generics.args
-    };
-    for arg in args {
-        if !first {
-            write!(buf, ", ")?;
-        }
-        first = false;
-        print_generic_arg(arg, buf)?;
-    }
-    for binding in &generics.bindings {
-        if !first {
-            write!(buf, ", ")?;
-        }
-        first = false;
-        write!(buf, "{}", binding.name)?;
-        if !binding.bounds.is_empty() {
-            write!(buf, ": ")?;
-            print_type_bounds(&binding.bounds, buf)?;
-        }
-        if let Some(ty) = &binding.type_ref {
-            write!(buf, " = ")?;
-            print_type_ref(ty, buf)?;
-        }
-    }
-    Ok(())
-}
-
-pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result {
-    match arg {
-        GenericArg::Type(ty) => print_type_ref(ty, buf),
-        GenericArg::Const(c) => write!(buf, "{}", c),
-        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name),
-    }
-}
-
-pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result {
-    // FIXME: deduplicate with `HirDisplay` impl
-    match type_ref {
-        TypeRef::Never => write!(buf, "!")?,
-        TypeRef::Placeholder => write!(buf, "_")?,
-        TypeRef::Tuple(fields) => {
-            write!(buf, "(")?;
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(buf, ", ")?;
-                }
-                print_type_ref(field, buf)?;
-            }
-            write!(buf, ")")?;
-        }
-        TypeRef::Path(path) => print_path(path, buf)?,
-        TypeRef::RawPtr(pointee, mtbl) => {
-            let mtbl = match mtbl {
-                Mutability::Shared => "*const",
-                Mutability::Mut => "*mut",
-            };
-            write!(buf, "{} ", mtbl)?;
-            print_type_ref(pointee, buf)?;
-        }
-        TypeRef::Reference(pointee, lt, mtbl) => {
-            let mtbl = match mtbl {
-                Mutability::Shared => "",
-                Mutability::Mut => "mut ",
-            };
-            write!(buf, "&")?;
-            if let Some(lt) = lt {
-                write!(buf, "{} ", lt.name)?;
-            }
-            write!(buf, "{}", mtbl)?;
-            print_type_ref(pointee, buf)?;
-        }
-        TypeRef::Array(elem, len) => {
-            write!(buf, "[")?;
-            print_type_ref(elem, buf)?;
-            write!(buf, "; {}]", len)?;
-        }
-        TypeRef::Slice(elem) => {
-            write!(buf, "[")?;
-            print_type_ref(elem, buf)?;
-            write!(buf, "]")?;
-        }
-        TypeRef::Fn(args_and_ret, varargs) => {
-            let ((_, return_type), args) =
-                args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
-            write!(buf, "fn(")?;
-            for (i, (_, typeref)) in args.iter().enumerate() {
-                if i != 0 {
-                    write!(buf, ", ")?;
-                }
-                print_type_ref(typeref, buf)?;
-            }
-            if *varargs {
-                if !args.is_empty() {
-                    write!(buf, ", ")?;
-                }
-                write!(buf, "...")?;
-            }
-            write!(buf, ") -> ")?;
-            print_type_ref(return_type, buf)?;
-        }
-        TypeRef::Macro(_ast_id) => {
-            write!(buf, "<macro>")?;
-        }
-        TypeRef::Error => write!(buf, "{{unknown}}")?,
-        TypeRef::ImplTrait(bounds) => {
-            write!(buf, "impl ")?;
-            print_type_bounds(bounds, buf)?;
-        }
-        TypeRef::DynTrait(bounds) => {
-            write!(buf, "dyn ")?;
-            print_type_bounds(bounds, buf)?;
-        }
-    }
-
-    Ok(())
-}
-
-pub(crate) fn print_type_bounds(
-    bounds: &[Interned<TypeBound>],
-    buf: &mut dyn Write,
-) -> fmt::Result {
-    for (i, bound) in bounds.iter().enumerate() {
-        if i != 0 {
-            write!(buf, " + ")?;
-        }
-
-        match bound.as_ref() {
-            TypeBound::Path(path, modifier) => {
-                match modifier {
-                    TraitBoundModifier::None => (),
-                    TraitBoundModifier::Maybe => write!(buf, "?")?,
-                }
-                print_path(path, buf)?;
-            }
-            TypeBound::ForLifetime(lifetimes, path) => {
-                write!(buf, "for<{}> ", lifetimes.iter().format(", "))?;
-                print_path(path, buf)?;
-            }
-            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?,
-            TypeBound::Error => write!(buf, "{{unknown}}")?,
-        }
-    }
-
-    Ok(())
-}
diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/type_ref.rs
index 5b4c71be7f..9248059627 100644
--- a/crates/hir-def/src/type_ref.rs
+++ b/crates/hir-def/src/type_ref.rs
@@ -77,10 +77,6 @@ impl Rawness {
             Rawness::Ref
         }
     }
-
-    pub fn is_raw(&self) -> bool {
-        matches!(self, Self::RawPtr)
-    }
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs
index c1ddef03ba..11c0a6764e 100644
--- a/crates/hir-expand/src/ast_id_map.rs
+++ b/crates/hir-expand/src/ast_id_map.rs
@@ -15,7 +15,7 @@ use std::{
 use la_arena::{Arena, Idx};
 use profile::Count;
 use rustc_hash::FxHasher;
-use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
+use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
 
 /// `AstId` points to an AST node in a specific file.
 pub struct FileAstId<N: AstNode> {
@@ -92,18 +92,12 @@ impl AstIdMap {
         // change parent's id. This means that, say, adding a new function to a
         // trait does not change ids of top-level items, which helps caching.
         bdfs(node, |it| {
-            match_ast! {
-                match it {
-                    ast::Item(module_item) => {
-                        res.alloc(module_item.syntax());
-                        true
-                    },
-                    ast::BlockExpr(block) => {
-                        res.alloc(block.syntax());
-                        true
-                    },
-                    _ => false,
-                }
+            let kind = it.kind();
+            if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
+                res.alloc(&it);
+                true
+            } else {
+                false
             }
         });
         res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ());
@@ -123,6 +117,7 @@ impl AstIdMap {
         let raw = self.erased_ast_id(item.syntax());
         FileAstId { raw, _ty: PhantomData }
     }
+
     fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
         let ptr = SyntaxNodePtr::new(item);
         let hash = hash_ptr(&ptr);
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index bd60c3d268..bc97ee15c7 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -321,7 +321,11 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
                 ast::Item::cast(node.clone())?
                     .attrs()
                     .take(derive_attr_index as usize + 1)
-                    // FIXME
+                    // FIXME, this resolution should not be done syntactically
+                    // derive is a proper macro now, no longer builtin
+                    // But we do not have resolution at this stage, this means
+                    // we need to know about all macro calls for the given ast item here
+                    // so we require some kind of mapping...
                     .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
                     .map(|it| it.syntax().clone())
                     .collect()
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 252293090b..f6b97fd540 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -130,7 +130,6 @@ pub struct MacroDefId {
 pub enum MacroDefKind {
     Declarative(AstId<ast::Macro>),
     BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
-    // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
     BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
     BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
     BuiltInEager(EagerExpander, AstId<ast::Macro>),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3561bdeba7..8f984210e1 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -72,7 +72,7 @@ use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use once_cell::unsync::Lazy;
 use rustc_hash::FxHashSet;
-use stdx::{impl_from, never};
+use stdx::{format_to, impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasDocComments, HasName},
     AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
@@ -1136,20 +1136,6 @@ impl DefWithBody {
         }
     }
 
-    fn id(&self) -> DefWithBodyId {
-        match self {
-            DefWithBody::Function(it) => it.id.into(),
-            DefWithBody::Static(it) => it.id.into(),
-            DefWithBody::Const(it) => it.id.into(),
-        }
-    }
-
-    /// A textual representation of the HIR of this def's body for debugging purposes.
-    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
-        let body = db.body(self.id());
-        body.pretty_print(db.upcast(), self.id())
-    }
-
     pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
         let krate = self.module(db).id.krate();
 
@@ -1484,6 +1470,19 @@ impl Function {
         let def_map = db.crate_def_map(loc.krate(db).into());
         def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
     }
+
+    /// A textual representation of the HIR of this function for debugging purposes.
+    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
+        let body = db.body(self.id.into());
+
+        let mut result = String::new();
+        format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
+        for (id, expr) in body.exprs.iter() {
+            format_to!(result, "{:?}: {:?}\n", id, expr);
+        }
+
+        result
+    }
 }
 
 // Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 3ada181f1e..fa2c6f09ab 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -119,6 +119,8 @@ pub(crate) fn hover(
     }
 
     let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())));
+    // prefer descending the same token kind in attribute expansions, in normal macros text
+    // equivalency is more important
     let descended = if in_attr {
         [sema.descend_into_macros_with_kind_preference(original_token.clone())].into()
     } else {
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs
index d2bbbf6d26..bf0835ed7e 100644
--- a/crates/ide/src/view_hir.rs
+++ b/crates/ide/src/view_hir.rs
@@ -1,4 +1,4 @@
-use hir::{DefWithBody, Semantics};
+use hir::{Function, Semantics};
 use ide_db::base_db::FilePosition;
 use ide_db::RootDatabase;
 use syntax::{algo::find_node_at_offset, ast, AstNode};
@@ -19,12 +19,8 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
     let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
 
-    let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
-    let def: DefWithBody = match item {
-        ast::Item::Fn(it) => sema.to_def(&it)?.into(),
-        ast::Item::Const(it) => sema.to_def(&it)?.into(),
-        ast::Item::Static(it) => sema.to_def(&it)?.into(),
-        _ => return None,
-    };
-    Some(def.debug_hir(db))
+    let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?;
+
+    let function: Function = sema.to_def(&function)?;
+    Some(function.debug_hir(db))
 }
diff --git a/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
index 38e9c7dd7e..2f6d4706d8 100644
--- a/crates/rust-analyzer/src/bin/rustc_wrapper.rs
+++ b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
@@ -17,11 +17,6 @@ pub(crate) fn run_rustc_skipping_cargo_checking(
     rustc_executable: OsString,
     args: Vec<OsString>,
 ) -> io::Result<ExitCode> {
-    // `CARGO_CFG_TARGET_ARCH` is only set by cargo when executing build scripts
-    // We don't want to exit out checks unconditionally with success if a build
-    // script tries to invoke checks themselves
-    // See https://github.com/rust-lang/rust-analyzer/issues/12973 for context
-    let not_invoked_by_build_script = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_none();
     let is_cargo_check = args.iter().any(|arg| {
         let arg = arg.to_string_lossy();
         // `cargo check` invokes `rustc` with `--emit=metadata` argument.
@@ -34,7 +29,7 @@ pub(crate) fn run_rustc_skipping_cargo_checking(
         //            The default output filename is CRATE_NAME.rmeta.
         arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link")
     });
-    if not_invoked_by_build_script && is_cargo_check {
+    if is_cargo_check {
         return Ok(ExitCode(Some(0)));
     }
     run_rustc(rustc_executable, args)
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 943d043bc1..47daa732d5 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1320,7 +1320,8 @@ pub(crate) fn publish_diagnostics(
                 .unwrap(),
             }),
             source: Some("rust-analyzer".to_string()),
-            message: d.message,
+            // https://github.com/rust-lang/rust-analyzer/issues/11404
+            message: if !d.message.is_empty() { d.message } else { " ".to_string() },
             related_information: None,
             tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None },
             data: None,
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 7741999824..b504c24878 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -9,7 +9,6 @@ use std::{
 
 use always_assert::always;
 use crossbeam_channel::{select, Receiver};
-use flycheck::FlycheckHandle;
 use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
 use itertools::Itertools;
 use lsp_server::{Connection, Notification, Request};
@@ -206,14 +205,81 @@ impl GlobalState {
                 }
                 lsp_server::Message::Response(resp) => self.complete_request(resp),
             },
-            Event::Task(task) => {
+            Event::Task(mut task) => {
                 let _p = profile::span("GlobalState::handle_event/task");
                 let mut prime_caches_progress = Vec::new();
+                loop {
+                    match task {
+                        Task::Response(response) => self.respond(response),
+                        Task::Retry(req) => self.on_request(req),
+                        Task::Diagnostics(diagnostics_per_file) => {
+                            for (file_id, diagnostics) in diagnostics_per_file {
+                                self.diagnostics.set_native_diagnostics(file_id, diagnostics)
+                            }
+                        }
+                        Task::PrimeCaches(progress) => match progress {
+                            PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
+                            PrimeCachesProgress::Report(_) => {
+                                match prime_caches_progress.last_mut() {
+                                    Some(last @ PrimeCachesProgress::Report(_)) => {
+                                        // Coalesce subsequent update events.
+                                        *last = progress;
+                                    }
+                                    _ => prime_caches_progress.push(progress),
+                                }
+                            }
+                            PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
+                        },
+                        Task::FetchWorkspace(progress) => {
+                            let (state, msg) = match progress {
+                                ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
+                                ProjectWorkspaceProgress::Report(msg) => {
+                                    (Progress::Report, Some(msg))
+                                }
+                                ProjectWorkspaceProgress::End(workspaces) => {
+                                    self.fetch_workspaces_queue.op_completed(workspaces);
 
-                self.handle_task(&mut prime_caches_progress, task);
-                // Coalesce multiple task events into one loop turn
-                while let Ok(task) = self.task_pool.receiver.try_recv() {
-                    self.handle_task(&mut prime_caches_progress, task);
+                                    let old = Arc::clone(&self.workspaces);
+                                    self.switch_workspaces("fetched workspace".to_string());
+                                    let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
+
+                                    if self.config.run_build_scripts() && workspaces_updated {
+                                        self.fetch_build_data_queue
+                                            .request_op(format!("workspace updated"));
+                                    }
+
+                                    (Progress::End, None)
+                                }
+                            };
+
+                            self.report_progress("Fetching", state, msg, None);
+                        }
+                        Task::FetchBuildData(progress) => {
+                            let (state, msg) = match progress {
+                                BuildDataProgress::Begin => (Some(Progress::Begin), None),
+                                BuildDataProgress::Report(msg) => {
+                                    (Some(Progress::Report), Some(msg))
+                                }
+                                BuildDataProgress::End(build_data_result) => {
+                                    self.fetch_build_data_queue.op_completed(build_data_result);
+
+                                    self.switch_workspaces("fetched build data".to_string());
+
+                                    (Some(Progress::End), None)
+                                }
+                            };
+
+                            if let Some(state) = state {
+                                self.report_progress("Loading", state, msg, None);
+                            }
+                        }
+                    }
+
+                    // Coalesce multiple task events into one loop turn
+                    task = match self.task_pool.receiver.try_recv() {
+                        Ok(task) => task,
+                        Err(_) => break,
+                    };
                 }
 
                 for progress in prime_caches_progress {
@@ -260,20 +326,119 @@ impl GlobalState {
                     self.report_progress("Indexing", state, message, Some(fraction));
                 }
             }
-            Event::Vfs(message) => {
+            Event::Vfs(mut task) => {
                 let _p = profile::span("GlobalState::handle_event/vfs");
-                self.handle_vfs_msg(message);
-                // Coalesce many VFS event into a single loop turn
-                while let Ok(message) = self.loader.receiver.try_recv() {
-                    self.handle_vfs_msg(message);
+                loop {
+                    match task {
+                        vfs::loader::Message::Loaded { files } => {
+                            let vfs = &mut self.vfs.write().0;
+                            for (path, contents) in files {
+                                let path = VfsPath::from(path);
+                                if !self.mem_docs.contains(&path) {
+                                    vfs.set_file_contents(path, contents);
+                                }
+                            }
+                        }
+                        vfs::loader::Message::Progress { n_total, n_done, config_version } => {
+                            always!(config_version <= self.vfs_config_version);
+
+                            self.vfs_progress_config_version = config_version;
+                            self.vfs_progress_n_total = n_total;
+                            self.vfs_progress_n_done = n_done;
+
+                            let state = if n_done == 0 {
+                                Progress::Begin
+                            } else if n_done < n_total {
+                                Progress::Report
+                            } else {
+                                assert_eq!(n_done, n_total);
+                                Progress::End
+                            };
+                            self.report_progress(
+                                "Roots Scanned",
+                                state,
+                                Some(format!("{}/{}", n_done, n_total)),
+                                Some(Progress::fraction(n_done, n_total)),
+                            )
+                        }
+                    }
+                    // Coalesce many VFS event into a single loop turn
+                    task = match self.loader.receiver.try_recv() {
+                        Ok(task) => task,
+                        Err(_) => break,
+                    }
                 }
             }
-            Event::Flycheck(message) => {
+            Event::Flycheck(mut task) => {
                 let _p = profile::span("GlobalState::handle_event/flycheck");
-                self.handle_flycheck_msg(message);
-                // Coalesce many flycheck updates into a single loop turn
-                while let Ok(message) = self.flycheck_receiver.try_recv() {
-                    self.handle_flycheck_msg(message);
+                loop {
+                    match task {
+                        flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
+                            let snap = self.snapshot();
+                            let diagnostics =
+                                crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
+                                    &self.config.diagnostics_map(),
+                                    &diagnostic,
+                                    &workspace_root,
+                                    &snap,
+                                );
+                            for diag in diagnostics {
+                                match url_to_file_id(&self.vfs.read().0, &diag.url) {
+                                    Ok(file_id) => self.diagnostics.add_check_diagnostic(
+                                        id,
+                                        file_id,
+                                        diag.diagnostic,
+                                        diag.fix,
+                                    ),
+                                    Err(err) => {
+                                        tracing::error!(
+                                            "File with cargo diagnostic not found in VFS: {}",
+                                            err
+                                        );
+                                    }
+                                };
+                            }
+                        }
+
+                        flycheck::Message::Progress { id, progress } => {
+                            let (state, message) = match progress {
+                                flycheck::Progress::DidStart => {
+                                    self.diagnostics.clear_check(id);
+                                    (Progress::Begin, None)
+                                }
+                                flycheck::Progress::DidCheckCrate(target) => {
+                                    (Progress::Report, Some(target))
+                                }
+                                flycheck::Progress::DidCancel => (Progress::End, None),
+                                flycheck::Progress::DidFinish(result) => {
+                                    if let Err(err) = result {
+                                        self.show_and_log_error(
+                                            "cargo check failed".to_string(),
+                                            Some(err.to_string()),
+                                        );
+                                    }
+                                    (Progress::End, None)
+                                }
+                            };
+
+                            // When we're running multiple flychecks, we have to include a disambiguator in
+                            // the title, or the editor complains. Note that this is a user-facing string.
+                            let title = if self.flycheck.len() == 1 {
+                                match self.config.flycheck() {
+                                    Some(config) => format!("{}", config),
+                                    None => "cargo check".to_string(),
+                                }
+                            } else {
+                                format!("cargo check (#{})", id + 1)
+                            };
+                            self.report_progress(&title, state, message, None);
+                        }
+                    }
+                    // Coalesce many flycheck updates into a single loop turn
+                    task = match self.flycheck_receiver.try_recv() {
+                        Ok(task) => task,
+                        Err(_) => break,
+                    }
                 }
             }
         }
@@ -282,13 +447,13 @@ impl GlobalState {
         let memdocs_added_or_removed = self.mem_docs.take_changes();
 
         if self.is_quiescent() {
-            let became_quiescent = !(was_quiescent
-                || self.fetch_workspaces_queue.op_requested()
-                || self.fetch_build_data_queue.op_requested());
-
-            if became_quiescent {
-                // Project has loaded properly, kick off initial flycheck
-                self.flycheck.iter().for_each(FlycheckHandle::update);
+            if !was_quiescent
+                && !self.fetch_workspaces_queue.op_requested()
+                && !self.fetch_build_data_queue.op_requested()
+            {
+                for flycheck in &self.flycheck {
+                    flycheck.update();
+                }
                 if self.config.prefill_caches() {
                     self.prime_caches_queue.request_op("became quiescent".to_string());
                 }
@@ -327,15 +492,28 @@ impl GlobalState {
                     continue;
                 }
 
-                let uri = file_id_to_url(&self.vfs.read().0, file_id);
-                let diagnostics =
+                let url = file_id_to_url(&self.vfs.read().0, file_id);
+                let mut diagnostics =
                     self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
-                let version = from_proto::vfs_path(&uri)
+                // https://github.com/rust-lang/rust-analyzer/issues/11404
+                for d in &mut diagnostics {
+                    if d.message.is_empty() {
+                        d.message = " ".to_string();
+                    }
+                    if let Some(rds) = d.related_information.as_mut() {
+                        for rd in rds {
+                            if rd.message.is_empty() {
+                                rd.message = " ".to_string();
+                            }
+                        }
+                    }
+                }
+                let version = from_proto::vfs_path(&url)
                     .map(|path| self.mem_docs.get(&path).map(|it| it.version))
                     .unwrap_or_default();
 
                 self.send_notification::<lsp_types::notification::PublishDiagnostics>(
-                    lsp_types::PublishDiagnosticsParams { uri, diagnostics, version },
+                    lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version },
                 );
             }
         }
@@ -397,171 +575,11 @@ impl GlobalState {
         Ok(())
     }
 
-    fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>, task: Task) {
-        match task {
-            Task::Response(response) => self.respond(response),
-            Task::Retry(req) => self.on_request(req),
-            Task::Diagnostics(diagnostics_per_file) => {
-                for (file_id, diagnostics) in diagnostics_per_file {
-                    self.diagnostics.set_native_diagnostics(file_id, diagnostics)
-                }
-            }
-            Task::PrimeCaches(progress) => match progress {
-                PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
-                PrimeCachesProgress::Report(_) => {
-                    match prime_caches_progress.last_mut() {
-                        Some(last @ PrimeCachesProgress::Report(_)) => {
-                            // Coalesce subsequent update events.
-                            *last = progress;
-                        }
-                        _ => prime_caches_progress.push(progress),
-                    }
-                }
-                PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
-            },
-            Task::FetchWorkspace(progress) => {
-                let (state, msg) = match progress {
-                    ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
-                    ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
-                    ProjectWorkspaceProgress::End(workspaces) => {
-                        self.fetch_workspaces_queue.op_completed(workspaces);
-
-                        let old = Arc::clone(&self.workspaces);
-                        self.switch_workspaces("fetched workspace".to_string());
-                        let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
-
-                        if self.config.run_build_scripts() && workspaces_updated {
-                            self.fetch_build_data_queue.request_op(format!("workspace updated"));
-                        }
-
-                        (Progress::End, None)
-                    }
-                };
-
-                self.report_progress("Fetching", state, msg, None);
-            }
-            Task::FetchBuildData(progress) => {
-                let (state, msg) = match progress {
-                    BuildDataProgress::Begin => (Some(Progress::Begin), None),
-                    BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
-                    BuildDataProgress::End(build_data_result) => {
-                        self.fetch_build_data_queue.op_completed(build_data_result);
-
-                        self.switch_workspaces("fetched build data".to_string());
-
-                        (Some(Progress::End), None)
-                    }
-                };
-
-                if let Some(state) = state {
-                    self.report_progress("Loading", state, msg, None);
-                }
-            }
-        }
-    }
-
-    fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
-        match message {
-            vfs::loader::Message::Loaded { files } => {
-                let vfs = &mut self.vfs.write().0;
-                for (path, contents) in files {
-                    let path = VfsPath::from(path);
-                    if !self.mem_docs.contains(&path) {
-                        vfs.set_file_contents(path, contents);
-                    }
-                }
-            }
-            vfs::loader::Message::Progress { n_total, n_done, config_version } => {
-                always!(config_version <= self.vfs_config_version);
-
-                self.vfs_progress_config_version = config_version;
-                self.vfs_progress_n_total = n_total;
-                self.vfs_progress_n_done = n_done;
-
-                let state = if n_done == 0 {
-                    Progress::Begin
-                } else if n_done < n_total {
-                    Progress::Report
-                } else {
-                    assert_eq!(n_done, n_total);
-                    Progress::End
-                };
-                self.report_progress(
-                    "Roots Scanned",
-                    state,
-                    Some(format!("{}/{}", n_done, n_total)),
-                    Some(Progress::fraction(n_done, n_total)),
-                )
-            }
-        }
-    }
-
-    fn handle_flycheck_msg(&mut self, message: flycheck::Message) {
-        match message {
-            flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
-                let snap = self.snapshot();
-                let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
-                    &self.config.diagnostics_map(),
-                    &diagnostic,
-                    &workspace_root,
-                    &snap,
-                );
-                for diag in diagnostics {
-                    match url_to_file_id(&self.vfs.read().0, &diag.url) {
-                        Ok(file_id) => self.diagnostics.add_check_diagnostic(
-                            id,
-                            file_id,
-                            diag.diagnostic,
-                            diag.fix,
-                        ),
-                        Err(err) => {
-                            tracing::error!("File with cargo diagnostic not found in VFS: {}", err);
-                        }
-                    };
-                }
-            }
-
-            flycheck::Message::Progress { id, progress } => {
-                let (state, message) = match progress {
-                    flycheck::Progress::DidStart => {
-                        self.diagnostics.clear_check(id);
-                        (Progress::Begin, None)
-                    }
-                    flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
-                    flycheck::Progress::DidCancel => (Progress::End, None),
-                    flycheck::Progress::DidFinish(result) => {
-                        if let Err(err) = result {
-                            self.show_and_log_error(
-                                "cargo check failed".to_string(),
-                                Some(err.to_string()),
-                            );
-                        }
-                        (Progress::End, None)
-                    }
-                };
-
-                // When we're running multiple flychecks, we have to include a disambiguator in
-                // the title, or the editor complains. Note that this is a user-facing string.
-                let title = if self.flycheck.len() == 1 {
-                    match self.config.flycheck() {
-                        Some(config) => format!("{}", config),
-                        None => "cargo check".to_string(),
-                    }
-                } else {
-                    format!("cargo check (#{})", id + 1)
-                };
-                self.report_progress(&title, state, message, None);
-            }
-        }
-    }
-
-    /// Registers and handles a request. This should only be called once per incoming request.
     fn on_new_request(&mut self, request_received: Instant, req: Request) {
         self.register_request(&req, request_received);
         self.on_request(req);
     }
 
-    /// Handles a request.
     fn on_request(&mut self, req: Request) {
         if self.shutdown_requested {
             self.respond(lsp_server::Response::new_err(
@@ -652,7 +670,6 @@ impl GlobalState {
             .finish();
     }
 
-    /// Handles an incoming notification.
     fn on_notification(&mut self, not: Notification) -> Result<()> {
         NotificationDispatcher { not: Some(not), global_state: self }
             .on::<lsp_types::notification::Cancel>(|this, params| {
@@ -726,8 +743,6 @@ impl GlobalState {
                 let mut updated = false;
                 if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
                     let (vfs, _) = &*this.vfs.read();
-
-                    // Trigger flychecks for all workspaces that depend on the saved file
                     if let Some(file_id) = vfs.file_id(&vfs_path) {
                         let analysis = this.analysis_host.analysis();
                         // Crates containing or depending on the saved file
@@ -785,8 +800,6 @@ impl GlobalState {
                             }
                         }
                     }
-
-                    // Re-fetch workspaces if a workspace related file has changed
                     if let Some(abs_path) = vfs_path.as_path() {
                         if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
                             this.fetch_workspaces_queue
@@ -794,8 +807,6 @@ impl GlobalState {
                         }
                     }
                 }
-
-                // No specific flycheck was triggered, so let's trigger all of them.
                 if !updated {
                     for flycheck in &this.flycheck {
                         flycheck.update();
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 27ab31db8d..8a2dea6b35 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -105,22 +105,6 @@ export async function createClient(
         traceOutputChannel: traceOutputChannel(),
         outputChannel: outputChannel(),
         middleware: {
-            async handleDiagnostics(uri, diagnostics, next) {
-                // Workaround for https://github.com/microsoft/vscode/issues/155531
-                for (const diagnostic of diagnostics) {
-                    if (!diagnostic.message) {
-                        diagnostic.message = " ";
-                    }
-                    if (diagnostic.relatedInformation) {
-                        for (const relatedInformation of diagnostic.relatedInformation) {
-                            if (!relatedInformation.message) {
-                                relatedInformation.message = " ";
-                            }
-                        }
-                    }
-                }
-                next(uri, diagnostics);
-            },
             async provideHover(
                 document: vscode.TextDocument,
                 position: vscode.Position,
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index f58de9da1b..1b793bb0b1 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -433,7 +433,7 @@ export function syntaxTree(ctx: Ctx): Cmd {
 // The contents of the file come from the `TextDocumentContentProvider`
 export function viewHir(ctx: Ctx): Cmd {
     const tdcp = new (class implements vscode.TextDocumentContentProvider {
-        readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.rs");
+        readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt");
         readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
         constructor() {
             vscode.workspace.onDidChangeTextDocument(


Test patch:
diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs
index e30d9652bb..5cdf36cc61 100644
--- a/crates/hir-def/src/item_tree/tests.rs
+++ b/crates/hir-def/src/item_tree/tests.rs
@@ -283,10 +283,10 @@ struct S {
         "#,
         expect![[r#"
             pub(self) struct S {
-                pub(self) a: Mixed::<'a, T, Item = (), OtherItem = u8>,
-                pub(self) b: Qualified::<Self=Fully>::Syntax,
-                pub(self) c: <TypeAnchored>::Path::<'a>,
-                pub(self) d: dyn for<'a> Trait::<'a>,
+                pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
+                pub(self) b: Qualified<Self=Fully>::Syntax,
+                pub(self) c: <TypeAnchored>::Path<'a>,
+                pub(self) d: dyn for<'a> Trait<'a>,
             }
         "#]],
     )
@@ -329,7 +329,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
                 T: Copy,
                 U: ?Sized;
 
-            impl<'a, 'b, T, const K: u8> S::<'a, 'b, T, K>
+            impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
             where
                 T: Copy,
                 T: 'a,
@@ -352,7 +352,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
             where
                 Self: Super,
                 T: 'a,
-                Self: for<'a> Tr::<'a, T>
+                Self: for<'a> Tr<'a, T>
             {
             }
         "#]],