about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/eager.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs93
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs70
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs35
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs116
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs62
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tls.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs69
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs69
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs70
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs84
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs81
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/helpers.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs74
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/traits.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs153
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs72
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs45
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs100
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs261
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs103
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs16
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs77
-rw-r--r--src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/utils.rs1
179 files changed, 2480 insertions, 1245 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index a988317e046..f5fe8f87701 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -14,7 +14,7 @@ use hir_expand::{name::Name, ExpandError, InFile};
 use la_arena::{Arena, ArenaMap, Idx, RawIdx};
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use span::MacroFileId;
+use span::{Edition, MacroFileId};
 use syntax::{ast, AstPtr, SyntaxNodePtr};
 use triomphe::Arc;
 
@@ -201,8 +201,13 @@ impl Body {
         self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
     }
 
-    pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String {
-        pretty::print_body_hir(db, self, owner)
+    pub fn pretty_print(
+        &self,
+        db: &dyn DefDatabase,
+        owner: DefWithBodyId,
+        edition: Edition,
+    ) -> String {
+        pretty::print_body_hir(db, self, owner, edition)
     }
 
     pub fn pretty_print_expr(
@@ -210,8 +215,9 @@ impl Body {
         db: &dyn DefDatabase,
         owner: DefWithBodyId,
         expr: ExprId,
+        edition: Edition,
     ) -> String {
-        pretty::print_expr_hir(db, self, owner, expr)
+        pretty::print_expr_hir(db, self, owner, expr, edition)
     }
 
     fn new(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index edaee60937d..55740a68acd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -3,6 +3,7 @@
 use std::fmt::{self, Write};
 
 use itertools::Itertools;
+use span::Edition;
 
 use crate::{
     hir::{
@@ -15,20 +16,26 @@ use crate::{
 
 use super::*;
 
-pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
+pub(super) fn print_body_hir(
+    db: &dyn DefDatabase,
+    body: &Body,
+    owner: DefWithBodyId,
+    edition: Edition,
+) -> String {
     let header = match owner {
-        DefWithBodyId::FunctionId(it) => {
-            it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db.upcast())))
-        }
+        DefWithBodyId::FunctionId(it) => it
+            .lookup(db)
+            .id
+            .resolved(db, |it| format!("fn {}", it.name.display(db.upcast(), edition))),
         DefWithBodyId::StaticId(it) => it
             .lookup(db)
             .id
-            .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast()))),
+            .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast(), edition))),
         DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
             format!(
                 "const {} = ",
                 match &it.name {
-                    Some(name) => name.display(db.upcast()).to_string(),
+                    Some(name) => name.display(db.upcast(), edition).to_string(),
                     None => "_".to_owned(),
                 }
             )
@@ -39,13 +46,13 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
             let enum_loc = loc.parent.lookup(db);
             format!(
                 "enum {}::{}",
-                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
-                loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
+                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
+                loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
             )
         }
     };
 
-    let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
+    let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false, edition };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
         let function_data = &db.function_data(it);
@@ -86,8 +93,10 @@ pub(super) fn print_expr_hir(
     body: &Body,
     _owner: DefWithBodyId,
     expr: ExprId,
+    edition: Edition,
 ) -> String {
-    let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false };
+    let mut p =
+        Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false, edition };
     p.print_expr(expr);
     p.buf
 }
@@ -113,6 +122,7 @@ struct Printer<'a> {
     buf: String,
     indent_level: usize,
     needs_indent: bool,
+    edition: Edition,
 }
 
 impl Write for Printer<'_> {
@@ -173,13 +183,14 @@ impl Printer<'_> {
             Expr::OffsetOf(offset_of) => {
                 w!(self, "builtin#offset_of(");
                 self.print_type_ref(&offset_of.container);
+                let edition = self.edition;
                 w!(
                     self,
                     ", {})",
                     offset_of
                         .fields
                         .iter()
-                        .format_with(".", |field, f| f(&field.display(self.db.upcast())))
+                        .format_with(".", |field, f| f(&field.display(self.db.upcast(), edition)))
                 );
             }
             Expr::Path(path) => self.print_path(path),
@@ -201,7 +212,7 @@ impl Printer<'_> {
             }
             Expr::Loop { body, label } => {
                 if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast()));
+                    w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast(), self.edition));
                 }
                 w!(self, "loop ");
                 self.print_expr(*body);
@@ -221,10 +232,11 @@ impl Printer<'_> {
             }
             Expr::MethodCall { receiver, method_name, args, generic_args } => {
                 self.print_expr(*receiver);
-                w!(self, ".{}", method_name.display(self.db.upcast()));
+                w!(self, ".{}", method_name.display(self.db.upcast(), self.edition));
                 if let Some(args) = generic_args {
                     w!(self, "::<");
-                    print_generic_args(self.db, args, self).unwrap();
+                    let edition = self.edition;
+                    print_generic_args(self.db, args, self, edition).unwrap();
                     w!(self, ">");
                 }
                 w!(self, "(");
@@ -259,13 +271,13 @@ impl Printer<'_> {
             Expr::Continue { label } => {
                 w!(self, "continue");
                 if let Some(lbl) = label {
-                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
+                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
                 }
             }
             Expr::Break { expr, label } => {
                 w!(self, "break");
                 if let Some(lbl) = label {
-                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
+                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
                 }
                 if let Some(expr) = expr {
                     self.whitespace();
@@ -307,9 +319,10 @@ impl Printer<'_> {
                 }
 
                 w!(self, "{{");
+                let edition = self.edition;
                 self.indented(|p| {
                     for field in &**fields {
-                        w!(p, "{}: ", field.name.display(self.db.upcast()));
+                        w!(p, "{}: ", field.name.display(self.db.upcast(), edition));
                         p.print_expr(field.expr);
                         wln!(p, ",");
                     }
@@ -326,7 +339,7 @@ impl Printer<'_> {
             }
             Expr::Field { expr, name } => {
                 self.print_expr(*expr);
-                w!(self, ".{}", name.display(self.db.upcast()));
+                w!(self, ".{}", name.display(self.db.upcast(), self.edition));
             }
             Expr::Await { expr } => {
                 self.print_expr(*expr);
@@ -464,8 +477,9 @@ impl Printer<'_> {
             }
             Expr::Literal(lit) => self.print_literal(lit),
             Expr::Block { id: _, statements, tail, label } => {
-                let label =
-                    label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast())));
+                let label = label.map(|lbl| {
+                    format!("{}: ", self.body[lbl].name.display(self.db.upcast(), self.edition))
+                });
                 self.print_block(label.as_deref(), statements, tail);
             }
             Expr::Unsafe { id: _, statements, tail } => {
@@ -539,9 +553,10 @@ impl Printer<'_> {
                 }
 
                 w!(self, " {{");
+                let edition = self.edition;
                 self.indented(|p| {
                     for arg in args.iter() {
-                        w!(p, "{}: ", arg.name.display(self.db.upcast()));
+                        w!(p, "{}: ", arg.name.display(self.db.upcast(), edition));
                         p.print_pat(arg.pat);
                         wln!(p, ",");
                     }
@@ -686,11 +701,13 @@ impl Printer<'_> {
     }
 
     fn print_type_ref(&mut self, ty: &TypeRef) {
-        print_type_ref(self.db, ty, self).unwrap();
+        let edition = self.edition;
+        print_type_ref(self.db, ty, self, edition).unwrap();
     }
 
     fn print_path(&mut self, path: &Path) {
-        print_path(self.db, path, self).unwrap();
+        let edition = self.edition;
+        print_path(self.db, path, self, edition).unwrap();
     }
 
     fn print_binding(&mut self, id: BindingId) {
@@ -701,6 +718,6 @@ impl Printer<'_> {
             BindingAnnotation::Ref => "ref ",
             BindingAnnotation::RefMut => "ref mut ",
         };
-        w!(self, "{}{}", mode, name.display(self.db.upcast()));
+        w!(self, "{}{}", mode, name.display(self.db.upcast(), self.edition));
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index 0011d3a20c2..38fc01d8fca 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -219,7 +219,7 @@ fn main() {
                 },
             );
         }"#]]
-    .assert_eq(&body.pretty_print(&db, def))
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
 }
 
 #[test]
@@ -285,7 +285,7 @@ impl SsrError {
                 ),
             );
         }"#]]
-    .assert_eq(&body.pretty_print(&db, def))
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
 }
 
 #[test]
@@ -333,5 +333,5 @@ fn f(a: i32, b: u32) -> String {
                 );
             };
         }"#]]
-    .assert_eq(&body.pretty_print(&db, def))
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 5a3a3e91897..f5e03e5281e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -651,6 +651,7 @@ mod tests {
     use expect_test::{expect, Expect};
     use hir_expand::db::ExpandDatabase;
     use itertools::Itertools;
+    use span::Edition;
     use stdx::format_to;
     use syntax::ast::AstNode;
     use test_fixture::WithFixture;
@@ -717,8 +718,10 @@ mod tests {
                 "{:7}(imports {}): {}\n",
                 format!("{:?}", prefix),
                 if ignore_local_imports { '✖' } else { '✔' },
-                found_path
-                    .map_or_else(|| "<unresolvable>".to_owned(), |it| it.display(&db).to_string()),
+                found_path.map_or_else(
+                    || "<unresolvable>".to_owned(),
+                    |it| it.display(&db, Edition::CURRENT).to_string()
+                ),
             );
         }
         expect.assert_eq(&res);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
index 390e7da677f..e1c3bd25bcf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -250,7 +250,7 @@ pub(crate) fn parse(
                 }
             }
             ArgRef::Name(name, span) => {
-                let name = Name::new(name, tt::IdentIsRaw::No, call_ctx);
+                let name = Name::new(name, call_ctx);
                 if let Some((index, _)) = args.by_name(&name) {
                     record_usage(name, span);
                     // Name found in `args`, so we resolve it to its index.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index 8f618b2d303..b74cd90f693 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -10,6 +10,7 @@ use hir_expand::{
     AstId,
 };
 use intern::{sym, Interned, Symbol};
+use span::Edition;
 use syntax::ast::{self, HasGenericArgs, HasName, IsString};
 
 use crate::{
@@ -419,18 +420,22 @@ impl ConstRef {
         param.default_val().map(|default| Self::from_const_arg(lower_ctx, Some(default)))
     }
 
-    pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a {
-        struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef);
+    pub fn display<'a>(
+        &'a self,
+        db: &'a dyn ExpandDatabase,
+        edition: Edition,
+    ) -> impl fmt::Display + 'a {
+        struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef, Edition);
         impl fmt::Display for Display<'_> {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 match self.1 {
                     ConstRef::Scalar(s) => s.fmt(f),
-                    ConstRef::Path(n) => n.display(self.0).fmt(f),
+                    ConstRef::Path(n) => n.display(self.0, self.2).fmt(f),
                     ConstRef::Complex(_) => f.write_str("{const}"),
                 }
             }
         }
-        Display(db, self)
+        Display(db, self, edition)
     }
 
     // We special case literals and single identifiers, to speed up things.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 8cc022e4c60..9574e5d9cd3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -8,6 +8,7 @@ use hir_expand::name::Name;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
+use span::Edition;
 use stdx::{format_to, TupleExt};
 use syntax::ToSmolStr;
 use triomphe::Arc;
@@ -66,7 +67,12 @@ impl ImportMap {
         for (k, v) in self.item_to_info_map.iter() {
             format_to!(out, "{:?} ({:?}) -> ", k, v.1);
             for v in &v.0 {
-                format_to!(out, "{}:{:?}, ", v.name.display(db.upcast()), v.container);
+                format_to!(
+                    out,
+                    "{}:{:?}, ",
+                    v.name.display(db.upcast(), Edition::CURRENT),
+                    v.container
+                );
             }
             format_to!(out, "\n");
         }
@@ -83,7 +89,7 @@ impl ImportMap {
             // We've only collected items, whose name cannot be tuple field so unwrapping is fine.
             .flat_map(|(&item, (info, _))| {
                 info.iter().enumerate().map(move |(idx, info)| {
-                    (item, info.name.display(db.upcast()).to_smolstr(), idx as u32)
+                    (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32)
                 })
             })
             .collect();
@@ -461,7 +467,7 @@ fn search_maps(
                     query.search_mode.check(
                         &query.query,
                         query.case_sensitive,
-                        &info.name.display(db.upcast()).to_smolstr(),
+                        &info.name.unescaped().display(db.upcast()).to_smolstr(),
                     )
                 });
             res.extend(iter.map(TupleExt::head));
@@ -577,7 +583,7 @@ mod tests {
         Some(format!(
             "{}::{}",
             render_path(db, &trait_info[0]),
-            assoc_item_name.display(db.upcast())
+            assoc_item_name.display(db.upcast(), Edition::CURRENT)
         ))
     }
 
@@ -616,7 +622,7 @@ mod tests {
             module = parent;
         }
 
-        segments.iter().rev().map(|it| it.display(db.upcast())).join("::")
+        segments.iter().rev().map(|it| it.display(db.upcast(), Edition::CURRENT)).join("::")
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index df6b1f55c1d..89b011094a4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -9,6 +9,7 @@ use la_arena::Idx;
 use once_cell::sync::Lazy;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
+use span::Edition;
 use stdx::format_to;
 use syntax::ast;
 
@@ -706,7 +707,7 @@ impl ItemScope {
             format_to!(
                 buf,
                 "{}:",
-                name.map_or("_".to_owned(), |name| name.display(db).to_string())
+                name.map_or("_".to_owned(), |name| name.display(db, Edition::LATEST).to_string())
             );
 
             if let Some((.., i)) = def.types {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 28eebb286ed..517f40ebd1c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -51,7 +51,7 @@ use la_arena::{Arena, Idx, RawIdx};
 use once_cell::sync::OnceCell;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use span::{AstIdNode, FileAstId, SyntaxContextId};
+use span::{AstIdNode, Edition, FileAstId, SyntaxContextId};
 use stdx::never;
 use syntax::{ast, match_ast, SyntaxKind};
 use triomphe::Arc;
@@ -199,8 +199,8 @@ impl ItemTree {
         Attrs::filter(db, krate, self.raw_attrs(of).clone())
     }
 
-    pub fn pretty_print(&self, db: &dyn DefDatabase) -> String {
-        pretty::print_item_tree(db, self)
+    pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String {
+        pretty::print_item_tree(db, self, edition)
     }
 
     fn data(&self) -> &ItemTreeData {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 740759e6e39..b5a65abce86 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -3,7 +3,7 @@
 use std::fmt::{self, Write};
 
 use la_arena::{Idx, RawIdx};
-use span::ErasedFileAstId;
+use span::{Edition, ErasedFileAstId};
 
 use crate::{
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
@@ -18,8 +18,9 @@ use crate::{
     visibility::RawVisibility,
 };
 
-pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
-    let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
+pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Edition) -> String {
+    let mut p =
+        Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition };
 
     if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
         p.print_attrs(attrs, true, "\n");
@@ -56,6 +57,7 @@ struct Printer<'a> {
     buf: String,
     indent_level: usize,
     needs_indent: bool,
+    edition: Edition,
 }
 
 impl Printer<'_> {
@@ -97,7 +99,7 @@ impl Printer<'_> {
                 self,
                 "#{}[{}{}]{}",
                 inner,
-                attr.path.display(self.db.upcast()),
+                attr.path.display(self.db.upcast(), self.edition),
                 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
                 separated_by,
             );
@@ -113,13 +115,14 @@ impl Printer<'_> {
     fn print_visibility(&mut self, vis: RawVisibilityId) {
         match &self.tree[vis] {
             RawVisibility::Module(path, _expl) => {
-                w!(self, "pub({}) ", path.display(self.db.upcast()))
+                w!(self, "pub({}) ", path.display(self.db.upcast(), self.edition))
             }
             RawVisibility::Public => w!(self, "pub "),
         };
     }
 
     fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
+        let edition = self.edition;
         match kind {
             FieldsShape::Record => {
                 self.whitespace();
@@ -131,7 +134,7 @@ impl Printer<'_> {
                             "\n",
                         );
                         this.print_visibility(*visibility);
-                        w!(this, "{}: ", name.display(self.db.upcast()));
+                        w!(this, "{}: ", name.display(self.db.upcast(), edition));
                         this.print_type_ref(type_ref);
                         wln!(this, ",");
                     }
@@ -147,7 +150,7 @@ impl Printer<'_> {
                             "\n",
                         );
                         this.print_visibility(*visibility);
-                        w!(this, "{}: ", name.display(self.db.upcast()));
+                        w!(this, "{}: ", name.display(self.db.upcast(), edition));
                         this.print_type_ref(type_ref);
                         wln!(this, ",");
                     }
@@ -186,20 +189,20 @@ impl Printer<'_> {
     fn print_use_tree(&mut self, use_tree: &UseTree) {
         match &use_tree.kind {
             UseTreeKind::Single { path, alias } => {
-                w!(self, "{}", path.display(self.db.upcast()));
+                w!(self, "{}", path.display(self.db.upcast(), self.edition));
                 if let Some(alias) = alias {
-                    w!(self, " as {}", alias);
+                    w!(self, " as {}", alias.display(self.edition));
                 }
             }
             UseTreeKind::Glob { path } => {
                 if let Some(path) = path {
-                    w!(self, "{}::", path.display(self.db.upcast()));
+                    w!(self, "{}::", path.display(self.db.upcast(), self.edition));
                 }
                 w!(self, "*");
             }
             UseTreeKind::Prefixed { prefix, list } => {
                 if let Some(prefix) = prefix {
-                    w!(self, "{}::", prefix.display(self.db.upcast()));
+                    w!(self, "{}::", prefix.display(self.db.upcast(), self.edition));
                 }
                 w!(self, "{{");
                 for (i, tree) in list.iter().enumerate() {
@@ -229,9 +232,9 @@ impl Printer<'_> {
                 let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "extern crate {}", name.display(self.db.upcast()));
+                w!(self, "extern crate {}", name.display(self.db.upcast(), self.edition));
                 if let Some(alias) = alias {
-                    w!(self, " as {}", alias);
+                    w!(self, " as {}", alias.display(self.edition));
                 }
                 wln!(self, ";");
             }
@@ -278,7 +281,7 @@ impl Printer<'_> {
                 if let Some(abi) = abi {
                     w!(self, "extern \"{}\" ", abi);
                 }
-                w!(self, "fn {}", name.display(self.db.upcast()));
+                w!(self, "fn {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(explicit_generic_params, it.into());
                 w!(self, "(");
                 if !params.is_empty() {
@@ -314,7 +317,7 @@ impl Printer<'_> {
                     &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "struct {}", name.display(self.db.upcast()));
+                w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(
                     FieldParent::Struct(it),
@@ -332,7 +335,7 @@ impl Printer<'_> {
                 let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "union {}", name.display(self.db.upcast()));
+                w!(self, "union {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(
                     FieldParent::Union(it),
@@ -346,15 +349,16 @@ impl Printer<'_> {
                 let Enum { name, visibility, variants, generic_params, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "enum {}", name.display(self.db.upcast()));
+                w!(self, "enum {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
+                let edition = self.edition;
                 self.indented(|this| {
                     for variant in FileItemTreeId::range_iter(variants.clone()) {
                         let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
                         this.print_ast_id(ast_id.erase());
                         this.print_attrs_of(variant, "\n");
-                        w!(this, "{}", name.display(self.db.upcast()));
+                        w!(this, "{}", name.display(self.db.upcast(), edition));
                         this.print_fields(FieldParent::Variant(variant), *kind, fields);
                         wln!(this, ",");
                     }
@@ -367,7 +371,7 @@ impl Printer<'_> {
                 self.print_visibility(*visibility);
                 w!(self, "const ");
                 match name {
-                    Some(name) => w!(self, "{}", name.display(self.db.upcast())),
+                    Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
                     None => w!(self, "_"),
                 }
                 w!(self, ": ");
@@ -382,7 +386,7 @@ impl Printer<'_> {
                 if *mutable {
                     w!(self, "mut ");
                 }
-                w!(self, "{}: ", name.display(self.db.upcast()));
+                w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
                 self.print_type_ref(type_ref);
                 w!(self, " = _;");
                 wln!(self);
@@ -398,7 +402,7 @@ impl Printer<'_> {
                 if *is_auto {
                     w!(self, "auto ");
                 }
-                w!(self, "trait {}", name.display(self.db.upcast()));
+                w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
@@ -412,7 +416,7 @@ impl Printer<'_> {
                 let TraitAlias { name, visibility, generic_params, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "trait {}", name.display(self.db.upcast()));
+                w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 w!(self, " = ");
                 self.print_where_clause(generic_params);
@@ -457,7 +461,7 @@ impl Printer<'_> {
                     &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "type {}", name.display(self.db.upcast()));
+                w!(self, "type {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
@@ -475,7 +479,7 @@ impl Printer<'_> {
                 let Mod { name, visibility, kind, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "mod {}", name.display(self.db.upcast()));
+                w!(self, "mod {}", name.display(self.db.upcast(), self.edition));
                 match kind {
                     ModKind::Inline { items } => {
                         w!(self, " {{");
@@ -500,18 +504,22 @@ impl Printer<'_> {
                     ctxt,
                     expand_to
                 );
-                wln!(self, "{}!(...);", path.display(self.db.upcast()));
+                wln!(self, "{}!(...);", path.display(self.db.upcast(), self.edition));
             }
             ModItem::MacroRules(it) => {
                 let MacroRules { name, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
-                wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast()));
+                wln!(
+                    self,
+                    "macro_rules! {} {{ ... }}",
+                    name.display(self.db.upcast(), self.edition)
+                );
             }
             ModItem::Macro2(it) => {
                 let Macro2 { name, visibility, ast_id } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast()));
+                wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast(), self.edition));
             }
         }
 
@@ -519,15 +527,18 @@ impl Printer<'_> {
     }
 
     fn print_type_ref(&mut self, type_ref: &TypeRef) {
-        print_type_ref(self.db, type_ref, self).unwrap();
+        let edition = self.edition;
+        print_type_ref(self.db, type_ref, self, edition).unwrap();
     }
 
     fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
-        print_type_bounds(self.db, bounds, self).unwrap();
+        let edition = self.edition;
+        print_type_bounds(self.db, bounds, self, edition).unwrap();
     }
 
     fn print_path(&mut self, path: &Path) {
-        print_path(self.db, path, self).unwrap();
+        let edition = self.edition;
+        print_path(self.db, path, self, edition).unwrap();
     }
 
     fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@@ -543,7 +554,7 @@ impl Printer<'_> {
             }
             first = false;
             self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
-            w!(self, "{}", lt.name.display(self.db.upcast()));
+            w!(self, "{}", lt.name.display(self.db.upcast(), self.edition));
         }
         for (idx, x) in params.iter_type_or_consts() {
             if !first {
@@ -553,11 +564,11 @@ impl Printer<'_> {
             self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
             match x {
                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
-                    Some(name) => w!(self, "{}", name.display(self.db.upcast())),
+                    Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
                     None => w!(self, "_anon_{}", idx.into_raw()),
                 },
                 TypeOrConstParamData::ConstParamData(konst) => {
-                    w!(self, "const {}: ", konst.name.display(self.db.upcast()));
+                    w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
                     self.print_type_ref(&konst.ty);
                 }
             }
@@ -580,6 +591,7 @@ impl Printer<'_> {
         }
 
         w!(self, "\nwhere");
+        let edition = self.edition;
         self.indented(|this| {
             for (i, pred) in params.where_predicates().enumerate() {
                 if i != 0 {
@@ -592,8 +604,8 @@ impl Printer<'_> {
                         wln!(
                             this,
                             "{}: {},",
-                            target.name.display(self.db.upcast()),
-                            bound.name.display(self.db.upcast())
+                            target.name.display(self.db.upcast(), edition),
+                            bound.name.display(self.db.upcast(), edition)
                         );
                         continue;
                     }
@@ -603,7 +615,7 @@ impl Printer<'_> {
                             if i != 0 {
                                 w!(this, ", ");
                             }
-                            w!(this, "{}", lt.display(self.db.upcast()));
+                            w!(this, "{}", lt.display(self.db.upcast(), edition));
                         }
                         w!(this, "> ");
                         (target, bound)
@@ -613,7 +625,7 @@ impl Printer<'_> {
                 match target {
                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
                     WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
-                        Some(name) => w!(this, "{}", name.display(self.db.upcast())),
+                        Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
                         None => w!(this, "_anon_{}", id.into_raw()),
                     },
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index c6930401a6f..5c07369f4b5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -1,4 +1,5 @@
 use expect_test::{expect, Expect};
+use span::Edition;
 use test_fixture::WithFixture;
 
 use crate::{db::DefDatabase, test_db::TestDB};
@@ -6,7 +7,7 @@ use crate::{db::DefDatabase, test_db::TestDB};
 fn check(ra_fixture: &str, expect: Expect) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
     let item_tree = db.file_item_tree(file_id.into());
-    let pretty = item_tree.pretty_print(&db);
+    let pretty = item_tree.pretty_print(&db, Edition::CURRENT);
     expect.assert_eq(&pretty);
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 8825e463363..11601c683e1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -328,6 +328,10 @@ impl DefMap {
     /// The module id of a crate or block root.
     pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
 
+    pub fn edition(&self) -> Edition {
+        self.data.edition
+    }
+
     pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> {
         let crate_graph = db.crate_graph();
         let krate = &crate_graph[crate_id];
@@ -550,7 +554,7 @@ impl DefMap {
             for (name, child) in
                 map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
             {
-                let path = format!("{path}::{}", name.display(db.upcast()));
+                let path = format!("{path}::{}", name.display(db.upcast(), Edition::LATEST));
                 buf.push('\n');
                 go(buf, db, map, &path, *child);
             }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index debc5a44326..22eb5a174d3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -548,7 +548,7 @@ impl DefCollector<'_> {
             types => {
                 tracing::debug!(
                     "could not resolve prelude path `{}` to module (resolved to {:?})",
-                    path.display(self.db.upcast()),
+                    path.display(self.db.upcast(), Edition::LATEST),
                     types
                 );
             }
@@ -768,7 +768,7 @@ impl DefCollector<'_> {
     }
 
     fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
-        let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast()))
+        let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast(), Edition::LATEST))
             .entered();
         tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
         match import.source {
@@ -2151,7 +2151,7 @@ impl ModCollector<'_, '_> {
             }
             tracing::debug!(
                 "non-builtin attribute {}",
-                attr.path.display(self.def_collector.db.upcast())
+                attr.path.display(self.def_collector.db.upcast(), Edition::LATEST)
             );
 
             let ast_id = AstIdWithPath::new(
@@ -2286,8 +2286,8 @@ impl ModCollector<'_, '_> {
                         stdx::always!(
                             name == mac.name,
                             "built-in macro {} has #[rustc_builtin_macro] which declares different name {}",
-                            mac.name.display(self.def_collector.db.upcast()),
-                            name.display(self.def_collector.db.upcast())
+                            mac.name.display(self.def_collector.db.upcast(), Edition::LATEST),
+                            name.display(self.def_collector.db.upcast(), Edition::LATEST),
                         );
                         helpers_opt = Some(helpers);
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index 390c934f6da..a05c4dcf9bd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -1,6 +1,7 @@
 use expect_test::expect;
 
 use itertools::Itertools;
+use span::Edition;
 
 use super::*;
 
@@ -1100,7 +1101,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
     assert_eq!(def_map.data.exported_derives.len(), 1);
     match def_map.data.exported_derives.values().next() {
         Some(helpers) => match &**helpers {
-            [attr] => assert_eq!(attr.display(&db).to_string(), "helper_attr"),
+            [attr] => assert_eq!(attr.display(&db, Edition::CURRENT).to_string(), "helper_attr"),
             _ => unreachable!(),
         },
         _ => unreachable!(),
@@ -1456,7 +1457,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     let actual = def_map
         .macro_use_prelude
         .keys()
-        .map(|name| name.display(&db).to_string())
+        .map(|name| name.display(&db, Edition::CURRENT).to_string())
         .sorted()
         .join("\n");
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index 1327d9aa62e..071b55c83d8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -144,14 +144,14 @@ pub struct Baz;
 
             crate::r#async
             Bar: t v
-            foo: t
             r#async: t
-
-            crate::r#async::foo
-            Foo: t v
+            foo: t
 
             crate::r#async::r#async
             Baz: t v
+
+            crate::r#async::foo
+            Foo: t v
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index f90bc954a9b..077863c0c93 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -13,7 +13,8 @@ use crate::{
 };
 use hir_expand::name::Name;
 use intern::Interned;
-use syntax::{ast, ToSmolStr};
+use span::Edition;
+use syntax::ast;
 
 pub use hir_expand::mod_path::{path, ModPath, PathKind};
 
@@ -25,11 +26,21 @@ pub enum ImportAlias {
     Alias(Name),
 }
 
-impl Display for ImportAlias {
+impl ImportAlias {
+    pub fn display(&self, edition: Edition) -> impl Display + '_ {
+        ImportAliasDisplay { value: self, edition }
+    }
+}
+
+struct ImportAliasDisplay<'a> {
+    value: &'a ImportAlias,
+    edition: Edition,
+}
+impl Display for ImportAliasDisplay<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
+        match self.value {
             ImportAlias::Underscore => f.write_str("_"),
-            ImportAlias::Alias(name) => f.write_str(&name.display_no_db().to_smolstr()),
+            ImportAlias::Alias(name) => Display::fmt(&name.display_no_db(self.edition), f),
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index 3ee88b536fc..d5ef17a91fb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -5,6 +5,7 @@ use std::fmt::{self, Write};
 use hir_expand::mod_path::PathKind;
 use intern::Interned;
 use itertools::Itertools;
+use span::Edition;
 
 use crate::{
     db::DefDatabase,
@@ -13,46 +14,51 @@ use crate::{
     type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
 };
 
-pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
+pub(crate) fn print_path(
+    db: &dyn DefDatabase,
+    path: &Path,
+    buf: &mut dyn Write,
+    edition: Edition,
+) -> fmt::Result {
     if let Path::LangItem(it, s) = path {
         write!(buf, "builtin#lang(")?;
         match *it {
             LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
             LangItemTarget::EnumId(it) => {
-                write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.enum_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::Function(it) => {
-                write!(buf, "{}", db.function_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.function_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::Static(it) => {
-                write!(buf, "{}", db.static_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.static_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::Struct(it) => {
-                write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.struct_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::Union(it) => {
-                write!(buf, "{}", db.union_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.union_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::TypeAlias(it) => {
-                write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::Trait(it) => {
-                write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.trait_data(it).name.display(db.upcast(), edition))?
             }
             LangItemTarget::EnumVariant(it) => {
-                write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast()))?
+                write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast(), edition))?
             }
         }
 
         if let Some(s) = s {
-            write!(buf, "::{}", s.display(db.upcast()))?;
+            write!(buf, "::{}", s.display(db.upcast(), edition))?;
         }
         return write!(buf, ")");
     }
     match path.type_anchor() {
         Some(anchor) => {
             write!(buf, "<")?;
-            print_type_ref(db, anchor, buf)?;
+            print_type_ref(db, anchor, buf, edition)?;
             write!(buf, ">::")?;
         }
         None => match path.kind() {
@@ -78,10 +84,10 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write)
             write!(buf, "::")?;
         }
 
-        write!(buf, "{}", segment.name.display(db.upcast()))?;
+        write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
         if let Some(generics) = segment.args_and_bindings {
             write!(buf, "::<")?;
-            print_generic_args(db, generics, buf)?;
+            print_generic_args(db, generics, buf, edition)?;
 
             write!(buf, ">")?;
         }
@@ -94,12 +100,13 @@ pub(crate) fn print_generic_args(
     db: &dyn DefDatabase,
     generics: &GenericArgs,
     buf: &mut dyn Write,
+    edition: Edition,
 ) -> 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(db, self_ty, buf)?;
+        print_generic_arg(db, self_ty, buf, edition)?;
         first = false;
         args
     } else {
@@ -110,21 +117,21 @@ pub(crate) fn print_generic_args(
             write!(buf, ", ")?;
         }
         first = false;
-        print_generic_arg(db, arg, buf)?;
+        print_generic_arg(db, arg, buf, edition)?;
     }
     for binding in generics.bindings.iter() {
         if !first {
             write!(buf, ", ")?;
         }
         first = false;
-        write!(buf, "{}", binding.name.display(db.upcast()))?;
+        write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
         if !binding.bounds.is_empty() {
             write!(buf, ": ")?;
-            print_type_bounds(db, &binding.bounds, buf)?;
+            print_type_bounds(db, &binding.bounds, buf, edition)?;
         }
         if let Some(ty) = &binding.type_ref {
             write!(buf, " = ")?;
-            print_type_ref(db, ty, buf)?;
+            print_type_ref(db, ty, buf, edition)?;
         }
     }
     Ok(())
@@ -134,11 +141,12 @@ pub(crate) fn print_generic_arg(
     db: &dyn DefDatabase,
     arg: &GenericArg,
     buf: &mut dyn Write,
+    edition: Edition,
 ) -> fmt::Result {
     match arg {
-        GenericArg::Type(ty) => print_type_ref(db, ty, buf),
-        GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())),
-        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())),
+        GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
+        GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
+        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
     }
 }
 
@@ -146,6 +154,7 @@ pub(crate) fn print_type_ref(
     db: &dyn DefDatabase,
     type_ref: &TypeRef,
     buf: &mut dyn Write,
+    edition: Edition,
 ) -> fmt::Result {
     // FIXME: deduplicate with `HirDisplay` impl
     match type_ref {
@@ -157,18 +166,18 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, field, buf)?;
+                print_type_ref(db, field, buf, edition)?;
             }
             write!(buf, ")")?;
         }
-        TypeRef::Path(path) => print_path(db, path, buf)?,
+        TypeRef::Path(path) => print_path(db, path, buf, edition)?,
         TypeRef::RawPtr(pointee, mtbl) => {
             let mtbl = match mtbl {
                 Mutability::Shared => "*const",
                 Mutability::Mut => "*mut",
             };
             write!(buf, "{mtbl} ")?;
-            print_type_ref(db, pointee, buf)?;
+            print_type_ref(db, pointee, buf, edition)?;
         }
         TypeRef::Reference(pointee, lt, mtbl) => {
             let mtbl = match mtbl {
@@ -177,19 +186,19 @@ pub(crate) fn print_type_ref(
             };
             write!(buf, "&")?;
             if let Some(lt) = lt {
-                write!(buf, "{} ", lt.name.display(db.upcast()))?;
+                write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
             }
             write!(buf, "{mtbl}")?;
-            print_type_ref(db, pointee, buf)?;
+            print_type_ref(db, pointee, buf, edition)?;
         }
         TypeRef::Array(elem, len) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf)?;
-            write!(buf, "; {}]", len.display(db.upcast()))?;
+            print_type_ref(db, elem, buf, edition)?;
+            write!(buf, "; {}]", len.display(db.upcast(), edition))?;
         }
         TypeRef::Slice(elem) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf)?;
+            print_type_ref(db, elem, buf, edition)?;
             write!(buf, "]")?;
         }
         TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
@@ -208,7 +217,7 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, typeref, buf)?;
+                print_type_ref(db, typeref, buf, edition)?;
             }
             if *varargs {
                 if !args.is_empty() {
@@ -217,7 +226,7 @@ pub(crate) fn print_type_ref(
                 write!(buf, "...")?;
             }
             write!(buf, ") -> ")?;
-            print_type_ref(db, return_type, buf)?;
+            print_type_ref(db, return_type, buf, edition)?;
         }
         TypeRef::Macro(_ast_id) => {
             write!(buf, "<macro>")?;
@@ -225,11 +234,11 @@ pub(crate) fn print_type_ref(
         TypeRef::Error => write!(buf, "{{unknown}}")?,
         TypeRef::ImplTrait(bounds) => {
             write!(buf, "impl ")?;
-            print_type_bounds(db, bounds, buf)?;
+            print_type_bounds(db, bounds, buf, edition)?;
         }
         TypeRef::DynTrait(bounds) => {
             write!(buf, "dyn ")?;
-            print_type_bounds(db, bounds, buf)?;
+            print_type_bounds(db, bounds, buf, edition)?;
         }
     }
 
@@ -240,6 +249,7 @@ pub(crate) fn print_type_bounds(
     db: &dyn DefDatabase,
     bounds: &[Interned<TypeBound>],
     buf: &mut dyn Write,
+    edition: Edition,
 ) -> fmt::Result {
     for (i, bound) in bounds.iter().enumerate() {
         if i != 0 {
@@ -252,17 +262,17 @@ pub(crate) fn print_type_bounds(
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(buf, "?")?,
                 }
-                print_path(db, path, buf)?;
+                print_path(db, path, buf, edition)?;
             }
             TypeBound::ForLifetime(lifetimes, path) => {
                 write!(
                     buf,
                     "for<{}> ",
-                    lifetimes.iter().map(|it| it.display(db.upcast())).format(", ")
+                    lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
                 )?;
-                print_path(db, path, buf)?;
+                print_path(db, path, buf, edition)?;
             }
-            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?,
+            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
             TypeBound::Error => write!(buf, "{{unknown}}")?,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index 3528b2dde73..1dadfe2ba99 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -176,9 +176,10 @@ fn eager_macro_recur(
             Some(path) => match macro_resolver(&path) {
                 Some(def) => def,
                 None => {
+                    let edition = db.crate_graph()[krate].edition;
                     error = Some(ExpandError::other(
                         span_map.span_at(call.syntax().text_range().start()),
-                        format!("unresolved macro {}", path.display(db)),
+                        format!("unresolved macro {}", path.display(db, edition)),
                     ));
                     offset += call.syntax().text_range().len();
                     continue;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index 2c26fe414d9..dcf2af39979 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -14,7 +14,7 @@ use crate::{
 use base_db::CrateId;
 use intern::sym;
 use smallvec::SmallVec;
-use span::SyntaxContextId;
+use span::{Edition, SyntaxContextId};
 use syntax::{ast, AstNode};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -140,8 +140,12 @@ impl ModPath {
         UnescapedModPath(self)
     }
 
-    pub fn display<'a>(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
-        Display { db, path: self }
+    pub fn display<'a>(
+        &'a self,
+        db: &'a dyn crate::db::ExpandDatabase,
+        edition: Edition,
+    ) -> impl fmt::Display + 'a {
+        Display { db, path: self, edition }
     }
 }
 
@@ -154,11 +158,12 @@ impl Extend<Name> for ModPath {
 struct Display<'a> {
     db: &'a dyn ExpandDatabase,
     path: &'a ModPath,
+    edition: Edition,
 }
 
 impl fmt::Display for Display<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path, f, true)
+        display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition))
     }
 }
 
@@ -169,7 +174,7 @@ struct UnescapedDisplay<'a> {
 
 impl fmt::Display for UnescapedDisplay<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path.0, f, false)
+        display_fmt_path(self.db, self.path.0, f, Escape::No)
     }
 }
 
@@ -178,11 +183,17 @@ impl From<Name> for ModPath {
         ModPath::from_segments(PathKind::Plain, iter::once(name))
     }
 }
+
+enum Escape {
+    No,
+    IfNeeded(Edition),
+}
+
 fn display_fmt_path(
     db: &dyn ExpandDatabase,
     path: &ModPath,
     f: &mut fmt::Formatter<'_>,
-    escaped: bool,
+    escaped: Escape,
 ) -> fmt::Result {
     let mut first_segment = true;
     let mut add_segment = |s| -> fmt::Result {
@@ -210,10 +221,9 @@ fn display_fmt_path(
             f.write_str("::")?;
         }
         first_segment = false;
-        if escaped {
-            segment.display(db).fmt(f)?;
-        } else {
-            segment.unescaped().display(db).fmt(f)?;
+        match escaped {
+            Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?,
+            Escape::No => segment.unescaped().display(db).fmt(f)?,
         }
     }
     Ok(())
@@ -322,9 +332,11 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
         tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF,
         tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => {
             let mut deg = 1;
-            while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw })) = leaves.next() {
+            while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw: _ })) =
+                leaves.next()
+            {
                 if *text != sym::super_ {
-                    segments.push(Name::new_symbol_maybe_raw(text.clone(), *is_raw, span.ctx));
+                    segments.push(Name::new_symbol(text.clone(), span.ctx));
                     break;
                 }
                 deg += 1;
@@ -333,19 +345,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
         }
         tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate,
         tt::Leaf::Ident(ident) => {
-            segments.push(Name::new_symbol_maybe_raw(
-                ident.sym.clone(),
-                ident.is_raw,
-                ident.span.ctx,
-            ));
+            segments.push(Name::new_symbol(ident.sym.clone(), ident.span.ctx));
             PathKind::Plain
         }
         _ => return None,
     };
     segments.extend(leaves.filter_map(|leaf| match leaf {
-        ::tt::Leaf::Ident(ident) => {
-            Some(Name::new_symbol_maybe_raw(ident.sym.clone(), ident.is_raw, ident.span.ctx))
-        }
+        ::tt::Leaf::Ident(ident) => Some(Name::new_symbol(ident.sym.clone(), ident.span.ctx)),
         _ => None,
     }));
     Some(ModPath { kind, segments })
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 2a52aaba6af..54313904a7e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -3,22 +3,22 @@
 use std::fmt;
 
 use intern::{sym, Symbol};
-use span::SyntaxContextId;
-use syntax::{ast, utils::is_raw_identifier};
+use span::{Edition, SyntaxContextId};
+use syntax::ast;
+use syntax::utils::is_raw_identifier;
 
 /// `Name` is a wrapper around string, which is used in hir for both references
 /// and declarations. In theory, names should also carry hygiene info, but we are
 /// not there yet!
 ///
-/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
-/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
-/// name without "r#".
+/// Note that the rawness (`r#`) of names does not depend on whether they are written raw.
+/// This is because we want to show (in completions etc.) names as raw depending on the needs
+/// of the current crate, for example if it is edition 2021 complete `gen` even if the defining
+/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well.
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Name {
     symbol: Symbol,
     ctx: (),
-    // FIXME: We should probably encode rawness as a property here instead, once we have hygiene
-    // in here we've got 4 bytes of padding to fill anyways
 }
 
 impl fmt::Debug for Name {
@@ -42,6 +42,7 @@ impl PartialOrd for Name {
     }
 }
 
+// No need to strip `r#`, all comparisons are done against well-known symbols.
 impl PartialEq<Symbol> for Name {
     fn eq(&self, sym: &Symbol) -> bool {
         self.symbol == *sym
@@ -55,16 +56,16 @@ impl PartialEq<Name> for Symbol {
 }
 
 /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct UnescapedName<'a>(&'a Name);
 
-impl UnescapedName<'_> {
-    pub fn display(&self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + '_ {
+impl<'a> UnescapedName<'a> {
+    pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
         _ = db;
         UnescapedDisplay { name: self }
     }
     #[doc(hidden)]
-    pub fn display_no_db(&self) -> impl fmt::Display + '_ {
+    pub fn display_no_db(self) -> impl fmt::Display + 'a {
         UnescapedDisplay { name: self }
     }
 }
@@ -77,16 +78,9 @@ impl Name {
         Name { symbol: Symbol::intern(text), ctx: () }
     }
 
-    pub fn new(text: &str, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name {
+    pub fn new(text: &str, ctx: SyntaxContextId) -> Name {
         _ = ctx;
-        Name {
-            symbol: if raw.yes() {
-                Symbol::intern(&format!("{}{text}", raw.as_str()))
-            } else {
-                Symbol::intern(text)
-            },
-            ctx: (),
-        }
+        Self::new_text(text)
     }
 
     pub fn new_tuple_field(idx: usize) -> Name {
@@ -97,26 +91,9 @@ impl Name {
         Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
     }
 
-    /// Shortcut to create a name from a string literal.
-    fn new_ref(text: &str) -> Name {
-        Name { symbol: Symbol::intern(text), ctx: () }
-    }
-
     /// Resolve a name from the text of token.
     fn resolve(raw_text: &str) -> Name {
-        // FIXME: Edition
-        match raw_text.strip_prefix("r#") {
-            // When `raw_text` starts with "r#" but the name does not coincide with any
-            // keyword, we never need the prefix so we strip it.
-            Some(text) if !is_raw_identifier(text, span::Edition::CURRENT) => Name::new_ref(text),
-            // Keywords (in the current edition) *can* be used as a name in earlier editions of
-            // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
-            // escaped form.
-            None if is_raw_identifier(raw_text, span::Edition::CURRENT) => {
-                Name::new_text(&format!("r#{}", raw_text))
-            }
-            _ => Name::new_text(raw_text),
-        }
+        Name::new_text(raw_text.trim_start_matches("r#"))
     }
 
     /// A fake name for things missing in the source code.
@@ -162,19 +139,23 @@ impl Name {
         UnescapedName(self)
     }
 
-    pub fn is_escaped(&self) -> bool {
-        self.symbol.as_str().starts_with("r#")
+    pub fn is_escaped(&self, edition: Edition) -> bool {
+        is_raw_identifier(self.symbol.as_str(), edition)
     }
 
-    pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
+    pub fn display<'a>(
+        &'a self,
+        db: &dyn crate::db::ExpandDatabase,
+        edition: Edition,
+    ) -> impl fmt::Display + 'a {
         _ = db;
-        Display { name: self }
+        self.display_no_db(edition)
     }
 
     // FIXME: Remove this
     #[doc(hidden)]
-    pub fn display_no_db(&self) -> impl fmt::Display + '_ {
-        Display { name: self }
+    pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
+        Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
     }
 
     pub fn symbol(&self) -> &Symbol {
@@ -186,39 +167,39 @@ impl Name {
         Self { symbol, ctx: () }
     }
 
-    pub fn new_symbol_maybe_raw(sym: Symbol, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Self {
-        if raw.no() {
-            Self { symbol: sym, ctx: () }
-        } else {
-            Name::new(sym.as_str(), raw, ctx)
-        }
-    }
-
     // FIXME: This needs to go once we have hygiene
     pub const fn new_symbol_root(sym: Symbol) -> Self {
         Self { symbol: sym, ctx: () }
     }
+
+    #[inline]
+    pub fn eq_ident(&self, ident: &str) -> bool {
+        self.as_str() == ident.trim_start_matches("r#")
+    }
 }
 
 struct Display<'a> {
     name: &'a Name,
+    needs_escaping: bool,
 }
 
 impl fmt::Display for Display<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.needs_escaping {
+            write!(f, "r#")?;
+        }
         fmt::Display::fmt(self.name.symbol.as_str(), f)
     }
 }
 
 struct UnescapedDisplay<'a> {
-    name: &'a UnescapedName<'a>,
+    name: UnescapedName<'a>,
 }
 
 impl fmt::Display for UnescapedDisplay<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let symbol = &self.name.0.symbol.as_str();
-        let text = symbol.strip_prefix("r#").unwrap_or(symbol);
-        fmt::Display::fmt(&text, f)
+        let symbol = self.name.0.symbol.as_str();
+        fmt::Display::fmt(symbol, f)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index a151ee01e64..a3e4da5d1af 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -5,6 +5,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
 
 use hir_expand::name::Name;
 use intern::sym;
+use span::Edition;
 use tracing::debug;
 
 use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds};
@@ -424,18 +425,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
 
     fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
         let id = from_chalk_trait_id(trait_id);
-        self.db.trait_data(id).name.display(self.db.upcast()).to_string()
+        self.db.trait_data(id).name.display(self.db.upcast(), self.edition()).to_string()
     }
     fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
+        let edition = self.edition();
         match adt_id {
             hir_def::AdtId::StructId(id) => {
-                self.db.struct_data(id).name.display(self.db.upcast()).to_string()
+                self.db.struct_data(id).name.display(self.db.upcast(), edition).to_string()
             }
             hir_def::AdtId::EnumId(id) => {
-                self.db.enum_data(id).name.display(self.db.upcast()).to_string()
+                self.db.enum_data(id).name.display(self.db.upcast(), edition).to_string()
             }
             hir_def::AdtId::UnionId(id) => {
-                self.db.union_data(id).name.display(self.db.upcast()).to_string()
+                self.db.union_data(id).name.display(self.db.upcast(), edition).to_string()
             }
         }
     }
@@ -445,7 +447,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     }
     fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
         let id = self.db.associated_ty_data(assoc_ty_id).name;
-        self.db.type_alias_data(id).name.display(self.db.upcast()).to_string()
+        self.db.type_alias_data(id).name.display(self.db.upcast(), self.edition()).to_string()
     }
     fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
         format!("Opaque_{}", opaque_ty_id.0)
@@ -519,6 +521,10 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
 }
 
 impl<'a> ChalkContext<'a> {
+    fn edition(&self) -> Edition {
+        self.db.crate_graph()[self.krate].edition
+    }
+
     fn for_trait_impls(
         &self,
         trait_id: hir_def::TraitId,
@@ -843,7 +849,7 @@ fn impl_def_datum(
         "impl {:?}: {}{} where {:?}",
         chalk_id,
         if negative { "!" } else { "" },
-        trait_ref.display(db),
+        trait_ref.display(db, db.crate_graph()[krate].edition),
         where_clauses
     );
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index dc3817ce3f4..a0399a06f23 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -1,3 +1,4 @@
+use base_db::SourceDatabase;
 use chalk_ir::Substitution;
 use hir_def::db::DefDatabase;
 use rustc_apfloat::{
@@ -94,9 +95,10 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
 fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
+    let edition = db.crate_graph()[db.test_crate()].edition;
     match e {
-        ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter),
-        ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter),
+        ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
+        ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition),
     }
     .unwrap();
     err
@@ -110,7 +112,9 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const, ConstEvalEr
         .declarations()
         .find_map(|x| match x {
             hir_def::ModuleDefId::ConstId(x) => {
-                if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" {
+                if db.const_data(x).name.as_ref()?.display(db, file_id.edition()).to_string()
+                    == "GOAL"
+                {
                     Some(x)
                 } else {
                     None
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index b0934400608..024fc32f863 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -17,17 +17,18 @@ use std::fmt;
 
 use hir_def::{
     data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId,
-    EnumId, EnumVariantId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId,
-    StructId, TraitId, TypeAliasId,
+    EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId,
+    StaticId, StructId, TraitId, TypeAliasId,
 };
 use hir_expand::{
     name::{AsName, Name},
-    HirFileId, MacroFileIdExt,
+    HirFileId, HirFileIdExt, MacroFileIdExt,
 };
 use intern::sym;
 use stdx::{always, never};
 use syntax::{
     ast::{self, HasName},
+    utils::is_raw_identifier,
     AstNode, AstPtr, ToSmolStr,
 };
 
@@ -318,17 +319,21 @@ impl<'a> DeclValidator<'a> {
     /// This includes function parameters except for trait implementation associated functions.
     fn validate_func_body(&mut self, func: FunctionId) {
         let body = self.db.body(func.into());
+        let edition = self.edition(func);
         let mut pats_replacements = body
             .pats
             .iter()
             .filter_map(|(pat_id, pat)| match pat {
                 Pat::Bind { id, .. } => {
                     let bind_name = &body.bindings[*id].name;
+                    let mut suggested_text =
+                        to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?;
+                    if is_raw_identifier(&suggested_text, edition) {
+                        suggested_text.insert_str(0, "r#");
+                    }
                     let replacement = Replacement {
                         current_name: bind_name.clone(),
-                        suggested_text: to_lower_snake_case(
-                            &bind_name.display_no_db().to_smolstr(),
-                        )?,
+                        suggested_text,
                         expected_case: CaseType::LowerSnakeCase,
                     };
                     Some((pat_id, replacement))
@@ -377,6 +382,11 @@ impl<'a> DeclValidator<'a> {
         }
     }
 
+    fn edition(&self, id: impl HasModule) -> span::Edition {
+        let krate = id.krate(self.db.upcast());
+        self.db.crate_graph()[krate].edition
+    }
+
     fn validate_struct(&mut self, struct_id: StructId) {
         // Check the structure name.
         let non_camel_case_allowed =
@@ -405,16 +415,17 @@ impl<'a> DeclValidator<'a> {
         let VariantData::Record(fields) = data.variant_data.as_ref() else {
             return;
         };
+        let edition = self.edition(struct_id);
         let mut struct_fields_replacements = fields
             .iter()
             .filter_map(|(_, field)| {
-                to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| {
-                    Replacement {
+                to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
+                    |new_name| Replacement {
                         current_name: field.name.clone(),
                         suggested_text: new_name,
                         expected_case: CaseType::LowerSnakeCase,
-                    }
-                })
+                    },
+                )
             })
             .peekable();
 
@@ -498,14 +509,17 @@ impl<'a> DeclValidator<'a> {
             self.validate_enum_variant_fields(*variant_id);
         }
 
+        let edition = self.edition(enum_id);
         let mut enum_variants_replacements = data
             .variants
             .iter()
             .filter_map(|(_, name)| {
-                to_camel_case(&name.display_no_db().to_smolstr()).map(|new_name| Replacement {
-                    current_name: name.clone(),
-                    suggested_text: new_name,
-                    expected_case: CaseType::UpperCamelCase,
+                to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| {
+                    Replacement {
+                        current_name: name.clone(),
+                        suggested_text: new_name,
+                        expected_case: CaseType::UpperCamelCase,
+                    }
                 })
             })
             .peekable();
@@ -566,16 +580,17 @@ impl<'a> DeclValidator<'a> {
         let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
             return;
         };
+        let edition = self.edition(variant_id);
         let mut variant_field_replacements = fields
             .iter()
             .filter_map(|(_, field)| {
-                to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| {
-                    Replacement {
+                to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
+                    |new_name| Replacement {
                         current_name: field.name.clone(),
                         suggested_text: new_name,
                         expected_case: CaseType::LowerSnakeCase,
-                    }
-                })
+                    },
+                )
             })
             .peekable();
 
@@ -704,18 +719,22 @@ impl<'a> DeclValidator<'a> {
     ) where
         N: AstNode + HasName + fmt::Debug,
         S: HasSource<Value = N>,
-        L: Lookup<Data = S, Database<'a> = dyn DefDatabase + 'a>,
+        L: Lookup<Data = S, Database<'a> = dyn DefDatabase + 'a> + HasModule + Copy,
     {
         let to_expected_case_type = match expected_case {
             CaseType::LowerSnakeCase => to_lower_snake_case,
             CaseType::UpperSnakeCase => to_upper_snake_case,
             CaseType::UpperCamelCase => to_camel_case,
         };
-        let Some(replacement) =
-            to_expected_case_type(&name.display(self.db.upcast()).to_smolstr()).map(|new_name| {
-                Replacement { current_name: name.clone(), suggested_text: new_name, expected_case }
-            })
-        else {
+        let edition = self.edition(item_id);
+        let Some(replacement) = to_expected_case_type(
+            &name.display(self.db.upcast(), edition).to_smolstr(),
+        )
+        .map(|new_name| Replacement {
+            current_name: name.clone(),
+            suggested_text: new_name,
+            expected_case,
+        }) else {
             return;
         };
 
@@ -748,12 +767,13 @@ impl<'a> DeclValidator<'a> {
             return;
         };
 
+        let edition = file_id.original_file(self.db.upcast()).edition();
         let diagnostic = IncorrectCase {
             file: file_id,
             ident_type,
             ident: AstPtr::new(&name_ast),
             expected_case: replacement.expected_case,
-            ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
+            ident_text: replacement.current_name.display(self.db.upcast(), edition).to_string(),
             suggested_text: replacement.suggested_text,
         };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 6e5a7cce9c9..f8b5c7d0ce2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -4,6 +4,7 @@
 
 use std::fmt;
 
+use base_db::CrateId;
 use chalk_solve::rust_ir::AdtKind;
 use either::Either;
 use hir_def::{
@@ -15,6 +16,7 @@ use intern::sym;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::constructor::Constructor;
+use span::Edition;
 use syntax::{
     ast::{self, UnaryOp},
     AstNode,
@@ -258,7 +260,13 @@ impl ExprValidator {
         if !witnesses.is_empty() {
             self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
                 match_expr,
-                uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, m_arms.is_empty()),
+                uncovered_patterns: missing_match_arms(
+                    &cx,
+                    scrut_ty,
+                    witnesses,
+                    m_arms.is_empty(),
+                    self.owner.krate(db.upcast()),
+                ),
             });
         }
     }
@@ -345,7 +353,13 @@ impl ExprValidator {
             if !witnesses.is_empty() {
                 self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet {
                     pat,
-                    uncovered_patterns: missing_match_arms(&cx, ty, witnesses, false),
+                    uncovered_patterns: missing_match_arms(
+                        &cx,
+                        ty,
+                        witnesses,
+                        false,
+                        self.owner.krate(db.upcast()),
+                    ),
                 });
             }
         }
@@ -616,24 +630,26 @@ fn missing_match_arms<'p>(
     scrut_ty: &Ty,
     witnesses: Vec<WitnessPat<'p>>,
     arms_is_empty: bool,
+    krate: CrateId,
 ) -> String {
-    struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>);
+    struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, Edition);
     impl fmt::Display for DisplayWitness<'_, '_> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            let DisplayWitness(witness, cx) = *self;
+            let DisplayWitness(witness, cx, edition) = *self;
             let pat = cx.hoist_witness_pat(witness);
-            write!(f, "{}", pat.display(cx.db))
+            write!(f, "{}", pat.display(cx.db, edition))
         }
     }
 
+    let edition = cx.db.crate_graph()[krate].edition;
     let non_empty_enum = match scrut_ty.as_adt() {
         Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
         _ => false,
     };
     if arms_is_empty && !non_empty_enum {
-        format!("type `{}` is non-empty", scrut_ty.display(cx.db))
+        format!("type `{}` is non-empty", scrut_ty.display(cx.db, edition))
     } else {
-        let pat_display = |witness| DisplayWitness(witness, cx);
+        let pat_display = |witness| DisplayWitness(witness, cx, edition);
         const LIMIT: usize = 3;
         match &*witnesses {
             [witness] => format!("`{}` not covered", pat_display(witness)),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index a0ee7c0748b..4bc07bc9ec8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -14,6 +14,7 @@ use hir_def::{
     body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId,
 };
 use hir_expand::name::Name;
+use span::Edition;
 use stdx::{always, never};
 
 use crate::{
@@ -151,7 +152,11 @@ impl<'a> PatCtxt<'a> {
                 match (bm, ty.kind(Interner)) {
                     (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty,
                     (BindingMode::Ref(_), _) => {
-                        never!("`ref {}` has wrong type {:?}", name.display(self.db.upcast()), ty);
+                        never!(
+                            "`ref {}` has wrong type {:?}",
+                            name.display(self.db.upcast(), Edition::LATEST),
+                            ty
+                        );
                         self.errors.push(PatternError::UnexpectedType);
                         return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
                     }
@@ -297,7 +302,7 @@ impl HirDisplay for Pat {
             PatKind::Wild => write!(f, "_"),
             PatKind::Never => write!(f, "!"),
             PatKind::Binding { name, subpattern } => {
-                write!(f, "{}", name.display(f.db.upcast()))?;
+                write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                 if let Some(subpattern) = subpattern {
                     write!(f, " @ ")?;
                     subpattern.hir_fmt(f)?;
@@ -317,14 +322,22 @@ impl HirDisplay for Pat {
                 if let Some(variant) = variant {
                     match variant {
                         VariantId::EnumVariantId(v) => {
-                            write!(f, "{}", f.db.enum_variant_data(v).name.display(f.db.upcast()))?;
-                        }
-                        VariantId::StructId(s) => {
-                            write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))?
-                        }
-                        VariantId::UnionId(u) => {
-                            write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))?
+                            write!(
+                                f,
+                                "{}",
+                                f.db.enum_variant_data(v).name.display(f.db.upcast(), f.edition())
+                            )?;
                         }
+                        VariantId::StructId(s) => write!(
+                            f,
+                            "{}",
+                            f.db.struct_data(s).name.display(f.db.upcast(), f.edition())
+                        )?,
+                        VariantId::UnionId(u) => write!(
+                            f,
+                            "{}",
+                            f.db.union_data(u).name.display(f.db.upcast(), f.edition())
+                        )?,
                     };
 
                     let variant_data = variant.variant_data(f.db.upcast());
@@ -341,7 +354,9 @@ impl HirDisplay for Pat {
                                     write!(
                                         f,
                                         "{}: ",
-                                        rec_fields[p.field].name.display(f.db.upcast())
+                                        rec_fields[p.field]
+                                            .name
+                                            .display(f.db.upcast(), f.edition())
                                     )?;
                                     p.pattern.hir_fmt(f)
                                 })
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 5a96d396ab8..4ef053130a8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -33,6 +33,7 @@ use rustc_apfloat::{
     Float,
 };
 use smallvec::SmallVec;
+use span::Edition;
 use stdx::{never, IsNoneOr};
 use triomphe::Arc;
 
@@ -131,7 +132,11 @@ pub trait HirDisplay {
 
     /// Returns a `Display`able type that is human-readable.
     /// Use this for showing types to the user (e.g. diagnostics)
-    fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
+    fn display<'a>(
+        &'a self,
+        db: &'a dyn HirDatabase,
+        edition: Edition,
+    ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
     {
@@ -142,7 +147,7 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics,
+            display_target: DisplayTarget::Diagnostics { edition },
             show_container_bounds: false,
         }
     }
@@ -153,6 +158,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         max_size: Option<usize>,
+        edition: Edition,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -164,7 +170,7 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics,
+            display_target: DisplayTarget::Diagnostics { edition },
             show_container_bounds: false,
         }
     }
@@ -175,6 +181,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         limited_size: Option<usize>,
+        edition: Edition,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -186,7 +193,7 @@ pub trait HirDisplay {
             limited_size,
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics,
+            display_target: DisplayTarget::Diagnostics { edition },
             show_container_bounds: false,
         }
     }
@@ -242,6 +249,7 @@ pub trait HirDisplay {
         &'a self,
         db: &'a dyn HirDatabase,
         show_container_bounds: bool,
+        edition: Edition,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -253,13 +261,23 @@ pub trait HirDisplay {
             limited_size: None,
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics,
+            display_target: DisplayTarget::Diagnostics { edition },
             show_container_bounds,
         }
     }
 }
 
 impl HirFormatter<'_> {
+    pub fn edition(&self) -> Edition {
+        match self.display_target {
+            DisplayTarget::Diagnostics { edition } => edition,
+            DisplayTarget::SourceCode { module_id, .. } => {
+                self.db.crate_graph()[module_id.krate()].edition
+            }
+            DisplayTarget::Test => Edition::CURRENT,
+        }
+    }
+
     pub fn write_joined<T: HirDisplay>(
         &mut self,
         iter: impl IntoIterator<Item = T>,
@@ -324,7 +342,7 @@ pub enum DisplayTarget {
     /// Display types for inlays, doc popups, autocompletion, etc...
     /// Showing `{unknown}` or not qualifying paths is fine here.
     /// There's no reason for this to fail.
-    Diagnostics,
+    Diagnostics { edition: Edition },
     /// Display types for inserting them in source files.
     /// The generated code should compile, so paths need to be qualified.
     SourceCode { module_id: ModuleId, allow_opaque: bool },
@@ -460,7 +478,7 @@ impl HirDisplay for ProjectionTy {
             ">::{}",
             f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id))
                 .name
-                .display(f.db.upcast())
+                .display(f.db.upcast(), f.edition())
         )?;
         let proj_params_count =
             self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
@@ -499,7 +517,7 @@ impl HirDisplay for Const {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
                 let param_data = &generics[id.local_id];
-                write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?;
+                write!(f, "{}", param_data.name().unwrap().display(f.db.upcast(), f.edition()))?;
                 Ok(())
             }
             ConstValue::Concrete(c) => match &c.interned {
@@ -633,7 +651,7 @@ fn render_const_scalar(
             TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 {
                 hir_def::AdtId::StructId(s) => {
                     let data = f.db.struct_data(s);
-                    write!(f, "&{}", data.name.display(f.db.upcast()))?;
+                    write!(f, "&{}", data.name.display(f.db.upcast(), f.edition()))?;
                     Ok(())
                 }
                 _ => f.write_str("<unsized-enum-or-union>"),
@@ -691,7 +709,7 @@ fn render_const_scalar(
             match adt.0 {
                 hir_def::AdtId::StructId(s) => {
                     let data = f.db.struct_data(s);
-                    write!(f, "{}", data.name.display(f.db.upcast()))?;
+                    write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
                     let field_types = f.db.field_types(s.into());
                     render_variant_after_name(
                         &data.variant_data,
@@ -705,7 +723,7 @@ fn render_const_scalar(
                     )
                 }
                 hir_def::AdtId::UnionId(u) => {
-                    write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))
+                    write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast(), f.edition()))
                 }
                 hir_def::AdtId::EnumId(e) => {
                     let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else {
@@ -717,7 +735,7 @@ fn render_const_scalar(
                         return f.write_str("<failed-to-detect-variant>");
                     };
                     let data = f.db.enum_variant_data(var_id);
-                    write!(f, "{}", data.name.display(f.db.upcast()))?;
+                    write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
                     let field_types = f.db.field_types(var_id.into());
                     render_variant_after_name(
                         &data.variant_data,
@@ -802,11 +820,11 @@ fn render_variant_after_name(
             if matches!(data, VariantData::Record(_)) {
                 write!(f, " {{")?;
                 if let Some((id, data)) = it.next() {
-                    write!(f, " {}: ", data.name.display(f.db.upcast()))?;
+                    write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
                     render_field(f, id)?;
                 }
                 for (id, data) in it {
-                    write!(f, ", {}: ", data.name.display(f.db.upcast()))?;
+                    write!(f, ", {}: ", data.name.display(f.db.upcast(), f.edition()))?;
                     render_field(f, id)?;
                 }
                 write!(f, " }}")?;
@@ -1000,15 +1018,23 @@ impl HirDisplay for Ty {
                     CallableDefId::FunctionId(ff) => {
                         write!(f, "fn ")?;
                         f.start_location_link(def.into());
-                        write!(f, "{}", db.function_data(ff).name.display(f.db.upcast()))?
+                        write!(
+                            f,
+                            "{}",
+                            db.function_data(ff).name.display(f.db.upcast(), f.edition())
+                        )?
                     }
                     CallableDefId::StructId(s) => {
                         f.start_location_link(def.into());
-                        write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))?
+                        write!(f, "{}", db.struct_data(s).name.display(f.db.upcast(), f.edition()))?
                     }
                     CallableDefId::EnumVariantId(e) => {
                         f.start_location_link(def.into());
-                        write!(f, "{}", db.enum_variant_data(e).name.display(f.db.upcast()))?
+                        write!(
+                            f,
+                            "{}",
+                            db.enum_variant_data(e).name.display(f.db.upcast(), f.edition())
+                        )?
                     }
                 };
                 f.end_location_link();
@@ -1053,13 +1079,13 @@ impl HirDisplay for Ty {
             TyKind::Adt(AdtId(def_id), parameters) => {
                 f.start_location_link((*def_id).into());
                 match f.display_target {
-                    DisplayTarget::Diagnostics | DisplayTarget::Test => {
+                    DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
                         let name = match *def_id {
                             hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
                             hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
                             hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
                         };
-                        write!(f, "{}", name.display(f.db.upcast()))?;
+                        write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                     }
                     DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
                         if let Some(path) = find_path::find_path(
@@ -1075,7 +1101,7 @@ impl HirDisplay for Ty {
                                 prefer_absolute: false,
                             },
                         ) {
-                            write!(f, "{}", path.display(f.db.upcast()))?;
+                            write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
                         } else {
                             return Err(HirDisplayError::DisplaySourceCodeError(
                                 DisplaySourceCodeError::PathNotFound,
@@ -1101,12 +1127,12 @@ impl HirDisplay for Ty {
                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
                 if f.display_target.is_test() {
                     f.start_location_link(trait_.into());
-                    write!(f, "{}", trait_data.name.display(f.db.upcast()))?;
+                    write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?;
                     f.end_location_link();
                     write!(f, "::")?;
 
                     f.start_location_link(type_alias.into());
-                    write!(f, "{}", type_alias_data.name.display(f.db.upcast()))?;
+                    write!(f, "{}", type_alias_data.name.display(f.db.upcast(), f.edition()))?;
                     f.end_location_link();
                     // Note that the generic args for the associated type come before those for the
                     // trait (including the self type).
@@ -1124,7 +1150,7 @@ impl HirDisplay for Ty {
                 let alias = from_foreign_def_id(*type_alias);
                 let type_alias = db.type_alias_data(alias);
                 f.start_location_link(alias.into());
-                write!(f, "{}", type_alias.name.display(f.db.upcast()))?;
+                write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
                 f.end_location_link();
             }
             TyKind::OpaqueType(opaque_ty_id, parameters) => {
@@ -1256,7 +1282,10 @@ impl HirDisplay for Ty {
                             write!(
                                 f,
                                 "{}",
-                                p.name.clone().unwrap_or_else(Name::missing).display(f.db.upcast())
+                                p.name
+                                    .clone()
+                                    .unwrap_or_else(Name::missing)
+                                    .display(f.db.upcast(), f.edition())
                             )?
                         }
                         TypeParamProvenance::ArgumentImplTrait => {
@@ -1289,7 +1318,7 @@ impl HirDisplay for Ty {
                         }
                     },
                     TypeOrConstParamData::ConstParamData(p) => {
-                        write!(f, "{}", p.name.display(f.db.upcast()))?;
+                        write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?;
                     }
                 }
             }
@@ -1632,7 +1661,7 @@ fn write_bounds_like_dyn_trait(
                 // existential) here, which is the only thing that's
                 // possible in actual Rust, and hence don't print it
                 f.start_location_link(trait_.into());
-                write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
+                write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
                 f.end_location_link();
                 if is_fn_trait {
                     if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
@@ -1706,7 +1735,7 @@ fn write_bounds_like_dyn_trait(
                     let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
                     let type_alias = f.db.type_alias_data(assoc_ty_id);
                     f.start_location_link(assoc_ty_id.into());
-                    write!(f, "{}", type_alias.name.display(f.db.upcast()))?;
+                    write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
                     f.end_location_link();
 
                     let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
@@ -1770,7 +1799,7 @@ fn fmt_trait_ref(
     }
     let trait_ = tr.hir_trait_id();
     f.start_location_link(trait_.into());
-    write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
+    write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
     f.end_location_link();
     let substs = tr.substitution.as_slice(Interner);
     hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
@@ -1796,7 +1825,11 @@ impl HirDisplay for WhereClause {
                 write!(f, ">::",)?;
                 let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
                 f.start_location_link(type_alias.into());
-                write!(f, "{}", f.db.type_alias_data(type_alias).name.display(f.db.upcast()),)?;
+                write!(
+                    f,
+                    "{}",
+                    f.db.type_alias_data(type_alias).name.display(f.db.upcast(), f.edition()),
+                )?;
                 f.end_location_link();
                 write!(f, " = ")?;
                 ty.hir_fmt(f)?;
@@ -1832,7 +1865,7 @@ impl HirDisplay for LifetimeData {
                 let id = lt_from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
                 let param_data = &generics[id.local_id];
-                write!(f, "{}", param_data.name.display(f.db.upcast()))?;
+                write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?;
                 Ok(())
             }
             _ if f.display_target.is_source_code() => write!(f, "'_"),
@@ -1913,7 +1946,7 @@ impl HirDisplay for TypeRef {
                 };
                 write!(f, "&")?;
                 if let Some(lifetime) = lifetime {
-                    write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
+                    write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
                 write!(f, "{mutability}")?;
                 inner.hir_fmt(f)?;
@@ -1921,7 +1954,7 @@ impl HirDisplay for TypeRef {
             TypeRef::Array(inner, len) => {
                 write!(f, "[")?;
                 inner.hir_fmt(f)?;
-                write!(f, "; {}]", len.display(f.db.upcast()))?;
+                write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
             }
             TypeRef::Slice(inner) => {
                 write!(f, "[")?;
@@ -1942,7 +1975,7 @@ impl HirDisplay for TypeRef {
                     for index in 0..function_parameters.len() {
                         let (param_name, param_type) = &function_parameters[index];
                         if let Some(name) = param_name {
-                            write!(f, "{}: ", name.display(f.db.upcast()))?;
+                            write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
                         }
 
                         param_type.hir_fmt(f)?;
@@ -2000,12 +2033,15 @@ impl HirDisplay for TypeBound {
                 }
                 path.hir_fmt(f)
             }
-            TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name.display(f.db.upcast())),
+            TypeBound::Lifetime(lifetime) => {
+                write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
+            }
             TypeBound::ForLifetime(lifetimes, path) => {
+                let edition = f.edition();
                 write!(
                     f,
                     "for<{}> ",
-                    lifetimes.iter().map(|it| it.display(f.db.upcast())).format(", ")
+                    lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
                 )?;
                 path.hir_fmt(f)
             }
@@ -2071,7 +2107,7 @@ impl HirDisplay for Path {
             if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
                 write!(f, "::")?;
             }
-            write!(f, "{}", segment.name.display(f.db.upcast()))?;
+            write!(f, "{}", segment.name.display(f.db.upcast(), f.edition()))?;
             if let Some(generic_args) = segment.args_and_bindings {
                 // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
                 // Do we actually format expressions?
@@ -2116,7 +2152,7 @@ impl HirDisplay for Path {
                     } else {
                         write!(f, ", ")?;
                     }
-                    write!(f, "{}", binding.name.display(f.db.upcast()))?;
+                    write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?;
                     match &binding.type_ref {
                         Some(ty) => {
                             write!(f, " = ")?;
@@ -2150,9 +2186,11 @@ impl HirDisplay for hir_def::path::GenericArg {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         match self {
             hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
-            hir_def::path::GenericArg::Const(c) => write!(f, "{}", c.display(f.db.upcast())),
+            hir_def::path::GenericArg::Const(c) => {
+                write!(f, "{}", c.display(f.db.upcast(), f.edition()))
+            }
             hir_def::path::GenericArg::Lifetime(lifetime) => {
-                write!(f, "{}", lifetime.name.display(f.db.upcast()))
+                write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 034ed2d691b..03072790d02 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -255,7 +255,9 @@ impl CapturedItem {
 
     pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
         let body = db.body(owner);
-        let mut result = body[self.place.local].name.display(db.upcast()).to_string();
+        let krate = owner.krate(db.upcast());
+        let edition = db.crate_graph()[krate].edition;
+        let mut result = body[self.place.local].name.display(db.upcast(), edition).to_string();
         let mut field_need_paren = false;
         for proj in &self.place.projections {
             match proj {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 8cb428a610a..f40d508f755 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -42,19 +42,20 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
                 hir_def::ModuleDefId::AdtId(x) => {
                     let name = match x {
                         hir_def::AdtId::StructId(x) => {
-                            db.struct_data(x).name.display_no_db().to_smolstr()
+                            db.struct_data(x).name.display_no_db(file_id.edition()).to_smolstr()
                         }
                         hir_def::AdtId::UnionId(x) => {
-                            db.union_data(x).name.display_no_db().to_smolstr()
+                            db.union_data(x).name.display_no_db(file_id.edition()).to_smolstr()
                         }
                         hir_def::AdtId::EnumId(x) => {
-                            db.enum_data(x).name.display_no_db().to_smolstr()
+                            db.enum_data(x).name.display_no_db(file_id.edition()).to_smolstr()
                         }
                     };
                     (name == "Goal").then_some(Either::Left(x))
                 }
                 hir_def::ModuleDefId::TypeAliasId(x) => {
-                    let name = db.type_alias_data(x).name.display_no_db().to_smolstr();
+                    let name =
+                        db.type_alias_data(x).name.display_no_db(file_id.edition()).to_smolstr();
                     (name == "Goal").then_some(Either::Right(x))
                 }
                 _ => None,
@@ -94,7 +95,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
         .declarations()
         .find_map(|x| match x {
             hir_def::ModuleDefId::FunctionId(x) => {
-                let name = db.function_data(x).name.display_no_db().to_smolstr();
+                let name = db.function_data(x).name.display_no_db(file_id.edition()).to_smolstr();
                 (name == "main").then_some(x)
             }
             _ => None,
@@ -104,7 +105,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
     let b = hir_body
         .bindings
         .iter()
-        .find(|x| x.1.name.display_no_db().to_smolstr() == "goal")
+        .find(|x| x.1.name.display_no_db(file_id.edition()).to_smolstr() == "goal")
         .unwrap()
         .0;
     let infer = db.infer(function_id.into());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 4c9e0a1e118..46611ae0de9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -66,6 +66,7 @@ use intern::{sym, Symbol};
 use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
 use rustc_hash::{FxHashMap, FxHashSet};
+use span::Edition;
 use syntax::ast::{make, ConstArg};
 use traits::FnTrait;
 use triomphe::Arc;
@@ -1025,7 +1026,11 @@ where
     collector.placeholders.into_iter().collect()
 }
 
-pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstArg> {
+pub fn known_const_to_ast(
+    konst: &Const,
+    db: &dyn HirDatabase,
+    edition: Edition,
+) -> Option<ConstArg> {
     if let ConstValue::Concrete(c) = &konst.interned().value {
         match c.interned {
             ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
@@ -1035,5 +1040,5 @@ pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstAr
             _ => (),
         }
     }
-    Some(make::expr_const_value(konst.display(db).to_string().as_str()))
+    Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 06a4236e0ac..9c727cb4ed1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -158,7 +158,10 @@ impl<V, T> ProjectionElem<V, T> {
                     subst.at(Interner, 0).assert_ty_ref(Interner).clone()
                 }
                 _ => {
-                    never!("Overloaded deref on type {} is not a projection", base.display(db));
+                    never!(
+                        "Overloaded deref on type {} is not a projection",
+                        base.display(db, db.crate_graph()[krate].edition)
+                    );
                     TyKind::Error.intern(Interner)
                 }
             },
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index f8083e89858..590cb3952ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -23,7 +23,7 @@ use rustc_apfloat::{
     Float,
 };
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::FileId;
+use span::{Edition, FileId};
 use stdx::never;
 use syntax::{SyntaxNodePtr, TextRange};
 use triomphe::Arc;
@@ -358,6 +358,7 @@ impl MirEvalError {
         f: &mut String,
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
+        edition: Edition,
     ) -> std::result::Result<(), std::fmt::Error> {
         writeln!(f, "Mir eval error:")?;
         let mut err = self;
@@ -370,7 +371,7 @@ impl MirEvalError {
                         writeln!(
                             f,
                             "In function {} ({:?})",
-                            function_name.name.display(db.upcast()),
+                            function_name.name.display(db.upcast(), edition),
                             func
                         )?;
                     }
@@ -415,7 +416,7 @@ impl MirEvalError {
                 write!(
                     f,
                     "Layout for type `{}` is not available due {err:?}",
-                    ty.display(db).with_closure_style(ClosureStyle::ClosureWithId)
+                    ty.display(db, edition).with_closure_style(ClosureStyle::ClosureWithId)
                 )?;
             }
             MirEvalError::MirLowerError(func, err) => {
@@ -423,16 +424,17 @@ impl MirEvalError {
                 writeln!(
                     f,
                     "MIR lowering for function `{}` ({:?}) failed due:",
-                    function_name.name.display(db.upcast()),
+                    function_name.name.display(db.upcast(), edition),
                     func
                 )?;
-                err.pretty_print(f, db, span_formatter)?;
+                err.pretty_print(f, db, span_formatter, edition)?;
             }
             MirEvalError::ConstEvalError(name, err) => {
                 MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
                     f,
                     db,
                     span_formatter,
+                    edition,
                 )?;
             }
             MirEvalError::UndefinedBehavior(_)
@@ -2675,10 +2677,11 @@ impl Evaluator<'_> {
                 let db = self.db.upcast();
                 let loc = variant.lookup(db);
                 let enum_loc = loc.parent.lookup(db);
+                let edition = self.db.crate_graph()[self.crate_id].edition;
                 let name = format!(
                     "{}::{}",
-                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
-                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
+                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
+                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
                 );
                 Err(MirEvalError::ConstEvalError(name, Box::new(e)))
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index d76f5381871..0cdad74a4f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -856,7 +856,11 @@ impl Evaluator<'_> {
                     Ok(ty_name) => ty_name,
                     // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
                     // render full paths.
-                    Err(_) => ty.display(self.db).to_string(),
+                    Err(_) => {
+                        let krate = locals.body.owner.krate(self.db.upcast());
+                        let edition = self.db.crate_graph()[krate].edition;
+                        ty.display(self.db, edition).to_string()
+                    }
                 };
                 let len = ty_name.len();
                 let addr = self.heap_allocate(len, 1)?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index b21a401fa76..371a5278dc9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -1,5 +1,5 @@
 use hir_def::db::DefDatabase;
-use span::EditionedFileId;
+use span::{Edition, EditionedFileId};
 use syntax::{TextRange, TextSize};
 use test_fixture::WithFixture;
 
@@ -15,7 +15,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
         .declarations()
         .find_map(|x| match x {
             hir_def::ModuleDefId::FunctionId(x) => {
-                if db.function_data(x).name.display(db).to_string() == "main" {
+                if db.function_data(x).name.display(db, Edition::CURRENT).to_string() == "main" {
                     Some(x)
                 } else {
                     None
@@ -63,7 +63,7 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr
             let span_formatter = |file, range: TextRange| {
                 format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end()))
             };
-            e.pretty_print(&mut err, &db, span_formatter).unwrap();
+            e.pretty_print(&mut err, &db, span_formatter, Edition::CURRENT).unwrap();
             panic!("Error in interpreting: {err}");
         }
         Ok((stdout, stderr)) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 9aa2eeebc17..a15549f9f9b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -21,7 +21,7 @@ use hir_expand::name::Name;
 use la_arena::ArenaMap;
 use rustc_apfloat::Float;
 use rustc_hash::FxHashMap;
-use span::FileId;
+use span::{Edition, FileId};
 use syntax::TextRange;
 use triomphe::Arc;
 
@@ -157,13 +157,18 @@ impl MirLowerError {
         f: &mut String,
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
+        edition: Edition,
     ) -> std::result::Result<(), std::fmt::Error> {
         match self {
             MirLowerError::ConstEvalError(name, e) => {
                 writeln!(f, "In evaluating constant {name}")?;
                 match &**e {
-                    ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter)?,
-                    ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?,
+                    ConstEvalError::MirLowerError(e) => {
+                        e.pretty_print(f, db, span_formatter, edition)?
+                    }
+                    ConstEvalError::MirEvalError(e) => {
+                        e.pretty_print(f, db, span_formatter, edition)?
+                    }
                 }
             }
             MirLowerError::MissingFunctionDefinition(owner, it) => {
@@ -171,15 +176,15 @@ impl MirLowerError {
                 writeln!(
                     f,
                     "Missing function definition for {}",
-                    body.pretty_print_expr(db.upcast(), *owner, *it)
+                    body.pretty_print_expr(db.upcast(), *owner, *it, edition)
                 )?;
             }
             MirLowerError::TypeMismatch(e) => match e {
                 Some(e) => writeln!(
                     f,
                     "Type mismatch: Expected {}, found {}",
-                    e.expected.display(db),
-                    e.actual.display(db),
+                    e.expected.display(db, edition),
+                    e.actual.display(db, edition),
                 )?,
                 None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
             },
@@ -189,11 +194,11 @@ impl MirLowerError {
                 writeln!(
                     f,
                     "Generic arg not provided for {}",
-                    param.name().unwrap_or(&Name::missing()).display(db.upcast())
+                    param.name().unwrap_or(&Name::missing()).display(db.upcast(), edition)
                 )?;
                 writeln!(f, "Provided args: [")?;
                 for g in subst.iter(Interner) {
-                    write!(f, "    {},", g.display(db))?;
+                    write!(f, "    {},", g.display(db, edition))?;
                 }
                 writeln!(f, "]")?;
             }
@@ -242,8 +247,8 @@ impl From<LayoutError> for MirLowerError {
 }
 
 impl MirLowerError {
-    fn unresolved_path(db: &dyn HirDatabase, p: &Path) -> Self {
-        Self::UnresolvedName(p.display(db).to_string())
+    fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
+        Self::UnresolvedName(p.display(db, edition).to_string())
     }
 }
 
@@ -436,7 +441,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
                             VariantId::UnionId(_) => implementation_error!("Union variant as path"),
                         }
                     } else {
-                        let unresolved_name = || MirLowerError::unresolved_path(self.db, p);
+                        let unresolved_name =
+                            || MirLowerError::unresolved_path(self.db, p, self.edition());
                         let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
                         resolver
                             .resolve_path_in_value_ns_fully(self.db.upcast(), p)
@@ -662,7 +668,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 let (func_id, generic_args) =
                     self.infer.method_resolution(expr_id).ok_or_else(|| {
                         MirLowerError::UnresolvedMethod(
-                            method_name.display(self.db.upcast()).to_string(),
+                            method_name.display(self.db.upcast(), self.edition()).to_string(),
                         )
                     })?;
                 let func = Operand::from_fn(self.db, func_id, generic_args);
@@ -803,7 +809,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 };
                 let variant_id =
                     self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
-                        Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()),
+                        Some(p) => MirLowerError::UnresolvedName(
+                            p.display(self.db, self.edition()).to_string(),
+                        ),
                         None => MirLowerError::RecordLiteralWithoutPath,
                     })?;
                 let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) {
@@ -1378,7 +1386,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         "only `char` and numeric types are allowed in range patterns"
                     ),
                 };
-                let unresolved_name = || MirLowerError::unresolved_path(self.db, c.as_ref());
+                let edition = self.edition();
+                let unresolved_name =
+                    || MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
                 let resolver = self.owner.resolver(self.db.upcast());
                 let pr = resolver
                     .resolve_path_in_value_ns(self.db.upcast(), c.as_ref())
@@ -1904,19 +1914,25 @@ impl<'ctx> MirLowerCtx<'ctx> {
         match r {
             Ok(r) => Ok(r),
             Err(e) => {
+                let edition = self.edition();
                 let db = self.db.upcast();
                 let loc = variant.lookup(db);
                 let enum_loc = loc.parent.lookup(db);
                 let name = format!(
                     "{}::{}",
-                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
-                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
+                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition),
+                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
                 );
                 Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
             }
         }
     }
 
+    fn edition(&self) -> Edition {
+        let krate = self.owner.krate(self.db.upcast());
+        self.db.crate_graph()[krate].edition
+    }
+
     fn drop_until_scope(
         &mut self,
         scope_index: usize,
@@ -2121,18 +2137,24 @@ pub fn mir_body_for_closure_query(
 }
 
 pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<MirBody>> {
+    let krate = def.krate(db.upcast());
+    let edition = db.crate_graph()[krate].edition;
     let detail = match def {
-        DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(),
-        DefWithBodyId::StaticId(it) => db.static_data(it).name.display(db.upcast()).to_string(),
+        DefWithBodyId::FunctionId(it) => {
+            db.function_data(it).name.display(db.upcast(), edition).to_string()
+        }
+        DefWithBodyId::StaticId(it) => {
+            db.static_data(it).name.display(db.upcast(), edition).to_string()
+        }
         DefWithBodyId::ConstId(it) => db
             .const_data(it)
             .name
             .clone()
             .unwrap_or_else(Name::missing)
-            .display(db.upcast())
+            .display(db.upcast(), edition)
             .to_string(),
         DefWithBodyId::VariantId(it) => {
-            db.enum_variant_data(it).name.display(db.upcast()).to_string()
+            db.enum_variant_data(it).name.display(db.upcast(), edition).to_string()
         }
         DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 34e0f30afb7..b1c0d1f2b39 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -347,7 +347,8 @@ impl MirLowerCtx<'_> {
                         // A const don't bind anything. Only needs check.
                         return Ok((current, current_else));
                     }
-                    let unresolved_name = || MirLowerError::unresolved_path(self.db, p);
+                    let unresolved_name =
+                        || MirLowerError::unresolved_path(self.db, p, self.edition());
                     let resolver = self.owner.resolver(self.db.upcast());
                     let pr = resolver
                         .resolve_path_in_value_ns(self.db.upcast(), p)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 0c641d7c6c2..df56071aa9a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -9,6 +9,7 @@ use either::Either;
 use hir_def::{body::Body, hir::BindingId};
 use hir_expand::{name::Name, Lookup};
 use la_arena::ArenaMap;
+use span::Edition;
 
 use crate::{
     db::HirDatabase,
@@ -44,18 +45,21 @@ impl MirBody {
         ctx.for_body(|this| match ctx.body.owner {
             hir_def::DefWithBodyId::FunctionId(id) => {
                 let data = db.function_data(id);
-                w!(this, "fn {}() ", data.name.display(db.upcast()));
+                w!(this, "fn {}() ", data.name.display(db.upcast(), Edition::LATEST));
             }
             hir_def::DefWithBodyId::StaticId(id) => {
                 let data = db.static_data(id);
-                w!(this, "static {}: _ = ", data.name.display(db.upcast()));
+                w!(this, "static {}: _ = ", data.name.display(db.upcast(), Edition::LATEST));
             }
             hir_def::DefWithBodyId::ConstId(id) => {
                 let data = db.const_data(id);
                 w!(
                     this,
                     "const {}: _ = ",
-                    data.name.as_ref().unwrap_or(&Name::missing()).display(db.upcast())
+                    data.name
+                        .as_ref()
+                        .unwrap_or(&Name::missing())
+                        .display(db.upcast(), Edition::LATEST)
                 );
             }
             hir_def::DefWithBodyId::VariantId(id) => {
@@ -64,8 +68,12 @@ impl MirBody {
                 w!(
                     this,
                     "enum {}::{} = ",
-                    enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()),
-                    loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()),
+                    enum_loc.id.item_tree(db.upcast())[enum_loc.id.value]
+                        .name
+                        .display(db.upcast(), Edition::LATEST),
+                    loc.id.item_tree(db.upcast())[loc.id.value]
+                        .name
+                        .display(db.upcast(), Edition::LATEST),
                 )
             }
             hir_def::DefWithBodyId::InTypeConstId(id) => {
@@ -122,7 +130,7 @@ impl HirDisplay for LocalName {
         match self {
             LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())),
             LocalName::Binding(n, l) => {
-                write!(f, "{}_{}", n.display(f.db.upcast()), u32::from(l.into_raw()))
+                write!(f, "{}_{}", n.display(f.db.upcast(), f.edition()), u32::from(l.into_raw()))
             }
         }
     }
@@ -200,7 +208,7 @@ impl<'a> MirPrettyCtx<'a> {
             wln!(
                 self,
                 "let {}: {};",
-                self.local_name(id).display(self.db),
+                self.local_name(id).display_test(self.db),
                 self.hir_display(&local.ty)
             );
         }
@@ -231,10 +239,18 @@ impl<'a> MirPrettyCtx<'a> {
                             wln!(this, ";");
                         }
                         StatementKind::StorageDead(p) => {
-                            wln!(this, "StorageDead({})", this.local_name(*p).display(self.db));
+                            wln!(
+                                this,
+                                "StorageDead({})",
+                                this.local_name(*p).display_test(self.db)
+                            );
                         }
                         StatementKind::StorageLive(p) => {
-                            wln!(this, "StorageLive({})", this.local_name(*p).display(self.db));
+                            wln!(
+                                this,
+                                "StorageLive({})",
+                                this.local_name(*p).display_test(self.db)
+                            );
                         }
                         StatementKind::Deinit(p) => {
                             w!(this, "Deinit(");
@@ -297,7 +313,7 @@ impl<'a> MirPrettyCtx<'a> {
         fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) {
             let Some((last, head)) = projections.split_last() else {
                 // no projection
-                w!(this, "{}", this.local_name(local).display(this.db));
+                w!(this, "{}", this.local_name(local).display_test(this.db));
                 return;
             };
             match last {
@@ -317,13 +333,13 @@ impl<'a> MirPrettyCtx<'a> {
                             w!(
                                 this,
                                 " as {}).{}",
-                                variant_name.display(this.db.upcast()),
-                                name.display(this.db.upcast())
+                                variant_name.display(this.db.upcast(), Edition::LATEST),
+                                name.display(this.db.upcast(), Edition::LATEST)
                             );
                         }
                         hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => {
                             f(this, local, head);
-                            w!(this, ".{}", name.display(this.db.upcast()));
+                            w!(this, ".{}", name.display(this.db.upcast(), Edition::LATEST));
                         }
                     }
                 }
@@ -337,7 +353,7 @@ impl<'a> MirPrettyCtx<'a> {
                 }
                 ProjectionElem::Index(l) => {
                     f(this, local, head);
-                    w!(this, "[{}]", this.local_name(*l).display(this.db));
+                    w!(this, "[{}]", this.local_name(*l).display_test(this.db));
                 }
                 it => {
                     f(this, local, head);
@@ -387,7 +403,7 @@ impl<'a> MirPrettyCtx<'a> {
             Rvalue::Repeat(op, len) => {
                 w!(self, "[");
                 self.operand(op);
-                w!(self, "; {}]", len.display(self.db));
+                w!(self, "; {}]", len.display_test(self.db));
             }
             Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => {
                 w!(self, "Adt(");
@@ -458,6 +474,6 @@ impl<'a> MirPrettyCtx<'a> {
     }
 
     fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a {
-        ty.display(self.db).with_closure_style(ClosureStyle::ClosureWithSubst)
+        ty.display_test(self.db).with_closure_style(ClosureStyle::ClosureWithSubst)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
index db5fa320577..6cb59491fac 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
@@ -2,6 +2,7 @@
 use std::fmt::{self, Display};
 
 use itertools::Itertools;
+use span::Edition;
 
 use crate::{
     chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
@@ -24,7 +25,7 @@ impl DebugContext<'_> {
             AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
             AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
         };
-        name.display(self.0.upcast()).fmt(f)?;
+        name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
         Ok(())
     }
 
@@ -35,7 +36,7 @@ impl DebugContext<'_> {
     ) -> Result<(), fmt::Error> {
         let trait_: hir_def::TraitId = from_chalk_trait_id(id);
         let trait_data = self.0.trait_data(trait_);
-        trait_data.name.display(self.0.upcast()).fmt(f)?;
+        trait_data.name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
         Ok(())
     }
 
@@ -54,8 +55,8 @@ impl DebugContext<'_> {
         write!(
             fmt,
             "{}::{}",
-            trait_data.name.display(self.0.upcast()),
-            type_alias_data.name.display(self.0.upcast())
+            trait_data.name.display(self.0.upcast(), Edition::LATEST),
+            type_alias_data.name.display(self.0.upcast(), Edition::LATEST)
         )?;
         Ok(())
     }
@@ -75,7 +76,7 @@ impl DebugContext<'_> {
         let trait_ref = projection_ty.trait_ref(self.0);
         let trait_params = trait_ref.substitution.as_slice(Interner);
         let self_ty = trait_ref.self_type_parameter(Interner);
-        write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast()))?;
+        write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast(), Edition::LATEST))?;
         if trait_params.len() > 1 {
             write!(
                 fmt,
@@ -83,7 +84,7 @@ impl DebugContext<'_> {
                 trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
             )?;
         }
-        write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast()))?;
+        write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast(), Edition::LATEST))?;
 
         let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
         let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
@@ -110,9 +111,11 @@ impl DebugContext<'_> {
             CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(),
         };
         match def {
-            CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())),
+            CallableDefId::FunctionId(_) => {
+                write!(fmt, "{{fn {}}}", name.display(self.0.upcast(), Edition::LATEST))
+            }
             CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
-                write!(fmt, "{{ctor {}}}", name.display(self.0.upcast()))
+                write!(fmt, "{{ctor {}}}", name.display(self.0.upcast(), Edition::LATEST))
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 00791c51491..51ccd4ef293 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -14,6 +14,7 @@ use hir_def::{
 };
 use hir_expand::name::Name;
 use intern::sym;
+use span::Edition;
 use stdx::{never, panic_context};
 use triomphe::Arc;
 
@@ -114,7 +115,7 @@ pub(crate) fn trait_solve_query(
 ) -> Option<Solution> {
     let detail = match &goal.value.goal.data(Interner) {
         GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
-            db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string()
+            db.trait_data(it.hir_trait_id()).name.display(db.upcast(), Edition::LATEST).to_string()
         }
         GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
         _ => "??".to_owned(),
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index 02d92620e05..af60c233e55 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -328,11 +328,9 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
         };
         let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() {
             Ok(idx) => Name::new_tuple_field(idx),
-            Err(_) => Name::new(
-                segment.split_once('<').map_or(segment, |it| it.0),
-                tt::IdentIsRaw::No,
-                SyntaxContextId::ROOT,
-            ),
+            Err(_) => {
+                Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT)
+            }
         });
         Some(ModPath::from_segments(kind, parts))
     };
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 12dd8b5bf4f..923dca64667 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -84,7 +84,7 @@ impl HirDisplay for Function {
         if let Some(abi) = &data.abi {
             write!(f, "extern \"{}\" ", abi.as_str())?;
         }
-        write!(f, "fn {}", data.name.display(f.db.upcast()))?;
+        write!(f, "fn {}", data.name.display(f.db.upcast(), f.edition()))?;
 
         write_generic_params(GenericDefId::FunctionId(self.id), f)?;
 
@@ -107,7 +107,7 @@ impl HirDisplay for Function {
                 first = false;
             }
             match local {
-                Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?,
+                Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
                 None => f.write_str("_: ")?,
             }
             type_ref.hir_fmt(f)?;
@@ -177,7 +177,7 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
 
     if let Some(trait_) = impl_.trait_(db) {
         let trait_data = db.trait_data(trait_.id);
-        write!(f, " {} for", trait_data.name.display(db.upcast()))?;
+        write!(f, " {} for", trait_data.name.display(db.upcast(), f.edition()))?;
     }
 
     f.write_char(' ')?;
@@ -196,7 +196,7 @@ impl HirDisplay for SelfParam {
             {
                 f.write_char('&')?;
                 if let Some(lifetime) = lifetime {
-                    write!(f, "{} ", lifetime.name.display(f.db.upcast()))?;
+                    write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
                 if let hir_def::type_ref::Mutability::Mut = mut_ {
                     f.write_str("mut ")?;
@@ -227,7 +227,7 @@ impl HirDisplay for Struct {
         // FIXME: Render repr if its set explicitly?
         write_visibility(module_id, self.visibility(f.db), f)?;
         f.write_str("struct ")?;
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
         write_generic_params(def_id, f)?;
 
@@ -266,7 +266,7 @@ impl HirDisplay for Enum {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("enum ")?;
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
         write_generic_params(def_id, f)?;
 
@@ -283,7 +283,7 @@ impl HirDisplay for Union {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("union ")?;
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
         write_generic_params(def_id, f)?;
 
@@ -343,7 +343,7 @@ fn write_variants(
     } else {
         f.write_str("{\n")?;
         for variant in &variants[..count] {
-            write!(f, "    {}", variant.name(f.db).display(f.db.upcast()))?;
+            write!(f, "    {}", variant.name(f.db).display(f.db.upcast(), f.edition()))?;
             match variant.kind(f.db) {
                 StructKind::Tuple => {
                     let fields_str =
@@ -372,21 +372,21 @@ fn write_variants(
 impl HirDisplay for Field {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
-        write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
 
 impl HirDisplay for TupleField {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write!(f, "pub {}: ", self.name().display(f.db.upcast()))?;
+        write!(f, "pub {}: ", self.name().display(f.db.upcast(), f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
 
 impl HirDisplay for Variant {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         let data = self.variant_data(f.db);
         match &*data {
             VariantData::Unit => {}
@@ -424,9 +424,9 @@ impl HirDisplay for ExternCrateDecl {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("extern crate ")?;
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         if let Some(alias) = self.alias(f.db) {
-            write!(f, " as {alias}",)?;
+            write!(f, " as {}", alias.display(f.edition()))?;
         }
         Ok(())
     }
@@ -478,7 +478,7 @@ impl HirDisplay for TypeParam {
         match param_data {
             TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
-                    write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast()))?
+                    write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast(), f.edition()))?
                 }
                 TypeParamProvenance::ArgumentImplTrait => {
                     return write_bounds_like_dyn_trait_with_prefix(
@@ -491,7 +491,7 @@ impl HirDisplay for TypeParam {
                 }
             },
             TypeOrConstParamData::ConstParamData(p) => {
-                write!(f, "{}", p.name.display(f.db.upcast()))?;
+                write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?;
             }
         }
 
@@ -525,13 +525,13 @@ impl HirDisplay for TypeParam {
 
 impl HirDisplay for LifetimeParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write!(f, "{}", self.name(f.db).display(f.db.upcast()))
+        write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))
     }
 }
 
 impl HirDisplay for ConstParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?;
+        write!(f, "const {}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
@@ -563,7 +563,7 @@ fn write_generic_params(
     };
     for (_, lifetime) in params.iter_lt() {
         delim(f)?;
-        write!(f, "{}", lifetime.name.display(f.db.upcast()))?;
+        write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))?;
     }
     for (_, ty) in params.iter_type_or_consts() {
         if let Some(name) = &ty.name() {
@@ -573,7 +573,7 @@ fn write_generic_params(
                         continue;
                     }
                     delim(f)?;
-                    write!(f, "{}", name.display(f.db.upcast()))?;
+                    write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                     if let Some(default) = &ty.default {
                         f.write_str(" = ")?;
                         default.hir_fmt(f)?;
@@ -581,12 +581,12 @@ fn write_generic_params(
                 }
                 TypeOrConstParamData::ConstParamData(c) => {
                     delim(f)?;
-                    write!(f, "const {}: ", name.display(f.db.upcast()))?;
+                    write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
                     c.ty.hir_fmt(f)?;
 
                     if let Some(default) = &c.default {
                         f.write_str(" = ")?;
-                        write!(f, "{}", default.display(f.db.upcast()))?;
+                        write!(f, "{}", default.display(f.db.upcast(), f.edition()))?;
                     }
                 }
             }
@@ -639,7 +639,7 @@ fn write_where_predicates(
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
         WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
         WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
-            Some(name) => write!(f, "{}", name.display(f.db.upcast())),
+            Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
             None => f.write_str("{unnamed}"),
         },
     };
@@ -668,12 +668,13 @@ fn write_where_predicates(
                 bound.hir_fmt(f)?;
             }
             Lifetime { target, bound } => {
-                let target = target.name.display(f.db.upcast());
-                let bound = bound.name.display(f.db.upcast());
+                let target = target.name.display(f.db.upcast(), f.edition());
+                let bound = bound.name.display(f.db.upcast(), f.edition());
                 write!(f, "{target}: {bound}")?;
             }
             ForLifetime { lifetimes, target, bound } => {
-                let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", ");
+                let lifetimes =
+                    lifetimes.iter().map(|it| it.display(f.db.upcast(), f.edition())).join(", ");
                 write!(f, "for<{lifetimes}> ")?;
                 write_target(target, f)?;
                 f.write_str(": ")?;
@@ -685,7 +686,9 @@ fn write_where_predicates(
             f.write_str(" + ")?;
             match nxt {
                 TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
-                Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?,
+                Lifetime { bound, .. } => {
+                    write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
+                }
             }
         }
         f.write_str(",")?;
@@ -707,7 +710,7 @@ impl HirDisplay for Const {
         let data = db.const_data(self.id);
         f.write_str("const ")?;
         match &data.name {
-            Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?,
+            Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
             None => f.write_str("_: ")?,
         }
         data.type_ref.hir_fmt(f)?;
@@ -723,7 +726,7 @@ impl HirDisplay for Static {
         if data.mutable {
             f.write_str("mut ")?;
         }
-        write!(f, "{}: ", data.name.display(f.db.upcast()))?;
+        write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
         data.type_ref.hir_fmt(f)?;
         Ok(())
     }
@@ -777,7 +780,7 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi
     if data.is_auto {
         f.write_str("auto ")?;
     }
-    write!(f, "trait {}", data.name.display(f.db.upcast()))?;
+    write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;
     write_generic_params(GenericDefId::TraitId(trait_.id), f)?;
     Ok(())
 }
@@ -786,7 +789,7 @@ impl HirDisplay for TraitAlias {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.trait_alias_data(self.id);
-        write!(f, "trait {}", data.name.display(f.db.upcast()))?;
+        write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;
         let def_id = GenericDefId::TraitAliasId(self.id);
         write_generic_params(def_id, f)?;
         f.write_str(" = ")?;
@@ -802,7 +805,7 @@ impl HirDisplay for TypeAlias {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.type_alias_data(self.id);
-        write!(f, "type {}", data.name.display(f.db.upcast()))?;
+        write!(f, "type {}", data.name.display(f.db.upcast(), f.edition()))?;
         let def_id = GenericDefId::TypeAliasId(self.id);
         write_generic_params(def_id, f)?;
         if !data.bounds.is_empty() {
@@ -822,7 +825,7 @@ impl HirDisplay for Module {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         // FIXME: Module doesn't have visibility saved in data.
         match self.name(f.db) {
-            Some(name) => write!(f, "mod {}", name.display(f.db.upcast())),
+            Some(name) => write!(f, "mod {}", name.display(f.db.upcast(), f.edition())),
             None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) {
                 Some(name) => write!(f, "extern crate {name}"),
                 None => f.write_str("extern crate {unknown}"),
@@ -839,6 +842,6 @@ impl HirDisplay for Macro {
             hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
             hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"),
         }?;
-        write!(f, " {}", self.name(f.db).display(f.db.upcast()))
+        write!(f, " {}", self.name(f.db).display(f.db.upcast(), f.edition()))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 1a3becdf50e..57f810c7c79 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -340,13 +340,13 @@ impl ModuleDef {
         }
     }
 
-    pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
+    pub fn canonical_path(&self, db: &dyn HirDatabase, edition: Edition) -> Option<String> {
         let mut segments = vec![self.name(db)?];
         for m in self.module(db)?.path_to_root(db) {
             segments.extend(m.name(db))
         }
         segments.reverse();
-        Some(segments.iter().map(|it| it.display(db.upcast())).join("::"))
+        Some(segments.iter().map(|it| it.display(db.upcast(), edition)).join("::"))
     }
 
     pub fn canonical_module_path(
@@ -556,13 +556,14 @@ impl Module {
         style_lints: bool,
     ) {
         let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered();
+        let edition = db.crate_graph()[self.id.krate()].edition;
         let def_map = self.id.def_map(db.upcast());
         for diag in def_map.diagnostics() {
             if diag.in_module != self.id.local_id {
                 // FIXME: This is accidentally quadratic.
                 continue;
             }
-            emit_def_diagnostic(db, acc, diag);
+            emit_def_diagnostic(db, acc, diag, edition);
         }
 
         if !self.id.is_block_module() {
@@ -582,7 +583,7 @@ impl Module {
                 }
                 ModuleDef::Trait(t) => {
                     for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
-                        emit_def_diagnostic(db, acc, diag);
+                        emit_def_diagnostic(db, acc, diag, edition);
                     }
 
                     for item in t.items(db) {
@@ -599,19 +600,19 @@ impl Module {
                     match adt {
                         Adt::Struct(s) => {
                             for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
-                                emit_def_diagnostic(db, acc, diag);
+                                emit_def_diagnostic(db, acc, diag, edition);
                             }
                         }
                         Adt::Union(u) => {
                             for diag in db.union_data_with_diagnostics(u.id).1.iter() {
-                                emit_def_diagnostic(db, acc, diag);
+                                emit_def_diagnostic(db, acc, diag, edition);
                             }
                         }
                         Adt::Enum(e) => {
                             for v in e.variants(db) {
                                 acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
                                 for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
-                                    emit_def_diagnostic(db, acc, diag);
+                                    emit_def_diagnostic(db, acc, diag, edition);
                                 }
                             }
                         }
@@ -645,7 +646,7 @@ impl Module {
             let ast_id_map = db.ast_id_map(file_id);
 
             for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
-                emit_def_diagnostic(db, acc, diag);
+                emit_def_diagnostic(db, acc, diag, edition);
             }
 
             if inherent_impls.invalid_impls().contains(&impl_def.id) {
@@ -869,23 +870,32 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>
                 never!("declarative expander for non decl-macro: {:?}", e);
                 return;
             };
+            let krate = HasModule::krate(&m.id, db.upcast());
+            let edition = db.crate_graph()[krate].edition;
             emit_def_diagnostic_(
                 db,
                 acc,
                 &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
+                edition,
             );
         }
     }
 }
 
-fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
-    emit_def_diagnostic_(db, acc, &diag.kind)
+fn emit_def_diagnostic(
+    db: &dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic>,
+    diag: &DefDiagnostic,
+    edition: Edition,
+) {
+    emit_def_diagnostic_(db, acc, &diag.kind, edition)
 }
 
 fn emit_def_diagnostic_(
     db: &dyn HirDatabase,
     acc: &mut Vec<AnyDiagnostic>,
     diag: &DefDiagnosticKind,
+    edition: Edition,
 ) {
     match diag {
         DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
@@ -910,7 +920,7 @@ fn emit_def_diagnostic_(
                 MacroError {
                     node: InFile::new(ast.file_id, item.syntax_node_ptr()),
                     precise_location: None,
-                    message: format!("{}: {message}", path.display(db.upcast())),
+                    message: format!("{}: {message}", path.display(db.upcast(), edition)),
                     error,
                 }
                 .into(),
@@ -1764,7 +1774,7 @@ impl DefWithBody {
     /// 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())
+        body.pretty_print(db.upcast(), self.id(), Edition::CURRENT)
     }
 
     /// A textual representation of the MIR of this def's body for debugging purposes.
@@ -2259,6 +2269,8 @@ impl Function {
         db: &dyn HirDatabase,
         span_formatter: impl Fn(FileId, TextRange) -> String,
     ) -> String {
+        let krate = HasModule::krate(&self.id, db.upcast());
+        let edition = db.crate_graph()[krate].edition;
         let body = match db.monomorphized_mir_body(
             self.id.into(),
             Substitution::empty(Interner),
@@ -2267,7 +2279,7 @@ impl Function {
             Ok(body) => body,
             Err(e) => {
                 let mut r = String::new();
-                _ = e.pretty_print(&mut r, db, &span_formatter);
+                _ = e.pretty_print(&mut r, db, &span_formatter, edition);
                 return r;
             }
         };
@@ -2276,7 +2288,7 @@ impl Function {
             Ok(_) => "pass".to_owned(),
             Err(e) => {
                 let mut r = String::new();
-                _ = e.pretty_print(&mut r, db, &span_formatter);
+                _ = e.pretty_print(&mut r, db, &span_formatter, edition);
                 r
             }
         };
@@ -2510,7 +2522,11 @@ impl Const {
         Type::from_value_def(db, self.id)
     }
 
-    pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
+    pub fn render_eval(
+        self,
+        db: &dyn HirDatabase,
+        edition: Edition,
+    ) -> Result<String, ConstEvalError> {
         let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
         let data = &c.data(Interner);
         if let TyKind::Scalar(s) = data.ty.kind(Interner) {
@@ -2532,7 +2548,7 @@ impl Const {
         if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) {
             Ok(s)
         } else {
-            Ok(format!("{}", c.display(db)))
+            Ok(format!("{}", c.display(db, edition)))
         }
     }
 }
@@ -3728,9 +3744,9 @@ impl ConstParam {
         Type::new(db, self.id.parent(), db.const_param_ty(self.id))
     }
 
-    pub fn default(self, db: &dyn HirDatabase) -> Option<ast::ConstArg> {
+    pub fn default(self, db: &dyn HirDatabase, edition: Edition) -> Option<ast::ConstArg> {
         let arg = generic_arg_from_param(db, self.id.into())?;
-        known_const_to_ast(arg.constant(Interner)?, db)
+        known_const_to_ast(arg.constant(Interner)?, db, edition)
     }
 }
 
@@ -4038,12 +4054,20 @@ impl Closure {
         TyKind::Closure(self.id, self.subst).intern(Interner)
     }
 
-    pub fn display_with_id(&self, db: &dyn HirDatabase) -> String {
-        self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string()
+    pub fn display_with_id(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+        self.clone()
+            .as_ty()
+            .display(db, edition)
+            .with_closure_style(ClosureStyle::ClosureWithId)
+            .to_string()
     }
 
-    pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String {
-        self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string()
+    pub fn display_with_impl(&self, db: &dyn HirDatabase, edition: Edition) -> String {
+        self.clone()
+            .as_ty()
+            .display(db, edition)
+            .with_closure_style(ClosureStyle::ImplFn)
+            .to_string()
     }
 
     pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> {
@@ -4704,18 +4728,20 @@ impl Type {
     pub fn type_and_const_arguments<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
+        edition: Edition,
     ) -> impl Iterator<Item = SmolStr> + 'a {
         self.ty
             .strip_references()
             .as_adt()
             .into_iter()
             .flat_map(|(_, substs)| substs.iter(Interner))
-            .filter_map(|arg| {
+            .filter_map(move |arg| {
                 // arg can be either a `Ty` or `constant`
                 if let Some(ty) = arg.ty(Interner) {
-                    Some(format_smolstr!("{}", ty.display(db)))
+                    Some(format_smolstr!("{}", ty.display(db, edition)))
                 } else {
-                    arg.constant(Interner).map(|const_| format_smolstr!("{}", const_.display(db)))
+                    arg.constant(Interner)
+                        .map(|const_| format_smolstr!("{}", const_.display(db, edition)))
                 }
             })
     }
@@ -4724,13 +4750,17 @@ impl Type {
     pub fn generic_parameters<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
+        edition: Edition,
     ) -> impl Iterator<Item = SmolStr> + 'a {
         // iterate the lifetime
         self.as_adt()
-            .and_then(|a| a.lifetime(db).map(|lt| lt.name.display_no_db().to_smolstr()))
+            .and_then(|a| {
+                // Lifetimes do not need edition-specific handling as they cannot be escaped.
+                a.lifetime(db).map(|lt| lt.name.display_no_db(Edition::Edition2015).to_smolstr())
+            })
             .into_iter()
             // add the type and const parameters
-            .chain(self.type_and_const_arguments(db))
+            .chain(self.type_and_const_arguments(db, edition))
     }
 
     pub fn iterate_method_candidates_with_traits<T>(
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index b1f5df681f2..cabb7e3db3d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -9,6 +9,7 @@ use hir_def::{
 };
 use hir_expand::HirFileId;
 use hir_ty::{db::HirDatabase, display::HirDisplay};
+use span::Edition;
 use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
 
 use crate::{Module, ModuleDef, Semantics};
@@ -54,6 +55,7 @@ pub struct SymbolCollector<'a> {
     symbols: Vec<FileSymbol>,
     work: Vec<SymbolCollectorWork>,
     current_container_name: Option<SmolStr>,
+    edition: Edition,
 }
 
 /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect
@@ -65,10 +67,13 @@ impl<'a> SymbolCollector<'a> {
             symbols: Default::default(),
             work: Default::default(),
             current_container_name: None,
+            edition: Edition::Edition2015,
         }
     }
 
     pub fn collect(&mut self, module: Module) {
+        self.edition = module.krate().edition(self.db);
+
         // The initial work is the root module we're collecting, additional work will
         // be populated as we traverse the module's definitions.
         self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None });
@@ -209,7 +214,8 @@ impl<'a> SymbolCollector<'a> {
 
     fn collect_from_impl(&mut self, impl_id: ImplId) {
         let impl_data = self.db.impl_data(impl_id);
-        let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string()));
+        let impl_name =
+            Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string()));
         self.with_container_name(impl_name, |s| {
             for &assoc_item_id in impl_data.items.iter() {
                 s.push_assoc_item(assoc_item_id)
@@ -239,16 +245,16 @@ impl<'a> SymbolCollector<'a> {
     fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
         match body_id {
             DefWithBodyId::FunctionId(id) => {
-                Some(self.db.function_data(id).name.display_no_db().to_smolstr())
+                Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr())
             }
             DefWithBodyId::StaticId(id) => {
-                Some(self.db.static_data(id).name.display_no_db().to_smolstr())
+                Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr())
             }
             DefWithBodyId::ConstId(id) => {
-                Some(self.db.const_data(id).name.as_ref()?.display_no_db().to_smolstr())
+                Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr())
             }
             DefWithBodyId::VariantId(id) => {
-                Some(self.db.enum_variant_data(id).name.display_no_db().to_smolstr())
+                Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr())
             }
             DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
         }
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index 0c8f6932c71..6ad074e8e5c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -7,6 +7,7 @@ use hir_ty::{
     display::{DisplaySourceCodeError, HirDisplay},
 };
 use itertools::Itertools;
+use span::Edition;
 
 use crate::{
     Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef,
@@ -29,9 +30,10 @@ fn mod_item_path_str(
     sema_scope: &SemanticsScope<'_>,
     def: &ModuleDef,
     cfg: ImportPathConfig,
+    edition: Edition,
 ) -> Result<String, DisplaySourceCodeError> {
     let path = mod_item_path(sema_scope, def, cfg);
-    path.map(|it| it.display(sema_scope.db.upcast()).to_string())
+    path.map(|it| it.display(sema_scope.db.upcast(), edition).to_string())
         .ok_or(DisplaySourceCodeError::PathNotFound)
 }
 
@@ -97,37 +99,38 @@ impl Expr {
         sema_scope: &SemanticsScope<'_>,
         many_formatter: &mut dyn FnMut(&Type) -> String,
         cfg: ImportPathConfig,
+        edition: Edition,
     ) -> Result<String, DisplaySourceCodeError> {
         let db = sema_scope.db;
-        let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg);
+        let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg, edition);
         match self {
             Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) {
                 Some(container) => {
-                    let container_name = container_name(container, sema_scope, cfg)?;
+                    let container_name = container_name(container, sema_scope, cfg, edition)?;
                     let const_name = it
                         .name(db)
-                        .map(|c| c.display(db.upcast()).to_string())
+                        .map(|c| c.display(db.upcast(), edition).to_string())
                         .unwrap_or(String::new());
                     Ok(format!("{container_name}::{const_name}"))
                 }
                 None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
             },
             Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
-            Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()),
-            Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()),
+            Expr::Local(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()),
+            Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()),
             Expr::FamousType { value, .. } => Ok(value.to_string()),
             Expr::Function { func, params, .. } => {
                 let args = params
                     .iter()
-                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg))
+                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
 
                 match func.as_assoc_item(db).map(|it| it.container(db)) {
                     Some(container) => {
-                        let container_name = container_name(container, sema_scope, cfg)?;
-                        let fn_name = func.name(db).display(db.upcast()).to_string();
+                        let container_name = container_name(container, sema_scope, cfg, edition)?;
+                        let fn_name = func.name(db).display(db.upcast(), edition).to_string();
                         Ok(format!("{container_name}::{fn_name}({args})"))
                     }
                     None => {
@@ -141,12 +144,13 @@ impl Expr {
                     return Ok(many_formatter(&target.ty(db)));
                 }
 
-                let func_name = func.name(db).display(db.upcast()).to_string();
+                let func_name = func.name(db).display(db.upcast(), edition).to_string();
                 let self_param = func.self_param(db).unwrap();
-                let target_str = target.gen_source_code(sema_scope, many_formatter, cfg)?;
+                let target_str =
+                    target.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
                 let args = params
                     .iter()
-                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg))
+                    .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
@@ -176,7 +180,7 @@ impl Expr {
                     StructKind::Tuple => {
                         let args = params
                             .iter()
-                            .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg))
+                            .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition))
                             .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                             .into_iter()
                             .join(", ");
@@ -190,8 +194,8 @@ impl Expr {
                             .map(|(a, f)| {
                                 let tmp = format!(
                                     "{}: {}",
-                                    f.name(db).display(db.upcast()),
-                                    a.gen_source_code(sema_scope, many_formatter, cfg)?
+                                    f.name(db).display(db.upcast(), edition),
+                                    a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
                                 );
                                 Ok(tmp)
                             })
@@ -211,7 +215,7 @@ impl Expr {
                     StructKind::Tuple => {
                         let args = params
                             .iter()
-                            .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg))
+                            .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
                             .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                             .into_iter()
                             .join(", ");
@@ -225,8 +229,8 @@ impl Expr {
                             .map(|(a, f)| {
                                 let tmp = format!(
                                     "{}: {}",
-                                    f.name(db).display(db.upcast()),
-                                    a.gen_source_code(sema_scope, many_formatter, cfg)?
+                                    f.name(db).display(db.upcast(), edition),
+                                    a.gen_source_code(sema_scope, many_formatter, cfg, edition)?
                                 );
                                 Ok(tmp)
                             })
@@ -244,7 +248,7 @@ impl Expr {
             Expr::Tuple { params, .. } => {
                 let args = params
                     .iter()
-                    .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg))
+                    .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition))
                     .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
                     .into_iter()
                     .join(", ");
@@ -256,8 +260,8 @@ impl Expr {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
-                let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg)?;
-                let field = field.name(db).display(db.upcast()).to_string();
+                let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
+                let field = field.name(db).display(db.upcast(), edition).to_string();
                 Ok(format!("{strukt}.{field}"))
             }
             Expr::Reference(expr) => {
@@ -265,7 +269,7 @@ impl Expr {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
-                let inner = expr.gen_source_code(sema_scope, many_formatter, cfg)?;
+                let inner = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?;
                 Ok(format!("&{inner}"))
             }
             Expr::Many(ty) => Ok(many_formatter(ty)),
@@ -353,17 +357,18 @@ fn container_name(
     container: AssocItemContainer,
     sema_scope: &SemanticsScope<'_>,
     cfg: ImportPathConfig,
+    edition: Edition,
 ) -> Result<String, DisplaySourceCodeError> {
     let container_name = match container {
         crate::AssocItemContainer::Trait(trait_) => {
-            mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg)?
+            mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg, edition)?
         }
         crate::AssocItemContainer::Impl(imp) => {
             let self_ty = imp.self_ty(sema_scope.db);
             // Should it be guaranteed that `mod_item_path` always exists?
             match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) {
-                Some(path) => path.display(sema_scope.db.upcast()).to_string(),
-                None => self_ty.display(sema_scope.db).to_string(),
+                Some(path) => path.display(sema_scope.db.upcast(), edition).to_string(),
+                None => self_ty.display(sema_scope.db, edition).to_string(),
             }
         }
     };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 4cd15f1c755..7f8ea44fb12 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -1,5 +1,8 @@
 use hir::HasSource;
-use syntax::ast::{self, make, AstNode};
+use syntax::{
+    ast::{self, make, AstNode},
+    Edition,
+};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -150,14 +153,22 @@ fn add_missing_impl_members_inner(
             &missing_items,
             trait_,
             &new_impl_def,
-            target_scope,
+            &target_scope,
         );
 
         if let Some(cap) = ctx.config.snippet_cap {
             let mut placeholder = None;
             if let DefaultMethods::No = mode {
                 if let ast::AssocItem::Fn(func) = &first_new_item {
-                    if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() {
+                    if try_gen_trait_body(
+                        ctx,
+                        func,
+                        trait_ref,
+                        &impl_def,
+                        target_scope.krate().edition(ctx.sema.db),
+                    )
+                    .is_none()
+                    {
                         if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                         {
                             if m.syntax().text() == "todo!()" {
@@ -182,9 +193,11 @@ fn try_gen_trait_body(
     func: &ast::Fn,
     trait_ref: hir::TraitRef,
     impl_def: &ast::Impl,
+    edition: Edition,
 ) -> Option<()> {
-    let trait_path =
-        make::ext::ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db()).to_string());
+    let trait_path = make::ext::ident_path(
+        &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
+    );
     let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?;
     let adt = hir_ty.as_adt()?.source(ctx.db())?;
     gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref))
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index f4569ca848f..b6abb06a2af 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -445,7 +445,8 @@ fn build_pat(
 ) -> Option<ast::Pat> {
     match var {
         ExtendedVariant::Variant(var) => {
-            let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?);
+            let edition = module.krate().edition(db);
+            let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
             // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
             Some(match var.source(db)?.value.kind() {
                 ast::StructKind::Tuple(field_list) => {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index db53e49d846..d86948818b1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -8,7 +8,7 @@ use ide_db::{
         insert_use::{insert_use, insert_use_as_alias, ImportScope},
     },
 };
-use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
+use syntax::{ast, AstNode, Edition, NodeOrToken, SyntaxElement};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 
@@ -120,13 +120,14 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     // prioritize more relevant imports
     proposed_imports
         .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
+    let edition = current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
 
     let group_label = group_label(import_assets.import_candidate());
     for import in proposed_imports {
         let import_path = import.import_path;
 
         let (assist_id, import_name) =
-            (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db()));
+            (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db(), edition));
         acc.add_group(
             &group_label,
             assist_id,
@@ -138,7 +139,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
                     ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
                     ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
                 };
-                insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use);
+                insert_use(&scope, mod_path_to_ast(&import_path, edition), &ctx.config.insert_use);
             },
         );
 
@@ -165,7 +166,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
                         };
                         insert_use_as_alias(
                             &scope,
-                            mod_path_to_ast(&import_path),
+                            mod_path_to_ast(&import_path, edition),
                             &ctx.config.insert_use,
                         );
                     },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
index 3a0754d60f8..cd5fe0f8626 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -339,6 +339,7 @@ fn augment_references_with_imports(
 
     let cfg = ctx.config.import_path_config();
 
+    let edition = target_module.krate().edition(ctx.db());
     references
         .into_iter()
         .filter_map(|FileReference { range, name, .. }| {
@@ -361,7 +362,10 @@ fn augment_references_with_imports(
                         cfg,
                     )
                     .map(|mod_path| {
-                        make::path_concat(mod_path_to_ast(&mod_path), make::path_from_text("Bool"))
+                        make::path_concat(
+                            mod_path_to_ast(&mod_path, edition),
+                            make::path_from_text("Bool"),
+                        )
                     });
 
                 import_scope.zip(path)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index 77f9c66b354..a5c5b08d5b0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
     };
     // Verify this is `bool::then` that is being called.
     let func = ctx.sema.resolve_method_call(&mcall)?;
-    if func.name(ctx.sema.db).display(ctx.db()).to_string() != "then" {
+    if !func.name(ctx.sema.db).eq_ident("then") {
         return None;
     }
     let assoc = func.as_assoc_item(ctx.sema.db)?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
index 5aa94590e67..8c59ef4314f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -51,7 +51,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
             Some(hir::PathResolution::Def(module_def)) => module_def,
             _ => return None,
         };
-        mod_path_to_ast(&module.find_path(ctx.db(), src_type_def, cfg)?)
+        mod_path_to_ast(
+            &module.find_path(ctx.db(), src_type_def, cfg)?,
+            module.krate().edition(ctx.db()),
+        )
     };
 
     let dest_type = match &ast_trait {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index e86ff0dbebc..3c9a9174104 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -114,12 +114,16 @@ pub(crate) fn convert_for_loop_with_for_each(
         |builder| {
             let mut buf = String::new();
 
-            if let Some((expr_behind_ref, method)) =
+            if let Some((expr_behind_ref, method, krate)) =
                 is_ref_and_impls_iter_method(&ctx.sema, &iterable)
             {
                 // We have either "for x in &col" and col implements a method called iter
                 //             or "for x in &mut col" and col implements a method called iter_mut
-                format_to!(buf, "{expr_behind_ref}.{}()", method.display(ctx.db()));
+                format_to!(
+                    buf,
+                    "{expr_behind_ref}.{}()",
+                    method.display(ctx.db(), krate.edition(ctx.db()))
+                );
             } else if let ast::Expr::RangeExpr(..) = iterable {
                 // range expressions need to be parenthesized for the syntax to be correct
                 format_to!(buf, "({iterable})");
@@ -144,7 +148,7 @@ pub(crate) fn convert_for_loop_with_for_each(
 fn is_ref_and_impls_iter_method(
     sema: &hir::Semantics<'_, ide_db::RootDatabase>,
     iterable: &ast::Expr,
-) -> Option<(ast::Expr, hir::Name)> {
+) -> Option<(ast::Expr, hir::Name, hir::Crate)> {
     let ref_expr = match iterable {
         ast::Expr::RefExpr(r) => r,
         _ => return None,
@@ -172,7 +176,7 @@ fn is_ref_and_impls_iter_method(
         return None;
     }
 
-    Some((expr_behind_ref, wanted_method))
+    Some((expr_behind_ref, wanted_method, krate))
 }
 
 /// Whether iterable implements core::Iterator
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
index 0f0b4442d8a..91af9b05bbb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
@@ -211,7 +211,7 @@ fn augment_references_with_imports(
                     )
                     .map(|mod_path| {
                         make::path_concat(
-                            mod_path_to_ast(&mod_path),
+                            mod_path_to_ast(&mod_path, target_module.krate().edition(ctx.db())),
                             make::path_from_text(struct_name),
                         )
                     });
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 095b8f958d0..b229b750e88 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -7,7 +7,7 @@ use ide_db::{
     FxHashMap, FxHashSet,
 };
 use itertools::Itertools;
-use syntax::{ast, ted, AstNode, SmolStr, SyntaxNode, ToSmolStr};
+use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
 use text_edit::TextRange;
 
 use crate::{
@@ -81,6 +81,7 @@ struct StructEditData {
     has_private_members: bool,
     is_nested: bool,
     is_ref: bool,
+    edition: Edition,
 }
 
 fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<StructEditData> {
@@ -145,6 +146,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
         names_in_scope,
         is_nested,
         is_ref,
+        edition: module.krate().edition(ctx.db()),
     })
 }
 
@@ -180,7 +182,7 @@ fn build_assignment_edit(
 ) -> AssignmentEdit {
     let ident_pat = builder.make_mut(data.ident_pat.clone());
 
-    let struct_path = mod_path_to_ast(&data.struct_def_path);
+    let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
     let is_ref = ident_pat.ref_token().is_some();
     let is_mut = ident_pat.mut_token().is_some();
 
@@ -247,7 +249,7 @@ fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(
             .visible_fields
             .iter()
             .map(|field| {
-                let field_name = field.name(ctx.db()).display_no_db().to_smolstr();
+                let field_name = field.name(ctx.db()).display_no_db(data.edition).to_smolstr();
                 let new_name = new_field_name(field_name.clone(), &data.names_in_scope);
                 (field_name, new_name)
             })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index 9beb616d99b..3d6d37ad93d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -66,7 +66,9 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
             let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
             let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
-                let path = make::ext::ident_path(&n.display(ctx.db()).to_string());
+                let path = make::ext::ident_path(
+                    &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(),
+                );
                 make::use_tree(path, None, None, false)
             }))
             .clone_for_update();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 0a2cb6d5ef8..cfcb09b9f7d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -23,7 +23,7 @@ use syntax::{
         self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams,
         HasName,
     },
-    match_ast, ted, SyntaxElement,
+    match_ast, ted, Edition, SyntaxElement,
     SyntaxKind::{self, COMMENT},
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
 };
@@ -84,7 +84,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     };
 
     let body = extraction_target(&node, range)?;
-    let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema)?;
 
     let (locals_used, self_param) = body.analyze(&ctx.sema);
 
@@ -92,6 +91,9 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     let insert_after = node_to_insert_after(&body, anchor)?;
     let semantics_scope = ctx.sema.scope(&insert_after)?;
     let module = semantics_scope.module();
+    let edition = semantics_scope.krate().edition(ctx.db());
+
+    let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema, edition)?;
 
     let ret_ty = body.return_ty(ctx)?;
     let control_flow = body.external_control_flow(ctx, &container_info)?;
@@ -217,7 +219,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                     );
 
                     if let Some(mod_path) = mod_path {
-                        insert_use(&scope, mod_path_to_ast(&mod_path), &ctx.config.insert_use);
+                        insert_use(
+                            &scope,
+                            mod_path_to_ast(&mod_path, edition),
+                            &ctx.config.insert_use,
+                        );
                     }
                 }
             }
@@ -238,7 +244,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef {
     let mut names_in_scope = vec![];
     semantics_scope.process_all_names(&mut |name, _| {
-        names_in_scope.push(name.display(semantics_scope.db.upcast()).to_string())
+        names_in_scope.push(
+            name.display(
+                semantics_scope.db.upcast(),
+                semantics_scope.krate().edition(semantics_scope.db),
+            )
+            .to_string(),
+        )
     });
 
     let default_name = "fun_name";
@@ -366,6 +378,7 @@ struct ContainerInfo {
     ret_type: Option<hir::Type>,
     generic_param_lists: Vec<ast::GenericParamList>,
     where_clauses: Vec<ast::WhereClause>,
+    edition: Edition,
 }
 
 /// Control flow that is exported from extracted function
@@ -489,8 +502,8 @@ impl Param {
         }
     }
 
-    fn to_arg(&self, ctx: &AssistContext<'_>) -> ast::Expr {
-        let var = path_expr_from_local(ctx, self.var);
+    fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr {
+        let var = path_expr_from_local(ctx, self.var, edition);
         match self.kind() {
             ParamKind::Value | ParamKind::MutValue => var,
             ParamKind::SharedRef => make::expr_ref(var, false),
@@ -498,8 +511,13 @@ impl Param {
         }
     }
 
-    fn to_param(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Param {
-        let var = self.var.name(ctx.db()).display(ctx.db()).to_string();
+    fn to_param(
+        &self,
+        ctx: &AssistContext<'_>,
+        module: hir::Module,
+        edition: Edition,
+    ) -> ast::Param {
+        let var = self.var.name(ctx.db()).display(ctx.db(), edition).to_string();
         let var_name = make::name(&var);
         let pat = match self.kind() {
             ParamKind::MutValue => make::ident_pat(false, true, var_name),
@@ -520,7 +538,7 @@ impl Param {
 }
 
 impl TryKind {
-    fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>) -> Option<TryKind> {
+    fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option<TryKind> {
         if ty.is_unknown() {
             // We favour Result for `expr?`
             return Some(TryKind::Result { ty });
@@ -529,7 +547,7 @@ impl TryKind {
         let name = adt.name(ctx.db());
         // FIXME: use lang items to determine if it is std type or user defined
         //        E.g. if user happens to define type named `Option`, we would have false positive
-        let name = &name.display(ctx.db()).to_string();
+        let name = &name.display(ctx.db(), edition).to_string();
         match name.as_str() {
             "Option" => Some(TryKind::Option),
             "Result" => Some(TryKind::Result { ty }),
@@ -828,6 +846,7 @@ impl FunctionBody {
     fn analyze_container(
         &self,
         sema: &Semantics<'_, RootDatabase>,
+        edition: Edition,
     ) -> Option<(ContainerInfo, bool)> {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
@@ -927,6 +946,7 @@ impl FunctionBody {
                 ret_type: ty,
                 generic_param_lists,
                 where_clauses,
+                edition,
             },
             contains_tail_expr,
         ))
@@ -1015,7 +1035,7 @@ impl FunctionBody {
         let kind = match (try_expr, ret_expr, break_expr, continue_expr) {
             (Some(_), _, None, None) => {
                 let ret_ty = container_info.ret_type.clone()?;
-                let kind = TryKind::of_ty(ret_ty, ctx)?;
+                let kind = TryKind::of_ty(ret_ty, ctx, container_info.edition)?;
 
                 Some(FlowKind::Try { kind })
             }
@@ -1397,7 +1417,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
 fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
-    let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx)));
+    let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
     let name = fun.name.clone();
     let mut call_expr = if fun.self_param.is_some() {
         let self_arg = make::expr_path(make::ext::ident_path("self"));
@@ -1420,13 +1440,13 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy
         [] => None,
         [var] => {
             let name = var.local.name(ctx.db());
-            let name = make::name(&name.display(ctx.db()).to_string());
+            let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string());
             Some(ast::Pat::IdentPat(make::ident_pat(false, var.mut_usage_outside_body, name)))
         }
         vars => {
             let binding_pats = vars.iter().map(|var| {
                 let name = var.local.name(ctx.db());
-                let name = make::name(&name.display(ctx.db()).to_string());
+                let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string());
                 make::ident_pat(false, var.mut_usage_outside_body, name).into()
             });
             Some(ast::Pat::TuplePat(make::tuple_pat(binding_pats)))
@@ -1569,8 +1589,8 @@ impl FlowHandler {
     }
 }
 
-fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local) -> ast::Expr {
-    let name = var.name(ctx.db()).display(ctx.db()).to_string();
+fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) -> ast::Expr {
+    let name = var.name(ctx.db()).display(ctx.db(), edition).to_string();
     make::expr_path(make::ext::ident_path(&name))
 }
 
@@ -1581,7 +1601,7 @@ fn format_function(
     old_indent: IndentLevel,
 ) -> ast::Fn {
     let fun_name = make::name(&fun.name.text());
-    let params = fun.make_param_list(ctx, module);
+    let params = fun.make_param_list(ctx, module, fun.mods.edition);
     let ret_ty = fun.make_ret_ty(ctx, module);
     let body = make_body(ctx, old_indent, fun);
     let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
@@ -1707,9 +1727,14 @@ impl Function {
         type_params_in_descendant_paths.chain(type_params_in_params).collect()
     }
 
-    fn make_param_list(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::ParamList {
+    fn make_param_list(
+        &self,
+        ctx: &AssistContext<'_>,
+        module: hir::Module,
+        edition: Edition,
+    ) -> ast::ParamList {
         let self_param = self.self_param.clone();
-        let params = self.params.iter().map(|param| param.to_param(ctx, module));
+        let params = self.params.iter().map(|param| param.to_param(ctx, module, edition));
         make::param_list(self_param, params)
     }
 
@@ -1842,10 +1867,12 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
                 None => match fun.outliving_locals.as_slice() {
                     [] => {}
                     [var] => {
-                        tail_expr = Some(path_expr_from_local(ctx, var.local));
+                        tail_expr = Some(path_expr_from_local(ctx, var.local, fun.mods.edition));
                     }
                     vars => {
-                        let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local));
+                        let exprs = vars
+                            .iter()
+                            .map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
                         let expr = make::expr_tuple(exprs);
                         tail_expr = Some(expr);
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index a62fdeb6173..615b5d3f98b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,7 +1,7 @@
 use std::iter;
 
 use either::Either;
-use hir::{Module, ModuleDef, Name, Variant};
+use hir::{HasCrate, Module, ModuleDef, Name, Variant};
 use ide_db::{
     defs::Definition,
     helpers::mod_path_to_ast,
@@ -16,7 +16,7 @@ use syntax::{
         self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
         HasName, HasVisibility,
     },
-    match_ast, ted, SyntaxElement,
+    match_ast, ted, Edition, SyntaxElement,
     SyntaxKind::*,
     SyntaxNode, T,
 };
@@ -58,6 +58,7 @@ pub(crate) fn extract_struct_from_enum_variant(
         "Extract struct from enum variant",
         target,
         |builder| {
+            let edition = enum_hir.krate(ctx.db()).edition(ctx.db());
             let variant_hir_name = variant_hir.name(ctx.db());
             let enum_module_def = ModuleDef::from(enum_hir);
             let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all();
@@ -82,7 +83,7 @@ pub(crate) fn extract_struct_from_enum_variant(
                     references,
                 );
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import)
+                    apply_references(ctx.config.insert_use, path, node, import, edition)
                 });
             }
             builder.edit_file(ctx.file_id());
@@ -98,7 +99,7 @@ pub(crate) fn extract_struct_from_enum_variant(
                     references,
                 );
                 processed.into_iter().for_each(|(path, node, import)| {
-                    apply_references(ctx.config.insert_use, path, node, import)
+                    apply_references(ctx.config.insert_use, path, node, import, edition)
                 });
             }
 
@@ -169,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
             ),
             _ => false,
         })
-        .any(|(name, _)| name.display(db).to_string() == variant_name.to_string())
+        .any(|(name, _)| name.eq_ident(variant_name.text().as_str()))
 }
 
 fn extract_generic_params(
@@ -359,9 +360,10 @@ fn apply_references(
     segment: ast::PathSegment,
     node: SyntaxNode,
     import: Option<(ImportScope, hir::ModPath)>,
+    edition: Edition,
 ) {
     if let Some((scope, path)) = import {
-        insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg);
+        insert_use(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg);
     }
     // deep clone to prevent cycle
     let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs
index 758f50d3f47..ee321864805 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs
@@ -45,8 +45,9 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<
     let new_field_list =
         make::record_pat_field_list(old_field_list.fields(), None).clone_for_update();
     for (f, _) in missing_fields.iter() {
+        let edition = ctx.sema.scope(record_pat.syntax())?.krate().edition(ctx.db());
         let field = make::record_pat_field_shorthand(make::name_ref(
-            &f.name(ctx.sema.db).display_no_db().to_smolstr(),
+            &f.name(ctx.sema.db).display_no_db(edition).to_smolstr(),
         ));
         new_field_list.add_field(field.clone_for_update());
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 9950f9c1474..7a92d8911bf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -4,7 +4,7 @@ use hir::{
 use ide_db::FileId;
 use syntax::{
     ast::{self, edit_in_place::HasVisibilityEdit, make, HasVisibility as _},
-    AstNode, TextRange, ToSmolStr,
+    AstNode, TextRange,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
     let (_, def) = module
         .scope(ctx.db(), None)
         .into_iter()
-        .find(|(name, _)| name.display_no_db().to_smolstr() == name_ref.text().as_str())?;
+        .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?;
     let ScopeDef::ModuleDef(def) = def else {
         return None;
     };
@@ -71,7 +71,10 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
     let assist_label = match target_name {
         None => format!("Change visibility to {missing_visibility}"),
         Some(name) => {
-            format!("Change visibility of {} to {missing_visibility}", name.display(ctx.db()))
+            format!(
+                "Change visibility of {} to {missing_visibility}",
+                name.display(ctx.db(), current_module.krate().edition(ctx.db()))
+            )
         }
     };
 
@@ -92,6 +95,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
     let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?;
 
     let current_module = ctx.sema.scope(record_field.syntax())?.module();
+    let current_edition = current_module.krate().edition(ctx.db());
     let visibility = record_field_def.visibility(ctx.db());
     if visibility.is_visible_from(ctx.db(), current_module.into()) {
         return None;
@@ -123,8 +127,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
     let target_name = record_field_def.name(ctx.db());
     let assist_label = format!(
         "Change visibility of {}.{} to {missing_visibility}",
-        parent_name.display(ctx.db()),
-        target_name.display(ctx.db())
+        parent_name.display(ctx.db(), current_edition),
+        target_name.display(ctx.db(), current_edition)
     );
 
     acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 2150003bc14..bbb902f8a2a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -51,6 +51,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
     let strukt_name = strukt.name()?;
     let current_module = ctx.sema.scope(strukt.syntax())?.module();
+    let current_edition = current_module.krate().edition(ctx.db());
 
     let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() {
         Some(field) => {
@@ -89,7 +90,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
     methods.sort_by(|(a, _), (b, _)| a.cmp(b));
     for (name, method) in methods {
         let adt = ast::Adt::Struct(strukt.clone());
-        let name = name.display(ctx.db()).to_string();
+        let name = name.display(ctx.db(), current_edition).to_string();
         // if `find_struct_impl` returns None, that means that a function named `name` already exists.
         let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else {
             continue;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 5a3457e5b7a..933ab2058ec 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -22,7 +22,7 @@ use syntax::{
         WherePred,
     },
     ted::{self, Position},
-    AstNode, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
+    AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
 };
 
 // Assist: generate_delegate_trait
@@ -109,6 +109,7 @@ struct Field {
     ty: ast::Type,
     range: syntax::TextRange,
     impls: Vec<Delegee>,
+    edition: Edition,
 }
 
 impl Field {
@@ -119,6 +120,7 @@ impl Field {
         let db = ctx.sema.db;
 
         let module = ctx.sema.file_to_module_def(ctx.file_id())?;
+        let edition = module.krate().edition(ctx.db());
 
         let (name, range, ty) = match f {
             Either::Left(f) => {
@@ -147,7 +149,7 @@ impl Field {
             }
         }
 
-        Some(Field { name, ty, range, impls })
+        Some(Field { name, ty, range, impls, edition })
     }
 }
 
@@ -163,18 +165,18 @@ enum Delegee {
 }
 
 impl Delegee {
-    fn signature(&self, db: &dyn HirDatabase) -> String {
+    fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
         let mut s = String::new();
 
         let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
 
         for m in it.module(db).path_to_root(db).iter().rev() {
             if let Some(name) = m.name(db) {
-                s.push_str(&format!("{}::", name.display_no_db().to_smolstr()));
+                s.push_str(&format!("{}::", name.display_no_db(edition).to_smolstr()));
             }
         }
 
-        s.push_str(&it.name(db).display_no_db().to_smolstr());
+        s.push_str(&it.name(db).display_no_db(edition).to_smolstr());
         s
     }
 }
@@ -212,9 +214,11 @@ impl Struct {
             // if self.hir_ty.impls_trait(db, trait_, &[]) {
             //     continue;
             // }
-            let signature = delegee.signature(db);
+            let signature = delegee.signature(db, field.edition);
 
-            let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else {
+            let Some(delegate) =
+                generate_impl(ctx, self, &field.ty, &field.name, delegee, field.edition)
+            else {
                 continue;
             };
 
@@ -240,6 +244,7 @@ fn generate_impl(
     field_ty: &ast::Type,
     field_name: &str,
     delegee: &Delegee,
+    edition: Edition,
 ) -> Option<ast::Impl> {
     let delegate: ast::Impl;
     let db = ctx.db();
@@ -259,7 +264,7 @@ fn generate_impl(
                 strukt_params.clone(),
                 strukt_params.map(|params| params.to_generic_args()),
                 delegee.is_auto(db),
-                make::ty(&delegee.name(db).display_no_db().to_smolstr()),
+                make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
                 strukt_ty,
                 bound_def.where_clause(),
                 ast_strukt.where_clause(),
@@ -350,7 +355,7 @@ fn generate_impl(
             let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
 
             let path_type =
-                make::ty(&trait_.name(db).display_no_db().to_smolstr()).clone_for_update();
+                make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
             transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?;
 
             // 3) Generate delegate trait impl
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
index 2ac7057fe79..e558bb6da89 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
@@ -4,7 +4,7 @@ use hir::{ModPath, ModuleDef};
 use ide_db::{famous_defs::FamousDefs, RootDatabase};
 use syntax::{
     ast::{self, HasName},
-    AstNode, SyntaxNode,
+    AstNode, Edition, SyntaxNode,
 };
 
 use crate::{
@@ -77,6 +77,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
                 field_name.syntax(),
                 deref_type_to_generate,
                 trait_path,
+                module.krate().edition(ctx.db()),
             )
         },
     )
@@ -117,6 +118,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
                 field_list_index,
                 deref_type_to_generate,
                 trait_path,
+                module.krate().edition(ctx.db()),
             )
         },
     )
@@ -130,6 +132,7 @@ fn generate_edit(
     field_name: impl Display,
     deref_type: DerefType,
     trait_path: ModPath,
+    edition: Edition,
 ) {
     let start_offset = strukt.syntax().text_range().end();
     let impl_code = match deref_type {
@@ -147,8 +150,11 @@ fn generate_edit(
         ),
     };
     let strukt_adt = ast::Adt::Struct(strukt);
-    let deref_impl =
-        generate_trait_impl_text(&strukt_adt, &trait_path.display(db).to_string(), &impl_code);
+    let deref_impl = generate_trait_impl_text(
+        &strukt_adt,
+        &trait_path.display(db, edition).to_string(),
+        &impl_code,
+    );
     edit.insert(start_offset, deref_impl);
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index 51dd4884547..c5c70c9f8eb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -5,7 +5,7 @@ use stdx::{format_to, to_lower_snake_case};
 use syntax::{
     algo::skip_whitespace_token,
     ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName},
-    match_ast, AstNode, AstToken,
+    match_ast, AstNode, AstToken, Edition,
 };
 
 use crate::assist_context::{AssistContext, Assists};
@@ -139,7 +139,8 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<St
 
     let mut example = String::new();
 
-    let use_path = build_path(ast_func, ctx)?;
+    let edition = ctx.sema.scope(ast_func.syntax())?.krate().edition(ctx.db());
+    let use_path = build_path(ast_func, ctx, edition)?;
     let is_unsafe = ast_func.unsafe_token().is_some();
     let param_list = ast_func.param_list()?;
     let ref_mut_params = ref_mut_params(&param_list);
@@ -472,13 +473,13 @@ fn string_vec_from(string_array: &[&str]) -> Vec<String> {
 }
 
 /// Helper function to build the path of the module in the which is the node
-fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
+fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>, edition: Edition) -> Option<String> {
     let crate_name = crate_name(ast_func, ctx)?;
     let leaf = self_partial_type(ast_func)
         .or_else(|| ast_func.name().map(|n| n.to_string()))
         .unwrap_or_else(|| "*".into());
     let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into();
-    match module_def.canonical_path(ctx.db()) {
+    match module_def.canonical_path(ctx.db(), edition) {
         Some(path) => Some(format!("{crate_name}::{path}::{leaf}")),
         None => Some(format!("{crate_name}::{leaf}")),
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index b2980d5c630..cd29f77f0c9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -17,7 +17,7 @@ use syntax::{
         self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr,
         HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
     },
-    ted, SyntaxKind, SyntaxNode, TextRange, T,
+    ted, Edition, SyntaxKind, SyntaxNode, TextRange, T,
 };
 
 use crate::{
@@ -175,6 +175,7 @@ fn add_func_to_accumulator(
         edit.edit_file(file);
 
         let target = function_builder.target.clone();
+        let edition = function_builder.target_edition;
         let func = function_builder.render(ctx.config.snippet_cap, edit);
 
         if let Some(adt) =
@@ -183,7 +184,7 @@ fn add_func_to_accumulator(
         {
             let name = make::ty_path(make::ext::ident_path(&format!(
                 "{}",
-                adt.name(ctx.db()).display(ctx.db())
+                adt.name(ctx.db()).display(ctx.db(), edition)
             )));
 
             // FIXME: adt may have generic params.
@@ -222,6 +223,7 @@ struct FunctionBuilder {
     should_focus_return_type: bool,
     visibility: Visibility,
     is_async: bool,
+    target_edition: Edition,
 }
 
 impl FunctionBuilder {
@@ -237,6 +239,7 @@ impl FunctionBuilder {
     ) -> Option<Self> {
         let target_module =
             target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
+        let target_edition = target_module.krate().edition(ctx.db());
 
         let current_module = ctx.sema.scope(call.syntax())?.module();
         let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
@@ -258,7 +261,9 @@ impl FunctionBuilder {
 
         // If generated function has the name "new" and is an associated function, we generate fn body
         // as a constructor and assume a "Self" return type.
-        if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) {
+        if let Some(body) =
+            make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info, target_edition)
+        {
             ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self"))));
             should_focus_return_type = false;
             fn_body = body;
@@ -288,6 +293,7 @@ impl FunctionBuilder {
             should_focus_return_type,
             visibility,
             is_async,
+            target_edition,
         })
     }
 
@@ -299,6 +305,8 @@ impl FunctionBuilder {
         target_module: Module,
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
+        let target_edition = target_module.krate().edition(ctx.db());
+
         let current_module = ctx.sema.scope(call.syntax())?.module();
         let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
 
@@ -336,6 +344,7 @@ impl FunctionBuilder {
             should_focus_return_type,
             visibility,
             is_async,
+            target_edition,
         })
     }
 
@@ -425,6 +434,7 @@ fn make_fn_body_as_new_function(
     ctx: &AssistContext<'_>,
     fn_name: &str,
     adt_info: &Option<AdtInfo>,
+    edition: Edition,
 ) -> Option<ast::BlockExpr> {
     if fn_name != "new" {
         return None;
@@ -441,7 +451,10 @@ fn make_fn_body_as_new_function(
                     .iter()
                     .map(|field| {
                         make::record_expr_field(
-                            make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))),
+                            make::name_ref(&format!(
+                                "{}",
+                                field.name(ctx.db()).display(ctx.db(), edition)
+                            )),
                             Some(placeholder_expr.clone()),
                         )
                     })
@@ -1102,8 +1115,9 @@ fn fn_arg_type(
 
         if ty.is_reference() || ty.is_mutable_reference() {
             let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
+            let target_edition = target_module.krate().edition(ctx.db());
             convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
-                .map(|conversion| conversion.convert_type(ctx.db()).to_string())
+                .map(|conversion| conversion.convert_type(ctx.db(), target_edition).to_string())
                 .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
         } else {
             ty.display_source_code(ctx.db(), target_module.into(), true).ok()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 60214aaaf69..8e349e84a96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -233,7 +233,7 @@ fn generate_getter_from_info(
                 .map(|conversion| {
                     cov_mark::hit!(convert_reference_type);
                     (
-                        conversion.convert_type(ctx.db()),
+                        conversion.convert_type(ctx.db(), krate.edition(ctx.db())),
                         conversion.getter(record_field_info.field_name.to_string()),
                     )
                 })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index b985b5e66c4..b9dede7cbdc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -64,10 +64,13 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                     ctx.config.import_path_config(),
                 )?;
 
+                let edition = current_module.krate().edition(ctx.db());
+
                 let expr = use_trivial_constructor(
                     ctx.sema.db,
-                    ide_db::helpers::mod_path_to_ast(&type_path),
+                    ide_db::helpers::mod_path_to_ast(&type_path, edition),
                     &ty,
+                    edition,
                 )?;
 
                 Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr)))
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index 111ea50fdc9..f1c2acdd3ed 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -51,10 +51,13 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
             | ast::Expr::MatchExpr(_)
             | ast::Expr::MacroExpr(_)
             | ast::Expr::BinExpr(_)
-            | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) {
-                Ok(result) => result,
-                Err(_) => return None,
-            },
+            | ast::Expr::CallExpr(_) => {
+                let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db());
+                match konst.render_eval(ctx.sema.db, edition) {
+                    Ok(result) => result,
+                    Err(_) => return None,
+                }
+            }
             _ => return None,
         };
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
index 3057745a97b..743ea947615 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
@@ -104,9 +104,13 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             };
             builder.delete(range_to_delete);
 
-            let const_ref = format!("Self::{}", name.display(ctx.db()));
-            for range in usages.file_ranges().map(|it| it.range) {
-                builder.replace(range, const_ref.clone());
+            let usages = usages.iter().flat_map(|(file_id, usages)| {
+                let edition = file_id.edition();
+                usages.iter().map(move |usage| (edition, usage.range))
+            });
+            for (edition, range) in usages {
+                let const_ref = format!("Self::{}", name.display(ctx.db(), edition));
+                builder.replace(range, const_ref);
             }
 
             // Heuristically inserting the extracted const after the consecutive existing consts
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index 14381085a78..8a7a06b380f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
     let path = format!("../{module_name}.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index e679a68f446..9692b705929 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                                 .string_value_unescape()
                                 .is_none() =>
                     {
-                        format_to!(buf, "{}/", name.display(db))
+                        format_to!(buf, "{}/", name.unescaped().display(db))
                     }
                     _ => (),
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index c89d54ff039..2925e2334b4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
     let path = format!("./{module_name}/mod.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
index b1e98045fcf..14518c4d2cc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -42,6 +42,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let resolved_call = ctx.sema.resolve_method_call(&call)?;
 
     let current_module = ctx.sema.scope(call.syntax())?.module();
+    let current_edition = current_module.krate().edition(ctx.db());
     let target_module_def = ModuleDef::from(resolved_call);
     let item_in_ns = ItemInNs::from(target_module_def);
     let receiver_path = current_module.find_path(
@@ -61,6 +62,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 |replace_with: String| builder.replace(range, replace_with),
                 &receiver_path,
                 item_in_ns,
+                current_edition,
             )
         },
     );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index d8e7da15d5b..ac88861fe4f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -8,6 +8,7 @@ use ide_db::{
     imports::import_assets::{ImportCandidate, LocatedImport},
 };
 use syntax::ast::HasGenericArgs;
+use syntax::Edition;
 use syntax::{
     ast,
     ast::{make, HasArgList},
@@ -93,6 +94,8 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             NodeOrToken::Token(t) => t.parent()?,
         })
         .map(|scope| scope.module());
+    let current_edition =
+        current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
     // prioritize more relevant imports
     proposed_imports.sort_by_key(|import| {
         Reverse(super::auto_import::relevance_score(ctx, import, current_module.as_ref()))
@@ -103,13 +106,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
         acc.add_group(
             &group_label,
             AssistId("qualify_path", AssistKind::QuickFix),
-            label(ctx.db(), candidate, &import),
+            label(ctx.db(), candidate, &import, current_edition),
             range,
             |builder| {
                 qualify_candidate.qualify(
                     |replace_with: String| builder.replace(range, replace_with),
                     &import.import_path,
                     import.item_to_import,
+                    current_edition,
                 )
             },
         );
@@ -130,8 +134,9 @@ impl QualifyCandidate<'_> {
         mut replacer: impl FnMut(String),
         import: &hir::ModPath,
         item: hir::ItemInNs,
+        edition: Edition,
     ) {
-        let import = mod_path_to_ast(import);
+        let import = mod_path_to_ast(import, edition);
         match self {
             QualifyCandidate::QualifierStart(segment, generics) => {
                 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
@@ -203,7 +208,7 @@ fn find_trait_method(
     if let Some(hir::AssocItem::Function(method)) =
         trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
             item.name(db)
-                .map(|name| name.display(db).to_string() == trait_method_name.to_string())
+                .map(|name| name.eq_ident(trait_method_name.text().as_str()))
                 .unwrap_or(false)
         })
     {
@@ -233,14 +238,19 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
     GroupLabel(format!("Qualify {name}"))
 }
 
-fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String {
+fn label(
+    db: &RootDatabase,
+    candidate: &ImportCandidate,
+    import: &LocatedImport,
+    edition: Edition,
+) -> String {
     let import_path = &import.import_path;
 
     match candidate {
         ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
-            format!("Qualify as `{}`", import_path.display(db))
+            format!("Qualify as `{}`", import_path.display(db, edition))
         }
-        _ => format!("Qualify with `{}`", import_path.display(db)),
+        _ => format!("Qualify with `{}`", import_path.display(db, edition)),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 02562566977..df7a5112f12 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -1,7 +1,7 @@
 use either::Either;
 use ide_db::FxHashMap;
 use itertools::Itertools;
-use syntax::{ast, ted, AstNode};
+use syntax::{ast, ted, AstNode, SmolStr, ToSmolStr};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
@@ -25,8 +25,9 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         path.syntax().parent().and_then(<Either<ast::RecordExpr, ast::RecordPat>>::cast)?;
 
     let ranks = compute_fields_ranks(&path, ctx)?;
-    let get_rank_of_field =
-        |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX);
+    let get_rank_of_field = |of: Option<SmolStr>| {
+        *ranks.get(of.unwrap_or_default().trim_start_matches("r#")).unwrap_or(&usize::MAX)
+    };
 
     let field_list = match &record {
         Either::Left(it) => Either::Left(it.record_expr_field_list()?),
@@ -36,7 +37,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         Either::Left(it) => Either::Left((
             it.fields()
                 .sorted_unstable_by_key(|field| {
-                    get_rank_of_field(field.field_name().map(|it| it.to_string()))
+                    get_rank_of_field(field.field_name().map(|it| it.to_smolstr()))
                 })
                 .collect::<Vec<_>>(),
             it,
@@ -44,7 +45,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         Either::Right(it) => Either::Right((
             it.fields()
                 .sorted_unstable_by_key(|field| {
-                    get_rank_of_field(field.field_name().map(|it| it.to_string()))
+                    get_rank_of_field(field.field_name().map(|it| it.to_smolstr()))
                 })
                 .collect::<Vec<_>>(),
             it,
@@ -97,7 +98,7 @@ fn compute_fields_ranks(
         .fields(ctx.db())
         .into_iter()
         .enumerate()
-        .map(|(idx, field)| (field.name(ctx.db()).display(ctx.db()).to_string(), idx))
+        .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx))
         .collect();
 
     Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index cf135f83e7b..ada89ce7c40 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -77,7 +77,8 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 ast::AssocItem::MacroCall(_) => None,
             };
 
-            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX)
+            name.and_then(|n| ranks.get(n.text().as_str().trim_start_matches("r#")).copied())
+                .unwrap_or(usize::MAX)
         })
         .collect();
 
@@ -114,7 +115,7 @@ fn compute_item_ranks(
             .iter()
             .flat_map(|i| i.name(ctx.db()))
             .enumerate()
-            .map(|(idx, name)| (name.display(ctx.db()).to_string(), idx))
+            .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx))
             .collect(),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 5ff4af19fbf..248f18789ce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -70,6 +70,7 @@ pub(crate) fn replace_derive_with_manual_impl(
 
     let current_module = ctx.sema.scope(adt.syntax())?.module();
     let current_crate = current_module.krate();
+    let current_edition = current_crate.edition(ctx.db());
 
     let found_traits = items_locator::items_with_name(
         &ctx.sema,
@@ -85,7 +86,7 @@ pub(crate) fn replace_derive_with_manual_impl(
         current_module
             .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config())
             .as_ref()
-            .map(mod_path_to_ast)
+            .map(|path| mod_path_to_ast(path, current_edition))
             .zip(Some(trait_))
     });
 
@@ -214,7 +215,7 @@ fn impl_def_from_trait(
     let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
 
     let first_assoc_item =
-        add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope);
+        add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope);
 
     // Generate a default `impl` function body for the derived trait.
     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index d0aa835e79a..65330b34c4a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -5,7 +5,7 @@ use ide_db::{
 };
 use syntax::{
     ast::{self, make, HasGenericArgs},
-    match_ast, ted, AstNode, SyntaxNode,
+    match_ast, ted, AstNode, Edition, SyntaxNode,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -29,32 +29,32 @@ pub(crate) fn replace_qualified_name_with_use(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
 ) -> Option<()> {
-    let path: ast::Path = ctx.find_node_at_offset()?;
+    let original_path: ast::Path = ctx.find_node_at_offset()?;
     // We don't want to mess with use statements
-    if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
+    if original_path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() {
         cov_mark::hit!(not_applicable_in_use);
         return None;
     }
 
-    if path.qualifier().is_none() {
+    if original_path.qualifier().is_none() {
         cov_mark::hit!(dont_import_trivial_paths);
         return None;
     }
 
     // only offer replacement for non assoc items
-    match ctx.sema.resolve_path(&path)? {
+    match ctx.sema.resolve_path(&original_path)? {
         hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
         _ => return None,
     }
     // then search for an import for the first path segment of what we want to replace
     // that way it is less likely that we import the item from a different location due re-exports
-    let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? {
+    let module = match ctx.sema.resolve_path(&original_path.first_qualifier_or_self())? {
         hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
         _ => return None,
     };
 
     let starts_with_name_ref = !matches!(
-        path.first_segment().and_then(|it| it.kind()),
+        original_path.first_segment().and_then(|it| it.kind()),
         Some(
             ast::PathSegmentKind::CrateKw
                 | ast::PathSegmentKind::SuperKw
@@ -63,7 +63,7 @@ pub(crate) fn replace_qualified_name_with_use(
     );
     let path_to_qualifier = starts_with_name_ref
         .then(|| {
-            ctx.sema.scope(path.syntax())?.module().find_use_path(
+            ctx.sema.scope(original_path.syntax())?.module().find_use_path(
                 ctx.sema.db,
                 module,
                 ctx.config.insert_use.prefix_kind,
@@ -72,8 +72,8 @@ pub(crate) fn replace_qualified_name_with_use(
         })
         .flatten();
 
-    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
-    let target = path.syntax().text_range();
+    let scope = ImportScope::find_insert_use_container(original_path.syntax(), &ctx.sema)?;
+    let target = original_path.syntax().text_range();
     acc.add(
         AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
         "Replace qualified path with use",
@@ -86,13 +86,19 @@ pub(crate) fn replace_qualified_name_with_use(
                 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
                 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
             };
-            shorten_paths(scope.as_syntax_node(), &path);
-            let path = drop_generic_args(&path);
+            shorten_paths(scope.as_syntax_node(), &original_path);
+            let path = drop_generic_args(&original_path);
+            let edition = ctx
+                .sema
+                .scope(original_path.syntax())
+                .map(|semantics_scope| semantics_scope.krate().edition(ctx.db()))
+                .unwrap_or(Edition::CURRENT);
             // stick the found import in front of the to be replaced path
-            let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) {
-                Some(qualifier) => make::path_concat(qualifier, path),
-                None => path,
-            };
+            let path =
+                match path_to_qualifier.and_then(|it| mod_path_to_ast(&it, edition).qualifier()) {
+                    Some(qualifier) => make::path_concat(qualifier, path),
+                    None => path,
+                };
             insert_use(&scope, path, &ctx.config.insert_use);
         },
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 4913cfdea94..66671c934c4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -48,15 +48,17 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
 
     let mut formatter = |_: &hir::Type| String::from("todo!()");
 
+    let edition = scope.krate().edition(ctx.db());
     let paths = paths
         .into_iter()
         .filter_map(|path| {
-            path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config()).ok()
+            path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config(), edition)
+                .ok()
         })
         .unique();
 
     let macro_name = macro_call.name(ctx.sema.db);
-    let macro_name = macro_name.display(ctx.sema.db);
+    let macro_name = macro_name.display(ctx.sema.db, edition);
 
     for code in paths {
         acc.add_group(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
index 98975a324dc..9ab36bf7757 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
@@ -141,7 +141,8 @@ pub(crate) fn desugar_async_into_impl_future(
         ModuleDef::Trait(future_trait),
         ctx.config.import_path_config(),
     )?;
-    let trait_path = trait_path.display(ctx.db());
+    let edition = scope.krate().edition(ctx.db());
+    let trait_path = trait_path.display(ctx.db(), edition);
 
     acc.add(
         AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index c67693ea2bb..b8a6f3b6dbe 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -14,7 +14,7 @@ use syntax::{
         edit_in_place::{AttrsOwnerEdit, Indent, Removable},
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
-    ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile,
+    ted, AstNode, AstToken, Direction, Edition, NodeOrToken, SourceFile,
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
 };
@@ -174,7 +174,7 @@ pub fn add_trait_assoc_items_to_impl(
     original_items: &[InFile<ast::AssocItem>],
     trait_: hir::Trait,
     impl_: &ast::Impl,
-    target_scope: hir::SemanticsScope<'_>,
+    target_scope: &hir::SemanticsScope<'_>,
 ) -> ast::AssocItem {
     let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
     let items = original_items.iter().map(|InFile { file_id, value: original_item }| {
@@ -195,7 +195,7 @@ pub fn add_trait_assoc_items_to_impl(
             // FIXME: Paths in nested macros are not handled well. See
             // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
             let transform =
-                PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone());
+                PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
             transform.apply(cloned_item.syntax());
         }
         cloned_item.remove_attrs_and_docs();
@@ -684,31 +684,31 @@ enum ReferenceConversionType {
 }
 
 impl ReferenceConversion {
-    pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> ast::Type {
+    pub(crate) fn convert_type(&self, db: &dyn HirDatabase, edition: Edition) -> ast::Type {
         let ty = match self.conversion {
-            ReferenceConversionType::Copy => self.ty.display(db).to_string(),
+            ReferenceConversionType::Copy => self.ty.display(db, edition).to_string(),
             ReferenceConversionType::AsRefStr => "&str".to_owned(),
             ReferenceConversionType::AsRefSlice => {
                 let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db).to_string();
+                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
                 format!("&[{type_argument_name}]")
             }
             ReferenceConversionType::Dereferenced => {
                 let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db).to_string();
+                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
                 format!("&{type_argument_name}")
             }
             ReferenceConversionType::Option => {
                 let type_argument_name =
-                    self.ty.type_arguments().next().unwrap().display(db).to_string();
+                    self.ty.type_arguments().next().unwrap().display(db, edition).to_string();
                 format!("Option<&{type_argument_name}>")
             }
             ReferenceConversionType::Result => {
                 let mut type_arguments = self.ty.type_arguments();
                 let first_type_argument_name =
-                    type_arguments.next().unwrap().display(db).to_string();
+                    type_arguments.next().unwrap().display(db, edition).to_string();
                 let second_type_argument_name =
-                    type_arguments.next().unwrap().display(db).to_string();
+                    type_arguments.next().unwrap().display(db, edition).to_string();
                 format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
             }
         };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
index fc43d243b36..3130ef06955 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{self, HasName},
-    match_ast, AstNode, SmolStr,
+    match_ast, AstNode, Edition, SmolStr,
 };
 
 /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait`
@@ -271,24 +271,25 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> {
 fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> {
     let ty = sema.type_of_expr(expr)?.adjusted();
     let ty = ty.remove_ref().unwrap_or(ty);
+    let edition = sema.scope(expr.syntax())?.krate().edition(sema.db);
 
-    name_of_type(&ty, sema.db)
+    name_of_type(&ty, sema.db, edition)
 }
 
-fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> {
+fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<String> {
     let name = if let Some(adt) = ty.as_adt() {
-        let name = adt.name(db).display(db).to_string();
+        let name = adt.name(db).display(db, edition).to_string();
 
         if WRAPPER_TYPES.contains(&name.as_str()) {
             let inner_ty = ty.type_arguments().next()?;
-            return name_of_type(&inner_ty, db);
+            return name_of_type(&inner_ty, db, edition);
         }
 
         name
     } else if let Some(trait_) = ty.as_dyn_trait() {
-        trait_name(&trait_, db)?
+        trait_name(&trait_, db, edition)?
     } else if let Some(traits) = ty.as_impl_traits(db) {
-        let mut iter = traits.filter_map(|t| trait_name(&t, db));
+        let mut iter = traits.filter_map(|t| trait_name(&t, db, edition));
         let name = iter.next()?;
         if iter.next().is_some() {
             return None;
@@ -300,8 +301,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> {
     normalize(&name)
 }
 
-fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option<String> {
-    let name = trait_.name(db).display(db).to_string();
+fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option<String> {
+    let name = trait_.name(db).display(db, edition).to_string();
     if USELESS_TRAITS.contains(&name.as_str()) {
         return None;
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 58e9b724df2..b537150608b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -85,6 +85,7 @@ impl Completions {
             CompletionItemKind::Keyword,
             ctx.source_range(),
             SmolStr::new_static(keyword),
+            ctx.edition,
         );
         item.add_to(self, ctx.db);
     }
@@ -124,7 +125,8 @@ impl Completions {
         kw: &str,
         snippet: &str,
     ) {
-        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
+        let mut item =
+            CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition);
 
         match ctx.config.snippet_cap {
             Some(cap) => {
@@ -149,7 +151,8 @@ impl Completions {
         kw: &str,
         snippet: &str,
     ) {
-        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
+        let mut item =
+            CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition);
 
         match ctx.config.snippet_cap {
             Some(cap) => item.insert_snippet(cap, snippet),
@@ -544,7 +547,8 @@ impl Completions {
         CompletionItem::new(
             SymbolKind::LifetimeParam,
             ctx.source_range(),
-            name.display_no_db().to_smolstr(),
+            name.display_no_db(ctx.edition).to_smolstr(),
+            ctx.edition,
         )
         .add_to(self, ctx.db)
     }
@@ -553,7 +557,8 @@ impl Completions {
         CompletionItem::new(
             SymbolKind::Label,
             ctx.source_range(),
-            name.display_no_db().to_smolstr(),
+            name.display_no_db(ctx.edition).to_smolstr(),
+            ctx.edition,
         )
         .add_to(self, ctx.db)
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index a7a6cdebd36..88f4461f4dd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -48,11 +48,15 @@ pub(crate) fn complete_known_attribute_input(
 
     match path.text().as_str() {
         "repr" => repr::complete_repr(acc, ctx, tt),
-        "feature" => {
-            lint::complete_lint(acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt)?, FEATURES)
-        }
+        "feature" => lint::complete_lint(
+            acc,
+            ctx,
+            colon_prefix,
+            &parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
+            FEATURES,
+        ),
         "allow" | "warn" | "deny" | "forbid" => {
-            let existing_lints = parse_tt_as_comma_sep_paths(tt)?;
+            let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?;
 
             let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
                 .iter()
@@ -66,9 +70,12 @@ pub(crate) fn complete_known_attribute_input(
             lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
         }
         "cfg" => cfg::complete_cfg(acc, ctx),
-        "macro_use" => {
-            macro_use::complete_macro_use(acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt)?)
-        }
+        "macro_use" => macro_use::complete_macro_use(
+            acc,
+            ctx,
+            extern_crate,
+            &parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
+        ),
         _ => (),
     }
     Some(())
@@ -130,8 +137,12 @@ pub(crate) fn complete_attribute_path(
     });
 
     let add_completion = |attr_completion: &AttrCompletion| {
-        let mut item =
-            CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), attr_completion.label);
+        let mut item = CompletionItem::new(
+            SymbolKind::Attribute,
+            ctx.source_range(),
+            attr_completion.label,
+            ctx.edition,
+        );
 
         if let Some(lookup) = attr_completion.lookup {
             item.lookup_by(lookup);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
index 6e7d50ede06..cda0da13b26 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -8,7 +8,8 @@ use crate::{completions::Completions, context::CompletionContext, CompletionItem
 
 pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
     let add_completion = |item: &str| {
-        let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item);
+        let mut completion =
+            CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item, ctx.edition);
         completion.insert_text(format!(r#""{item}""#));
         acc.add(completion.build(ctx.db));
     };
@@ -41,7 +42,12 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
             name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
                 let s = s.as_str();
                 let insert_text = format!(r#""{s}""#);
-                let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+                let mut item = CompletionItem::new(
+                    SymbolKind::BuiltinAttr,
+                    ctx.source_range(),
+                    s,
+                    ctx.edition,
+                );
                 item.insert_text(insert_text);
 
                 acc.add(item.build(ctx.db));
@@ -49,7 +55,8 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
         },
         None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
             let s = s.as_str();
-            let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+            let item =
+                CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition);
             acc.add(item.build(ctx.db));
         }),
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
index 0127a428248..1f8927401b2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
@@ -62,7 +62,7 @@ pub(crate) fn complete_derive_path(
                     _ => return acc.add_macro(ctx, path_ctx, mac, name),
                 };
 
-                let name_ = name.display_no_db().to_smolstr();
+                let name_ = name.display_no_db(ctx.edition).to_smolstr();
                 let find = DEFAULT_DERIVE_DEPENDENCIES
                     .iter()
                     .find(|derive_completion| derive_completion.label == name_);
@@ -72,10 +72,9 @@ pub(crate) fn complete_derive_path(
                         let mut components = vec![derive_completion.label];
                         components.extend(derive_completion.dependencies.iter().filter(
                             |&&dependency| {
-                                !existing_derives
-                                    .iter()
-                                    .map(|it| it.name(ctx.db))
-                                    .any(|it| it.display_no_db().to_smolstr() == dependency)
+                                !existing_derives.iter().map(|it| it.name(ctx.db)).any(|it| {
+                                    it.display_no_db(ctx.edition).to_smolstr() == dependency
+                                })
                             },
                         ));
                         let lookup = components.join(", ");
@@ -85,6 +84,7 @@ pub(crate) fn complete_derive_path(
                             SymbolKind::Derive,
                             ctx.source_range(),
                             SmolStr::from_iter(label),
+                            ctx.edition,
                         );
                         if let Some(docs) = mac.docs(ctx.db) {
                             item.documentation(docs);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
index f9dec538064..d5f9cd5fc76 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
@@ -54,7 +54,8 @@ pub(super) fn complete_lint(
             Some(qual) if !is_qualified => format!("{qual}::{name}"),
             _ => name.to_owned(),
         };
-        let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label);
+        let mut item =
+            CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition);
         item.documentation(Documentation::new(description.to_owned()));
         item.add_to(acc, ctx.db)
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs
index 7e3a62405a7..deb12282c02 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs
@@ -28,7 +28,8 @@ pub(super) fn complete_macro_use(
                 continue;
             }
 
-            let item = CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name);
+            let item =
+                CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name, ctx.edition);
             item.add_to(acc, ctx.db);
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs
index 14f464b7753..12652b44892 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs
@@ -30,7 +30,12 @@ pub(super) fn complete_repr(
                 continue;
             }
 
-            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label);
+            let mut item = CompletionItem::new(
+                SymbolKind::BuiltinAttr,
+                ctx.source_range(),
+                label,
+                ctx.edition,
+            );
             if let Some(lookup) = lookup {
                 item.lookup_by(lookup);
             }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index a07daf4c4e4..d55bc3ea5d0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -29,6 +29,7 @@ pub(crate) fn complete_dot(
             CompletionItemKind::Keyword,
             ctx.source_range(),
             SmolStr::new_static("await"),
+            ctx.edition,
         );
         item.detail("expr.await");
         item.add_to(acc, ctx.db);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index 23d93d3b746..c9013d1d17d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -56,7 +56,7 @@ pub(crate) fn complete_cargo_env_vars(
     let range = original.text_range_between_quotes()?;
 
     CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| {
-        let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var);
+        let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var, ctx.edition);
         item.detail(detail);
         item.add_to(acc, ctx.db);
     });
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
index b5d5604c751..1a06e0a3a0e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
@@ -52,8 +52,13 @@ pub(crate) fn complete_extern_abi(
     let abi_str = expanded;
     let source_range = abi_str.text_range_between_quotes()?;
     for &abi in SUPPORTED_CALLING_CONVENTIONS {
-        CompletionItem::new(CompletionItemKind::Keyword, source_range, SmolStr::new_static(abi))
-            .add_to(acc, ctx.db);
+        CompletionItem::new(
+            CompletionItemKind::Keyword,
+            source_range,
+            SmolStr::new_static(abi),
+            ctx.edition,
+        )
+        .add_to(acc, ctx.db);
     }
     Some(())
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
index 2427f4e49f2..7cb710c2d96 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
@@ -19,7 +19,8 @@ pub(crate) fn complete_extern_crate(acc: &mut Completions, ctx: &CompletionConte
         let mut item = CompletionItem::new(
             CompletionItemKind::SymbolKind(SymbolKind::Module),
             ctx.source_range(),
-            name.display_no_db().to_smolstr(),
+            name.display_no_db(ctx.edition).to_smolstr(),
+            ctx.edition,
         );
         item.set_documentation(module.docs(ctx.db));
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index fdce7c547a4..2a6b310d3a2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -411,7 +411,7 @@ fn compute_fuzzy_completion_order_key(
     cov_mark::hit!(certain_fuzzy_order_test);
     let import_name = match proposed_mod_path.segments().last() {
         // FIXME: nasty alloc, this is a hot path!
-        Some(name) => name.display_no_db().to_smolstr().to_ascii_lowercase(),
+        Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(),
         None => return usize::MAX,
     };
     match import_name.match_indices(user_input_lowercased).next() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
index a59246229bb..ee3b817ee8c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
@@ -32,7 +32,7 @@ pub(crate) fn complete_fn_param(
     let comma_wrapper = comma_wrapper(ctx);
     let mut add_new_item_to_acc = |label: &str| {
         let mk_item = |label: &str, range: TextRange| {
-            CompletionItem::new(CompletionItemKind::Binding, range, label)
+            CompletionItem::new(CompletionItemKind::Binding, range, label, ctx.edition)
         };
         let item = match &comma_wrapper {
             Some((fmt, range)) => mk_item(&fmt(label), *range),
@@ -50,7 +50,7 @@ pub(crate) fn complete_fn_param(
         ParamKind::Closure(closure) => {
             let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?;
             params_from_stmt_list_scope(ctx, stmt_list, |name, ty| {
-                add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db)));
+                add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db, ctx.edition)));
             });
         }
     }
@@ -101,8 +101,8 @@ fn fill_fn_params(
     if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) {
         params_from_stmt_list_scope(ctx, stmt_list, |name, ty| {
             file_params
-                .entry(format!("{}: {ty}", name.display(ctx.db)))
-                .or_insert(name.display(ctx.db).to_string());
+                .entry(format!("{}: {ty}", name.display(ctx.db, ctx.edition)))
+                .or_insert(name.display(ctx.db, ctx.edition).to_string());
         });
     }
     remove_duplicated(&mut file_params, param_list.params());
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
index 23affc36592..a87c60c694a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
@@ -35,7 +35,8 @@ pub(crate) fn format_string(
         CompletionItem::new(
             CompletionItemKind::Binding,
             source_range,
-            name.display_no_db().to_smolstr(),
+            name.display_no_db(ctx.edition).to_smolstr(),
+            ctx.edition,
         )
         .add_to(acc, ctx.db);
     });
@@ -50,7 +51,8 @@ pub(crate) fn format_string(
             CompletionItem::new(
                 CompletionItemKind::SymbolKind(symbol_kind),
                 source_range,
-                name.display_no_db().to_smolstr(),
+                name.display_no_db(ctx.edition).to_smolstr(),
+                ctx.edition,
             )
             .add_to(acc, ctx.db);
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 2fd7805e60d..fc6e1ebf05f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -184,7 +184,7 @@ fn add_function_impl(
     let label = format_smolstr!(
         "{}fn {}({})",
         if is_async { "async " } else { "" },
-        fn_name.display(ctx.db),
+        fn_name.display(ctx.db, ctx.edition),
         if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
     );
 
@@ -194,11 +194,11 @@ fn add_function_impl(
         SymbolKind::Function
     });
 
-    let mut item = CompletionItem::new(completion_kind, replacement_range, label);
+    let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition);
     item.lookup_by(format!(
         "{}fn {}",
         if is_async { "async " } else { "" },
-        fn_name.display(ctx.db)
+        fn_name.display(ctx.db, ctx.edition)
     ))
     .set_documentation(func.docs(ctx.db))
     .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
@@ -262,7 +262,8 @@ fn add_type_alias_impl(
 
     let label = format_smolstr!("type {alias_name} =");
 
-    let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label);
+    let mut item =
+        CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition);
     item.lookup_by(format!("type {alias_name}"))
         .set_documentation(type_alias.docs(ctx.db))
         .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
@@ -320,7 +321,7 @@ fn add_const_impl(
     const_: hir::Const,
     impl_def: hir::Impl,
 ) {
-    let const_name = const_.name(ctx.db).map(|n| n.display_no_db().to_smolstr());
+    let const_name = const_.name(ctx.db).map(|n| n.display_no_db(ctx.edition).to_smolstr());
 
     if let Some(const_name) = const_name {
         if let Some(source) = ctx.sema.source(const_) {
@@ -334,7 +335,8 @@ fn add_const_impl(
                 let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro());
                 let replacement = format!("{label} ");
 
-                let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label);
+                let mut item =
+                    CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition);
                 item.lookup_by(format_smolstr!("const {const_name}"))
                     .set_documentation(const_.docs(ctx.db))
                     .set_relevance(CompletionRelevance {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
index 03fe93c563f..9efc52428ef 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
@@ -41,7 +41,7 @@ pub(crate) fn complete_lifetime(
         if matches!(
             res,
             ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
-                 if param_lifetime != Some(&*name.display_no_db().to_smolstr())
+                 if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr())
         ) {
             acc.add_lifetime(ctx, name);
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index d9a10893bf5..05e2892fdc8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -53,7 +53,7 @@ pub(crate) fn complete_mod(
 
     let existing_mod_declarations = current_module
         .children(ctx.db)
-        .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db).to_string()))
+        .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db, ctx.edition).to_string()))
         .filter(|module| module != ctx.original_token.text())
         .collect::<FxHashSet<_>>();
 
@@ -99,7 +99,8 @@ pub(crate) fn complete_mod(
             if mod_under_caret.semicolon_token().is_none() {
                 label.push(';');
             }
-            let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label);
+            let item =
+                CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label, ctx.edition);
             item.add_to(acc, ctx.db)
         });
 
@@ -140,7 +141,9 @@ fn directory_to_look_for_submodules(
     module_chain_to_containing_module_file(module, db)
         .into_iter()
         .filter_map(|module| module.name(db))
-        .try_fold(base_directory, |path, name| path.join(&name.display_no_db().to_smolstr()))
+        .try_fold(base_directory, |path, name| {
+            path.join(&name.unescaped().display_no_db().to_smolstr())
+        })
 }
 
 fn module_chain_to_containing_module_file(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 977e0d80a4d..a632f148936 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -72,7 +72,10 @@ pub(crate) fn complete_postfix(
                     let mut item = postfix_snippet(
                         "drop",
                         "fn drop(&mut self)",
-                        &format!("{path}($0{receiver_text})", path = path.display(ctx.db)),
+                        &format!(
+                            "{path}($0{receiver_text})",
+                            path = path.display(ctx.db, ctx.edition)
+                        ),
                     );
                     item.set_documentation(drop_fn.docs(ctx.db));
                     item.add_to(acc, ctx.db);
@@ -335,8 +338,12 @@ fn build_postfix_snippet_builder<'ctx>(
     ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
         move |label, detail, snippet| {
             let edit = TextEdit::replace(delete_range, snippet.to_owned());
-            let mut item =
-                CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
+            let mut item = CompletionItem::new(
+                CompletionItemKind::Snippet,
+                ctx.source_range(),
+                label,
+                ctx.edition,
+            );
             item.detail(detail).snippet_edit(cap, edit);
             let postfix_match = if ctx.original_token.text() == label {
                 cov_mark::hit!(postfix_exact_match_is_high_priority);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index 1dcf41f8dd2..117a5e3d935 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -73,6 +73,7 @@ pub(crate) fn complete_record_expr_fields(
                     CompletionItemKind::Snippet,
                     ctx.source_range(),
                     SmolStr::new_static(".."),
+                    ctx.edition,
                 );
                 item.insert_text(".");
                 item.add_to(acc, ctx.db);
@@ -101,6 +102,7 @@ pub(crate) fn add_default_update(
             SymbolKind::Field,
             ctx.source_range(),
             SmolStr::new_static(completion_text),
+            ctx.edition,
         );
         let completion_text =
             completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
index e831113350a..357709e0c1f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
@@ -118,7 +118,8 @@ macro_rules! $1 {
 }
 
 fn snippet(ctx: &CompletionContext<'_>, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
-    let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
+    let mut item =
+        CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label, ctx.edition);
     item.insert_snippet(cap, snippet);
     item
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 8e5b55360dc..45704549e60 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -107,7 +107,11 @@ pub(crate) fn complete_use_path(
                             let item = CompletionItem::new(
                                 CompletionItemKind::SymbolKind(SymbolKind::Enum),
                                 ctx.source_range(),
-                                format_smolstr!("{}::", e.name(ctx.db).display(ctx.db)),
+                                format_smolstr!(
+                                    "{}::",
+                                    e.name(ctx.db).display(ctx.db, ctx.edition)
+                                ),
+                                ctx.edition,
                             );
                             acc.add(item.build(ctx.db));
                         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 5b64a98a8bb..bcd9df94194 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -437,6 +437,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(crate) module: hir::Module,
     /// Whether nightly toolchain is used. Cached since this is looked up a lot.
     is_nightly: bool,
+    pub(crate) edition: Edition,
 
     /// The expected name of what we are completing.
     /// This is usually the parameter name of the function argument we are completing.
@@ -467,9 +468,9 @@ impl CompletionContext<'_> {
                 cov_mark::hit!(completes_if_lifetime_without_idents);
                 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
             }
-            IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
-            // FIXME: Edition
-            _ if kind.is_keyword(Edition::CURRENT) => self.original_token.text_range(),
+            LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
+            // We want to consider all keywords in all editions.
+            _ if kind.is_any_identifier() => self.original_token.text_range(),
             _ => TextRange::empty(self.position.offset),
         }
     }
@@ -717,6 +718,7 @@ impl<'a> CompletionContext<'a> {
 
         let krate = scope.krate();
         let module = scope.module();
+        let edition = krate.edition(db);
 
         let toolchain = db.toolchain_channel(krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
@@ -743,6 +745,7 @@ impl<'a> CompletionContext<'a> {
             krate,
             module,
             is_nightly,
+            edition,
             expected_name,
             expected_type,
             qualifier_ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 1e972b9b4ce..ed359394f1c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -1385,7 +1385,7 @@ fn pattern_context_for(
                                         }).map(|enum_| enum_.variants(sema.db))
                                     })
                                 }).map(|variants| variants.iter().filter_map(|variant| {
-                                        let variant_name = variant.name(sema.db).display(sema.db).to_string();
+                                        let variant_name = variant.name(sema.db).unescaped().display(sema.db).to_string();
 
                                         let variant_already_present = match_arm_list.arms().any(|arm| {
                                             arm.pat().and_then(|pat| {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 3657a7d969b..a30a115da1f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -10,7 +10,7 @@ use ide_db::{
 use itertools::Itertools;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
-use syntax::{format_smolstr, SmolStr, TextRange, TextSize};
+use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
 use text_edit::TextEdit;
 
 use crate::{
@@ -400,6 +400,7 @@ impl CompletionItem {
         kind: impl Into<CompletionItemKind>,
         source_range: TextRange,
         label: impl Into<SmolStr>,
+        edition: Edition,
     ) -> Builder {
         let label = label.into();
         Builder {
@@ -419,6 +420,7 @@ impl CompletionItem {
             ref_match: None,
             imports_to_add: Default::default(),
             doc_aliases: vec![],
+            edition,
         }
     }
 
@@ -464,6 +466,7 @@ pub(crate) struct Builder {
     trigger_call_info: bool,
     relevance: CompletionRelevance,
     ref_match: Option<(Mutability, TextSize)>,
+    edition: Edition,
 }
 
 impl Builder {
@@ -517,7 +520,7 @@ impl Builder {
             label_detail.replace(format_smolstr!(
                 "{} (use {})",
                 label_detail.as_deref().unwrap_or_default(),
-                import_edit.import_path.display(db)
+                import_edit.import_path.display(db, self.edition)
             ));
         } else if let Some(trait_name) = self.trait_name {
             label_detail.replace(format_smolstr!(
@@ -536,8 +539,8 @@ impl Builder {
             .into_iter()
             .filter_map(|import| {
                 Some((
-                    import.import_path.display(db).to_string(),
-                    import.import_path.segments().last()?.display(db).to_string(),
+                    import.import_path.display(db, self.edition).to_string(),
+                    import.import_path.segments().last()?.display(db, self.edition).to_string(),
                 ))
             })
             .collect();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 90c1728074d..58d1fad0950 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -245,6 +245,7 @@ pub fn resolve_completion_edits(
 
     let current_module = sema.scope(position_for_import)?.module();
     let current_crate = current_module.krate();
+    let current_edition = current_crate.edition(db);
     let new_ast = scope.clone_for_update();
     let mut import_insert = TextEdit::builder();
 
@@ -261,9 +262,13 @@ pub fn resolve_completion_edits(
             .filter_map(|candidate| {
                 current_module.find_use_path(db, candidate, config.insert_use.prefix_kind, cfg)
             })
-            .find(|mod_path| mod_path.display(db).to_string() == full_import_path);
+            .find(|mod_path| mod_path.display(db, current_edition).to_string() == full_import_path);
         if let Some(import_path) = import {
-            insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use);
+            insert_use::insert_use(
+                &new_ast,
+                mod_path_to_ast(&import_path, current_edition),
+                &config.insert_use,
+            );
         }
     });
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 02d667c5205..ff5ec3a29f3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -17,7 +17,7 @@ use ide_db::{
     imports::import_assets::LocatedImport,
     RootDatabase, SnippetCap, SymbolKind,
 };
-use syntax::{ast, format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange, ToSmolStr};
+use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
 use text_edit::TextEdit;
 
 use crate::{
@@ -133,19 +133,22 @@ pub(crate) fn render_field(
     let db = ctx.db();
     let is_deprecated = ctx.is_deprecated(field);
     let name = field.name(db);
-    let (name, escaped_name) =
-        (name.unescaped().display(db).to_smolstr(), name.display_no_db().to_smolstr());
+    let (name, escaped_name) = (
+        name.unescaped().display(db).to_smolstr(),
+        name.display_no_db(ctx.completion.edition).to_smolstr(),
+    );
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
-        field_with_receiver(db, receiver.as_ref(), &name),
+        field_with_receiver(db, receiver.as_ref(), &name, ctx.completion.edition),
+        ctx.completion.edition,
     );
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, ty),
         exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
         ..CompletionRelevance::default()
     });
-    item.detail(ty.display(db).to_string())
+    item.detail(ty.display(db, ctx.completion.edition).to_string())
         .set_documentation(field.docs(db))
         .set_deprecated(is_deprecated)
         .lookup_by(name);
@@ -159,7 +162,8 @@ pub(crate) fn render_field(
 
         builder.replace(
             ctx.source_range(),
-            field_with_receiver(db, receiver.as_ref(), &escaped_name).into(),
+            field_with_receiver(db, receiver.as_ref(), &escaped_name, ctx.completion.edition)
+                .into(),
         );
 
         let expected_fn_type =
@@ -183,7 +187,12 @@ pub(crate) fn render_field(
 
         item.text_edit(builder.finish());
     } else {
-        item.insert_text(field_with_receiver(db, receiver.as_ref(), &escaped_name));
+        item.insert_text(field_with_receiver(
+            db,
+            receiver.as_ref(),
+            &escaped_name,
+            ctx.completion.edition,
+        ));
     }
     if let Some(receiver) = &dot_access.receiver {
         if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
@@ -200,10 +209,11 @@ fn field_with_receiver(
     db: &RootDatabase,
     receiver: Option<&hir::Name>,
     field_name: &str,
+    edition: Edition,
 ) -> SmolStr {
     receiver.map_or_else(
         || field_name.into(),
-        |receiver| format_smolstr!("{}.{field_name}", receiver.display(db)),
+        |receiver| format_smolstr!("{}.{field_name}", receiver.display(db, edition)),
     )
 }
 
@@ -216,9 +226,16 @@ pub(crate) fn render_tuple_field(
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
-        field_with_receiver(ctx.db(), receiver.as_ref(), &field.to_string()),
+        field_with_receiver(
+            ctx.db(),
+            receiver.as_ref(),
+            &field.to_string(),
+            ctx.completion.edition,
+        ),
+        ctx.completion.edition,
     );
-    item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
+    item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
+        .lookup_by(field.to_string());
     item.build(ctx.db())
 }
 
@@ -226,8 +243,12 @@ pub(crate) fn render_type_inference(
     ty_string: String,
     ctx: &CompletionContext<'_>,
 ) -> CompletionItem {
-    let mut builder =
-        CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
+    let mut builder = CompletionItem::new(
+        CompletionItemKind::InferredType,
+        ctx.source_range(),
+        ty_string,
+        ctx.edition,
+    );
     builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
     builder.build(ctx.db)
 }
@@ -296,7 +317,7 @@ pub(crate) fn render_expr(
 
     let cfg = ctx.config.import_path_config();
 
-    let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg).ok()?;
+    let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
 
     let source_range = match ctx.original_token.parent() {
         Some(node) => match node.ancestors().find_map(ast::Path::cast) {
@@ -306,10 +327,13 @@ pub(crate) fn render_expr(
         None => ctx.source_range(),
     };
 
-    let mut item = CompletionItem::new(CompletionItemKind::Expression, source_range, label);
+    let mut item =
+        CompletionItem::new(CompletionItemKind::Expression, source_range, label, ctx.edition);
 
-    let snippet =
-        format!("{}$0", expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg).ok()?);
+    let snippet = format!(
+        "{}$0",
+        expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg, ctx.edition).ok()?
+    );
     let edit = TextEdit::replace(source_range, snippet);
     item.snippet_edit(ctx.config.snippet_cap?, edit);
     item.documentation(Documentation::new(String::from("Autogenerated expression by term search")));
@@ -396,10 +420,10 @@ fn render_resolution_path(
     let config = completion.config;
     let requires_import = import_to_add.is_some();
 
-    let name = local_name.display_no_db().to_smolstr();
+    let name = local_name.display_no_db(ctx.completion.edition).to_smolstr();
     let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
-    if local_name.is_escaped() {
-        item.insert_text(local_name.display_no_db().to_smolstr());
+    if local_name.is_escaped(completion.edition) {
+        item.insert_text(local_name.display_no_db(completion.edition).to_smolstr());
     }
     // Add `<>` for generic types
     let type_path_no_ty_args = matches!(
@@ -421,14 +445,17 @@ fn render_resolution_path(
                 item.lookup_by(name.clone())
                     .label(SmolStr::from_iter([&name, "<…>"]))
                     .trigger_call_info()
-                    .insert_snippet(cap, format!("{}<$0>", local_name.display(db)));
+                    .insert_snippet(
+                        cap,
+                        format!("{}<$0>", local_name.display(db, completion.edition)),
+                    );
             }
         }
     }
 
     let mut set_item_relevance = |ty: Type| {
         if !ty.is_unknown() {
-            item.detail(ty.display(db).to_string());
+            item.detail(ty.display(db, completion.edition).to_string());
         }
 
         item.set_relevance(CompletionRelevance {
@@ -485,6 +512,7 @@ fn render_resolution_simple_(
         kind,
         ctx.source_range(),
         local_name.unescaped().display(db).to_smolstr(),
+        ctx.completion.edition,
     );
     item.set_relevance(ctx.completion_relevance())
         .set_documentation(scope_def_docs(db, resolution))
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index 3bfec0de6bc..415d87c6239 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -14,11 +14,14 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option
 fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
     let db = ctx.db();
     let name = const_.name(db)?;
-    let (name, escaped_name) =
-        (name.unescaped().display(db).to_smolstr(), name.display(db).to_smolstr());
-    let detail = const_.display(db).to_string();
+    let (name, escaped_name) = (
+        name.unescaped().display(db).to_smolstr(),
+        name.display(db, ctx.completion.edition).to_smolstr(),
+    );
+    let detail = const_.display(db, ctx.completion.edition).to_string();
 
-    let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name);
+    let mut item =
+        CompletionItem::new(SymbolKind::Const, ctx.source_range(), name, ctx.completion.edition);
     item.set_documentation(ctx.docs(const_))
         .set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_))
         .detail(detail)
@@ -26,7 +29,7 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem>
 
     if let Some(actm) = const_.as_assoc_item(db) {
         if let Some(trt) = actm.container_or_implemented_trait(db) {
-            item.trait_name(trt.name(db).display_no_db().to_smolstr());
+            item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr());
         }
     }
     item.insert_text(escaped_name);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 05b2d0ae386..74092b53f52 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -4,7 +4,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
 use ide_db::{SnippetCap, SymbolKind};
 use itertools::Itertools;
 use stdx::{format_to, to_lower_snake_case};
-use syntax::{format_smolstr, AstNode, SmolStr, ToSmolStr};
+use syntax::{format_smolstr, AstNode, Edition, SmolStr, ToSmolStr};
 
 use crate::{
     context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
@@ -62,9 +62,16 @@ fn render(
                 receiver.unescaped().display(ctx.db()),
                 name.unescaped().display(ctx.db())
             ),
-            format_smolstr!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())),
+            format_smolstr!(
+                "{}.{}",
+                receiver.display(ctx.db(), completion.edition),
+                name.display(ctx.db(), completion.edition)
+            ),
+        ),
+        _ => (
+            name.unescaped().display(db).to_smolstr(),
+            name.display(db, completion.edition).to_smolstr(),
         ),
-        _ => (name.unescaped().display(db).to_smolstr(), name.display(db).to_smolstr()),
     };
     let has_self_param = func.self_param(db).is_some();
     let mut item = CompletionItem::new(
@@ -75,6 +82,7 @@ fn render(
         }),
         ctx.source_range(),
         call.clone(),
+        completion.edition,
     );
 
     let ret_type = func.ret_type(db);
@@ -141,9 +149,9 @@ fn render(
     }
 
     let detail = if ctx.completion.config.full_function_signatures {
-        detail_full(db, func)
+        detail_full(db, func, ctx.completion.edition)
     } else {
-        detail(db, func)
+        detail(db, func, ctx.completion.edition)
     };
     item.set_documentation(ctx.docs(func))
         .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
@@ -161,7 +169,9 @@ fn render(
         None => {
             if let Some(actm) = assoc_item {
                 if let Some(trt) = actm.container_or_implemented_trait(db) {
-                    item.trait_name(trt.name(db).display_no_db().to_smolstr());
+                    item.trait_name(
+                        trt.name(db).display_no_db(ctx.completion.edition).to_smolstr(),
+                    );
                 }
             }
         }
@@ -219,7 +229,7 @@ pub(super) fn add_call_parens<'b>(
                 params.iter().enumerate().format_with(", ", |(index, param), f| {
                     match param.name(ctx.db) {
                         Some(n) => {
-                            let smol_str = n.display_no_db().to_smolstr();
+                            let smol_str = n.display_no_db(ctx.edition).to_smolstr();
                             let text = smol_str.as_str().trim_start_matches('_');
                             let ref_ = ref_of_param(ctx, text, param.ty());
                             f(&format_args!("${{{}:{ref_}{text}}}", index + offset))
@@ -238,7 +248,7 @@ pub(super) fn add_call_parens<'b>(
                     format!(
                         "{}(${{1:{}}}{}{})$0",
                         escaped_name,
-                        self_param.display(ctx.db),
+                        self_param.display(ctx.db, ctx.edition),
                         if params.is_empty() { "" } else { ", " },
                         function_params_snippet
                     )
@@ -276,7 +286,7 @@ fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'sta
     ""
 }
 
-fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
+fn detail(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
     let mut ret_ty = func.ret_type(db);
     let mut detail = String::new();
 
@@ -293,15 +303,15 @@ fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
         format_to!(detail, "unsafe ");
     }
 
-    format_to!(detail, "fn({})", params_display(db, func));
+    format_to!(detail, "fn({})", params_display(db, func, edition));
     if !ret_ty.is_unit() {
-        format_to!(detail, " -> {}", ret_ty.display(db));
+        format_to!(detail, " -> {}", ret_ty.display(db, edition));
     }
     detail
 }
 
-fn detail_full(db: &dyn HirDatabase, func: hir::Function) -> String {
-    let signature = format!("{}", func.display(db));
+fn detail_full(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
+    let signature = format!("{}", func.display(db, edition));
     let mut detail = String::with_capacity(signature.len());
 
     for segment in signature.split_whitespace() {
@@ -315,16 +325,16 @@ fn detail_full(db: &dyn HirDatabase, func: hir::Function) -> String {
     detail
 }
 
-fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String {
+fn params_display(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
     if let Some(self_param) = func.self_param(db) {
         let assoc_fn_params = func.assoc_fn_params(db);
         let params = assoc_fn_params
             .iter()
             .skip(1) // skip the self param because we are manually handling that
-            .map(|p| p.ty().display(db));
+            .map(|p| p.ty().display(db, edition));
         format!(
             "{}{}",
-            self_param.display(db),
+            self_param.display(db, edition),
             params.format_with("", |display, f| {
                 f(&", ")?;
                 f(&display)
@@ -332,7 +342,7 @@ fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String {
         )
     } else {
         let assoc_fn_params = func.assoc_fn_params(db);
-        assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ")
+        assoc_fn_params.iter().map(|p| p.ty().display(db, edition)).join(", ")
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index 27435307d50..c71356e5300 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -76,16 +76,16 @@ fn render(
     };
     let (qualified_name, escaped_qualified_name) = (
         qualified_name.unescaped().display(ctx.db()).to_string(),
-        qualified_name.display(ctx.db()).to_string(),
+        qualified_name.display(ctx.db(), completion.edition).to_string(),
     );
     let snippet_cap = ctx.snippet_cap();
 
     let mut rendered = match kind {
         StructKind::Tuple if should_add_parens => {
-            render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name)
+            render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition)
         }
         StructKind::Record if should_add_parens => {
-            render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name)
+            render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition)
         }
         _ => RenderedLiteral {
             literal: escaped_qualified_name.clone(),
@@ -103,7 +103,10 @@ fn render(
     }
     let label = format_literal_label(&qualified_name, kind, snippet_cap);
     let lookup = if qualified {
-        format_literal_lookup(&short_qualified_name.display(ctx.db()).to_string(), kind)
+        format_literal_lookup(
+            &short_qualified_name.display(ctx.db(), completion.edition).to_string(),
+            kind,
+        )
     } else {
         format_literal_lookup(&qualified_name, kind)
     };
@@ -112,6 +115,7 @@ fn render(
         CompletionItemKind::SymbolKind(thing.symbol_kind()),
         ctx.source_range(),
         label,
+        completion.edition,
     );
 
     item.lookup_by(lookup);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index de715bcbfaf..6490171fbb4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -46,8 +46,10 @@ fn render(
         ctx.source_range()
     };
 
-    let (name, escaped_name) =
-        (name.unescaped().display(ctx.db()).to_smolstr(), name.display(ctx.db()).to_smolstr());
+    let (name, escaped_name) = (
+        name.unescaped().display(ctx.db()).to_smolstr(),
+        name.display(ctx.db(), completion.edition).to_smolstr(),
+    );
     let docs = ctx.docs(macro_);
     let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
     let is_fn_like = macro_.is_fn_like(completion.db);
@@ -59,9 +61,10 @@ fn render(
         SymbolKind::from(macro_.kind(completion.db)),
         source_range,
         label(&ctx, needs_bang, bra, ket, &name),
+        completion.edition,
     );
     item.set_deprecated(ctx.is_deprecated(macro_))
-        .detail(macro_.display(completion.db).to_string())
+        .detail(macro_.display(completion.db, completion.edition).to_string())
         .set_documentation(docs)
         .set_relevance(ctx.completion_relevance());
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 598b8762b68..5675dfb5c6f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -3,7 +3,7 @@
 use hir::{db::HirDatabase, Name, StructKind};
 use ide_db::{documentation::HasDocs, SnippetCap};
 use itertools::Itertools;
-use syntax::{SmolStr, ToSmolStr};
+use syntax::{Edition, SmolStr, ToSmolStr};
 
 use crate::{
     context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
@@ -31,8 +31,10 @@ pub(crate) fn render_struct_pat(
     }
 
     let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
-    let (name, escaped_name) =
-        (name.unescaped().display(ctx.db()).to_smolstr(), name.display(ctx.db()).to_smolstr());
+    let (name, escaped_name) = (
+        name.unescaped().display(ctx.db()).to_smolstr(),
+        name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
+    );
     let kind = strukt.kind(ctx.db());
     let label = format_literal_label(name.as_str(), kind, ctx.snippet_cap());
     let lookup = format_literal_lookup(name.as_str(), kind);
@@ -60,13 +62,13 @@ pub(crate) fn render_variant_pat(
     let (name, escaped_name) = match path {
         Some(path) => (
             path.unescaped().display(ctx.db()).to_string().into(),
-            path.display(ctx.db()).to_string().into(),
+            path.display(ctx.db(), ctx.completion.edition).to_string().into(),
         ),
         None => {
             let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
             let it = (
                 name.unescaped().display(ctx.db()).to_smolstr(),
-                name.display(ctx.db()).to_smolstr(),
+                name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
             );
             it
         }
@@ -119,7 +121,12 @@ fn build_completion(
         relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty);
     }
 
-    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
+    let mut item = CompletionItem::new(
+        CompletionItemKind::Binding,
+        ctx.source_range(),
+        label,
+        ctx.completion.edition,
+    );
     item.set_documentation(ctx.docs(def))
         .set_deprecated(ctx.is_deprecated(def))
         .detail(&pat)
@@ -142,9 +149,14 @@ fn render_pat(
 ) -> Option<String> {
     let mut pat = match kind {
         StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
-        StructKind::Record => {
-            render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
-        }
+        StructKind::Record => render_record_as_pat(
+            ctx.db(),
+            ctx.snippet_cap(),
+            fields,
+            name,
+            fields_omitted,
+            ctx.completion.edition,
+        ),
         StructKind::Unit => name.to_owned(),
     };
 
@@ -173,6 +185,7 @@ fn render_record_as_pat(
     fields: &[hir::Field],
     name: &str,
     fields_omitted: bool,
+    edition: Edition,
 ) -> String {
     let fields = fields.iter();
     match snippet_cap {
@@ -180,7 +193,7 @@ fn render_record_as_pat(
             format!(
                 "{name} {{ {}{} }}",
                 fields.enumerate().format_with(", ", |(idx, field), f| {
-                    f(&format_args!("{}${}", field.name(db).display(db.upcast()), idx + 1))
+                    f(&format_args!("{}${}", field.name(db).display(db.upcast(), edition), idx + 1))
                 }),
                 if fields_omitted { ", .." } else { "" },
                 name = name
@@ -189,7 +202,7 @@ fn render_record_as_pat(
         None => {
             format!(
                 "{name} {{ {}{} }}",
-                fields.map(|field| field.name(db).display_no_db().to_smolstr()).format(", "),
+                fields.map(|field| field.name(db).display_no_db(edition).to_smolstr()).format(", "),
                 if fields_omitted { ", .." } else { "" },
                 name = name
             )
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index b81caf24220..09eb19201c5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -33,14 +33,22 @@ fn render(
     let (name, escaped_name) = if with_eq {
         (
             SmolStr::from_iter([&name.unescaped().display(db).to_smolstr(), " = "]),
-            SmolStr::from_iter([&name.display_no_db().to_smolstr(), " = "]),
+            SmolStr::from_iter([&name.display_no_db(ctx.completion.edition).to_smolstr(), " = "]),
         )
     } else {
-        (name.unescaped().display(db).to_smolstr(), name.display_no_db().to_smolstr())
+        (
+            name.unescaped().display(db).to_smolstr(),
+            name.display_no_db(ctx.completion.edition).to_smolstr(),
+        )
     };
-    let detail = type_alias.display(db).to_string();
+    let detail = type_alias.display(db, ctx.completion.edition).to_string();
 
-    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name);
+    let mut item = CompletionItem::new(
+        SymbolKind::TypeAlias,
+        ctx.source_range(),
+        name,
+        ctx.completion.edition,
+    );
     item.set_documentation(ctx.docs(type_alias))
         .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias))
         .detail(detail)
@@ -48,7 +56,7 @@ fn render(
 
     if let Some(actm) = type_alias.as_assoc_item(db) {
         if let Some(trt) = actm.container_or_implemented_trait(db) {
-            item.trait_name(trt.name(db).display_no_db().to_smolstr());
+            item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr());
         }
     }
     item.insert_text(escaped_name);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
index ca7593c122e..e053e299d90 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
@@ -22,21 +22,29 @@ pub(crate) fn render_union_literal(
     let name = local_name.unwrap_or_else(|| un.name(ctx.db()));
 
     let (qualified_name, escaped_qualified_name) = match path {
-        Some(p) => (p.unescaped().display(ctx.db()).to_string(), p.display(ctx.db()).to_string()),
-        None => {
-            (name.unescaped().display(ctx.db()).to_string(), name.display(ctx.db()).to_string())
-        }
+        Some(p) => (
+            p.unescaped().display(ctx.db()).to_string(),
+            p.display(ctx.db(), ctx.completion.edition).to_string(),
+        ),
+        None => (
+            name.unescaped().display(ctx.db()).to_string(),
+            name.display(ctx.db(), ctx.completion.edition).to_string(),
+        ),
     };
     let label = format_literal_label(
-        &name.display_no_db().to_smolstr(),
+        &name.display_no_db(ctx.completion.edition).to_smolstr(),
         StructKind::Record,
         ctx.snippet_cap(),
     );
-    let lookup = format_literal_lookup(&name.display_no_db().to_smolstr(), StructKind::Record);
+    let lookup = format_literal_lookup(
+        &name.display_no_db(ctx.completion.edition).to_smolstr(),
+        StructKind::Record,
+    );
     let mut item = CompletionItem::new(
         CompletionItemKind::SymbolKind(SymbolKind::Union),
         ctx.source_range(),
         label,
+        ctx.completion.edition,
     );
 
     item.lookup_by(lookup);
@@ -54,7 +62,10 @@ pub(crate) fn render_union_literal(
             escaped_qualified_name,
             fields
                 .iter()
-                .map(|field| field.name(ctx.db()).display_no_db().to_smolstr())
+                .map(|field| field
+                    .name(ctx.db())
+                    .display_no_db(ctx.completion.edition)
+                    .to_smolstr())
                 .format(",")
         )
     } else {
@@ -62,7 +73,10 @@ pub(crate) fn render_union_literal(
             "{} {{ {} }}",
             escaped_qualified_name,
             fields.iter().format_with(", ", |field, f| {
-                f(&format_args!("{}: ()", field.name(ctx.db()).display(ctx.db())))
+                f(&format_args!(
+                    "{}: ()",
+                    field.name(ctx.db()).display(ctx.db(), ctx.completion.edition)
+                ))
             })
         )
     };
@@ -73,8 +87,8 @@ pub(crate) fn render_union_literal(
         fields.iter().format_with(", ", |field, f| {
             f(&format_args!(
                 "{}: {}",
-                field.name(ctx.db()).display(ctx.db()),
-                field.ty(ctx.db()).display(ctx.db())
+                field.name(ctx.db()).display(ctx.db(), ctx.completion.edition),
+                field.ty(ctx.db()).display(ctx.db(), ctx.completion.edition)
             ))
         }),
         if fields_omitted { ", .." } else { "" }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
index bc2df9e39f3..d8516ea1078 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
@@ -4,7 +4,7 @@ use crate::context::CompletionContext;
 use hir::{db::HirDatabase, sym, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
 use ide_db::SnippetCap;
 use itertools::Itertools;
-use syntax::SmolStr;
+use syntax::{Edition, SmolStr};
 
 /// A rendered struct, union, or enum variant, split into fields for actual
 /// auto-completion (`literal`, using `field: ()`) and display in the
@@ -21,20 +21,29 @@ pub(crate) fn render_record_lit(
     snippet_cap: Option<SnippetCap>,
     fields: &[hir::Field],
     path: &str,
+    edition: Edition,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
         return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
     }
     let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
         if snippet_cap.is_some() {
-            f(&format_args!("{}: ${{{}:()}}", field.name(db).display(db.upcast()), idx + 1))
+            f(&format_args!(
+                "{}: ${{{}:()}}",
+                field.name(db).display(db.upcast(), edition),
+                idx + 1
+            ))
         } else {
-            f(&format_args!("{}: ()", field.name(db).display(db.upcast())))
+            f(&format_args!("{}: ()", field.name(db).display(db.upcast(), edition)))
         }
     });
 
     let types = fields.iter().format_with(", ", |field, f| {
-        f(&format_args!("{}: {}", field.name(db).display(db.upcast()), field.ty(db).display(db)))
+        f(&format_args!(
+            "{}: {}",
+            field.name(db).display(db.upcast(), edition),
+            field.ty(db).display(db, edition)
+        ))
     });
 
     RenderedLiteral {
@@ -50,6 +59,7 @@ pub(crate) fn render_tuple_lit(
     snippet_cap: Option<SnippetCap>,
     fields: &[hir::Field],
     path: &str,
+    edition: Edition,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
         return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
@@ -62,7 +72,7 @@ pub(crate) fn render_tuple_lit(
         }
     });
 
-    let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db)));
+    let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db, edition)));
 
     RenderedLiteral {
         literal: format!("{path}({completions})"),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 415f2afeebb..04ba7e1f41b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -17,6 +17,7 @@ mod item_list;
 mod pattern;
 mod predicate;
 mod proc_macros;
+mod raw_identifiers;
 mod record;
 mod special;
 mod type_pos;
@@ -105,22 +106,35 @@ pub(crate) fn completion_list_with_trigger_character(
     completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
 }
 
-fn completion_list_with_config(
+fn completion_list_with_config_raw(
     config: CompletionConfig,
     ra_fixture: &str,
     include_keywords: bool,
     trigger_character: Option<char>,
-) -> String {
+) -> Vec<CompletionItem> {
     // filter out all but one built-in type completion for smaller test outputs
     let items = get_all_items(config, ra_fixture, trigger_character);
-    let items = items
+    items
         .into_iter()
         .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.clone(), it.detail.as_ref().map(ToOwned::to_owned)))
-        .collect();
-    render_completion_list(items)
+        .collect()
+}
+
+fn completion_list_with_config(
+    config: CompletionConfig,
+    ra_fixture: &str,
+    include_keywords: bool,
+    trigger_character: Option<char>,
+) -> String {
+    render_completion_list(completion_list_with_config_raw(
+        config,
+        ra_fixture,
+        include_keywords,
+        trigger_character,
+    ))
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs
new file mode 100644
index 00000000000..bc630189edc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs
@@ -0,0 +1,84 @@
+use base_db::SourceDatabase;
+use expect_test::{expect, Expect};
+use itertools::Itertools;
+
+use crate::tests::{completion_list_with_config_raw, position, TEST_CONFIG};
+
+fn check(ra_fixture: &str, expect: Expect) {
+    let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None);
+    let (db, position) = position(ra_fixture);
+    let mut actual = db.file_text(position.file_id).to_string();
+    completions
+        .into_iter()
+        .exactly_one()
+        .expect("more than one completion")
+        .text_edit
+        .apply(&mut actual);
+    expect.assert_eq(&actual);
+}
+
+#[test]
+fn keyword_since_edition_completes_without_raw_on_old_edition() {
+    check(
+        r#"
+//- /a.rs crate:a edition:2015
+pub fn dyn() {}
+
+//- /b.rs crate:b edition:2015 deps:a new_source_root:local
+fn foo() {
+    a::dyn$0
+"#,
+        expect![[r#"
+            fn foo() {
+                a::dyn()$0
+        "#]],
+    );
+
+    check(
+        r#"
+//- /a.rs crate:a edition:2018
+pub fn r#dyn() {}
+
+//- /b.rs crate:b edition:2015 deps:a new_source_root:local
+fn foo() {
+    a::dyn$0
+"#,
+        expect![[r#"
+            fn foo() {
+                a::dyn()$0
+        "#]],
+    );
+}
+
+#[test]
+fn keyword_since_edition_completes_with_raw_on_new_edition() {
+    check(
+        r#"
+//- /a.rs crate:a edition:2015
+pub fn dyn() {}
+
+//- /b.rs crate:b edition:2018 deps:a new_source_root:local
+fn foo() {
+    a::dyn$0
+"#,
+        expect![[r#"
+            fn foo() {
+                a::r#dyn()$0
+        "#]],
+    );
+
+    check(
+        r#"
+//- /a.rs crate:a edition:2018
+pub fn r#dyn() {}
+
+//- /b.rs crate:b edition:2018 deps:a new_source_root:local
+fn foo() {
+    a::dyn$0
+"#,
+        expect![[r#"
+            fn foo() {
+                a::r#dyn()$0
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 991bef344a3..5d4b1999088 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -14,10 +14,11 @@ use hir::{
     ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
     TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
 };
+use span::Edition;
 use stdx::{format_to, impl_from};
 use syntax::{
     ast::{self, AstNode},
-    match_ast, SyntaxKind, SyntaxNode, SyntaxToken, ToSmolStr,
+    match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
 };
 
 use crate::documentation::{Documentation, HasDocs};
@@ -157,6 +158,7 @@ impl Definition {
         &self,
         db: &RootDatabase,
         famous_defs: Option<&FamousDefs<'_, '_>>,
+        edition: Edition,
     ) -> Option<Documentation> {
         let docs = match self {
             Definition::Macro(it) => it.docs(db),
@@ -173,8 +175,8 @@ impl Definition {
             Definition::BuiltinType(it) => {
                 famous_defs.and_then(|fd| {
                     // std exposes prim_{} modules with docstrings on the root to document the builtins
-                    let primitive_mod = format!("prim_{}", it.name().display(fd.0.db));
-                    let doc_owner = find_std_module(fd, &primitive_mod)?;
+                    let primitive_mod = format!("prim_{}", it.name().display(fd.0.db, edition));
+                    let doc_owner = find_std_module(fd, &primitive_mod, edition)?;
                     doc_owner.docs(fd.0.db)
                 })
             }
@@ -192,13 +194,18 @@ impl Definition {
                 let AttributeTemplate { word, list, name_value_str } = it.template(db)?;
                 let mut docs = "Valid forms are:".to_owned();
                 if word {
-                    format_to!(docs, "\n - #\\[{}]", name.display(db));
+                    format_to!(docs, "\n - #\\[{}]", name.display(db, edition));
                 }
                 if let Some(list) = list {
-                    format_to!(docs, "\n - #\\[{}({})]", name.display(db), list);
+                    format_to!(docs, "\n - #\\[{}({})]", name.display(db, edition), list);
                 }
                 if let Some(name_value_str) = name_value_str {
-                    format_to!(docs, "\n - #\\[{} = {}]", name.display(db), name_value_str);
+                    format_to!(
+                        docs,
+                        "\n - #\\[{} = {}]",
+                        name.display(db, edition),
+                        name_value_str
+                    );
                 }
                 Some(Documentation::new(docs.replace('*', "\\*")))
             }
@@ -218,57 +225,63 @@ impl Definition {
         })
     }
 
-    pub fn label(&self, db: &RootDatabase) -> String {
+    pub fn label(&self, db: &RootDatabase, edition: Edition) -> String {
         match *self {
-            Definition::Macro(it) => it.display(db).to_string(),
-            Definition::Field(it) => it.display(db).to_string(),
-            Definition::TupleField(it) => it.display(db).to_string(),
-            Definition::Module(it) => it.display(db).to_string(),
-            Definition::Function(it) => it.display(db).to_string(),
-            Definition::Adt(it) => it.display(db).to_string(),
-            Definition::Variant(it) => it.display(db).to_string(),
-            Definition::Const(it) => it.display(db).to_string(),
-            Definition::Static(it) => it.display(db).to_string(),
-            Definition::Trait(it) => it.display(db).to_string(),
-            Definition::TraitAlias(it) => it.display(db).to_string(),
-            Definition::TypeAlias(it) => it.display(db).to_string(),
-            Definition::BuiltinType(it) => it.name().display(db).to_string(),
-            Definition::BuiltinLifetime(it) => it.name().display(db).to_string(),
+            Definition::Macro(it) => it.display(db, edition).to_string(),
+            Definition::Field(it) => it.display(db, edition).to_string(),
+            Definition::TupleField(it) => it.display(db, edition).to_string(),
+            Definition::Module(it) => it.display(db, edition).to_string(),
+            Definition::Function(it) => it.display(db, edition).to_string(),
+            Definition::Adt(it) => it.display(db, edition).to_string(),
+            Definition::Variant(it) => it.display(db, edition).to_string(),
+            Definition::Const(it) => it.display(db, edition).to_string(),
+            Definition::Static(it) => it.display(db, edition).to_string(),
+            Definition::Trait(it) => it.display(db, edition).to_string(),
+            Definition::TraitAlias(it) => it.display(db, edition).to_string(),
+            Definition::TypeAlias(it) => it.display(db, edition).to_string(),
+            Definition::BuiltinType(it) => it.name().display(db, edition).to_string(),
+            Definition::BuiltinLifetime(it) => it.name().display(db, edition).to_string(),
             Definition::Local(it) => {
                 let ty = it.ty(db);
-                let ty_display = ty.display_truncated(db, None);
+                let ty_display = ty.display_truncated(db, None, edition);
                 let is_mut = if it.is_mut(db) { "mut " } else { "" };
                 if it.is_self(db) {
                     format!("{is_mut}self: {ty_display}")
                 } else {
                     let name = it.name(db);
                     let let_kw = if it.is_param(db) { "" } else { "let " };
-                    format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db))
+                    format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db, edition))
                 }
             }
             Definition::SelfType(impl_def) => {
                 let self_ty = &impl_def.self_ty(db);
                 match self_ty.as_adt() {
-                    Some(it) => it.display(db).to_string(),
-                    None => self_ty.display(db).to_string(),
+                    Some(it) => it.display(db, edition).to_string(),
+                    None => self_ty.display(db, edition).to_string(),
                 }
             }
-            Definition::GenericParam(it) => it.display(db).to_string(),
-            Definition::Label(it) => it.name(db).display(db).to_string(),
-            Definition::ExternCrateDecl(it) => it.display(db).to_string(),
-            Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db)),
-            Definition::ToolModule(it) => it.name(db).display(db).to_string(),
-            Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
+            Definition::GenericParam(it) => it.display(db, edition).to_string(),
+            Definition::Label(it) => it.name(db).display(db, edition).to_string(),
+            Definition::ExternCrateDecl(it) => it.display(db, edition).to_string(),
+            Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db, edition)),
+            Definition::ToolModule(it) => it.name(db).display(db, edition).to_string(),
+            Definition::DeriveHelper(it) => {
+                format!("derive_helper {}", it.name(db).display(db, edition))
+            }
         }
     }
 }
 
-fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
+fn find_std_module(
+    famous_defs: &FamousDefs<'_, '_>,
+    name: &str,
+    edition: Edition,
+) -> Option<hir::Module> {
     let db = famous_defs.0.db;
     let std_crate = famous_defs.std()?;
     let std_root_module = std_crate.root_module();
     std_root_module.children(db).find(|module| {
-        module.name(db).map_or(false, |module| module.display(db).to_string() == name)
+        module.name(db).map_or(false, |module| module.display(db, edition).to_string() == name)
     })
 }
 
@@ -670,7 +683,7 @@ impl NameRefClass {
                                 hir::AssocItem::TypeAlias(it) => Some(it),
                                 _ => None,
                             })
-                            .find(|alias| alias.name(sema.db).display_no_db().to_smolstr() == name_ref.text().as_str())
+                            .find(|alias| alias.name(sema.db).eq_ident(name_ref.text().as_str()))
                         {
                             return Some(NameRefClass::Definition(Definition::TypeAlias(ty)));
                         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index 1a16a567f36..ba6e50abf65 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -2,7 +2,6 @@
 
 use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
 use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait};
-use syntax::ToSmolStr;
 
 use crate::RootDatabase;
 
@@ -199,18 +198,14 @@ impl FamousDefs<'_, '_> {
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
-                if name.display_no_db().to_smolstr() == segment {
+                if name.eq_ident(segment) {
                     Some(child)
                 } else {
                     None
                 }
             })?;
         }
-        let def = module
-            .scope(db, None)
-            .into_iter()
-            .find(|(name, _def)| name.display_no_db().to_smolstr() == trait_)?
-            .1;
+        let def = module.scope(db, None).into_iter().find(|(name, _def)| name.eq_ident(trait_))?.1;
         Some(def)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
index e6638dde5d4..63c09af3d68 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
@@ -4,7 +4,7 @@ use std::collections::VecDeque;
 
 use base_db::SourceRootDatabase;
 use hir::{Crate, DescendPreference, ItemInNs, ModuleDef, Name, Semantics};
-use span::FileId;
+use span::{Edition, FileId};
 use syntax::{
     ast::{self, make},
     AstToken, SyntaxKind, SyntaxToken, ToSmolStr, TokenAtOffset,
@@ -35,7 +35,7 @@ pub fn pick_token<T: AstToken>(mut tokens: TokenAtOffset<SyntaxToken>) -> Option
 }
 
 /// Converts the mod path struct into its ast representation.
-pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
+pub fn mod_path_to_ast(path: &hir::ModPath, edition: Edition) -> ast::Path {
     let _p = tracing::info_span!("mod_path_to_ast").entered();
 
     let mut segments = Vec::new();
@@ -50,11 +50,9 @@ pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
         hir::PathKind::Abs => is_abs = true,
     }
 
-    segments.extend(
-        path.segments().iter().map(|segment| {
-            make::path_segment(make::name_ref(&segment.display_no_db().to_smolstr()))
-        }),
-    );
+    segments.extend(path.segments().iter().map(|segment| {
+        make::path_segment(make::name_ref(&segment.display_no_db(edition).to_smolstr()))
+    }));
     make::path_from_segments(segments, is_abs)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index 1c4c15f2557..07e19733470 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -9,7 +9,7 @@ use itertools::{EitherOrBoth, Itertools};
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{
     ast::{self, make, HasName},
-    AstNode, SmolStr, SyntaxNode, ToSmolStr,
+    AstNode, SmolStr, SyntaxNode,
 };
 
 use crate::{
@@ -459,7 +459,7 @@ fn find_import_for_segment(
     unresolved_first_segment: &str,
 ) -> Option<ItemInNs> {
     let segment_is_name = item_name(db, original_item)
-        .map(|name| name.display_no_db().to_smolstr() == unresolved_first_segment)
+        .map(|name| name.eq_ident(unresolved_first_segment))
         .unwrap_or(false);
 
     Some(if segment_is_name {
@@ -483,7 +483,7 @@ fn module_with_segment_name(
     };
     while let Some(module) = current_module {
         if let Some(module_name) = module.name(db) {
-            if module_name.display_no_db().to_smolstr() == segment_name {
+            if module_name.eq_ident(segment_name) {
                 return Some(module);
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 0afa9163e31..49b3ca290f0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -5,6 +5,7 @@ use either::Either;
 use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope};
 use itertools::Itertools;
 use rustc_hash::FxHashMap;
+use span::Edition;
 use syntax::{
     ast::{self, make, AstNode, HasGenericArgs},
     ted, NodeOrToken, SyntaxNode,
@@ -146,6 +147,7 @@ impl<'a> PathTransform<'a> {
         let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default();
         let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default();
         let mut defaulted_params: Vec<DefaultedParam> = Default::default();
+        let target_edition = target_module.krate().edition(self.source_scope.db);
         self.generic_def
             .into_iter()
             .flat_map(|it| it.type_or_const_params(db))
@@ -190,7 +192,7 @@ impl<'a> PathTransform<'a> {
                     }
                 }
                 (Either::Left(k), None) => {
-                    if let Some(default) = k.default(db) {
+                    if let Some(default) = k.default(db, target_edition) {
                         if let Some(default) = default.expr() {
                             const_substs.insert(k, default.syntax().clone_for_update());
                             defaulted_params.push(Either::Right(k));
@@ -204,7 +206,9 @@ impl<'a> PathTransform<'a> {
             .into_iter()
             .flat_map(|it| it.lifetime_params(db))
             .zip(self.substs.lifetimes.clone())
-            .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?)))
+            .filter_map(|(k, v)| {
+                Some((k.name(db).display(db.upcast(), target_edition).to_string(), v.lifetime()?))
+            })
             .collect();
         let ctx = Ctx {
             type_substs,
@@ -213,6 +217,7 @@ impl<'a> PathTransform<'a> {
             target_module,
             source_scope: self.source_scope,
             same_self_type: self.target_scope.has_same_self_type(self.source_scope),
+            target_edition,
         };
         ctx.transform_default_values(defaulted_params);
         ctx
@@ -226,6 +231,7 @@ struct Ctx<'a> {
     target_module: hir::Module,
     source_scope: &'a SemanticsScope<'a>,
     same_self_type: bool,
+    target_edition: Edition,
 }
 
 fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
@@ -318,7 +324,7 @@ impl Ctx<'_> {
                                 hir::ModuleDef::Trait(trait_ref),
                                 cfg,
                             )?;
-                            match make::ty_path(mod_path_to_ast(&found_path)) {
+                            match make::ty_path(mod_path_to_ast(&found_path, self.target_edition)) {
                                 ast::Type::PathType(path_ty) => Some(path_ty),
                                 _ => None,
                             }
@@ -374,7 +380,7 @@ impl Ctx<'_> {
                 };
                 let found_path =
                     self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?;
-                let res = mod_path_to_ast(&found_path).clone_for_update();
+                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
                 if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
                     if let Some(segment) = res.segment() {
                         let old = segment.get_or_create_generic_arg_list();
@@ -417,7 +423,9 @@ impl Ctx<'_> {
                             cfg,
                         )?;
 
-                        if let Some(qual) = mod_path_to_ast(&found_path).qualifier() {
+                        if let Some(qual) =
+                            mod_path_to_ast(&found_path, self.target_edition).qualifier()
+                        {
                             let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
                             ted::replace(path.syntax(), res.syntax());
                             return Some(());
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 232f2428287..262eefeec00 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -29,6 +29,7 @@ use span::{Edition, EditionedFileId, FileId, SyntaxContextId};
 use stdx::{never, TupleExt};
 use syntax::{
     ast::{self, HasName},
+    utils::is_raw_identifier,
     AstNode, SyntaxKind, TextRange, T,
 };
 use text_edit::{TextEdit, TextEditBuilder};
@@ -72,6 +73,9 @@ impl Definition {
         sema: &Semantics<'_, RootDatabase>,
         new_name: &str,
     ) -> Result<SourceChange> {
+        // We append `r#` if needed.
+        let new_name = new_name.trim_start_matches("r#");
+
         // self.krate() returns None if
         // self is a built-in attr, built-in type or tool module.
         // it is not allowed for these defs to be renamed.
@@ -227,8 +231,7 @@ fn rename_mod(
     module: hir::Module,
     new_name: &str,
 ) -> Result<SourceChange> {
-    if IdentifierKind::classify(module.krate().edition(sema.db), new_name)? != IdentifierKind::Ident
-    {
+    if IdentifierKind::classify(new_name)? != IdentifierKind::Ident {
         bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
     }
 
@@ -240,7 +243,6 @@ fn rename_mod(
 
     let InFile { file_id, value: def_source } = module.definition_source(sema.db);
     if let ModuleSource::SourceFile(..) = def_source {
-        let new_name = new_name.trim_start_matches("r#");
         let anchor = file_id.original_file(sema.db).file_id();
 
         let is_mod_rs = module.is_mod_rs(sema.db);
@@ -289,9 +291,14 @@ fn rename_mod(
                     .original_file_range_opt(sema.db)
                     .map(TupleExt::head)
                 {
+                    let new_name = if is_raw_identifier(new_name, file_id.edition()) {
+                        format!("r#{new_name}")
+                    } else {
+                        new_name.to_owned()
+                    };
                     source_change.insert_source_edit(
                         file_id.file_id(),
-                        TextEdit::replace(file_range.range, new_name.to_owned()),
+                        TextEdit::replace(file_range.range, new_name),
                     )
                 };
             }
@@ -302,7 +309,10 @@ fn rename_mod(
     let def = Definition::Module(module);
     let usages = def.usages(sema).all();
     let ref_edits = usages.iter().map(|(file_id, references)| {
-        (EditionedFileId::file_id(file_id), source_edit_from_references(references, def, new_name))
+        (
+            EditionedFileId::file_id(file_id),
+            source_edit_from_references(references, def, new_name, file_id.edition()),
+        )
     });
     source_change.extend(ref_edits);
 
@@ -314,12 +324,7 @@ fn rename_reference(
     def: Definition,
     new_name: &str,
 ) -> Result<SourceChange> {
-    let ident_kind = IdentifierKind::classify(
-        def.krate(sema.db)
-            .ok_or_else(|| RenameError("definition has no krate?".into()))?
-            .edition(sema.db),
-        new_name,
-    )?;
+    let ident_kind = IdentifierKind::classify(new_name)?;
 
     if matches!(
         def,
@@ -351,7 +356,10 @@ fn rename_reference(
     }
     let mut source_change = SourceChange::default();
     source_change.extend(usages.iter().map(|(file_id, references)| {
-        (EditionedFileId::file_id(file_id), source_edit_from_references(references, def, new_name))
+        (
+            EditionedFileId::file_id(file_id),
+            source_edit_from_references(references, def, new_name, file_id.edition()),
+        )
     }));
 
     let mut insert_def_edit = |def| {
@@ -367,7 +375,13 @@ pub fn source_edit_from_references(
     references: &[FileReference],
     def: Definition,
     new_name: &str,
+    edition: Edition,
 ) -> TextEdit {
+    let new_name = if is_raw_identifier(new_name, edition) {
+        format!("r#{new_name}")
+    } else {
+        new_name.to_owned()
+    };
     let mut edit = TextEdit::builder();
     // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
     let mut edited_ranges = Vec::new();
@@ -383,10 +397,10 @@ pub fn source_edit_from_references(
             // to make special rewrites like shorthand syntax and such, so just rename the node in
             // the macro input
             FileReferenceNode::NameRef(name_ref) if name_range == range => {
-                source_edit_from_name_ref(&mut edit, name_ref, new_name, def)
+                source_edit_from_name_ref(&mut edit, name_ref, &new_name, def)
             }
             FileReferenceNode::Name(name) if name_range == range => {
-                source_edit_from_name(&mut edit, name, new_name)
+                source_edit_from_name(&mut edit, name, &new_name)
             }
             _ => false,
         };
@@ -394,7 +408,7 @@ pub fn source_edit_from_references(
             let (range, new_name) = match name {
                 FileReferenceNode::Lifetime(_) => (
                     TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
-                    new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
+                    new_name.strip_prefix('\'').unwrap_or(&new_name).to_owned(),
                 ),
                 _ => (range, new_name.to_owned()),
             };
@@ -522,6 +536,13 @@ fn source_edit_from_def(
     def: Definition,
     new_name: &str,
 ) -> Result<(FileId, TextEdit)> {
+    let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| {
+        if is_raw_identifier(new_name, file_id.edition()) {
+            format!("r#{new_name}")
+        } else {
+            new_name.to_owned()
+        }
+    };
     let mut edit = TextEdit::builder();
     if let Definition::Local(local) = def {
         let mut file_id = None;
@@ -536,7 +557,7 @@ fn source_edit_from_def(
                 {
                     Some(FileRange { file_id: file_id2, range }) => {
                         file_id = Some(file_id2);
-                        edit.replace(range, new_name.to_owned());
+                        edit.replace(range, new_name_edition_aware(new_name, file_id2));
                         continue;
                     }
                     None => {
@@ -550,7 +571,9 @@ fn source_edit_from_def(
                 // special cases required for renaming fields/locals in Record patterns
                 if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {
                     if let Some(name_ref) = pat_field.name_ref() {
-                        if new_name == name_ref.text() && pat.at_token().is_none() {
+                        if new_name == name_ref.text().as_str().trim_start_matches("r#")
+                            && pat.at_token().is_none()
+                        {
                             // Foo { field: ref mut local } -> Foo { ref mut field }
                             //       ^^^^^^ delete this
                             //                      ^^^^^ replace this with `field`
@@ -566,7 +589,10 @@ fn source_edit_from_def(
                             // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 }
                             // Foo { field: ref mut local } -> Foo { field: ref mut new_name }
                             //                      ^^^^^ replace this with `new_name`
-                            edit.replace(name_range, new_name.to_owned());
+                            edit.replace(
+                                name_range,
+                                new_name_edition_aware(new_name, source.file_id),
+                            );
                         }
                     } else {
                         // Foo { ref mut field } -> Foo { field: ref mut new_name }
@@ -576,10 +602,10 @@ fn source_edit_from_def(
                             pat.syntax().text_range().start(),
                             format!("{}: ", pat_field.field_name().unwrap()),
                         );
-                        edit.replace(name_range, new_name.to_owned());
+                        edit.replace(name_range, new_name_edition_aware(new_name, source.file_id));
                     }
                 } else {
-                    edit.replace(name_range, new_name.to_owned());
+                    edit.replace(name_range, new_name_edition_aware(new_name, source.file_id));
                 }
             }
         }
@@ -599,7 +625,7 @@ fn source_edit_from_def(
         }
         _ => (range, new_name.to_owned()),
     };
-    edit.replace(range, new_name);
+    edit.replace(range, new_name_edition_aware(&new_name, file_id));
     Ok((file_id.file_id(), edit.finish()))
 }
 
@@ -611,8 +637,9 @@ pub enum IdentifierKind {
 }
 
 impl IdentifierKind {
-    pub fn classify(edition: Edition, new_name: &str) -> Result<IdentifierKind> {
-        match parser::LexedStr::single_token(edition, new_name) {
+    pub fn classify(new_name: &str) -> Result<IdentifierKind> {
+        let new_name = new_name.trim_start_matches("r#");
+        match parser::LexedStr::single_token(Edition::LATEST, new_name) {
             Some(res) => match res {
                 (SyntaxKind::IDENT, _) => {
                     if let Some(inner) = new_name.strip_prefix("r#") {
@@ -626,6 +653,7 @@ impl IdentifierKind {
                 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
                     Ok(IdentifierKind::Lifetime)
                 }
+                _ if is_raw_identifier(new_name, Edition::LATEST) => Ok(IdentifierKind::Ident),
                 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
                 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
             },
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
index 6714e411e2f..dd4a665e8eb 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
@@ -1,5 +1,4 @@
 //! Utilities for formatting macro expanded nodes until we get a proper formatter.
-use span::Edition;
 use syntax::{
     ast::make,
     ted::{self, Position},
@@ -132,6 +131,6 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
 }
 
 fn is_text(k: SyntaxKind) -> bool {
-    // FIXME: Edition
-    k.is_keyword(Edition::CURRENT) || k.is_literal() || k == IDENT || k == UNDERSCORE
+    // Consider all keywords in all editions.
+    k.is_any_identifier() || k.is_literal() || k == UNDERSCORE
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index d10a55120a3..fa82902a74d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -457,13 +457,15 @@ impl Iterator for TreeWithDepthIterator {
 }
 
 /// Parses the input token tree as comma separated plain paths.
-pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
+pub fn parse_tt_as_comma_sep_paths(
+    input: ast::TokenTree,
+    edition: Edition,
+) -> Option<Vec<ast::Path>> {
     let r_paren = input.r_paren_token();
     let tokens =
         input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
             // seeing a keyword means the attribute is unclosed so stop parsing here
-            // FIXME: Edition
-            Some(tok) if tok.kind().is_keyword(Edition::CURRENT) => None,
+            Some(tok) if tok.kind().is_keyword(edition) => None,
             // don't include the right token tree parenthesis if it exists
             tok @ Some(_) if tok == r_paren => None,
             // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
index 48a585bf333..82aca50d039 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
@@ -34,19 +34,20 @@ pub fn get_missing_assoc_items(
     // may share the same name as a function or constant.
     let mut impl_fns_consts = FxHashSet::default();
     let mut impl_type = FxHashSet::default();
+    let edition = imp.module(sema.db).krate().edition(sema.db);
 
     for item in imp.items(sema.db) {
         match item {
             hir::AssocItem::Function(it) => {
-                impl_fns_consts.insert(it.name(sema.db).display(sema.db).to_string());
+                impl_fns_consts.insert(it.name(sema.db).display(sema.db, edition).to_string());
             }
             hir::AssocItem::Const(it) => {
                 if let Some(name) = it.name(sema.db) {
-                    impl_fns_consts.insert(name.display(sema.db).to_string());
+                    impl_fns_consts.insert(name.display(sema.db, edition).to_string());
                 }
             }
             hir::AssocItem::TypeAlias(it) => {
-                impl_type.insert(it.name(sema.db).display(sema.db).to_string());
+                impl_type.insert(it.name(sema.db).display(sema.db, edition).to_string());
             }
         }
     }
@@ -56,15 +57,14 @@ pub fn get_missing_assoc_items(
             .items(sema.db)
             .into_iter()
             .filter(|i| match i {
-                hir::AssocItem::Function(f) => {
-                    !impl_fns_consts.contains(&f.name(sema.db).display(sema.db).to_string())
-                }
+                hir::AssocItem::Function(f) => !impl_fns_consts
+                    .contains(&f.name(sema.db).display(sema.db, edition).to_string()),
                 hir::AssocItem::TypeAlias(t) => {
-                    !impl_type.contains(&t.name(sema.db).display(sema.db).to_string())
+                    !impl_type.contains(&t.name(sema.db).display(sema.db, edition).to_string())
                 }
                 hir::AssocItem::Const(c) => c
                     .name(sema.db)
-                    .map(|n| !impl_fns_consts.contains(&n.display(sema.db).to_string()))
+                    .map(|n| !impl_fns_consts.contains(&n.display(sema.db, edition).to_string()))
                     .unwrap_or_default(),
             })
             .collect()
@@ -116,6 +116,7 @@ mod tests {
     use expect_test::{expect, Expect};
     use hir::FilePosition;
     use hir::Semantics;
+    use span::Edition;
     use syntax::ast::{self, AstNode};
     use test_fixture::ChangeFixture;
 
@@ -140,7 +141,7 @@ mod tests {
             sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
         let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
         let actual = match trait_ {
-            Some(trait_) => trait_.name(&db).display(&db).to_string(),
+            Some(trait_) => trait_.name(&db).display(&db, Edition::CURRENT).to_string(),
             None => String::new(),
         };
         expect.assert_eq(&actual);
@@ -155,7 +156,7 @@ mod tests {
         let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
         let actual = items
             .into_iter()
-            .map(|item| item.name(&db).unwrap().display(&db).to_string())
+            .map(|item| item.name(&db).unwrap().display(&db, Edition::CURRENT).to_string())
             .collect::<Vec<_>>()
             .join("\n");
         expect.assert_eq(&actual);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 5b566c5067d..515bc418cb4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -5,10 +5,7 @@
 use std::iter;
 
 use hir::Semantics;
-use syntax::{
-    ast::{self, make, Pat},
-    ToSmolStr,
-};
+use syntax::ast::{self, make, Pat};
 
 use crate::RootDatabase;
 
@@ -29,7 +26,7 @@ impl TryEnum {
             _ => return None,
         };
         TryEnum::ALL.iter().find_map(|&var| {
-            if enum_.name(sema.db).display_no_db().to_smolstr() == var.type_name() {
+            if enum_.name(sema.db).eq_ident(var.type_name()) {
                 return Some(var);
             }
             None
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
index 965f432407b..c3f0bf37069 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
@@ -1,6 +1,7 @@
 //! Functionality for generating trivial constructors
 
 use hir::StructKind;
+use span::Edition;
 use syntax::{
     ast::{make, Expr, Path},
     ToSmolStr,
@@ -11,6 +12,7 @@ pub fn use_trivial_constructor(
     db: &crate::RootDatabase,
     path: Path,
     ty: &hir::Type,
+    edition: Edition,
 ) -> Option<Expr> {
     match ty.as_adt() {
         Some(hir::Adt::Enum(x)) => {
@@ -19,7 +21,7 @@ pub fn use_trivial_constructor(
                     let path = make::path_qualified(
                         path,
                         make::path_segment(make::name_ref(
-                            &variant.name(db).display_no_db().to_smolstr(),
+                            &variant.name(db).display_no_db(edition).to_smolstr(),
                         )),
                     );
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index 05fb1c29b31..02299197b12 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -12,7 +12,7 @@ pub(crate) fn expected_function(
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0618"),
-        format!("expected function, found {}", d.found.display(ctx.sema.db)),
+        format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.edition)),
         d.call.map(|it| it.into()),
     )
     .experimental()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 117088ca09c..ccb33fed100 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -12,7 +12,7 @@ use itertools::Itertools;
 use stdx::{format_to, never};
 use syntax::{
     ast::{self, make},
-    SyntaxKind, SyntaxNode,
+    Edition, SyntaxKind, SyntaxNode,
 };
 use text_edit::TextEdit;
 
@@ -104,6 +104,7 @@ pub(crate) fn json_in_items(
     file_id: EditionedFileId,
     node: &SyntaxNode,
     config: &DiagnosticsConfig,
+    edition: Edition,
 ) {
     (|| {
         if node.kind() == SyntaxKind::ERROR
@@ -156,7 +157,11 @@ pub(crate) fn json_in_items(
                                     config.insert_use.prefix_kind,
                                     cfg,
                                 ) {
-                                    insert_use(&scope, mod_path_to_ast(&it), &config.insert_use);
+                                    insert_use(
+                                        &scope,
+                                        mod_path_to_ast(&it, edition),
+                                        &config.insert_use,
+                                    );
                                 }
                             }
                         }
@@ -168,7 +173,11 @@ pub(crate) fn json_in_items(
                                     config.insert_use.prefix_kind,
                                     cfg,
                                 ) {
-                                    insert_use(&scope, mod_path_to_ast(&it), &config.insert_use);
+                                    insert_use(
+                                        &scope,
+                                        mod_path_to_ast(&it, edition),
+                                        &config.insert_use,
+                                    );
                                 }
                             }
                         }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index ea7908525ae..86c237f7b5e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -11,7 +11,7 @@ use stdx::format_to;
 use syntax::{
     algo,
     ast::{self, make},
-    AstNode, SyntaxNode, SyntaxNodePtr, ToSmolStr,
+    AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr,
 };
 use text_edit::TextEdit;
 
@@ -31,7 +31,7 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
     let mut message = String::from("missing structure fields:\n");
     for field in &d.missed_fields {
-        format_to!(message, "- {}\n", field.display(ctx.sema.db));
+        format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition));
     }
 
     let ptr = InFile::new(
@@ -134,8 +134,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 
                         use_trivial_constructor(
                             ctx.sema.db,
-                            ide_db::helpers::mod_path_to_ast(&type_path),
+                            ide_db::helpers::mod_path_to_ast(&type_path, ctx.edition),
                             ty,
+                            ctx.edition,
                         )
                     })();
 
@@ -146,7 +147,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                     }
                 };
                 let field = make::record_expr_field(
-                    make::name_ref(&f.name(ctx.sema.db).display_no_db().to_smolstr()),
+                    make::name_ref(&f.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr()),
                     field_expr,
                 );
                 new_field_list.add_field(field.clone_for_update());
@@ -160,7 +161,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
             let new_field_list = old_field_list.clone_for_update();
             for (f, _) in missing_fields.iter() {
                 let field = make::record_pat_field_shorthand(make::name_ref(
-                    &f.name(ctx.sema.db).display_no_db().to_smolstr(),
+                    &f.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr(),
                 ));
                 new_field_list.add_field(field.clone_for_update());
             }
@@ -169,9 +170,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     }
 }
 
-fn make_ty(ty: &hir::Type, db: &dyn HirDatabase, module: hir::Module) -> ast::Type {
+fn make_ty(
+    ty: &hir::Type,
+    db: &dyn HirDatabase,
+    module: hir::Module,
+    edition: Edition,
+) -> ast::Type {
     let ty_str = match ty.as_adt() {
-        Some(adt) => adt.name(db).display(db.upcast()).to_string(),
+        Some(adt) => adt.name(db).display(db.upcast(), edition).to_string(),
         None => {
             ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_owned())
         }
@@ -223,13 +229,13 @@ fn get_default_constructor(
 
     let famous_defs = FamousDefs(&ctx.sema, krate);
     if has_new_func {
-        Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module)))
+        Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module, ctx.edition)))
     } else if ty.as_adt() == famous_defs.core_option_Option()?.ty(ctx.sema.db).as_adt() {
         Some(make::ext::option_none())
     } else if !ty.is_array()
         && ty.impls_trait(ctx.sema.db, famous_defs.core_default_Default()?, &[])
     {
-        Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module)))
+        Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module, ctx.edition)))
     } else {
         None
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index fa9a6577fcf..06c6b0f3e4c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -8,7 +8,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0507"),
-        format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)),
+        format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.edition)),
         d.span,
     )
     .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 00352266ddb..e4b1f3ca959 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -40,7 +40,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
             DiagnosticCode::RustcHardError("E0384"),
             format!(
                 "cannot mutate immutable variable `{}`",
-                d.local.name(ctx.sema.db).display(ctx.sema.db)
+                d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition)
             ),
             d.span,
         )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
index f6ed0d7226a..fe32c590492 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
@@ -12,7 +12,7 @@ pub(crate) fn private_assoc_item(
     let name = d
         .item
         .name(ctx.sema.db)
-        .map(|name| format!("`{}` ", name.display(ctx.sema.db)))
+        .map(|name| format!("`{}` ", name.display(ctx.sema.db, ctx.edition)))
         .unwrap_or_default();
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index e91e64c81b0..237a9b87871 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -10,8 +10,8 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
         DiagnosticCode::RustcHardError("E0616"),
         format!(
             "field `{}` of `{}` is private",
-            d.field.name(ctx.sema.db).display(ctx.sema.db),
-            d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db)
+            d.field.name(ctx.sema.db).display(ctx.sema.db, ctx.edition),
+            d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db, ctx.edition)
         ),
         d.expr.map(|it| it.into()),
     )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 58d1b7f31d2..a35b67ce987 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -17,7 +17,7 @@ pub(crate) fn trait_impl_missing_assoc_item(
             hir::AssocItem::Const(_) => "`const ",
             hir::AssocItem::TypeAlias(_) => "`type ",
         })?;
-        f(&name.display(ctx.sema.db))?;
+        f(&name.display(ctx.sema.db, ctx.edition))?;
         f(&"`")
     });
     Diagnostic::new(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 6d756484ebc..3de51ca4a30 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -18,11 +18,11 @@ pub(crate) fn trait_impl_redundant_assoc_item(
 ) -> Diagnostic {
     let db = ctx.sema.db;
     let name = d.assoc_item.0.clone();
-    let redundant_assoc_item_name = name.display(db);
+    let redundant_assoc_item_name = name.display(db, ctx.edition);
     let assoc_item = d.assoc_item.1;
 
     let default_range = d.impl_.syntax_node_ptr().text_range();
-    let trait_name = d.trait_.name(db).display_no_db().to_smolstr();
+    let trait_name = d.trait_.name(db).display_no_db(ctx.edition).to_smolstr();
 
     let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item {
         hir::AssocItem::Function(id) => {
@@ -30,7 +30,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
             (
                 format!("`fn {redundant_assoc_item_name}`"),
                 function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
-                format!("\n    {};", function.display(db)),
+                format!("\n    {};", function.display(db, ctx.edition)),
             )
         }
         hir::AssocItem::Const(id) => {
@@ -38,7 +38,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
             (
                 format!("`const {redundant_assoc_item_name}`"),
                 constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
-                format!("\n    {};", constant.display(db)),
+                format!("\n    {};", constant.display(db, ctx.edition)),
             )
         }
         hir::AssocItem::TypeAlias(id) => {
@@ -48,7 +48,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
                 type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
                 format!(
                     "\n    type {};",
-                    type_alias.name(ctx.sema.db).display_no_db().to_smolstr()
+                    type_alias.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr()
                 ),
             )
         }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 6f5c68d4b5c..5cce7c4aed5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -40,8 +40,12 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         DiagnosticCode::RustcHardError("E0308"),
         format!(
             "expected {}, found {}",
-            d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId),
-            d.actual.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId),
+            d.expected
+                .display(ctx.sema.db, ctx.edition)
+                .with_closure_style(ClosureStyle::ClosureWithId),
+            d.actual
+                .display(ctx.sema.db, ctx.edition)
+                .with_closure_style(ClosureStyle::ClosureWithId),
         ),
         display_range,
     )
@@ -199,8 +203,8 @@ fn str_ref_to_owned(
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
-    let expected = d.expected.display(ctx.sema.db);
-    let actual = d.actual.display(ctx.sema.db);
+    let expected = d.expected.display(ctx.sema.db, ctx.edition);
+    let actual = d.actual.display(ctx.sema.db, ctx.edition);
 
     // FIXME do this properly
     if expected.to_string() != "String" || actual.to_string() != "&str" {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index b4a566e3188..b5c242e1e9f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -26,7 +26,9 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
         (
             format!(
                 "invalid `_` expression, expected type `{}`",
-                d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId),
+                d.expected
+                    .display(ctx.sema.db, ctx.edition)
+                    .with_closure_style(ClosureStyle::ClosureWithId),
             ),
             fixes(ctx, d),
         )
@@ -69,6 +71,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
                     prefer_prelude: ctx.config.prefer_prelude,
                     prefer_absolute: ctx.config.prefer_absolute,
                 },
+                ctx.edition,
             )
             .ok()
         })
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index 97943b7e8b3..6af36fb9e73 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -9,7 +9,7 @@ pub(crate) fn undeclared_label(
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("undeclared-label"),
-        format!("use of undeclared label `{}`", name.display(ctx.sema.db)),
+        format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index a1573bab8ae..e0822fc5b33 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -11,7 +11,7 @@ use ide_db::{
 use paths::Utf8Component;
 use syntax::{
     ast::{self, edit::IndentLevel, HasModuleItem, HasName},
-    AstNode, TextRange, ToSmolStr,
+    AstNode, TextRange,
 };
 use text_edit::TextEdit;
 
@@ -112,8 +112,7 @@ fn fixes(
                 // shouldn't occur
                 _ => continue 'crates,
             };
-            match current.children.iter().find(|(name, _)| name.display_no_db().to_smolstr() == seg)
-            {
+            match current.children.iter().find(|(name, _)| name.eq_ident(seg)) {
                 Some((_, &child)) => current = &crate_def_map[child],
                 None => continue 'crates,
             }
@@ -162,11 +161,7 @@ fn fixes(
             // try finding a parent that has an inline tree from here on
             let mut current = module;
             for s in stack.iter().rev() {
-                match module
-                    .children
-                    .iter()
-                    .find(|(name, _)| name.display_no_db().to_smolstr() == s)
-                {
+                match module.children.iter().find(|(name, _)| name.eq_ident(s)) {
                     Some((_, child)) => {
                         current = &crate_def_map[*child];
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
index 3601041fc73..bdff2417ca1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
@@ -9,7 +9,7 @@ pub(crate) fn unreachable_label(
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0767"),
-        format!("use of unreachable label `{}`", name.display(ctx.sema.db)),
+        format!("use of unreachable label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index eb8eea69f67..76d624c47ab 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -36,8 +36,8 @@ pub(crate) fn unresolved_field(
         DiagnosticCode::RustcHardError("E0559"),
         format!(
             "no field `{}` on type `{}`{method_suffix}",
-            d.name.display(ctx.sema.db),
-            d.receiver.display(ctx.sema.db)
+            d.name.display(ctx.sema.db, ctx.edition),
+            d.receiver.display(ctx.sema.db, ctx.edition)
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index c8ff54cba3a..5b596123e75 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -13,7 +13,7 @@ pub(crate) fn unresolved_macro_call(
     let bang = if d.is_bang { "!" } else { "" };
     Diagnostic::new(
         DiagnosticCode::RustcHardError("unresolved-macro-call"),
-        format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db)),
+        format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db, ctx.edition)),
         display_range,
     )
     .experimental()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 387d56b890b..c0d038a238b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -30,8 +30,8 @@ pub(crate) fn unresolved_method(
         DiagnosticCode::RustcHardError("E0599"),
         format!(
             "no method `{}` on type `{}`{suffix}",
-            d.name.display(ctx.sema.db),
-            d.receiver.display(ctx.sema.db)
+            d.name.display(ctx.sema.db, ctx.edition),
+            d.receiver.display(ctx.sema.db, ctx.edition)
         ),
         adjusted_display_range(ctx, d.expr, &|expr| {
             Some(
@@ -154,9 +154,10 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         };
 
         let mut receiver_type_adt_name =
-            receiver_type.as_adt()?.name(db).display_no_db().to_smolstr();
+            receiver_type.as_adt()?.name(db).display_no_db(ctx.edition).to_smolstr();
 
-        let generic_parameters: Vec<SmolStr> = receiver_type.generic_parameters(db).collect();
+        let generic_parameters: Vec<SmolStr> =
+            receiver_type.generic_parameters(db, ctx.edition).collect();
         // if receiver should be pass as first arg in the assoc func,
         // we could omit generic parameters cause compiler can deduce it automatically
         if !need_to_take_receiver_as_first_arg && !generic_parameters.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index bf19331d9fd..c594754bd44 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -5,7 +5,7 @@ use ide_db::{
     source_change::SourceChange,
     FileRange, RootDatabase,
 };
-use syntax::TextRange;
+use syntax::{Edition, TextRange};
 use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -42,7 +42,14 @@ pub(crate) fn unused_variables(
             ast,
         )
         .with_fixes(name_range.and_then(|it| {
-            fixes(ctx.sema.db, var_name, it.range, diagnostic_range.into(), ast.file_id.is_macro())
+            fixes(
+                ctx.sema.db,
+                var_name,
+                it.range,
+                diagnostic_range.into(),
+                ast.file_id.is_macro(),
+                ctx.edition,
+            )
         }))
         .experimental(),
     )
@@ -54,6 +61,7 @@ fn fixes(
     name_range: TextRange,
     diagnostic_range: FileRange,
     is_in_marco: bool,
+    edition: Edition,
 ) -> Option<Vec<Assist>> {
     if is_in_marco {
         return None;
@@ -63,14 +71,14 @@ fn fixes(
         id: AssistId("unscore_unused_variable_name", AssistKind::QuickFix),
         label: Label::new(format!(
             "Rename unused {} to _{}",
-            var_name.display(db),
-            var_name.display(db)
+            var_name.display(db, edition),
+            var_name.display(db, edition)
         )),
         group: None,
         target: diagnostic_range.range,
         source_change: Some(SourceChange::from_text_edit(
             diagnostic_range.file_id,
-            TextEdit::replace(name_range, format!("_{}", var_name.display(db))),
+            TextEdit::replace(name_range, format!("_{}", var_name.display(db, edition))),
         )),
         command: None,
     }])
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index a61c5f0cd4d..bf320794afc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -90,7 +90,7 @@ use once_cell::sync::Lazy;
 use stdx::never;
 use syntax::{
     ast::{self, AstNode},
-    AstPtr, SyntaxNode, SyntaxNodePtr, TextRange,
+    AstPtr, Edition, SyntaxNode, SyntaxNodePtr, TextRange,
 };
 
 // FIXME: Make this an enum
@@ -279,6 +279,7 @@ struct DiagnosticsContext<'a> {
     config: &'a DiagnosticsConfig,
     sema: Semantics<'a, RootDatabase>,
     resolve: &'a AssistResolveStrategy,
+    edition: Edition,
 }
 
 impl DiagnosticsContext<'_> {
@@ -359,12 +360,19 @@ pub fn semantic_diagnostics(
     for node in parse.syntax().descendants() {
         handlers::useless_braces::useless_braces(&mut res, file_id, &node);
         handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
-        handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config);
+        handlers::json_is_not_rust::json_in_items(
+            &sema,
+            &mut res,
+            file_id,
+            &node,
+            config,
+            file_id.edition(),
+        );
     }
 
     let module = sema.file_to_module_def(file_id);
 
-    let ctx = DiagnosticsContext { config, sema, resolve };
+    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() };
 
     let mut diags = Vec::new();
     match module {
@@ -490,6 +498,7 @@ pub fn semantic_diagnostics(
         &mut rustc_stack,
         &mut clippy_stack,
         &mut diagnostics_of_range,
+        ctx.edition,
     );
 
     res.retain(|d| d.severity != Severity::Allow);
@@ -544,6 +553,7 @@ fn handle_lint_attributes(
     rustc_stack: &mut FxHashMap<String, Vec<Severity>>,
     clippy_stack: &mut FxHashMap<String, Vec<Severity>>,
     diagnostics_of_range: &mut FxHashMap<InFile<SyntaxNode>, &mut Diagnostic>,
+    edition: Edition,
 ) {
     let _g = tracing::info_span!("handle_lint_attributes").entered();
     let file_id = sema.hir_file_for(root);
@@ -552,9 +562,15 @@ fn handle_lint_attributes(
         match ev {
             syntax::WalkEvent::Enter(node) => {
                 for attr in node.children().filter_map(ast::Attr::cast) {
-                    parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| {
-                        stack.push(severity);
-                    });
+                    parse_lint_attribute(
+                        attr,
+                        rustc_stack,
+                        clippy_stack,
+                        |stack, severity| {
+                            stack.push(severity);
+                        },
+                        edition,
+                    );
                 }
                 if let Some(it) =
                     diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() })
@@ -591,6 +607,7 @@ fn handle_lint_attributes(
                             rustc_stack,
                             clippy_stack,
                             diagnostics_of_range,
+                            edition,
                         );
                         for stack in [&mut *rustc_stack, &mut *clippy_stack] {
                             stack.entry("__RA_EVERY_LINT".to_owned()).or_default().pop();
@@ -605,17 +622,24 @@ fn handle_lint_attributes(
                             rustc_stack,
                             clippy_stack,
                             diagnostics_of_range,
+                            edition,
                         );
                     }
                 }
             }
             syntax::WalkEvent::Leave(node) => {
                 for attr in node.children().filter_map(ast::Attr::cast) {
-                    parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| {
-                        if stack.pop() != Some(severity) {
-                            never!("Mismatched serevity in walking lint attributes");
-                        }
-                    });
+                    parse_lint_attribute(
+                        attr,
+                        rustc_stack,
+                        clippy_stack,
+                        |stack, severity| {
+                            if stack.pop() != Some(severity) {
+                                never!("Mismatched serevity in walking lint attributes");
+                            }
+                        },
+                        edition,
+                    );
                 }
             }
         }
@@ -627,6 +651,7 @@ fn parse_lint_attribute(
     rustc_stack: &mut FxHashMap<String, Vec<Severity>>,
     clippy_stack: &mut FxHashMap<String, Vec<Severity>>,
     job: impl Fn(&mut Vec<Severity>, Severity),
+    edition: Edition,
 ) {
     let Some((tag, args_tt)) = attr.as_simple_call() else {
         return;
@@ -637,7 +662,7 @@ fn parse_lint_attribute(
         "forbid" | "deny" => Severity::Error,
         _ => return,
     };
-    for lint in parse_tt_as_comma_sep_paths(args_tt).into_iter().flatten() {
+    for lint in parse_tt_as_comma_sep_paths(args_tt, edition).into_iter().flatten() {
         if let Some(lint) = lint.as_single_name_ref() {
             job(rustc_stack.entry(lint.to_string()).or_default(), severity);
         }
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 5f6d77c064c..6569f0f5552 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -8,6 +8,7 @@ use crate::{
 };
 use hir::{FileRange, ImportPathConfig, Semantics};
 use ide_db::FxHashMap;
+use parser::Edition;
 use std::{cell::Cell, iter::Peekable};
 use syntax::{
     ast::{self, AstNode, AstToken, HasGenericArgs},
@@ -626,6 +627,11 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                 match_error!("Failed to get receiver type for `{}`", expr.syntax().text())
             })?
             .original;
+        let edition = self
+            .sema
+            .scope(expr.syntax())
+            .map(|it| it.krate().edition(self.sema.db))
+            .unwrap_or(Edition::CURRENT);
         // Temporary needed to make the borrow checker happy.
         let res = code_type
             .autoderef(self.sema.db)
@@ -635,8 +641,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
             .ok_or_else(|| {
                 match_error!(
                     "Pattern type `{}` didn't match code type `{}`",
-                    pattern_type.display(self.sema.db),
-                    code_type.display(self.sema.db)
+                    pattern_type.display(self.sema.db, edition),
+                    code_type.display(self.sema.db, edition)
                 )
             });
         res
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index b4b83f62da2..65756601f66 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -2,6 +2,7 @@
 
 use ide_db::{FxHashMap, FxHashSet};
 use itertools::Itertools;
+use parser::Edition;
 use syntax::{
     ast::{self, AstNode, AstToken},
     SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
@@ -33,7 +34,7 @@ fn matches_to_edit_at_offset(
     for m in &matches.matches {
         edit_builder.replace(
             m.range.range.checked_sub(relative_start).unwrap(),
-            render_replace(db, m, file_src, rules),
+            render_replace(db, m, file_src, rules, m.range.file_id.edition()),
         );
     }
     edit_builder.finish()
@@ -54,6 +55,7 @@ struct ReplacementRenderer<'a> {
     // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1
     // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis.
     placeholder_tokens_requiring_parenthesis: FxHashSet<SyntaxToken>,
+    edition: Edition,
 }
 
 fn render_replace(
@@ -61,6 +63,7 @@ fn render_replace(
     match_info: &Match,
     file_src: &str,
     rules: &[ResolvedRule],
+    edition: Edition,
 ) -> String {
     let rule = &rules[match_info.rule_index];
     let template = rule
@@ -76,6 +79,7 @@ fn render_replace(
         out: String::new(),
         placeholder_tokens_requiring_parenthesis: FxHashSet::default(),
         placeholder_tokens_by_range: FxHashMap::default(),
+        edition,
     };
     renderer.render_node(&template.node);
     renderer.maybe_rerender_with_extra_parenthesis(&template.node);
@@ -105,7 +109,7 @@ impl ReplacementRenderer<'_> {
 
     fn render_node(&mut self, node: &SyntaxNode) {
         if let Some(mod_path) = self.match_info.rendered_template_paths.get(node) {
-            self.out.push_str(&mod_path.display(self.db).to_string());
+            self.out.push_str(&mod_path.display(self.db, self.edition).to_string());
             // Emit everything except for the segment's name-ref, since we already effectively
             // emitted that as part of `mod_path`.
             if let Some(path) = ast::Path::cast(node.clone()) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index e9e5240897e..cad0d06eeab 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -413,7 +413,8 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option<
 fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
     def.canonical_module_path(db).map(|it| {
         let mut path = String::new();
-        it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.display(db)));
+        it.flat_map(|it| it.name(db))
+            .for_each(|name| format_to!(path, "{}/", name.unescaped().display(db)));
         path
     })
 }
@@ -588,9 +589,11 @@ fn filename_and_frag_for_def(
 
     let res = match def {
         Definition::Adt(adt) => match adt {
-            Adt::Struct(s) => format!("struct.{}.html", s.name(db).display(db.upcast())),
-            Adt::Enum(e) => format!("enum.{}.html", e.name(db).display(db.upcast())),
-            Adt::Union(u) => format!("union.{}.html", u.name(db).display(db.upcast())),
+            Adt::Struct(s) => {
+                format!("struct.{}.html", s.name(db).unescaped().display(db.upcast()))
+            }
+            Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())),
+            Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())),
         },
         Definition::Module(m) => match m.name(db) {
             // `#[doc(keyword = "...")]` is internal used only by rust compiler
@@ -599,34 +602,48 @@ fn filename_and_frag_for_def(
                     Some(kw) => {
                         format!("keyword.{}.html", kw)
                     }
-                    None => format!("{}/index.html", name.display(db.upcast())),
+                    None => format!("{}/index.html", name.unescaped().display(db.upcast())),
                 }
             }
             None => String::from("index.html"),
         },
-        Definition::Trait(t) => format!("trait.{}.html", t.name(db).display(db.upcast())),
-        Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db).display(db.upcast())),
-        Definition::TypeAlias(t) => format!("type.{}.html", t.name(db).display(db.upcast())),
-        Definition::BuiltinType(t) => format!("primitive.{}.html", t.name().display(db.upcast())),
-        Definition::Function(f) => format!("fn.{}.html", f.name(db).display(db.upcast())),
+        Definition::Trait(t) => {
+            format!("trait.{}.html", t.name(db).unescaped().display(db.upcast()))
+        }
+        Definition::TraitAlias(t) => {
+            format!("traitalias.{}.html", t.name(db).unescaped().display(db.upcast()))
+        }
+        Definition::TypeAlias(t) => {
+            format!("type.{}.html", t.name(db).unescaped().display(db.upcast()))
+        }
+        Definition::BuiltinType(t) => {
+            format!("primitive.{}.html", t.name().unescaped().display(db.upcast()))
+        }
+        Definition::Function(f) => {
+            format!("fn.{}.html", f.name(db).unescaped().display(db.upcast()))
+        }
         Definition::Variant(ev) => {
             format!(
                 "enum.{}.html#variant.{}",
-                ev.parent_enum(db).name(db).display(db.upcast()),
-                ev.name(db).display(db.upcast())
+                ev.parent_enum(db).name(db).unescaped().display(db.upcast()),
+                ev.name(db).unescaped().display(db.upcast())
             )
         }
-        Definition::Const(c) => format!("const.{}.html", c.name(db)?.display(db.upcast())),
-        Definition::Static(s) => format!("static.{}.html", s.name(db).display(db.upcast())),
+        Definition::Const(c) => {
+            format!("const.{}.html", c.name(db)?.unescaped().display(db.upcast()))
+        }
+        Definition::Static(s) => {
+            format!("static.{}.html", s.name(db).unescaped().display(db.upcast()))
+        }
         Definition::Macro(mac) => match mac.kind(db) {
             hir::MacroKind::Declarative
             | hir::MacroKind::BuiltIn
             | hir::MacroKind::Attr
             | hir::MacroKind::ProcMacro => {
-                format!("macro.{}.html", mac.name(db).display(db.upcast()))
+                format!("macro.{}.html", mac.name(db).unescaped().display(db.upcast()))
             }
             hir::MacroKind::Derive => {
-                format!("derive.{}.html", mac.name(db).display(db.upcast()))
+                format!("derive.{}.html", mac.name(db).unescaped().display(db.upcast()))
             }
         },
         Definition::Field(field) => {
@@ -639,7 +656,7 @@ fn filename_and_frag_for_def(
             return Some((
                 def,
                 file,
-                Some(format!("structfield.{}", field.name(db).display(db.upcast()))),
+                Some(format!("structfield.{}", field.name(db).unescaped().display(db.upcast()))),
             ));
         }
         Definition::SelfType(impl_) => {
@@ -649,7 +666,7 @@ fn filename_and_frag_for_def(
             return Some((adt, file, Some(String::from("impl"))));
         }
         Definition::ExternCrateDecl(it) => {
-            format!("{}/index.html", it.name(db).display(db.upcast()))
+            format!("{}/index.html", it.name(db).unescaped().display(db.upcast()))
         }
         Definition::Local(_)
         | Definition::GenericParam(_)
@@ -679,14 +696,16 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) ->
             // Rustdoc makes this decision based on whether a method 'has defaultness'.
             // Currently this is only the case for provided trait methods.
             if is_trait_method && !function.has_body(db) {
-                format!("tymethod.{}", function.name(db).display(db.upcast()))
+                format!("tymethod.{}", function.name(db).unescaped().display(db.upcast()))
             } else {
-                format!("method.{}", function.name(db).display(db.upcast()))
+                format!("method.{}", function.name(db).unescaped().display(db.upcast()))
             }
         }
         AssocItem::Const(constant) => {
-            format!("associatedconstant.{}", constant.name(db)?.display(db.upcast()))
+            format!("associatedconstant.{}", constant.name(db)?.unescaped().display(db.upcast()))
+        }
+        AssocItem::TypeAlias(ty) => {
+            format!("associatedtype.{}", ty.name(db).unescaped().display(db.upcast()))
         }
-        AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db).display(db.upcast())),
     })
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index c8fe45c9cf0..9788c015442 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -3,6 +3,7 @@ use ide_db::{
     helpers::pick_best_token, syntax_helpers::insert_whitespace_into_node::insert_ws_into, FileId,
     RootDatabase,
 };
+use span::Edition;
 use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T};
 
 use crate::FilePosition;
@@ -83,7 +84,14 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         if let Some(item) = ast::Item::cast(node.clone()) {
             if let Some(def) = sema.resolve_attr_macro_call(&item) {
                 break (
-                    def.name(db).display(db).to_string(),
+                    def.name(db)
+                        .display(
+                            db,
+                            sema.attach_first_edition(position.file_id)
+                                .map(|it| it.edition())
+                                .unwrap_or(Edition::CURRENT),
+                        )
+                        .to_string(),
                     expand_macro_recur(&sema, &item)?,
                     SyntaxKind::MACRO_ITEMS,
                 );
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index b1d2b34ea48..6a6fbcb9a6b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -44,6 +44,8 @@ pub(crate) fn goto_definition(
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = &Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
+    let edition =
+        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
         | INT_NUMBER
@@ -55,7 +57,7 @@ pub(crate) fn goto_definition(
         | COMMENT => 4,
         // index and prefix ops
         T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
-        kind if kind.is_keyword(Edition::CURRENT) => 2,
+        kind if kind.is_keyword(edition) => 2,
         T!['('] | T![')'] => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 946dca85d46..a88261df106 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -11,7 +11,7 @@ use ide_db::{
     },
     FxHashMap, FxHashSet, RootDatabase,
 };
-use span::{Edition, EditionedFileId};
+use span::EditionedFileId;
 use syntax::{
     ast::{self, HasLoopBody},
     match_ast, AstNode,
@@ -65,7 +65,7 @@ pub(crate) fn highlight_related(
     let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
         T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
         T![->] => 4,
-        kind if kind.is_keyword(Edition::CURRENT) => 3,
+        kind if kind.is_keyword(file_id.edition()) => 3,
         IDENT | INT_NUMBER => 2,
         T![|] => 1,
         _ => 0,
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 75f8ac2d2b1..6c646cf4ee1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -67,7 +67,11 @@ pub enum HoverAction {
 }
 
 impl HoverAction {
-    fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Option<Self> {
+    fn goto_type_from_targets(
+        db: &RootDatabase,
+        targets: Vec<hir::ModuleDef>,
+        edition: Edition,
+    ) -> Option<Self> {
         let targets = targets
             .into_iter()
             .filter_map(|it| {
@@ -75,7 +79,8 @@ impl HoverAction {
                     mod_path: render::path(
                         db,
                         it.module(db)?,
-                        it.name(db).map(|name| name.display(db).to_string()),
+                        it.name(db).map(|name| name.display(db, edition).to_string()),
+                        edition,
                     ),
                     nav: it.try_to_nav(db)?.call_site(),
                 })
@@ -111,10 +116,12 @@ pub(crate) fn hover(
 ) -> Option<RangeInfo<HoverResult>> {
     let sema = &hir::Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
+    let edition =
+        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
     let mut res = if range.is_empty() {
-        hover_simple(sema, FilePosition { file_id, offset: range.start() }, file, config)
+        hover_simple(sema, FilePosition { file_id, offset: range.start() }, file, config, edition)
     } else {
-        hover_ranged(sema, frange, file, config)
+        hover_ranged(sema, frange, file, config, edition)
     }?;
 
     if let HoverDocFormat::PlainText = config.format {
@@ -129,6 +136,7 @@ fn hover_simple(
     FilePosition { file_id, offset }: FilePosition,
     file: SyntaxNode,
     config: &HoverConfig,
+    edition: Edition,
 ) -> Option<RangeInfo<HoverResult>> {
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
@@ -141,7 +149,7 @@ fn hover_simple(
         | T![_] => 4,
         // index and prefix ops and closure pipe
         T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] | T![|] => 3,
-        kind if kind.is_keyword(Edition::CURRENT) => 2,
+        kind if kind.is_keyword(edition) => 2,
         T!['('] | T![')'] => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
@@ -150,7 +158,7 @@ fn hover_simple(
     if let Some(doc_comment) = token_as_doc_comment(&original_token) {
         cov_mark::hit!(no_highlight_on_comment_hover);
         return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
-            let res = hover_for_definition(sema, file_id, def, &node, None, config);
+            let res = hover_for_definition(sema, file_id, def, &node, None, config, edition);
             Some(RangeInfo::new(range, res))
         });
     }
@@ -165,6 +173,7 @@ fn hover_simple(
             &original_token.parent()?,
             None,
             config,
+            edition,
         );
         return Some(RangeInfo::new(range, res));
     }
@@ -240,7 +249,7 @@ fn hover_simple(
                 .flatten()
                 .unique_by(|&(def, _, _)| def)
                 .map(|(def, macro_arm, node)| {
-                    hover_for_definition(sema, file_id, def, &node, macro_arm, config)
+                    hover_for_definition(sema, file_id, def, &node, macro_arm, config, edition)
                 })
                 .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
                     acc.actions.extend(actions);
@@ -249,9 +258,9 @@ fn hover_simple(
                 })
         })
         // try keywords
-        .or_else(|| descended().find_map(|token| render::keyword(sema, config, token)))
+        .or_else(|| descended().find_map(|token| render::keyword(sema, config, token, edition)))
         // try _ hovers
-        .or_else(|| descended().find_map(|token| render::underscore(sema, config, token)))
+        .or_else(|| descended().find_map(|token| render::underscore(sema, config, token, edition)))
         // try rest pattern hover
         .or_else(|| {
             descended().find_map(|token| {
@@ -266,7 +275,7 @@ fn hover_simple(
                 let record_pat =
                     record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?;
 
-                Some(render::struct_rest_pat(sema, config, &record_pat))
+                Some(render::struct_rest_pat(sema, config, &record_pat, edition))
             })
         })
         // try () call hovers
@@ -283,7 +292,7 @@ fn hover_simple(
                         _ => return None,
                     }
                 };
-                render::type_info_of(sema, config, &Either::Left(call_expr))
+                render::type_info_of(sema, config, &Either::Left(call_expr), edition)
             })
         })
         // try closure
@@ -293,12 +302,12 @@ fn hover_simple(
                     return None;
                 }
                 let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
-                render::closure_expr(sema, config, c)
+                render::closure_expr(sema, config, c, edition)
             })
         })
         // tokens
         .or_else(|| {
-            render::literal(sema, original_token.clone())
+            render::literal(sema, original_token.clone(), edition)
                 .map(|markup| HoverResult { markup, actions: vec![] })
         });
 
@@ -313,6 +322,7 @@ fn hover_ranged(
     FileRange { range, .. }: FileRange,
     file: SyntaxNode,
     config: &HoverConfig,
+    edition: Edition,
 ) -> Option<RangeInfo<HoverResult>> {
     // FIXME: make this work in attributes
     let expr_or_pat = file
@@ -321,15 +331,17 @@ fn hover_ranged(
         .take_while(|it| ast::MacroCall::can_cast(it.kind()) || !ast::Item::can_cast(it.kind()))
         .find_map(Either::<ast::Expr, ast::Pat>::cast)?;
     let res = match &expr_or_pat {
-        Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr),
+        Either::Left(ast::Expr::TryExpr(try_expr)) => {
+            render::try_expr(sema, config, try_expr, edition)
+        }
         Either::Left(ast::Expr::PrefixExpr(prefix_expr))
             if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
         {
-            render::deref_expr(sema, config, prefix_expr)
+            render::deref_expr(sema, config, prefix_expr, edition)
         }
         _ => None,
     };
-    let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat));
+    let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat, edition));
     res.map(|it| {
         let range = match expr_or_pat {
             Either::Left(it) => it.syntax().text_range(),
@@ -347,6 +359,7 @@ pub(crate) fn hover_for_definition(
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
     config: &HoverConfig,
+    edition: Edition,
 ) -> HoverResult {
     let famous_defs = match &def {
         Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
@@ -370,15 +383,22 @@ pub(crate) fn hover_for_definition(
     };
     let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
 
-    let markup =
-        render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, macro_arm, config);
+    let markup = render::definition(
+        sema.db,
+        def,
+        famous_defs.as_ref(),
+        &notable_traits,
+        macro_arm,
+        config,
+        edition,
+    );
     HoverResult {
         markup: render::process_markup(sema.db, def, &markup, config),
         actions: [
             show_fn_references_action(sema.db, def),
             show_implementations_action(sema.db, def),
             runnable_action(sema, def, file_id),
-            goto_type_action_for_def(sema.db, def, &notable_traits),
+            goto_type_action_for_def(sema.db, def, &notable_traits, edition),
         ]
         .into_iter()
         .flatten()
@@ -470,6 +490,7 @@ fn goto_type_action_for_def(
     db: &RootDatabase,
     def: Definition,
     notable_traits: &[(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)],
+    edition: Edition,
 ) -> Option<HoverAction> {
     let mut targets: Vec<hir::ModuleDef> = Vec::new();
     let mut push_new_def = |item: hir::ModuleDef| {
@@ -500,13 +521,13 @@ fn goto_type_action_for_def(
             Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
             Definition::Field(field) => field.ty(db),
             Definition::Function(function) => function.ret_type(db),
-            _ => return HoverAction::goto_type_from_targets(db, targets),
+            _ => return HoverAction::goto_type_from_targets(db, targets, edition),
         };
 
         walk_and_push_ty(db, &ty, &mut push_new_def);
     }
 
-    HoverAction::goto_type_from_targets(db, targets)
+    HoverAction::goto_type_from_targets(db, targets, edition)
 }
 
 fn walk_and_push_ty(
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 13b7ba1e2ba..3e41b42be44 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -35,27 +35,30 @@ pub(super) fn type_info_of(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
     expr_or_pat: &Either<ast::Expr, ast::Pat>,
+    edition: Edition,
 ) -> Option<HoverResult> {
     let ty_info = match expr_or_pat {
         Either::Left(expr) => sema.type_of_expr(expr)?,
         Either::Right(pat) => sema.type_of_pat(pat)?,
     };
-    type_info(sema, _config, ty_info)
+    type_info(sema, _config, ty_info, edition)
 }
 
 pub(super) fn closure_expr(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
     c: ast::ClosureExpr,
+    edition: Edition,
 ) -> Option<HoverResult> {
     let TypeInfo { original, .. } = sema.type_of_expr(&c.into())?;
-    closure_ty(sema, config, &TypeInfo { original, adjusted: None })
+    closure_ty(sema, config, &TypeInfo { original, adjusted: None }, edition)
 }
 
 pub(super) fn try_expr(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
     try_expr: &ast::TryExpr,
+    edition: Edition,
 ) -> Option<HoverResult> {
     let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
     let mut ancestors = try_expr.syntax().ancestors();
@@ -118,12 +121,12 @@ pub(super) fn try_expr(
     };
     walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
     walk_and_push_ty(sema.db, &body_ty, &mut push_new_def);
-    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) {
+    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) {
         res.actions.push(actions);
     }
 
-    let inner_ty = inner_ty.display(sema.db).to_string();
-    let body_ty = body_ty.display(sema.db).to_string();
+    let inner_ty = inner_ty.display(sema.db, edition).to_string();
+    let body_ty = body_ty.display(sema.db, edition).to_string();
     let ty_len_max = inner_ty.len().max(body_ty.len());
 
     let l = "Propagated as: ".len() - " Type: ".len();
@@ -147,6 +150,7 @@ pub(super) fn deref_expr(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
     deref_expr: &ast::PrefixExpr,
+    edition: Edition,
 ) -> Option<HoverResult> {
     let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
     let TypeInfo { original, adjusted } =
@@ -164,9 +168,9 @@ pub(super) fn deref_expr(
 
     res.markup = if let Some(adjusted_ty) = adjusted {
         walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
-        let original = original.display(sema.db).to_string();
-        let adjusted = adjusted_ty.display(sema.db).to_string();
-        let inner = inner_ty.display(sema.db).to_string();
+        let original = original.display(sema.db, edition).to_string();
+        let adjusted = adjusted_ty.display(sema.db, edition).to_string();
+        let inner = inner_ty.display(sema.db, edition).to_string();
         let type_len = "To type: ".len();
         let coerced_len = "Coerced to: ".len();
         let deref_len = "Dereferenced from: ".len();
@@ -184,8 +188,8 @@ pub(super) fn deref_expr(
         )
         .into()
     } else {
-        let original = original.display(sema.db).to_string();
-        let inner = inner_ty.display(sema.db).to_string();
+        let original = original.display(sema.db, edition).to_string();
+        let inner = inner_ty.display(sema.db, edition).to_string();
         let type_len = "To type: ".len();
         let deref_len = "Dereferenced from: ".len();
         let max_len = (original.len() + type_len).max(inner.len() + deref_len);
@@ -198,7 +202,7 @@ pub(super) fn deref_expr(
         )
         .into()
     };
-    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) {
+    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) {
         res.actions.push(actions);
     }
 
@@ -209,6 +213,7 @@ pub(super) fn underscore(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
     token: &SyntaxToken,
+    edition: Edition,
 ) -> Option<HoverResult> {
     if token.kind() != T![_] {
         return None;
@@ -217,8 +222,8 @@ pub(super) fn underscore(
     let _it = match_ast! {
         match parent {
             ast::InferType(it) => it,
-            ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it))),
-            ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it))),
+            ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it)),edition),
+            ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it)),edition),
             _ => return None,
         }
     };
@@ -251,16 +256,18 @@ pub(super) fn keyword(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
     token: &SyntaxToken,
+    edition: Edition,
 ) -> Option<HoverResult> {
-    if !token.kind().is_keyword(Edition::CURRENT) || !config.documentation || !config.keywords {
+    if !token.kind().is_keyword(edition) || !config.documentation || !config.keywords {
         return None;
     }
     let parent = token.parent()?;
     let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate());
 
-    let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent);
+    let KeywordHint { description, keyword_mod, actions } =
+        keyword_hints(sema, token, parent, edition);
 
-    let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
+    let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?;
     let docs = doc_owner.docs(sema.db)?;
     let markup = process_markup(
         sema.db,
@@ -278,6 +285,7 @@ pub(super) fn struct_rest_pat(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
     pattern: &ast::RecordPat,
+    edition: Edition,
 ) -> HoverResult {
     let missing_fields = sema.record_pattern_missing_fields(pattern);
 
@@ -299,7 +307,7 @@ pub(super) fn struct_rest_pat(
     res.markup = {
         let mut s = String::from(".., ");
         for (f, _) in &missing_fields {
-            s += f.display(sema.db).to_string().as_ref();
+            s += f.display(sema.db, edition).to_string().as_ref();
             s += ", ";
         }
         // get rid of trailing comma
@@ -307,7 +315,7 @@ pub(super) fn struct_rest_pat(
 
         Markup::fenced_block(&s)
     };
-    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) {
+    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) {
         res.actions.push(actions);
     }
     res
@@ -366,7 +374,7 @@ pub(super) fn process_markup(
     Markup::from(markup)
 }
 
-fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
+fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> {
     match def {
         Definition::Field(f) => Some(f.parent_def(db).name(db)),
         Definition::Local(l) => l.parent(db).name(db),
@@ -385,17 +393,22 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
             }
         }
     }
-    .map(|name| name.display(db).to_string())
+    .map(|name| name.display(db, edition).to_string())
 }
 
-pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
+pub(super) fn path(
+    db: &RootDatabase,
+    module: hir::Module,
+    item_name: Option<String>,
+    edition: Edition,
+) -> String {
     let crate_name =
         db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
     let module_path = module
         .path_to_root(db)
         .into_iter()
         .rev()
-        .flat_map(|it| it.name(db).map(|name| name.display(db).to_string()));
+        .flat_map(|it| it.name(db).map(|name| name.display(db, edition).to_string()));
     crate_name.into_iter().chain(module_path).chain(item_name).join("::")
 }
 
@@ -406,39 +419,42 @@ pub(super) fn definition(
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
     macro_arm: Option<u32>,
     config: &HoverConfig,
+    edition: Edition,
 ) -> Markup {
-    let mod_path = definition_mod_path(db, &def);
+    let mod_path = definition_mod_path(db, &def, edition);
     let label = match def {
         Definition::Trait(trait_) => {
-            trait_.display_limited(db, config.max_trait_assoc_items_count).to_string()
+            trait_.display_limited(db, config.max_trait_assoc_items_count, edition).to_string()
         }
         Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => {
-            adt.display_limited(db, config.max_fields_count).to_string()
+            adt.display_limited(db, config.max_fields_count, edition).to_string()
         }
         Definition::Variant(variant) => {
-            variant.display_limited(db, config.max_fields_count).to_string()
+            variant.display_limited(db, config.max_fields_count, edition).to_string()
         }
         Definition::Adt(adt @ Adt::Enum(_)) => {
-            adt.display_limited(db, config.max_enum_variants_count).to_string()
+            adt.display_limited(db, config.max_enum_variants_count, edition).to_string()
         }
         Definition::SelfType(impl_def) => {
             let self_ty = &impl_def.self_ty(db);
             match self_ty.as_adt() {
-                Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(),
-                None => self_ty.display(db).to_string(),
+                Some(adt) => adt.display_limited(db, config.max_fields_count, edition).to_string(),
+                None => self_ty.display(db, edition).to_string(),
             }
         }
         Definition::Macro(it) => {
-            let mut label = it.display(db).to_string();
+            let mut label = it.display(db, edition).to_string();
             if let Some(macro_arm) = macro_arm {
                 format_to!(label, " // matched arm #{}", macro_arm);
             }
             label
         }
-        Definition::Function(fn_) => fn_.display_with_container_bounds(db, true).to_string(),
-        _ => def.label(db),
+        Definition::Function(fn_) => {
+            fn_.display_with_container_bounds(db, true, edition).to_string()
+        }
+        _ => def.label(db, edition),
     };
-    let docs = def.docs(db, famous_defs);
+    let docs = def.docs(db, famous_defs, edition);
     let value = (|| match def {
         Definition::Variant(it) => {
             if !it.parent_enum(db).is_data_carrying(db) {
@@ -453,7 +469,7 @@ pub(super) fn definition(
             }
         }
         Definition::Const(it) => {
-            let body = it.render_eval(db);
+            let body = it.render_eval(db, edition);
             match body {
                 Ok(it) => Some(it),
                 Err(_) => {
@@ -511,7 +527,7 @@ pub(super) fn definition(
     };
 
     let mut desc = String::new();
-    if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits) {
+    if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits, edition) {
         desc.push_str(&notable_traits);
         desc.push('\n');
     }
@@ -528,7 +544,11 @@ pub(super) fn definition(
     markup(docs.map(Into::into), desc, mod_path)
 }
 
-pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Markup> {
+pub(super) fn literal(
+    sema: &Semantics<'_, RootDatabase>,
+    token: SyntaxToken,
+    edition: Edition,
+) -> Option<Markup> {
     let lit = token.parent().and_then(ast::Literal::cast)?;
     let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
         sema.type_of_pat(&p)?
@@ -575,7 +595,7 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) ->
             _ => return None
         }
     };
-    let ty = ty.display(sema.db);
+    let ty = ty.display(sema.db, edition);
 
     let mut s = format!("```rust\n{ty}\n```\n___\n\n");
     match value {
@@ -594,6 +614,7 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) ->
 fn render_notable_trait_comment(
     db: &RootDatabase,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+    edition: Edition,
 ) -> Option<String> {
     let mut desc = String::new();
     let mut needs_impl_header = true;
@@ -603,17 +624,17 @@ fn render_notable_trait_comment(
         } else {
             ", "
         });
-        format_to!(desc, "{}", trait_.name(db).display(db),);
+        format_to!(desc, "{}", trait_.name(db).display(db, edition));
         if !assoc_types.is_empty() {
             desc.push('<');
             format_to!(
                 desc,
                 "{}",
                 assoc_types.iter().format_with(", ", |(ty, name), f| {
-                    f(&name.display(db))?;
+                    f(&name.display(db, edition))?;
                     f(&" = ")?;
                     match ty {
-                        Some(ty) => f(&ty.display(db)),
+                        Some(ty) => f(&ty.display(db, edition)),
                         None => f(&"?"),
                     }
                 })
@@ -628,8 +649,9 @@ fn type_info(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
     ty: TypeInfo,
+    edition: Edition,
 ) -> Option<HoverResult> {
-    if let Some(res) = closure_ty(sema, config, &ty) {
+    if let Some(res) = closure_ty(sema, config, &ty, edition) {
         return Some(res);
     };
     let db = sema.db;
@@ -655,17 +677,17 @@ fn type_info(
                 } else {
                     ", "
                 });
-                format_to!(desc, "{}", trait_.name(db).display(db),);
+                format_to!(desc, "{}", trait_.name(db).display(db, edition));
                 if !assoc_types.is_empty() {
                     desc.push('<');
                     format_to!(
                         desc,
                         "{}",
                         assoc_types.into_iter().format_with(", ", |(ty, name), f| {
-                            f(&name.display(db))?;
+                            f(&name.display(db, edition))?;
                             f(&" = ")?;
                             match ty {
-                                Some(ty) => f(&ty.display(db)),
+                                Some(ty) => f(&ty.display(db, edition)),
                                 None => f(&"?"),
                             }
                         })
@@ -679,8 +701,8 @@ fn type_info(
             desc
         };
 
-        let original = original.display(db).to_string();
-        let adjusted = adjusted_ty.display(db).to_string();
+        let original = original.display(db, edition).to_string();
+        let adjusted = adjusted_ty.display(db, edition).to_string();
         let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
         format!(
             "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n{notable}```\n",
@@ -691,14 +713,15 @@ fn type_info(
         )
         .into()
     } else {
-        let mut desc = match render_notable_trait_comment(db, &notable_traits(db, &original)) {
-            Some(desc) => desc + "\n",
-            None => String::new(),
-        };
-        format_to!(desc, "{}", original.display(db));
+        let mut desc =
+            match render_notable_trait_comment(db, &notable_traits(db, &original), edition) {
+                Some(desc) => desc + "\n",
+                None => String::new(),
+            };
+        format_to!(desc, "{}", original.display(db, edition));
         Markup::fenced_block(&desc)
     };
-    if let Some(actions) = HoverAction::goto_type_from_targets(db, targets) {
+    if let Some(actions) = HoverAction::goto_type_from_targets(db, targets, edition) {
         res.actions.push(actions);
     }
     Some(res)
@@ -708,6 +731,7 @@ fn closure_ty(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
     TypeInfo { original, adjusted }: &TypeInfo,
+    edition: Edition,
 ) -> Option<HoverResult> {
     let c = original.as_closure()?;
     let mut captures_rendered = c.captured_items(sema.db)
@@ -740,12 +764,12 @@ fn closure_ty(
         walk_and_push_ty(sema.db, adjusted_ty, &mut push_new_def);
         format!(
             "\nCoerced to: {}",
-            adjusted_ty.display(sema.db).with_closure_style(hir::ClosureStyle::ImplFn)
+            adjusted_ty.display(sema.db, edition).with_closure_style(hir::ClosureStyle::ImplFn)
         )
     } else {
         String::new()
     };
-    let mut markup = format!("```rust\n{}", c.display_with_id(sema.db),);
+    let mut markup = format!("```rust\n{}", c.display_with_id(sema.db, edition));
 
     if let Some(layout) =
         render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None)
@@ -758,23 +782,23 @@ fn closure_ty(
     format_to!(
         markup,
         "\n{}\n```{adjusted}\n\n## Captures\n{}",
-        c.display_with_impl(sema.db),
+        c.display_with_impl(sema.db, edition),
         captures_rendered,
     );
 
     let mut res = HoverResult::default();
-    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) {
+    if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) {
         res.actions.push(actions);
     }
     res.markup = markup.into();
     Some(res)
 }
 
-fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
+fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> {
     if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) {
         return None;
     }
-    def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
+    def.module(db).map(|module| path(db, module, definition_owner_name(db, def, edition), edition))
 }
 
 fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup {
@@ -793,12 +817,16 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Marku
     buf.into()
 }
 
-fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
+fn find_std_module(
+    famous_defs: &FamousDefs<'_, '_>,
+    name: &str,
+    edition: Edition,
+) -> Option<hir::Module> {
     let db = famous_defs.0.db;
     let std_crate = famous_defs.std()?;
     let std_root_module = std_crate.root_module();
     std_root_module.children(db).find(|module| {
-        module.name(db).map_or(false, |module| module.display(db).to_string() == name)
+        module.name(db).map_or(false, |module| module.display(db, edition).to_string() == name)
     })
 }
 
@@ -889,6 +917,7 @@ fn keyword_hints(
     sema: &Semantics<'_, RootDatabase>,
     token: &SyntaxToken,
     parent: syntax::SyntaxNode,
+    edition: Edition,
 ) -> KeywordHint {
     match token.kind() {
         T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => {
@@ -906,12 +935,12 @@ fn keyword_hints(
                     walk_and_push_ty(sema.db, &ty.original, &mut push_new_def);
 
                     let ty = ty.adjusted();
-                    let description = format!("{}: {}", token.text(), ty.display(sema.db));
+                    let description = format!("{}: {}", token.text(), ty.display(sema.db, edition));
 
                     KeywordHint {
                         description,
                         keyword_mod,
-                        actions: HoverAction::goto_type_from_targets(sema.db, targets)
+                        actions: HoverAction::goto_type_from_targets(sema.db, targets, edition)
                             .into_iter()
                             .collect(),
                     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 18f0aeba29e..8b60e562d7b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -8630,3 +8630,75 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn raw_keyword_different_editions() {
+    check(
+        r#"
+//- /lib1.rs crate:with_edition_2015 edition:2015
+pub fn dyn() {}
+
+//- /lib2.rs crate:with_edition_2018 edition:2018 deps:with_edition_2015 new_source_root:local
+fn foo() {
+    with_edition_2015::r#dyn$0();
+}
+    "#,
+        expect![[r#"
+            *r#dyn*
+
+            ```rust
+            with_edition_2015
+            ```
+
+            ```rust
+            pub fn r#dyn()
+            ```
+        "#]],
+    );
+
+    check(
+        r#"
+//- /lib1.rs crate:with_edition_2018 edition:2018
+pub fn r#dyn() {}
+
+//- /lib2.rs crate:with_edition_2015 edition:2015 deps:with_edition_2018 new_source_root:local
+fn foo() {
+    with_edition_2018::dyn$0();
+}
+    "#,
+        expect![[r#"
+            *dyn*
+
+            ```rust
+            with_edition_2018
+            ```
+
+            ```rust
+            pub fn dyn()
+            ```
+        "#]],
+    );
+
+    check(
+        r#"
+//- /lib1.rs crate:escaping_needlessly edition:2015
+pub fn r#dyn() {}
+
+//- /lib2.rs crate:dependent edition:2015 deps:escaping_needlessly new_source_root:local
+fn foo() {
+    escaping_needlessly::dyn$0();
+}
+    "#,
+        expect![[r#"
+            *dyn*
+
+            ```rust
+            escaping_needlessly
+            ```
+
+            ```rust
+            pub fn dyn()
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 0a8d2727575..6a5d5e26a4f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -11,7 +11,7 @@ use hir::{
 use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
-use span::EditionedFileId;
+use span::{Edition, EditionedFileId};
 use stdx::never;
 use syntax::{
     ast::{self, AstNode},
@@ -372,6 +372,7 @@ fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     ty: &hir::Type,
+    edition: Edition,
 ) -> Option<InlayHintLabel> {
     fn rec(
         sema: &Semantics<'_, RootDatabase>,
@@ -380,6 +381,7 @@ fn label_of_ty(
         ty: &hir::Type,
         label_builder: &mut InlayHintLabelBuilder<'_>,
         config: &InlayHintsConfig,
+        edition: Edition,
     ) -> Result<(), HirDisplayError> {
         let iter_item_type = hint_iterator(sema, famous_defs, ty);
         match iter_item_type {
@@ -410,12 +412,12 @@ fn label_of_ty(
                 label_builder.write_str(LABEL_ITEM)?;
                 label_builder.end_location_link();
                 label_builder.write_str(LABEL_MIDDLE2)?;
-                rec(sema, famous_defs, max_length, &ty, label_builder, config)?;
+                rec(sema, famous_defs, max_length, &ty, label_builder, config, edition)?;
                 label_builder.write_str(LABEL_END)?;
                 Ok(())
             }
             None => ty
-                .display_truncated(sema.db, max_length)
+                .display_truncated(sema.db, max_length, edition)
                 .with_closure_style(config.closure_style)
                 .write_to(label_builder),
         }
@@ -427,7 +429,7 @@ fn label_of_ty(
         location: None,
         result: InlayHintLabel::default(),
     };
-    let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config);
+    let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
     let r = label_builder.finish();
     Some(r)
 }
@@ -569,7 +571,7 @@ fn hints(
         match node {
             ast::Expr(expr) => {
                 chaining::hints(hints, famous_defs, config, file_id, &expr);
-                adjustment::hints(hints, sema, config, &expr);
+                adjustment::hints(hints, sema, config, file_id, &expr);
                 match expr {
                     ast::Expr::CallExpr(it) => param_name::hints(hints, sema, config, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
@@ -600,7 +602,7 @@ fn hints(
                 // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
                 ast::Item::Impl(_) => None,
                 ast::Item::Fn(it) => {
-                    implicit_drop::hints(hints, sema, config, &it);
+                    implicit_drop::hints(hints, sema, config, file_id, &it);
                     fn_lifetime_fn::hints(hints, config, it)
                 },
                 // static type elisions
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 7932d8efbcf..756198d0c01 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -10,6 +10,7 @@ use hir::{
 };
 use ide_db::RootDatabase;
 
+use span::EditionedFileId;
 use stdx::never;
 use syntax::{
     ast::{self, make, AstNode},
@@ -25,6 +26,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
+    file_id: EditionedFileId,
     expr: &ast::Expr,
 ) -> Option<()> {
     if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
@@ -141,8 +143,8 @@ pub(super) fn hints(
             if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
             Some(InlayTooltip::Markdown(format!(
                 "`{}` → `{}` ({coercion} coercion)",
-                source.display(sema.db),
-                target.display(sema.db),
+                source.display(sema.db, file_id.edition()),
+                target.display(sema.db, file_id.edition()),
             ))),
             None,
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 7310852b8ed..d67afe14d7c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -22,7 +22,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
+    file_id: EditionedFileId,
     pat: &ast::IdentPat,
 ) -> Option<()> {
     if !config.type_hints {
@@ -67,7 +67,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let mut label = label_of_ty(famous_defs, config, &ty)?;
+    let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
 
     if config.hide_named_constructor_hints
         && is_named_constructor(sema, pat, &label.to_string()).is_some()
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 4e15213b8bb..35f4d46e187 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -14,7 +14,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
+    file_id: EditionedFileId,
     expr: &ast::Expr,
 ) -> Option<()> {
     if !config.chaining_hints {
@@ -58,7 +58,7 @@ pub(super) fn hints(
                     }
                 }
             }
-            let label = label_of_ty(famous_defs, config, &ty)?;
+            let label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
             acc.push(InlayHint {
                 range: expr.syntax().text_range(),
                 kind: InlayKind::Chaining,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 8f2777f3928..d78fd64bdf4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -36,8 +36,12 @@ pub(super) fn hints(
                     let ty = imp.self_ty(sema.db);
                     let trait_ = imp.trait_(sema.db);
                     let hint_text = match trait_ {
-                        Some(tr) => format!("impl {} for {}", tr.name(sema.db).display(sema.db), ty.display_truncated(sema.db, config.max_length)),
-                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
+                        Some(tr) => format!(
+                            "impl {} for {}",
+                            tr.name(sema.db).display(sema.db, file_id.edition()),
+                            ty.display_truncated(sema.db, config.max_length, file_id.edition(),
+                        )),
+                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, file_id.edition())),
                     };
                     (hint_text, None)
                 },
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index f6bd7ca064f..325c2040691 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
@@ -14,7 +14,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
+    file_id: EditionedFileId,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
@@ -43,7 +43,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let mut label = label_of_ty(famous_defs, config, &ty)?;
+    let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?;
 
     if arrow.is_none() {
         label.prepend_str(" -> ");
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index 7f901db28d3..b4695a2b351 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -12,6 +12,7 @@ use hir::{
 };
 use ide_db::{FileRange, RootDatabase};
 
+use span::EditionedFileId;
 use syntax::{
     ast::{self, AstNode},
     match_ast, ToSmolStr,
@@ -23,6 +24,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
+    file_id: EditionedFileId,
     def: &ast::Fn,
 ) -> Option<()> {
     if !config.implicit_drop_hints {
@@ -100,7 +102,7 @@ pub(super) fn hints(
                     })
                 });
             let binding = &hir.bindings[*binding];
-            let name = binding.name.display_no_db().to_smolstr();
+            let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
             if name.starts_with("<ra@") {
                 continue; // Ignore desugared variables
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 70d790efad3..0f3142ef3f8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -121,7 +121,9 @@ fn should_hide_param_name_hint(
     }
 
     let fn_name = match callable.kind() {
-        hir::CallableKind::Function(it) => Some(it.name(sema.db).display_no_db().to_smolstr()),
+        hir::CallableKind::Function(it) => {
+            Some(it.name(sema.db).unescaped().display_no_db().to_smolstr())
+        }
         _ => None,
     };
     let fn_name = fn_name.as_deref();
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 1b64bc92603..7b5fd651e3d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -249,10 +249,11 @@ pub(crate) fn def_to_moniker(
 
     let module = def.module(db)?;
     let krate = module.krate();
+    let edition = krate.edition(db);
     let mut description = vec![];
     description.extend(module.path_to_root(db).into_iter().filter_map(|x| {
         Some(MonikerDescriptor {
-            name: x.name(db)?.display(db).to_string(),
+            name: x.name(db)?.display(db, edition).to_string(),
             desc: def_to_kind(db, x.into()).into(),
         })
     }));
@@ -265,7 +266,7 @@ pub(crate) fn def_to_moniker(
                 // Because different traits can have functions with the same name,
                 // we have to include the trait name as part of the moniker for uniqueness.
                 description.push(MonikerDescriptor {
-                    name: trait_.name(db).display(db).to_string(),
+                    name: trait_.name(db).display(db, edition).to_string(),
                     desc: def_to_kind(db, trait_.into()).into(),
                 });
             }
@@ -274,14 +275,14 @@ pub(crate) fn def_to_moniker(
                 // we add both the struct name and the trait name to the path
                 if let Some(adt) = impl_.self_ty(db).as_adt() {
                     description.push(MonikerDescriptor {
-                        name: adt.name(db).display(db).to_string(),
+                        name: adt.name(db).display(db, edition).to_string(),
                         desc: def_to_kind(db, adt.into()).into(),
                     });
                 }
 
                 if let Some(trait_) = impl_.trait_(db) {
                     description.push(MonikerDescriptor {
-                        name: trait_.name(db).display(db).to_string(),
+                        name: trait_.name(db).display(db, edition).to_string(),
                         desc: def_to_kind(db, trait_.into()).into(),
                     });
                 }
@@ -291,7 +292,7 @@ pub(crate) fn def_to_moniker(
 
     if let Definition::Field(it) = def {
         description.push(MonikerDescriptor {
-            name: it.parent_def(db).name(db).display(db).to_string(),
+            name: it.parent_def(db).name(db).display(db, edition).to_string(),
             desc: def_to_kind(db, it.parent_def(db).into()).into(),
         });
     }
@@ -303,7 +304,7 @@ pub(crate) fn def_to_moniker(
             let parent_name = parent.name(db);
             if let Some(name) = parent_name {
                 description.push(MonikerDescriptor {
-                    name: name.display(db).to_string(),
+                    name: name.display(db, edition).to_string(),
                     desc: def_to_kind(db, parent).into(),
                 });
             }
@@ -326,53 +327,53 @@ pub(crate) fn def_to_moniker(
                 return None;
             }
 
-            MonikerDescriptor { name: local.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: local.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Macro(m) => {
-            MonikerDescriptor { name: m.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Function(f) => {
-            MonikerDescriptor { name: f.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: f.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Variant(v) => {
-            MonikerDescriptor { name: v.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: v.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Const(c) => {
-            MonikerDescriptor { name: c.name(db)?.display(db).to_string(), desc }
+            MonikerDescriptor { name: c.name(db)?.display(db, edition).to_string(), desc }
         }
         Definition::Trait(trait_) => {
-            MonikerDescriptor { name: trait_.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: trait_.name(db).display(db, edition).to_string(), desc }
         }
         Definition::TraitAlias(ta) => {
-            MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc }
         }
         Definition::TypeAlias(ta) => {
-            MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Module(m) => {
-            MonikerDescriptor { name: m.name(db)?.display(db).to_string(), desc }
+            MonikerDescriptor { name: m.name(db)?.display(db, edition).to_string(), desc }
         }
         Definition::BuiltinType(b) => {
-            MonikerDescriptor { name: b.name().display(db).to_string(), desc }
+            MonikerDescriptor { name: b.name().display(db, edition).to_string(), desc }
         }
         Definition::SelfType(imp) => MonikerDescriptor {
-            name: imp.self_ty(db).as_adt()?.name(db).display(db).to_string(),
+            name: imp.self_ty(db).as_adt()?.name(db).display(db, edition).to_string(),
             desc,
         },
         Definition::Field(it) => {
-            MonikerDescriptor { name: it.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: it.name(db).display(db, edition).to_string(), desc }
         }
         Definition::TupleField(it) => {
-            MonikerDescriptor { name: it.name().display(db).to_string(), desc }
+            MonikerDescriptor { name: it.name().display(db, edition).to_string(), desc }
         }
         Definition::Adt(adt) => {
-            MonikerDescriptor { name: adt.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: adt.name(db).display(db, edition).to_string(), desc }
         }
         Definition::Static(s) => {
-            MonikerDescriptor { name: s.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: s.name(db).display(db, edition).to_string(), desc }
         }
         Definition::ExternCrateDecl(m) => {
-            MonikerDescriptor { name: m.name(db).display(db).to_string(), desc }
+            MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc }
         }
     };
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 066141d36f1..9ace9fda62b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -5,14 +5,15 @@ use std::fmt;
 use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
-    db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource,
-    HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
+    db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasCrate,
+    HasSource, HirDisplay, HirFileId, HirFileIdExt, InFile, LocalSource, ModuleSource,
 };
 use ide_db::{
     defs::Definition,
     documentation::{Documentation, HasDocs},
     FileId, FileRange, RootDatabase, SymbolKind,
 };
+use span::Edition;
 use stdx::never;
 use syntax::{
     ast::{self, HasName},
@@ -97,7 +98,9 @@ impl NavigationTarget {
         db: &RootDatabase,
         module: hir::Module,
     ) -> UpmappingResult<NavigationTarget> {
-        let name = module.name(db).map(|it| it.display_no_db().to_smolstr()).unwrap_or_default();
+        let edition = module.krate().edition(db);
+        let name =
+            module.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default();
         match module.declaration_source(db) {
             Some(InFile { value, file_id }) => {
                 orig_range_with_focus(db, file_id, value.syntax(), value.name()).map(
@@ -110,7 +113,7 @@ impl NavigationTarget {
                             SymbolKind::Module,
                         );
                         res.docs = module.docs(db);
-                        res.description = Some(module.display(db).to_string());
+                        res.description = Some(module.display(db, edition).to_string());
                         res
                     },
                 )
@@ -175,6 +178,8 @@ impl NavigationTarget {
 
 impl TryToNav for FileSymbol {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
+        let edition =
+            self.def.module(db).map(|it| it.krate().edition(db)).unwrap_or(Edition::CURRENT);
         Some(
             orig_range_with_focus_r(
                 db,
@@ -185,27 +190,26 @@ impl TryToNav for FileSymbol {
             .map(|(FileRange { file_id, range: full_range }, focus_range)| {
                 NavigationTarget {
                     file_id,
-                    name: self
-                        .is_alias
-                        .then(|| self.def.name(db))
-                        .flatten()
-                        .map_or_else(|| self.name.clone(), |it| it.display_no_db().to_smolstr()),
+                    name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else(
+                        || self.name.clone(),
+                        |it| it.display_no_db(edition).to_smolstr(),
+                    ),
                     alias: self.is_alias.then(|| self.name.clone()),
                     kind: Some(hir::ModuleDefId::from(self.def).into()),
                     full_range,
                     focus_range,
                     container_name: self.container_name.clone(),
                     description: match self.def {
-                        hir::ModuleDef::Module(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Function(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Adt(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Variant(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Const(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Static(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Trait(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::TraitAlias(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::TypeAlias(it) => Some(it.display(db).to_string()),
-                        hir::ModuleDef::Macro(it) => Some(it.display(db).to_string()),
+                        hir::ModuleDef::Module(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Function(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Adt(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Variant(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Const(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Static(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Trait(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::TraitAlias(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::TypeAlias(it) => Some(it.display(db, edition).to_string()),
+                        hir::ModuleDef::Macro(it) => Some(it.display(db, edition).to_string()),
                         hir::ModuleDef::BuiltinType(_) => None,
                     },
                     docs: None,
@@ -271,11 +275,13 @@ pub(crate) trait ToNavFromAst: Sized {
     }
 }
 
-fn container_name(db: &RootDatabase, t: impl HasContainer) -> Option<SmolStr> {
+fn container_name(db: &RootDatabase, t: impl HasContainer, edition: Edition) -> Option<SmolStr> {
     match t.container(db) {
-        hir::ItemContainer::Trait(it) => Some(it.name(db).display_no_db().to_smolstr()),
+        hir::ItemContainer::Trait(it) => Some(it.name(db).display_no_db(edition).to_smolstr()),
         // FIXME: Handle owners of blocks correctly here
-        hir::ItemContainer::Module(it) => it.name(db).map(|name| name.display_no_db().to_smolstr()),
+        hir::ItemContainer::Module(it) => {
+            it.name(db).map(|name| name.display_no_db(edition).to_smolstr())
+        }
         _ => None,
     }
 }
@@ -283,32 +289,32 @@ fn container_name(db: &RootDatabase, t: impl HasContainer) -> Option<SmolStr> {
 impl ToNavFromAst for hir::Function {
     const KIND: SymbolKind = SymbolKind::Function;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 
 impl ToNavFromAst for hir::Const {
     const KIND: SymbolKind = SymbolKind::Const;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::Static {
     const KIND: SymbolKind = SymbolKind::Static;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::Struct {
     const KIND: SymbolKind = SymbolKind::Struct;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::Enum {
     const KIND: SymbolKind = SymbolKind::Enum;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::Variant {
@@ -317,25 +323,25 @@ impl ToNavFromAst for hir::Variant {
 impl ToNavFromAst for hir::Union {
     const KIND: SymbolKind = SymbolKind::Union;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::TypeAlias {
     const KIND: SymbolKind = SymbolKind::TypeAlias;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::Trait {
     const KIND: SymbolKind = SymbolKind::Trait;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 impl ToNavFromAst for hir::TraitAlias {
     const KIND: SymbolKind = SymbolKind::TraitAlias;
     fn container_name(self, db: &RootDatabase) -> Option<SmolStr> {
-        container_name(db, self)
+        container_name(db, self, self.krate(db).edition(db))
     }
 }
 
@@ -346,6 +352,7 @@ where
 {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let src = self.source(db)?;
+        let edition = src.file_id.original_file(db).edition();
         Some(
             NavigationTarget::from_named(
                 db,
@@ -354,7 +361,7 @@ where
             )
             .map(|mut res| {
                 res.docs = self.docs(db);
-                res.description = Some(self.display(db).to_string());
+                res.description = Some(self.display(db, edition).to_string());
                 res.container_name = self.container_name(db);
                 res
             }),
@@ -365,8 +372,10 @@ where
 impl ToNav for hir::Module {
     fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
         let InFile { file_id, value } = self.definition_source(db);
+        let edition = self.krate(db).edition(db);
 
-        let name = self.name(db).map(|it| it.display_no_db().to_smolstr()).unwrap_or_default();
+        let name =
+            self.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default();
         let (syntax, focus) = match &value {
             ModuleSource::SourceFile(node) => (node.syntax(), None),
             ModuleSource::Module(node) => (node.syntax(), node.name()),
@@ -418,6 +427,7 @@ impl TryToNav for hir::ExternCrateDecl {
         let focus = value
             .rename()
             .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right));
+        let edition = self.module(db).krate().edition(db);
 
         Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map(
             |(FileRange { file_id, range: full_range }, focus_range)| {
@@ -425,7 +435,7 @@ impl TryToNav for hir::ExternCrateDecl {
                     file_id,
                     self.alias_or_name(db)
                         .unwrap_or_else(|| self.name(db))
-                        .display_no_db()
+                        .display_no_db(edition)
                         .to_smolstr(),
                     focus_range,
                     full_range,
@@ -433,8 +443,8 @@ impl TryToNav for hir::ExternCrateDecl {
                 );
 
                 res.docs = self.docs(db);
-                res.description = Some(self.display(db).to_string());
-                res.container_name = container_name(db, *self);
+                res.description = Some(self.display(db, edition).to_string());
+                res.container_name = container_name(db, *self, edition);
                 res
             },
         ))
@@ -444,13 +454,14 @@ impl TryToNav for hir::ExternCrateDecl {
 impl TryToNav for hir::Field {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let src = self.source(db)?;
+        let edition = self.parent_def(db).module(db).krate().edition(db);
 
         let field_source = match &src.value {
             FieldSource::Named(it) => {
                 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map(
                     |mut res| {
                         res.docs = self.docs(db);
-                        res.description = Some(self.display(db).to_string());
+                        res.description = Some(self.display(db, edition).to_string());
                         res
                     },
                 )
@@ -531,10 +542,11 @@ impl ToNav for LocalSource {
             Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()),
             Either::Right(it) => (it.syntax(), it.name()),
         };
+        let edition = self.local.parent(db).module(db).krate().edition(db);
 
         orig_range_with_focus(db, file_id, node, name).map(
             |(FileRange { file_id, range: full_range }, focus_range)| {
-                let name = local.name(db).display_no_db().to_smolstr();
+                let name = local.name(db).display_no_db(edition).to_smolstr();
                 let kind = if local.is_self(db) {
                     SymbolKind::SelfParam
                 } else if local.is_param(db) {
@@ -567,7 +579,8 @@ impl ToNav for hir::Local {
 impl TryToNav for hir::Label {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).display_no_db().to_smolstr();
+        // Labels can't be keywords, so no escaping needed.
+        let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr();
 
         Some(orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
             |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
@@ -588,7 +601,8 @@ impl TryToNav for hir::Label {
 impl TryToNav for hir::TypeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let InFile { file_id, value } = self.merge().source(db)?;
-        let name = self.name(db).display_no_db().to_smolstr();
+        let edition = self.module(db).krate().edition(db);
+        let name = self.name(db).display_no_db(edition).to_smolstr();
 
         let value = match value {
             Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x),
@@ -630,7 +644,8 @@ impl TryToNav for hir::TypeOrConstParam {
 impl TryToNav for hir::LifetimeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).display_no_db().to_smolstr();
+        // Lifetimes cannot be keywords, so not escaping needed.
+        let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr();
 
         Some(orig_range(db, file_id, value.syntax()).map(
             |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
@@ -651,7 +666,8 @@ impl TryToNav for hir::LifetimeParam {
 impl TryToNav for hir::ConstParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let InFile { file_id, value } = self.merge().source(db)?;
-        let name = self.name(db).display_no_db().to_smolstr();
+        let edition = self.module(db).krate().edition(db);
+        let name = self.name(db).display_no_db(edition).to_smolstr();
 
         let value = match value {
             Either::Left(ast::TypeOrConstParam::Const(x)) => x,
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index aef162bf0ac..3e3d5ef6e65 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -306,8 +306,9 @@ fn handle_control_flow_keywords(
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<ReferenceSearchResult> {
     let file = sema.parse_guess_edition(file_id);
-    let token =
-        file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(Edition::CURRENT))?;
+    let edition =
+        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+    let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?;
 
     let references = match token.kind() {
         T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token),
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index ed0e3d89ddc..42b7472c645 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -6,19 +6,14 @@
 
 use hir::{AsAssocItem, HirFileIdExt, InFile, Semantics};
 use ide_db::{
-    base_db::SourceDatabase,
     defs::{Definition, NameClass, NameRefClass},
     rename::{bail, format_err, source_edit_from_references, IdentifierKind},
     source_change::SourceChangeBuilder,
     FileId, FileRange, RootDatabase,
 };
 use itertools::Itertools;
-use span::Edition;
 use stdx::{always, never};
-use syntax::{
-    ast, utils::is_raw_identifier, AstNode, SmolStr, SyntaxKind, SyntaxNode, TextRange, TextSize,
-    ToSmolStr,
-};
+use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize};
 
 use text_edit::TextEdit;
 
@@ -103,7 +98,7 @@ pub(crate) fn rename(
             // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
             // properly find "direct" usages/references.
             .map(|(.., def)| {
-                match IdentifierKind::classify(Edition::CURRENT_FIXME, new_name)? {
+                match IdentifierKind::classify(new_name)? {
                     IdentifierKind::Ident => (),
                     IdentifierKind::Lifetime => {
                         bail!("Cannot alias reference to a lifetime identifier")
@@ -125,7 +120,10 @@ pub(crate) fn rename(
 
                 let mut source_change = SourceChange::default();
                 source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
-                    (position.file_id, source_edit_from_references(refs, def, new_name))
+                    (
+                        position.file_id,
+                        source_edit_from_references(refs, def, new_name, file_id.edition()),
+                    )
                 }));
 
                 Ok(source_change)
@@ -163,12 +161,7 @@ pub(crate) fn will_rename_file(
     let sema = Semantics::new(db);
     let module = sema.file_to_module_def(file_id)?;
     let def = Definition::Module(module);
-    let mut change =
-        if is_raw_identifier(new_name_stem, db.crate_graph()[module.krate().into()].edition) {
-            def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()?
-        } else {
-            def.rename(&sema, new_name_stem).ok()?
-        };
+    let mut change = def.rename(&sema, new_name_stem).ok()?;
     change.file_system_edits.clear();
     Some(change)
 }
@@ -272,7 +265,7 @@ fn find_definitions(
                             // if the name differs from the definitions name it has to be an alias
                             if def
                                 .name(sema.db)
-                                .map_or(false, |it| it.display_no_db().to_smolstr() != name_ref.text().as_str())
+                                .map_or(false, |it| !it.eq_ident(name_ref.text().as_str()))
                             {
                                 Err(format_err!("Renaming aliases is currently unsupported"))
                             } else {
@@ -379,7 +372,7 @@ fn rename_to_self(
     let usages = def.usages(sema).all();
     let mut source_change = SourceChange::default();
     source_change.extend(usages.iter().map(|(file_id, references)| {
-        (file_id.into(), source_edit_from_references(references, def, "self"))
+        (file_id.into(), source_edit_from_references(references, def, "self", file_id.edition()))
     }));
     source_change.insert_source_edit(
         file_id.original_file(sema.db),
@@ -400,7 +393,7 @@ fn rename_self_to_param(
         return Ok(SourceChange::default());
     }
 
-    let identifier_kind = IdentifierKind::classify(Edition::CURRENT_FIXME, new_name)?;
+    let identifier_kind = IdentifierKind::classify(new_name)?;
 
     let InFile { file_id, value: self_param } =
         sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
@@ -415,7 +408,7 @@ fn rename_self_to_param(
     let mut source_change = SourceChange::default();
     source_change.insert_source_edit(file_id.original_file(sema.db), edit);
     source_change.extend(usages.iter().map(|(file_id, references)| {
-        (file_id.into(), source_edit_from_references(references, def, new_name))
+        (file_id.into(), source_edit_from_references(references, def, new_name, file_id.edition()))
     }));
     Ok(source_change)
 }
@@ -636,9 +629,9 @@ impl Foo {
     #[test]
     fn test_rename_to_invalid_identifier3() {
         check(
-            "let",
+            "super",
             r#"fn main() { let i$0 = 1; }"#,
-            "error: Invalid name `let`: not an identifier",
+            "error: Invalid name `super`: not an identifier",
         );
     }
 
@@ -687,11 +680,7 @@ impl Foo {
 
     #[test]
     fn test_rename_mod_invalid_raw_ident() {
-        check(
-            "r#self",
-            r#"mod foo$0 {}"#,
-            "error: Invalid name: `self` cannot be a raw identifier",
-        );
+        check("r#self", r#"mod foo$0 {}"#, "error: Invalid name `self`: not an identifier");
     }
 
     #[test]
@@ -1546,6 +1535,228 @@ pub fn baz() {}
     }
 
     #[test]
+    fn test_rename_each_usage_gets_appropriate_rawness() {
+        check_expect(
+            "dyn",
+            r#"
+//- /a.rs crate:a edition:2015
+pub fn foo() {}
+
+//- /b.rs crate:b edition:2018 deps:a new_source_root:local
+fn bar() {
+    a::foo$0();
+}
+    "#,
+            expect![[r#"
+                source_file_edits: [
+                    (
+                        FileId(
+                            0,
+                        ),
+                        [
+                            Indel {
+                                insert: "dyn",
+                                delete: 7..10,
+                            },
+                        ],
+                    ),
+                    (
+                        FileId(
+                            1,
+                        ),
+                        [
+                            Indel {
+                                insert: "r#dyn",
+                                delete: 18..21,
+                            },
+                        ],
+                    ),
+                ]
+                file_system_edits: []
+            "#]],
+        );
+
+        check_expect(
+            "dyn",
+            r#"
+//- /a.rs crate:a edition:2018
+pub fn foo() {}
+
+//- /b.rs crate:b edition:2015 deps:a new_source_root:local
+fn bar() {
+    a::foo$0();
+}
+    "#,
+            expect![[r#"
+                source_file_edits: [
+                    (
+                        FileId(
+                            0,
+                        ),
+                        [
+                            Indel {
+                                insert: "r#dyn",
+                                delete: 7..10,
+                            },
+                        ],
+                    ),
+                    (
+                        FileId(
+                            1,
+                        ),
+                        [
+                            Indel {
+                                insert: "dyn",
+                                delete: 18..21,
+                            },
+                        ],
+                    ),
+                ]
+                file_system_edits: []
+            "#]],
+        );
+
+        check_expect(
+            "r#dyn",
+            r#"
+//- /a.rs crate:a edition:2018
+pub fn foo$0() {}
+
+//- /b.rs crate:b edition:2015 deps:a new_source_root:local
+fn bar() {
+    a::foo();
+}
+    "#,
+            expect![[r#"
+                source_file_edits: [
+                    (
+                        FileId(
+                            0,
+                        ),
+                        [
+                            Indel {
+                                insert: "r#dyn",
+                                delete: 7..10,
+                            },
+                        ],
+                    ),
+                    (
+                        FileId(
+                            1,
+                        ),
+                        [
+                            Indel {
+                                insert: "dyn",
+                                delete: 18..21,
+                            },
+                        ],
+                    ),
+                ]
+                file_system_edits: []
+            "#]],
+        );
+    }
+
+    #[test]
+    fn rename_raw_identifier() {
+        check_expect(
+            "abc",
+            r#"
+//- /a.rs crate:a edition:2015
+pub fn dyn() {}
+
+fn foo() {
+    dyn$0();
+}
+
+//- /b.rs crate:b edition:2018 deps:a new_source_root:local
+fn bar() {
+    a::r#dyn();
+}
+    "#,
+            expect![[r#"
+                source_file_edits: [
+                    (
+                        FileId(
+                            0,
+                        ),
+                        [
+                            Indel {
+                                insert: "abc",
+                                delete: 7..10,
+                            },
+                            Indel {
+                                insert: "abc",
+                                delete: 32..35,
+                            },
+                        ],
+                    ),
+                    (
+                        FileId(
+                            1,
+                        ),
+                        [
+                            Indel {
+                                insert: "abc",
+                                delete: 18..23,
+                            },
+                        ],
+                    ),
+                ]
+                file_system_edits: []
+            "#]],
+        );
+
+        check_expect(
+            "abc",
+            r#"
+//- /a.rs crate:a edition:2018
+pub fn r#dyn() {}
+
+fn foo() {
+    r#dyn$0();
+}
+
+//- /b.rs crate:b edition:2015 deps:a new_source_root:local
+fn bar() {
+    a::dyn();
+}
+    "#,
+            expect![[r#"
+                source_file_edits: [
+                    (
+                        FileId(
+                            0,
+                        ),
+                        [
+                            Indel {
+                                insert: "abc",
+                                delete: 7..12,
+                            },
+                            Indel {
+                                insert: "abc",
+                                delete: 34..39,
+                            },
+                        ],
+                    ),
+                    (
+                        FileId(
+                            1,
+                        ),
+                        [
+                            Indel {
+                                insert: "abc",
+                                delete: 18..21,
+                            },
+                        ],
+                    ),
+                ]
+                file_system_edits: []
+            "#]],
+        );
+    }
+
+    #[test]
     fn test_enum_variant_from_module_1() {
         cov_mark::check!(rename_non_local);
         check(
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 5d4b8b36439..38dc522789d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -3,7 +3,8 @@ use std::fmt;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
 use hir::{
-    db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics,
+    db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, HirFileIdExt,
+    Semantics,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
@@ -14,7 +15,7 @@ use ide_db::{
     FilePosition, FxHashMap, FxHashSet, RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
-use span::TextSize;
+use span::{Edition, TextSize};
 use stdx::{always, format_to};
 use syntax::{
     ast::{self, AstNode},
@@ -321,6 +322,7 @@ pub(crate) fn runnable_fn(
     sema: &Semantics<'_, RootDatabase>,
     def: hir::Function,
 ) -> Option<Runnable> {
+    let edition = def.krate(sema.db).edition(sema.db);
     let under_cfg_test = has_cfg_test(def.module(sema.db).attrs(sema.db));
     let kind = if !under_cfg_test && def.is_main(sema.db) {
         RunnableKind::Bin
@@ -328,11 +330,11 @@ pub(crate) fn runnable_fn(
         let test_id = || {
             let canonical_path = {
                 let def: hir::ModuleDef = def.into();
-                def.canonical_path(sema.db)
+                def.canonical_path(sema.db, edition)
             };
             canonical_path
                 .map(TestId::Path)
-                .unwrap_or(TestId::Name(def.name(sema.db).display_no_db().to_smolstr()))
+                .unwrap_or(TestId::Name(def.name(sema.db).display_no_db(edition).to_smolstr()))
         };
 
         if def.is_test(sema.db) {
@@ -367,8 +369,11 @@ pub(crate) fn runnable_mod(
         .path_to_root(sema.db)
         .into_iter()
         .rev()
-        .filter_map(|it| it.name(sema.db))
-        .map(|it| it.display(sema.db).to_string())
+        .filter_map(|module| {
+            module.name(sema.db).map(|mod_name| {
+                mod_name.display(sema.db, module.krate().edition(sema.db)).to_string()
+            })
+        })
         .join("::");
 
     let attrs = def.attrs(sema.db);
@@ -381,6 +386,7 @@ pub(crate) fn runnable_impl(
     sema: &Semantics<'_, RootDatabase>,
     def: &hir::Impl,
 ) -> Option<Runnable> {
+    let edition = def.module(sema.db).krate().edition(sema.db);
     let attrs = def.attrs(sema.db);
     if !has_runnable_doc_test(&attrs) {
         return None;
@@ -389,13 +395,13 @@ pub(crate) fn runnable_impl(
     let nav = def.try_to_nav(sema.db)?.call_site();
     let ty = def.self_ty(sema.db);
     let adt_name = ty.as_adt()?.name(sema.db);
-    let mut ty_args = ty.generic_parameters(sema.db).peekable();
+    let mut ty_args = ty.generic_parameters(sema.db, edition).peekable();
     let params = if ty_args.peek().is_some() {
         format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)))
     } else {
         String::new()
     };
-    let mut test_id = format!("{}{params}", adt_name.display(sema.db));
+    let mut test_id = format!("{}{params}", adt_name.display(sema.db, edition));
     test_id.retain(|c| c != ' ');
     let test_id = TestId::Path(test_id);
 
@@ -419,8 +425,11 @@ fn runnable_mod_outline_definition(
         .path_to_root(sema.db)
         .into_iter()
         .rev()
-        .filter_map(|it| it.name(sema.db))
-        .map(|it| it.display(sema.db).to_string())
+        .filter_map(|module| {
+            module.name(sema.db).map(|mod_name| {
+                mod_name.display(sema.db, module.krate().edition(sema.db)).to_string()
+            })
+        })
         .join("::");
 
     let attrs = def.attrs(sema.db);
@@ -452,6 +461,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
         Definition::SelfType(it) => it.attrs(db),
         _ => return None,
     };
+    let edition = def.krate(db).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
     if !has_runnable_doc_test(&attrs) {
         return None;
     }
@@ -460,29 +470,29 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
         let mut path = String::new();
         def.canonical_module_path(db)?
             .flat_map(|it| it.name(db))
-            .for_each(|name| format_to!(path, "{}::", name.display(db)));
+            .for_each(|name| format_to!(path, "{}::", name.display(db, edition)));
         // This probably belongs to canonical_path?
         if let Some(assoc_item) = def.as_assoc_item(db) {
             if let Some(ty) = assoc_item.implementing_ty(db) {
                 if let Some(adt) = ty.as_adt() {
                     let name = adt.name(db);
-                    let mut ty_args = ty.generic_parameters(db).peekable();
-                    format_to!(path, "{}", name.display(db));
+                    let mut ty_args = ty.generic_parameters(db, edition).peekable();
+                    format_to!(path, "{}", name.display(db, edition));
                     if ty_args.peek().is_some() {
                         format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty)));
                     }
-                    format_to!(path, "::{}", def_name.display(db));
+                    format_to!(path, "::{}", def_name.display(db, edition));
                     path.retain(|c| c != ' ');
                     return Some(path);
                 }
             }
         }
-        format_to!(path, "{}", def_name.display(db));
+        format_to!(path, "{}", def_name.display(db, edition));
         Some(path)
     })();
 
-    let test_id =
-        path.map_or_else(|| TestId::Name(def_name.display_no_db().to_smolstr()), TestId::Path);
+    let test_id = path
+        .map_or_else(|| TestId::Name(def_name.display_no_db(edition).to_smolstr()), TestId::Path);
 
     let mut nav = match def {
         Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def),
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index b6c9e2f6366..9d3b8c6ebd1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -13,6 +13,7 @@ use ide_db::{
     documentation::{Documentation, HasDocs},
     FilePosition, FxIndexMap,
 };
+use span::Edition;
 use stdx::format_to;
 use syntax::{
     algo,
@@ -82,6 +83,8 @@ pub(crate) fn signature_help(
         // this prevents us from leaving the CallExpression
         .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
     let token = sema.descend_into_macros_single(DescendPreference::None, token);
+    let edition =
+        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
 
     for node in token.parent_ancestors() {
         match_ast! {
@@ -91,49 +94,49 @@ pub(crate) fn signature_help(
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_call(&sema, arg_list, token);
+                    return signature_help_for_call(&sema, arg_list, token, edition);
                 },
                 ast::GenericArgList(garg_list) => {
                     let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_generics(&sema, garg_list, token);
+                    return signature_help_for_generics(&sema, garg_list, token, edition);
                 },
                 ast::RecordExpr(record) => {
                     let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_record_lit(&sema, record, token);
+                    return signature_help_for_record_lit(&sema, record, token, edition);
                 },
                 ast::RecordPat(record) => {
                     let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_record_pat(&sema, record, token);
+                    return signature_help_for_record_pat(&sema, record, token, edition);
                 },
                 ast::TupleStructPat(tuple_pat) => {
                     let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token);
+                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition);
                 },
                 ast::TuplePat(tuple_pat) => {
                     let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_pat(&sema, tuple_pat, token);
+                    return signature_help_for_tuple_pat(&sema, tuple_pat, token, edition);
                 },
                 ast::TupleExpr(tuple_expr) => {
                     let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token);
                     if cursor_outside {
                         continue;
                     }
-                    return signature_help_for_tuple_expr(&sema, tuple_expr, token);
+                    return signature_help_for_tuple_expr(&sema, tuple_expr, token, edition);
                 },
                 _ => (),
             }
@@ -157,6 +160,7 @@ fn signature_help_for_call(
     sema: &Semantics<'_, RootDatabase>,
     arg_list: ast::ArgList,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     // Find the calling expression and its NameRef
     let mut nodes = arg_list.syntax().ancestors().skip(1);
@@ -181,7 +185,7 @@ fn signature_help_for_call(
     match callable.kind() {
         hir::CallableKind::Function(func) => {
             res.doc = func.docs(db);
-            format_to!(res.signature, "fn {}", func.name(db).display(db));
+            format_to!(res.signature, "fn {}", func.name(db).display(db, edition));
             fn_params = Some(match callable.receiver_param(db) {
                 Some(_self) => func.params_without_self(db),
                 None => func.assoc_fn_params(db),
@@ -189,15 +193,15 @@ fn signature_help_for_call(
         }
         hir::CallableKind::TupleStruct(strukt) => {
             res.doc = strukt.docs(db);
-            format_to!(res.signature, "struct {}", strukt.name(db).display(db));
+            format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));
         }
         hir::CallableKind::TupleEnumVariant(variant) => {
             res.doc = variant.docs(db);
             format_to!(
                 res.signature,
                 "enum {}::{}",
-                variant.parent_enum(db).name(db).display(db),
-                variant.name(db).display(db)
+                variant.parent_enum(db).name(db).display(db, edition),
+                variant.name(db).display(db, edition)
             );
         }
         hir::CallableKind::Closure(closure) => {
@@ -210,7 +214,7 @@ fn signature_help_for_call(
             Some(adt) => format_to!(
                 res.signature,
                 "<{} as {fn_trait}>::{}",
-                adt.name(db).display(db),
+                adt.name(db).display(db, edition),
                 fn_trait.function_name()
             ),
             None => format_to!(res.signature, "impl {fn_trait}"),
@@ -220,7 +224,7 @@ fn signature_help_for_call(
     res.signature.push('(');
     {
         if let Some((self_param, _)) = callable.receiver_param(db) {
-            format_to!(res.signature, "{}", self_param.display(db))
+            format_to!(res.signature, "{}", self_param.display(db, edition))
         }
         let mut buf = String::new();
         for (idx, p) in callable.params().into_iter().enumerate() {
@@ -240,8 +244,10 @@ fn signature_help_for_call(
             // This is overly conservative: we do not substitute known type vars
             // (see FIXME in tests::impl_trait) and falling back on any unknowns.
             match (p.ty().contains_unknown(), fn_params.as_deref()) {
-                (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)),
-                _ => format_to!(buf, "{}", p.ty().display(db)),
+                (true, Some(fn_params)) => {
+                    format_to!(buf, "{}", fn_params[idx].ty().display(db, edition))
+                }
+                _ => format_to!(buf, "{}", p.ty().display(db, edition)),
             }
             res.push_call_param(&buf);
         }
@@ -250,7 +256,7 @@ fn signature_help_for_call(
 
     let mut render = |ret_type: hir::Type| {
         if !ret_type.is_unit() {
-            format_to!(res.signature, " -> {}", ret_type.display(db));
+            format_to!(res.signature, " -> {}", ret_type.display(db, edition));
         }
     };
     match callable.kind() {
@@ -270,6 +276,7 @@ fn signature_help_for_generics(
     sema: &Semantics<'_, RootDatabase>,
     arg_list: ast::GenericArgList,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =
         generic_def_for_node(sema, &arg_list, &token)?;
@@ -284,11 +291,11 @@ fn signature_help_for_generics(
     match generics_def {
         hir::GenericDef::Function(it) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "fn {}", it.name(db).display(db));
+            format_to!(res.signature, "fn {}", it.name(db).display(db, edition));
         }
         hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "enum {}", it.name(db).display(db));
+            format_to!(res.signature, "enum {}", it.name(db).display(db, edition));
             if let Some(variant) = variant {
                 // In paths, generics of an enum can be specified *after* one of its variants.
                 // eg. `None::<u8>`
@@ -298,23 +305,23 @@ fn signature_help_for_generics(
         }
         hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "struct {}", it.name(db).display(db));
+            format_to!(res.signature, "struct {}", it.name(db).display(db, edition));
         }
         hir::GenericDef::Adt(hir::Adt::Union(it)) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "union {}", it.name(db).display(db));
+            format_to!(res.signature, "union {}", it.name(db).display(db, edition));
         }
         hir::GenericDef::Trait(it) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "trait {}", it.name(db).display(db));
+            format_to!(res.signature, "trait {}", it.name(db).display(db, edition));
         }
         hir::GenericDef::TraitAlias(it) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "trait {}", it.name(db).display(db));
+            format_to!(res.signature, "trait {}", it.name(db).display(db, edition));
         }
         hir::GenericDef::TypeAlias(it) => {
             res.doc = it.docs(db);
-            format_to!(res.signature, "type {}", it.name(db).display(db));
+            format_to!(res.signature, "type {}", it.name(db).display(db, edition));
         }
         // These don't have generic args that can be specified
         hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
@@ -339,11 +346,11 @@ fn signature_help_for_generics(
         }
 
         buf.clear();
-        format_to!(buf, "{}", param.display(db));
+        format_to!(buf, "{}", param.display(db, edition));
         res.push_generic_param(&buf);
     }
     if let hir::GenericDef::Trait(tr) = generics_def {
-        add_assoc_type_bindings(db, &mut res, tr, arg_list);
+        add_assoc_type_bindings(db, &mut res, tr, arg_list, edition);
     }
     res.signature.push('>');
 
@@ -355,6 +362,7 @@ fn add_assoc_type_bindings(
     res: &mut SignatureHelp,
     tr: Trait,
     args: ast::GenericArgList,
+    edition: Edition,
 ) {
     if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() {
         // Assoc type bindings are only valid in type bound position.
@@ -378,7 +386,7 @@ fn add_assoc_type_bindings(
 
     for item in tr.items_with_supertraits(db) {
         if let AssocItem::TypeAlias(ty) = item {
-            let name = ty.name(db).display_no_db().to_smolstr();
+            let name = ty.name(db).display_no_db(edition).to_smolstr();
             if !present_bindings.contains(&*name) {
                 buf.clear();
                 format_to!(buf, "{} = …", name);
@@ -392,6 +400,7 @@ fn signature_help_for_record_lit(
     sema: &Semantics<'_, RootDatabase>,
     record: ast::RecordExpr,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     signature_help_for_record_(
         sema,
@@ -403,6 +412,7 @@ fn signature_help_for_record_lit(
             .filter_map(|field| sema.resolve_record_field(&field))
             .map(|(field, _, ty)| (field, ty)),
         token,
+        edition,
     )
 }
 
@@ -410,6 +420,7 @@ fn signature_help_for_record_pat(
     sema: &Semantics<'_, RootDatabase>,
     record: ast::RecordPat,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     signature_help_for_record_(
         sema,
@@ -420,6 +431,7 @@ fn signature_help_for_record_pat(
             .fields()
             .filter_map(|field| sema.resolve_record_pat_field(&field)),
         token,
+        edition,
     )
 }
 
@@ -427,6 +439,7 @@ fn signature_help_for_tuple_struct_pat(
     sema: &Semantics<'_, RootDatabase>,
     pat: ast::TupleStructPat,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     let path = pat.path()?;
     let path_res = sema.resolve_path(&path)?;
@@ -445,8 +458,8 @@ fn signature_help_for_tuple_struct_pat(
         format_to!(
             res.signature,
             "enum {}::{} (",
-            en.name(db).display(db),
-            variant.name(db).display(db)
+            en.name(db).display(db, edition),
+            variant.name(db).display(db, edition)
         );
         variant.fields(db)
     } else {
@@ -459,7 +472,7 @@ fn signature_help_for_tuple_struct_pat(
         match adt {
             hir::Adt::Struct(it) => {
                 res.doc = it.docs(db);
-                format_to!(res.signature, "struct {} (", it.name(db).display(db));
+                format_to!(res.signature, "struct {} (", it.name(db).display(db, edition));
                 it.fields(db)
             }
             _ => return None,
@@ -472,6 +485,7 @@ fn signature_help_for_tuple_struct_pat(
         token,
         pat.fields(),
         fields.into_iter().map(|it| it.ty(db)),
+        edition,
     ))
 }
 
@@ -479,6 +493,7 @@ fn signature_help_for_tuple_pat(
     sema: &Semantics<'_, RootDatabase>,
     pat: ast::TuplePat,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     let db = sema.db;
     let field_pats = pat.fields();
@@ -498,6 +513,7 @@ fn signature_help_for_tuple_pat(
         token,
         field_pats,
         fields.into_iter(),
+        edition,
     ))
 }
 
@@ -505,6 +521,7 @@ fn signature_help_for_tuple_expr(
     sema: &Semantics<'_, RootDatabase>,
     expr: ast::TupleExpr,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     let active_parameter = Some(
         expr.syntax()
@@ -526,7 +543,7 @@ fn signature_help_for_tuple_expr(
     let fields = expr.original.tuple_fields(db);
     let mut buf = String::new();
     for ty in fields {
-        format_to!(buf, "{}", ty.display_truncated(db, Some(20)));
+        format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
         res.push_call_param(&buf);
         buf.clear();
     }
@@ -540,6 +557,7 @@ fn signature_help_for_record_(
     path: &ast::Path,
     fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
     token: SyntaxToken,
+    edition: Edition,
 ) -> Option<SignatureHelp> {
     let active_parameter = field_list_children
         .filter_map(NodeOrToken::into_token)
@@ -566,8 +584,8 @@ fn signature_help_for_record_(
         format_to!(
             res.signature,
             "enum {}::{} {{ ",
-            en.name(db).display(db),
-            variant.name(db).display(db)
+            en.name(db).display(db, edition),
+            variant.name(db).display(db, edition)
         );
     } else {
         let adt = match path_res {
@@ -580,12 +598,12 @@ fn signature_help_for_record_(
             hir::Adt::Struct(it) => {
                 fields = it.fields(db);
                 res.doc = it.docs(db);
-                format_to!(res.signature, "struct {} {{ ", it.name(db).display(db));
+                format_to!(res.signature, "struct {} {{ ", it.name(db).display(db, edition));
             }
             hir::Adt::Union(it) => {
                 fields = it.fields(db);
                 res.doc = it.docs(db);
-                format_to!(res.signature, "union {} {{ ", it.name(db).display(db));
+                format_to!(res.signature, "union {} {{ ", it.name(db).display(db, edition));
             }
             _ => return None,
         }
@@ -596,7 +614,12 @@ fn signature_help_for_record_(
     let mut buf = String::new();
     for (field, ty) in fields2 {
         let name = field.name(db);
-        format_to!(buf, "{}: {}", name.display(db), ty.display_truncated(db, Some(20)));
+        format_to!(
+            buf,
+            "{}: {}",
+            name.display(db, edition),
+            ty.display_truncated(db, Some(20), edition)
+        );
         res.push_record_field(&buf);
         buf.clear();
 
@@ -606,7 +629,12 @@ fn signature_help_for_record_(
     }
     for (name, field) in fields {
         let Some(field) = field else { continue };
-        format_to!(buf, "{}: {}", name.display(db), field.ty(db).display_truncated(db, Some(20)));
+        format_to!(
+            buf,
+            "{}: {}",
+            name.display(db, edition),
+            field.ty(db).display_truncated(db, Some(20), edition)
+        );
         res.push_record_field(&buf);
         buf.clear();
     }
@@ -621,6 +649,7 @@ fn signature_help_for_tuple_pat_ish(
     token: SyntaxToken,
     mut field_pats: AstChildren<ast::Pat>,
     fields: impl ExactSizeIterator<Item = hir::Type>,
+    edition: Edition,
 ) -> SignatureHelp {
     let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));
     let is_left_of_rest_pat =
@@ -647,7 +676,7 @@ fn signature_help_for_tuple_pat_ish(
 
     let mut buf = String::new();
     for ty in fields {
-        format_to!(buf, "{}", ty.display_truncated(db, Some(20)));
+        format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition));
         res.push_call_param(&buf);
         buf.clear();
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index eaccee08e8c..0f8d03c8d55 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -10,6 +10,7 @@ use ide_db::{
     helpers::get_definition,
     FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
 };
+use span::Edition;
 use syntax::{AstNode, SyntaxKind::*, SyntaxNode, TextRange, T};
 
 use crate::inlay_hints::InlayFieldsToResolve;
@@ -116,7 +117,11 @@ fn documentation_for_definition(
         _ => None,
     };
 
-    def.docs(sema.db, famous_defs.as_ref())
+    def.docs(
+        sema.db,
+        famous_defs.as_ref(),
+        def.krate(sema.db).map(|it| it.edition(sema.db)).unwrap_or(Edition::CURRENT),
+    )
 }
 
 impl StaticIndex<'_> {
@@ -161,6 +166,8 @@ impl StaticIndex<'_> {
         // hovers
         let sema = hir::Semantics::new(self.db);
         let tokens_or_nodes = sema.parse_guess_edition(file_id).syntax().clone();
+        let edition =
+            sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
         let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|it| match it {
             syntax::NodeOrToken::Node(_) => None,
             syntax::NodeOrToken::Token(it) => Some(it),
@@ -201,17 +208,20 @@ impl StaticIndex<'_> {
                         &node,
                         None,
                         &hover_config,
+                        edition,
                     )),
                     definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
                         FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
                     }),
                     references: vec![],
                     moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
-                    display_name: def.name(self.db).map(|name| name.display(self.db).to_string()),
+                    display_name: def
+                        .name(self.db)
+                        .map(|name| name.display(self.db, edition).to_string()),
                     enclosing_moniker: current_crate
                         .zip(def.enclosing_definition(self.db))
                         .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)),
-                    signature: Some(def.label(self.db)),
+                    signature: Some(def.label(self.db, edition)),
                     kind: def_to_kind(self.db, def),
                 });
                 self.def_map.insert(def, it);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 23185920058..e082fcdc765 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -501,7 +501,9 @@ fn traverse(
                 config.syntactic_name_ref_highlighting,
                 name_like,
             ),
-            NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)),
+            NodeOrToken::Token(token) => {
+                highlight::token(sema, token, file_id.edition()).zip(Some(None))
+            }
         };
         if let Some((mut highlight, binding_hash)) = element {
             if is_unlinked && highlight.tag == HlTag::UnresolvedReference {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 70fdc0a1b3a..eeba9cf35c9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -19,7 +19,11 @@ use crate::{
     Highlight, HlMod, HlTag,
 };
 
-pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Highlight> {
+pub(super) fn token(
+    sema: &Semantics<'_, RootDatabase>,
+    token: SyntaxToken,
+    edition: Edition,
+) -> Option<Highlight> {
     if let Some(comment) = ast::Comment::cast(token.clone()) {
         let h = HlTag::Comment;
         return Some(match comment.kind().doc {
@@ -42,7 +46,7 @@ pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> O
             HlTag::None.into()
         }
         p if p.is_punct() => punctuation(sema, token, p),
-        k if k.is_keyword(Edition::CURRENT) => keyword(sema, token, k)?,
+        k if k.is_keyword(edition) => keyword(sema, token, k)?,
         _ => return None,
     };
     Some(highlight)
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs
index 460fc4fe141..b441b4cc90e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs
@@ -1,5 +1,4 @@
 //! Syntax highlighting for macro_rules!.
-use span::Edition;
 use syntax::{SyntaxKind, SyntaxToken, TextRange, T};
 
 use crate::{HlRange, HlTag};
@@ -118,7 +117,7 @@ fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) {
 
 fn is_metavariable(token: &SyntaxToken) -> Option<TextRange> {
     match token.kind() {
-        kind if kind == SyntaxKind::IDENT || kind.is_keyword(Edition::CURRENT) => {
+        kind if kind.is_any_identifier() => {
             if let Some(_dollar) = token.prev_token().filter(|t| t.kind() == T![$]) {
                 return Some(token.text_range());
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
index dae79998dc4..a6352b99d4f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
@@ -16,5 +16,5 @@ pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
     let file_id = sema
         .attach_first_edition(file_id)
         .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
-    db.file_item_tree(file_id.into()).pretty_print(db)
+    db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition())
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index df3f2f18b4c..830c39e21ea 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -6,6 +6,7 @@ use ide_db::{
     helpers::{get_definition, pick_best_token},
     RootDatabase,
 };
+use span::Edition;
 use syntax::{AstNode, SyntaxKind};
 
 use crate::FilePosition;
@@ -85,6 +86,10 @@ pub(crate) fn view_memory_layout(
 ) -> Option<RecursiveMemoryLayout> {
     let sema = Semantics::new(db);
     let file = sema.parse_guess_edition(position.file_id);
+    let edition = sema
+        .attach_first_edition(position.file_id)
+        .map(|it| it.edition())
+        .unwrap_or(Edition::CURRENT);
     let token =
         pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
             SyntaxKind::IDENT => 3,
@@ -111,6 +116,7 @@ pub(crate) fn view_memory_layout(
         ty: &Type,
         layout: &Layout,
         parent_idx: usize,
+        edition: Edition,
     ) {
         let mut fields = ty
             .fields(db)
@@ -141,7 +147,7 @@ pub(crate) fn view_memory_layout(
             if let Ok(child_layout) = child_ty.layout(db) {
                 nodes.push(MemoryLayoutNode {
                     item_name: field.name(db),
-                    typename: child_ty.display(db).to_string(),
+                    typename: child_ty.display(db, edition).to_string(),
                     size: child_layout.size(),
                     alignment: child_layout.align(),
                     offset: match *field {
@@ -157,7 +163,7 @@ pub(crate) fn view_memory_layout(
                     item_name: field.name(db)
                         + format!("(no layout data: {:?})", child_ty.layout(db).unwrap_err())
                             .as_ref(),
-                    typename: child_ty.display(db).to_string(),
+                    typename: child_ty.display(db, edition).to_string(),
                     size: 0,
                     offset: 0,
                     alignment: 0,
@@ -170,7 +176,7 @@ pub(crate) fn view_memory_layout(
 
         for (i, (_, child_ty)) in fields.iter().enumerate() {
             if let Ok(child_layout) = child_ty.layout(db) {
-                read_layout(nodes, db, child_ty, &child_layout, children_start + i);
+                read_layout(nodes, db, child_ty, &child_layout, children_start + i, edition);
             }
         }
     }
@@ -188,7 +194,7 @@ pub(crate) fn view_memory_layout(
                 def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()),
             };
 
-            let typename = ty.display(db).to_string();
+            let typename = ty.display(db, edition).to_string();
 
             let mut nodes = vec![MemoryLayoutNode {
                 item_name,
@@ -200,7 +206,7 @@ pub(crate) fn view_memory_layout(
                 children_start: -1,
                 children_len: 0,
             }];
-            read_layout(&mut nodes, db, &ty, &layout, 0);
+            read_layout(&mut nodes, db, &ty, &layout, 0, edition);
 
             RecursiveMemoryLayout { nodes }
         })
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
index 3ca6bd4cb11..6a8cca9ccc7 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
@@ -3,6 +3,8 @@
 
 mod generated;
 
+use crate::Edition;
+
 #[allow(unreachable_pub)]
 pub use self::generated::SyntaxKind;
 
@@ -26,4 +28,11 @@ impl SyntaxKind {
     pub fn is_trivia(self) -> bool {
         matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
     }
+
+    /// Returns true if this is an identifier or a keyword.
+    #[inline]
+    pub fn is_any_identifier(self) -> bool {
+        // Assuming no edition removed keywords...
+        self == SyntaxKind::IDENT || self.is_keyword(Edition::LATEST)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
index 0bd6677b662..5eb6ff664f6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
@@ -21,7 +21,7 @@ use std::io::Read;
 use anyhow::Result;
 use hir::{Module, Name};
 use hir_ty::db::HirDatabase;
-use ide::AnalysisHost;
+use ide::{AnalysisHost, Edition};
 use itertools::Itertools;
 use vfs::Vfs;
 
@@ -85,6 +85,6 @@ fn full_name_of_item(db: &dyn HirDatabase, module: Module, name: Name) -> String
         .rev()
         .filter_map(|it| it.name(db))
         .chain(Some(name))
-        .map(|it| it.display(db.upcast()).to_string())
+        .map(|it| it.display(db.upcast(), Edition::LATEST).to_string())
         .join("::")
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 06f4ba815d0..44e56645ba3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -17,7 +17,7 @@ use hir_def::{
 };
 use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
 use ide::{
-    Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, InlayFieldsToResolve,
+    Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
     InlayHintsConfig, LineCol, RootDatabase,
 };
 use ide_db::{
@@ -309,7 +309,7 @@ impl flags::AnalysisStats {
         let mut fail = 0;
         for &c in consts {
             all += 1;
-            let Err(error) = c.render_eval(db) else {
+            let Err(error) = c.render_eval(db, Edition::LATEST) else {
                 continue;
             };
             if verbosity.is_spammy() {
@@ -442,6 +442,7 @@ impl flags::AnalysisStats {
                                 prefer_prelude: true,
                                 prefer_absolute: false,
                             },
+                            Edition::LATEST,
                         )
                         .unwrap();
                     syntax_hit_found |= trim(&original_text) == trim(&generated);
@@ -563,7 +564,7 @@ impl flags::AnalysisStats {
                     .rev()
                     .filter_map(|it| it.name(db))
                     .chain(Some(body.name(db).unwrap_or_else(Name::missing)))
-                    .map(|it| it.display(db).to_string())
+                    .map(|it| it.display(db, Edition::LATEST).to_string())
                     .join("::");
                 println!("Mir body for {full_name} failed due {e:?}");
             }
@@ -628,12 +629,14 @@ impl flags::AnalysisStats {
                             .filter_map(|it| it.name(db))
                             .rev()
                             .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
-                            .map(|it| it.display(db).to_string()),
+                            .map(|it| it.display(db, Edition::LATEST).to_string()),
                     )
                     .join("::")
             };
             if let Some(only_name) = self.only.as_deref() {
-                if name.display(db).to_string() != only_name && full_name() != only_name {
+                if name.display(db, Edition::LATEST).to_string() != only_name
+                    && full_name() != only_name
+                {
                     continue;
                 }
             }
@@ -687,7 +690,10 @@ impl flags::AnalysisStats {
                                 end.col,
                             ));
                         } else {
-                            bar.println(format!("{}: Unknown type", name.display(db)));
+                            bar.println(format!(
+                                "{}: Unknown type",
+                                name.display(db, Edition::LATEST)
+                            ));
                         }
                     }
                     true
@@ -708,17 +714,20 @@ impl flags::AnalysisStats {
                             start.col,
                             end.line + 1,
                             end.col,
-                            ty.display(db)
+                            ty.display(db, Edition::LATEST)
                         ));
                     } else {
-                        bar.println(format!("unknown location: {}", ty.display(db)));
+                        bar.println(format!(
+                            "unknown location: {}",
+                            ty.display(db, Edition::LATEST)
+                        ));
                     }
                 }
                 if unknown_or_partial && self.output == Some(OutputFormat::Csv) {
                     println!(
                         r#"{},type,"{}""#,
                         location_csv_expr(db, vfs, &sm(), expr_id),
-                        ty.display(db)
+                        ty.display(db, Edition::LATEST)
                     );
                 }
                 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
@@ -733,15 +742,15 @@ impl flags::AnalysisStats {
                                 start.col,
                                 end.line + 1,
                                 end.col,
-                                mismatch.expected.display(db),
-                                mismatch.actual.display(db)
+                                mismatch.expected.display(db, Edition::LATEST),
+                                mismatch.actual.display(db, Edition::LATEST)
                             ));
                         } else {
                             bar.println(format!(
                                 "{}: Expected {}, got {}",
-                                name.display(db),
-                                mismatch.expected.display(db),
-                                mismatch.actual.display(db)
+                                name.display(db, Edition::LATEST),
+                                mismatch.expected.display(db, Edition::LATEST),
+                                mismatch.actual.display(db, Edition::LATEST)
                             ));
                         }
                     }
@@ -749,8 +758,8 @@ impl flags::AnalysisStats {
                         println!(
                             r#"{},mismatch,"{}","{}""#,
                             location_csv_expr(db, vfs, &sm(), expr_id),
-                            mismatch.expected.display(db),
-                            mismatch.actual.display(db)
+                            mismatch.expected.display(db, Edition::LATEST),
+                            mismatch.actual.display(db, Edition::LATEST)
                         );
                     }
                 }
@@ -785,7 +794,10 @@ impl flags::AnalysisStats {
                                 end.col,
                             ));
                         } else {
-                            bar.println(format!("{}: Unknown type", name.display(db)));
+                            bar.println(format!(
+                                "{}: Unknown type",
+                                name.display(db, Edition::LATEST)
+                            ));
                         }
                     }
                     true
@@ -806,17 +818,20 @@ impl flags::AnalysisStats {
                             start.col,
                             end.line + 1,
                             end.col,
-                            ty.display(db)
+                            ty.display(db, Edition::LATEST)
                         ));
                     } else {
-                        bar.println(format!("unknown location: {}", ty.display(db)));
+                        bar.println(format!(
+                            "unknown location: {}",
+                            ty.display(db, Edition::LATEST)
+                        ));
                     }
                 }
                 if unknown_or_partial && self.output == Some(OutputFormat::Csv) {
                     println!(
                         r#"{},type,"{}""#,
                         location_csv_pat(db, vfs, &sm(), pat_id),
-                        ty.display(db)
+                        ty.display(db, Edition::LATEST)
                     );
                 }
                 if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) {
@@ -830,15 +845,15 @@ impl flags::AnalysisStats {
                                 start.col,
                                 end.line + 1,
                                 end.col,
-                                mismatch.expected.display(db),
-                                mismatch.actual.display(db)
+                                mismatch.expected.display(db, Edition::LATEST),
+                                mismatch.actual.display(db, Edition::LATEST)
                             ));
                         } else {
                             bar.println(format!(
                                 "{}: Expected {}, got {}",
-                                name.display(db),
-                                mismatch.expected.display(db),
-                                mismatch.actual.display(db)
+                                name.display(db, Edition::LATEST),
+                                mismatch.expected.display(db, Edition::LATEST),
+                                mismatch.actual.display(db, Edition::LATEST)
                             ));
                         }
                     }
@@ -846,8 +861,8 @@ impl flags::AnalysisStats {
                         println!(
                             r#"{},mismatch,"{}","{}""#,
                             location_csv_pat(db, vfs, &sm(), pat_id),
-                            mismatch.expected.display(db),
-                            mismatch.actual.display(db)
+                            mismatch.expected.display(db, Edition::LATEST),
+                            mismatch.actual.display(db, Edition::LATEST)
                         );
                     }
                 }
@@ -923,12 +938,16 @@ impl flags::AnalysisStats {
                             .filter_map(|it| it.name(db))
                             .rev()
                             .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
-                            .map(|it| it.display(db).to_string()),
+                            .map(|it| it.display(db, Edition::LATEST).to_string()),
                     )
                     .join("::")
             };
             if let Some(only_name) = self.only.as_deref() {
-                if body_id.name(db).unwrap_or_else(Name::missing).display(db).to_string()
+                if body_id
+                    .name(db)
+                    .unwrap_or_else(Name::missing)
+                    .display(db, Edition::LATEST)
+                    .to_string()
                     != only_name
                     && full_name() != only_name
                 {
diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
index 5153db23727..56e43e82ed2 100644
--- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
@@ -301,14 +301,11 @@ where
                         };
                     }
                     let leaf: tt::Leaf<_> = match kind {
-                        T![true] | T![false] => make_ident!(),
-                        IDENT => {
+                        k if k.is_any_identifier() => {
                             let text = token.to_text(conv);
                             tt::Ident::new(&text, conv.span_for(abs_range)).into()
                         }
                         UNDERSCORE => make_ident!(),
-                        // FIXME: Edition
-                        k if k.is_keyword(Edition::CURRENT) => make_ident!(),
                         k if k.is_literal() => {
                             let text = token.to_text(conv);
                             let span = conv.span_for(abs_range);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/utils.rs b/src/tools/rust-analyzer/crates/syntax/src/utils.rs
index 77d49b442e0..d1f60f0b71b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/utils.rs
@@ -2,6 +2,7 @@
 
 use crate::SyntaxKind;
 
+#[inline]
 pub fn is_raw_identifier(name: &str, edition: parser::Edition) -> bool {
     let is_keyword = SyntaxKind::from_keyword(name, edition).is_some();
     is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")