about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-10-28 11:01:12 +0000
committerGitHub <noreply@github.com>2024-10-28 11:01:12 +0000
commit25b0846e967c55c68657a85b7b191161f357a39d (patch)
tree70382a44a5867005f10e22277ef5f8174fd6367b
parent5346e847c4c4a2481f966a04ae45b4af3dc82bfc (diff)
parent3f638482a361d0fe56157776d98d2572fda0f945 (diff)
downloadrust-25b0846e967c55c68657a85b7b191161f357a39d.tar.gz
rust-25b0846e967c55c68657a85b7b191161f357a39d.zip
Merge pull request #18074 from ChayimFriedman2/typeref-source-map
internal: Build source map for `hir_def::TypeRef`s
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs341
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs203
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs271
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs388
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs100
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs168
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs174
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs326
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/db.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs20
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs472
-rw-r--r--src/tools/rust-analyzer/xtask/src/tidy.rs2
46 files changed, 2510 insertions, 928 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 1bfd7d2b731..5a386f6cf8d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -30,6 +30,7 @@ use crate::{
     nameres::DefMap,
     path::{ModPath, Path},
     src::HasSource,
+    type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
     BlockId, DefWithBodyId, HasModule, Lookup,
 };
 
@@ -69,6 +70,7 @@ pub struct Body {
     pub self_param: Option<BindingId>,
     /// The `ExprId` of the actual body expression.
     pub body_expr: ExprId,
+    pub types: TypesMap,
     /// Block expressions in this body that may contain inner items.
     block_scopes: Vec<BlockId>,
 
@@ -139,6 +141,8 @@ pub struct BodySourceMap {
     field_map_back: FxHashMap<ExprId, FieldSource>,
     pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
 
+    types: TypesSourceMap,
+
     // FIXME: Make this a sane struct.
     template_map: Option<
         Box<(
@@ -304,6 +308,7 @@ impl Body {
             binding_hygiene,
             expr_hygiene,
             pat_hygiene,
+            types,
         } = self;
         block_scopes.shrink_to_fit();
         exprs.shrink_to_fit();
@@ -314,6 +319,7 @@ impl Body {
         binding_hygiene.shrink_to_fit();
         expr_hygiene.shrink_to_fit();
         pat_hygiene.shrink_to_fit();
+        types.shrink_to_fit();
     }
 
     pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -542,6 +548,7 @@ impl Default for Body {
             binding_hygiene: Default::default(),
             expr_hygiene: Default::default(),
             pat_hygiene: Default::default(),
+            types: Default::default(),
         }
     }
 }
@@ -578,6 +585,14 @@ impl Index<BindingId> for Body {
     }
 }
 
+impl Index<TypeRefId> for Body {
+    type Output = TypeRef;
+
+    fn index(&self, b: TypeRefId) -> &TypeRef {
+        &self.types[b]
+    }
+}
+
 // FIXME: Change `node_` prefix to something more reasonable.
 // Perhaps `expr_syntax` and `expr_id`?
 impl BodySourceMap {
@@ -691,6 +706,7 @@ impl BodySourceMap {
             template_map,
             diagnostics,
             binding_definitions,
+            types,
         } = self;
         if let Some(template_map) = template_map {
             template_map.0.shrink_to_fit();
@@ -707,5 +723,6 @@ impl BodySourceMap {
         expansions.shrink_to_fit();
         diagnostics.shrink_to_fit();
         binding_definitions.shrink_to_fit();
+        types.shrink_to_fit();
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 6117664c64c..0b108b54e67 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -12,7 +12,7 @@ use hir_expand::{
     span_map::{ExpansionSpanMap, SpanMap},
     InFile, MacroDefId,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
 use rustc_hash::FxHashMap;
 use span::AstIdMap;
 use stdx::never;
@@ -274,8 +274,8 @@ impl ExprCollector<'_> {
         (self.body, self.source_map)
     }
 
-    fn ctx(&self) -> LowerCtx<'_> {
-        self.expander.ctx(self.db)
+    fn ctx(&mut self) -> LowerCtx<'_> {
+        self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
     }
 
     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -436,7 +436,7 @@ impl ExprCollector<'_> {
             }
             ast::Expr::PathExpr(e) => {
                 let (path, hygiene) = self
-                    .collect_expr_path(&e)
+                    .collect_expr_path(e)
                     .map(|(path, hygiene)| (Expr::Path(path), hygiene))
                     .unwrap_or((Expr::Missing, HygieneId::ROOT));
                 let expr_id = self.alloc_expr(path, syntax_ptr);
@@ -486,8 +486,7 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
             }
             ast::Expr::RecordExpr(e) => {
-                let path =
-                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
                     let fields = nfl
                         .fields()
@@ -534,7 +533,7 @@ impl ExprCollector<'_> {
             ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
             ast::Expr::CastExpr(e) => {
                 let expr = self.collect_expr_opt(e.expr());
-                let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
             }
             ast::Expr::RefExpr(e) => {
@@ -573,16 +572,13 @@ impl ExprCollector<'_> {
                     arg_types.reserve_exact(num_params);
                     for param in pl.params() {
                         let pat = this.collect_pat_top(param.pat());
-                        let type_ref =
-                            param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+                        let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
                         args.push(pat);
                         arg_types.push(type_ref);
                     }
                 }
-                let ret_type = e
-                    .ret_type()
-                    .and_then(|r| r.ty())
-                    .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+                let ret_type =
+                    e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
 
                 let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
                 let prev_try_block_label = this.current_try_block_label.take();
@@ -709,7 +705,7 @@ impl ExprCollector<'_> {
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
             ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
             ast::Expr::OffsetOfExpr(e) => {
-                let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
                 let fields = e.fields().map(|it| it.as_name()).collect();
                 self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
             }
@@ -717,15 +713,15 @@ impl ExprCollector<'_> {
         })
     }
 
-    fn collect_expr_path(&mut self, e: &ast::PathExpr) -> Option<(Path, HygieneId)> {
+    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
+        self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
+    }
+
+    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
         e.path().and_then(|path| {
-            let path = self.expander.parse_path(self.db, path)?;
-            let Path::Normal { type_anchor, mod_path, generic_args } = &path else {
-                panic!("path parsing produced a non-normal path");
-            };
+            let path = self.parse_path(path)?;
             // Need to enable `mod_path.len() < 1` for `self`.
-            let may_be_variable =
-                type_anchor.is_none() && mod_path.len() <= 1 && generic_args.is_none();
+            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
             let hygiene = if may_be_variable {
                 self.hygiene_id_for(e.syntax().text_range().start())
             } else {
@@ -790,17 +786,14 @@ impl ExprCollector<'_> {
             }
             ast::Expr::CallExpr(e) => {
                 let path = collect_path(self, e.expr()?)?;
-                let path = path
-                    .path()
-                    .and_then(|path| self.expander.parse_path(self.db, path))
-                    .map(Box::new);
+                let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
                 self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
             }
             ast::Expr::PathExpr(e) => {
                 let (path, hygiene) = self
-                    .collect_expr_path(e)
-                    .map(|(path, hygiene)| (Pat::Path(Box::new(path)), hygiene))
+                    .collect_expr_path(e.clone())
+                    .map(|(path, hygiene)| (Pat::Path(path), hygiene))
                     .unwrap_or((Pat::Missing, HygieneId::ROOT));
                 let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
                 if !hygiene.is_root() {
@@ -819,8 +812,7 @@ impl ExprCollector<'_> {
                 id
             }
             ast::Expr::RecordExpr(e) => {
-                let path =
-                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let record_field_list = e.record_expr_field_list()?;
                 let ellipsis = record_field_list.dotdot_token().is_some();
                 // FIXME: Report an error here if `record_field_list.spread().is_some()`.
@@ -1063,7 +1055,7 @@ impl ExprCollector<'_> {
             syntax_ptr,
         );
         let none_arm = MatchArm {
-            pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
+            pat: self.alloc_pat_desugared(Pat::Path(option_none)),
             guard: None,
             expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
         };
@@ -1325,8 +1317,7 @@ impl ExprCollector<'_> {
                     return;
                 }
                 let pat = self.collect_pat_top(stmt.pat());
-                let type_ref =
-                    stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
                 let else_branch = stmt
                     .let_else()
@@ -1552,8 +1543,7 @@ impl ExprCollector<'_> {
                 return pat;
             }
             ast::Pat::TupleStructPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let (args, ellipsis) = self.collect_tuple_pat(
                     p.fields(),
                     comma_follows_token(p.l_paren_token()),
@@ -1567,8 +1557,7 @@ impl ExprCollector<'_> {
                 Pat::Ref { pat, mutability }
             }
             ast::Pat::PathPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path));
                 path.map(Pat::Path).unwrap_or(Pat::Missing)
             }
             ast::Pat::OrPat(p) => 'b: {
@@ -1615,8 +1604,7 @@ impl ExprCollector<'_> {
             }
             ast::Pat::WildcardPat(_) => Pat::Wild,
             ast::Pat::RecordPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let record_pat_field_list =
                     &p.record_pat_field_list().expect("every struct should have a field list");
                 let args = record_pat_field_list
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
index 4213370ac19..c1b58dbdd0c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
@@ -158,9 +158,7 @@ impl ExprCollector<'_> {
                                 AsmOperand::Const(self.collect_expr_opt(c.expr()))
                             }
                             ast::AsmOperand::AsmSym(s) => {
-                                let Some(path) =
-                                    s.path().and_then(|p| self.expander.parse_path(self.db, p))
-                                else {
+                                let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
                                     continue;
                                 };
                                 AsmOperand::Sym(path)
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 591bb64af5a..f8b6eef3422 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
@@ -11,7 +11,6 @@ use crate::{
         Statement,
     },
     pretty::{print_generic_args, print_path, print_type_ref},
-    type_ref::TypeRef,
 };
 
 use super::*;
@@ -69,20 +68,20 @@ pub(super) fn print_body_hir(
     };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
-        let function_data = &db.function_data(it);
+        let function_data = db.function_data(it);
         let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
         if let Some(self_param) = body.self_param {
             p.print_binding(self_param);
             p.buf.push_str(": ");
             if let Some(ty) = params.next() {
-                p.print_type_ref(ty);
+                p.print_type_ref(*ty, &function_data.types_map);
                 p.buf.push_str(", ");
             }
         }
         body.params.iter().zip(params).for_each(|(&param, ty)| {
             p.print_pat(param);
             p.buf.push_str(": ");
-            p.print_type_ref(ty);
+            p.print_type_ref(*ty, &function_data.types_map);
             p.buf.push_str(", ");
         });
         // remove the last ", " in param list
@@ -92,7 +91,7 @@ pub(super) fn print_body_hir(
         p.buf.push(')');
         // return type
         p.buf.push_str(" -> ");
-        p.print_type_ref(ret_type);
+        p.print_type_ref(*ret_type, &function_data.types_map);
         p.buf.push(' ');
     }
     p.print_expr(body.body_expr);
@@ -242,7 +241,7 @@ impl Printer<'_> {
             Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
             Expr::OffsetOf(offset_of) => {
                 w!(self, "builtin#offset_of(");
-                self.print_type_ref(&offset_of.container);
+                self.print_type_ref(offset_of.container, &self.body.types);
                 let edition = self.edition;
                 w!(
                     self,
@@ -296,7 +295,7 @@ impl Printer<'_> {
                 if let Some(args) = generic_args {
                     w!(self, "::<");
                     let edition = self.edition;
-                    print_generic_args(self.db, args, self, edition).unwrap();
+                    print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
                     w!(self, ">");
                 }
                 w!(self, "(");
@@ -405,7 +404,7 @@ impl Printer<'_> {
             Expr::Cast { expr, type_ref } => {
                 self.print_expr(*expr);
                 w!(self, " as ");
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, &self.body.types);
             }
             Expr::Ref { expr, rawness, mutability } => {
                 w!(self, "&");
@@ -493,13 +492,13 @@ impl Printer<'_> {
                     self.print_pat(*pat);
                     if let Some(ty) = ty {
                         w!(self, ": ");
-                        self.print_type_ref(ty);
+                        self.print_type_ref(*ty, &self.body.types);
                     }
                 }
                 w!(self, "|");
                 if let Some(ret_ty) = ret_type {
                     w!(self, " -> ");
-                    self.print_type_ref(ret_ty);
+                    self.print_type_ref(*ret_ty, &self.body.types);
                 }
                 self.whitespace();
                 self.print_expr(*body);
@@ -734,7 +733,7 @@ impl Printer<'_> {
                 self.print_pat(*pat);
                 if let Some(ty) = type_ref {
                     w!(self, ": ");
-                    self.print_type_ref(ty);
+                    self.print_type_ref(*ty, &self.body.types);
                 }
                 if let Some(init) = initializer {
                     w!(self, " = ");
@@ -792,14 +791,14 @@ impl Printer<'_> {
         }
     }
 
-    fn print_type_ref(&mut self, ty: &TypeRef) {
+    fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
         let edition = self.edition;
-        print_type_ref(self.db, ty, self, edition).unwrap();
+        print_type_ref(self.db, ty, map, self, edition).unwrap();
     }
 
     fn print_path(&mut self, path: &Path) {
         let edition = self.edition;
-        print_path(self.db, path, self, edition).unwrap();
+        print_path(self.db, path, &self.body.types, self, edition).unwrap();
     }
 
     fn print_binding(&mut self, id: BindingId) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 263fad51d78..f49018eaf38 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -6,7 +6,7 @@ use base_db::CrateId;
 use hir_expand::{
     name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
 use la_arena::{Idx, RawIdx};
 use smallvec::SmallVec;
 use syntax::{ast, Parse};
@@ -25,7 +25,7 @@ use crate::{
         DefMap, MacroSubNs,
     },
     path::ImportAlias,
-    type_ref::{TraitRef, TypeBound, TypeRef},
+    type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
     visibility::RawVisibility,
     AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
     HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@@ -35,13 +35,14 @@ use crate::{
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FunctionData {
     pub name: Name,
-    pub params: Box<[Interned<TypeRef>]>,
-    pub ret_type: Interned<TypeRef>,
+    pub params: Box<[TypeRefId]>,
+    pub ret_type: TypeRefId,
     pub attrs: Attrs,
     pub visibility: RawVisibility,
     pub abi: Option<Symbol>,
     pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
     pub rustc_allow_incoherent_impl: bool,
+    pub types_map: Arc<TypesMap>,
     flags: FnFlags,
 }
 
@@ -110,13 +111,14 @@ impl FunctionData {
                 .filter(|&(idx, _)| {
                     item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
                 })
-                .filter_map(|(_, param)| param.type_ref.clone())
+                .filter_map(|(_, param)| param.type_ref)
                 .collect(),
-            ret_type: func.ret_type.clone(),
+            ret_type: func.ret_type,
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             visibility,
             abi: func.abi.clone(),
             legacy_const_generics_indices,
+            types_map: func.types_map.clone(),
             flags,
             rustc_allow_incoherent_impl,
         })
@@ -182,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TypeAliasData {
     pub name: Name,
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub type_ref: Option<TypeRefId>,
     pub visibility: RawVisibility,
     pub is_extern: bool,
     pub rustc_has_incoherent_inherent_impls: bool,
     pub rustc_allow_incoherent_impl: bool,
     /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
-    pub bounds: Box<[Interned<TypeBound>]>,
+    pub bounds: Box<[TypeBound]>,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl TypeAliasData {
@@ -216,12 +219,13 @@ impl TypeAliasData {
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
-            type_ref: typ.type_ref.clone(),
+            type_ref: typ.type_ref,
             visibility,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             rustc_has_incoherent_inherent_impls,
             rustc_allow_incoherent_impl,
             bounds: typ.bounds.clone(),
+            types_map: typ.types_map.clone(),
         })
     }
 }
@@ -343,13 +347,14 @@ impl TraitAliasData {
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct ImplData {
-    pub target_trait: Option<Interned<TraitRef>>,
-    pub self_ty: Interned<TypeRef>,
+    pub target_trait: Option<TraitRef>,
+    pub self_ty: TypeRefId,
     pub items: Box<[AssocItemId]>,
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
     pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl ImplData {
@@ -368,7 +373,7 @@ impl ImplData {
         let item_tree = tree_id.item_tree(db);
         let impl_def = &item_tree[tree_id.value];
         let target_trait = impl_def.target_trait.clone();
-        let self_ty = impl_def.self_ty.clone();
+        let self_ty = impl_def.self_ty;
         let is_negative = impl_def.is_negative;
         let is_unsafe = impl_def.is_unsafe;
 
@@ -387,6 +392,7 @@ impl ImplData {
                 is_negative,
                 is_unsafe,
                 macro_calls,
+                types_map: impl_def.types_map.clone(),
             }),
             DefDiagnostics::new(diagnostics),
         )
@@ -532,10 +538,11 @@ impl ExternCrateDeclData {
 pub struct ConstData {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
     pub rustc_allow_incoherent_impl: bool,
     pub has_body: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl ConstData {
@@ -556,10 +563,11 @@ impl ConstData {
 
         Arc::new(ConstData {
             name: konst.name.clone(),
-            type_ref: konst.type_ref.clone(),
+            type_ref: konst.type_ref,
             visibility,
             rustc_allow_incoherent_impl,
             has_body: konst.has_body,
+            types_map: konst.types_map.clone(),
         })
     }
 }
@@ -567,12 +575,13 @@ impl ConstData {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct StaticData {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
     pub mutable: bool,
     pub is_extern: bool,
     pub has_safe_kw: bool,
     pub has_unsafe_kw: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl StaticData {
@@ -583,12 +592,13 @@ impl StaticData {
 
         Arc::new(StaticData {
             name: statik.name.clone(),
-            type_ref: statik.type_ref.clone(),
+            type_ref: statik.type_ref,
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             has_safe_kw: statik.has_safe_kw,
             has_unsafe_kw: statik.has_unsafe_kw,
+            types_map: statik.types_map.clone(),
         })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index ba54451e594..068ebb3b7e9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -6,7 +6,7 @@ use cfg::CfgOptions;
 use either::Either;
 
 use hir_expand::name::Name;
-use intern::{sym, Interned};
+use intern::sym;
 use la_arena::Arena;
 use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
 use triomphe::Arc;
@@ -21,7 +21,7 @@ use crate::{
     lang_item::LangItem,
     nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
     tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
-    type_ref::TypeRef,
+    type_ref::{TypeRefId, TypesMap},
     visibility::RawVisibility,
     EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
 };
@@ -73,8 +73,8 @@ pub struct EnumVariantData {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum VariantData {
-    Record(Arena<FieldData>),
-    Tuple(Arena<FieldData>),
+    Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
+    Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
     Unit,
 }
 
@@ -82,7 +82,7 @@ pub enum VariantData {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FieldData {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
 }
 
@@ -208,7 +208,7 @@ impl StructData {
         }
 
         let strukt = &item_tree[loc.id.value];
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             loc.container.local_id,
@@ -219,12 +219,13 @@ impl StructData {
             &strukt.fields,
             None,
         );
+        let types_map = strukt.types_map.clone();
         (
             Arc::new(StructData {
                 name: strukt.name.clone(),
                 variant_data: Arc::new(match strukt.shape {
-                    FieldsShape::Record => VariantData::Record(data),
-                    FieldsShape::Tuple => VariantData::Tuple(data),
+                    FieldsShape::Record => VariantData::Record { fields, types_map },
+                    FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
                     FieldsShape::Unit => VariantData::Unit,
                 }),
                 repr,
@@ -258,7 +259,7 @@ impl StructData {
         }
 
         let union = &item_tree[loc.id.value];
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             loc.container.local_id,
@@ -269,10 +270,11 @@ impl StructData {
             &union.fields,
             None,
         );
+        let types_map = union.types_map.clone();
         (
             Arc::new(StructData {
                 name: union.name.clone(),
-                variant_data: Arc::new(VariantData::Record(data)),
+                variant_data: Arc::new(VariantData::Record { fields, types_map }),
                 repr,
                 visibility: item_tree[union.visibility].clone(),
                 flags,
@@ -360,7 +362,7 @@ impl EnumVariantData {
         let item_tree = loc.id.item_tree(db);
         let variant = &item_tree[loc.id.value];
 
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             container.local_id,
@@ -371,13 +373,14 @@ impl EnumVariantData {
             &variant.fields,
             Some(item_tree[loc.parent.lookup(db).id.value].visibility),
         );
+        let types_map = variant.types_map.clone();
 
         (
             Arc::new(EnumVariantData {
                 name: variant.name.clone(),
                 variant_data: Arc::new(match variant.shape {
-                    FieldsShape::Record => VariantData::Record(data),
-                    FieldsShape::Tuple => VariantData::Tuple(data),
+                    FieldsShape::Record => VariantData::Record { fields, types_map },
+                    FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
                     FieldsShape::Unit => VariantData::Unit,
                 }),
             }),
@@ -390,11 +393,20 @@ impl VariantData {
     pub fn fields(&self) -> &Arena<FieldData> {
         const EMPTY: &Arena<FieldData> = &Arena::new();
         match &self {
-            VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
+            VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
             _ => EMPTY,
         }
     }
 
+    pub fn types_map(&self) -> &TypesMap {
+        match &self {
+            VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
+                types_map
+            }
+            VariantData::Unit => TypesMap::EMPTY,
+        }
+    }
+
     // FIXME: Linear lookup
     pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
         self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
@@ -402,8 +414,8 @@ impl VariantData {
 
     pub fn kind(&self) -> StructKind {
         match self {
-            VariantData::Record(_) => StructKind::Record,
-            VariantData::Tuple(_) => StructKind::Tuple,
+            VariantData::Record { .. } => StructKind::Record,
+            VariantData::Tuple { .. } => StructKind::Tuple,
             VariantData::Unit => StructKind::Unit,
         }
     }
@@ -463,7 +475,7 @@ fn lower_field(
 ) -> FieldData {
     FieldData {
         name: field.name.clone(),
-        type_ref: field.type_ref.clone(),
+        type_ref: field.type_ref,
         visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index aeda302f35c..d7e83ce33e8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -2,7 +2,7 @@
 use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
 use either::Either;
 use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
 use la_arena::ArenaMap;
 use span::{EditionedFileId, MacroCallId};
 use syntax::{ast, AstPtr};
@@ -18,9 +18,10 @@ use crate::{
     },
     generics::GenericParams,
     import_map::ImportMap,
-    item_tree::{AttrOwner, ItemTree},
+    item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
     lang_item::{self, LangItem, LangItemTarget, LangItems},
     nameres::{diagnostics::DefDiagnostics, DefMap},
+    type_ref::TypesSourceMap,
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
     EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
@@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[ra_salsa::invoke(ItemTree::block_item_tree_query)]
     fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
 
+    #[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
+    fn file_item_tree_with_source_map(
+        &self,
+        file_id: HirFileId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
+    #[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
+    fn block_item_tree_with_source_map(
+        &self,
+        block_id: BlockId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
     #[ra_salsa::invoke(DefMap::crate_def_map_query)]
     fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
 
@@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
 
     #[ra_salsa::invoke(GenericParams::generic_params_query)]
-    fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
+    fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
+
+    /// If this returns `None` for the source map, that means it is the same as with the item tree.
+    #[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
+    fn generic_params_with_source_map(
+        &self,
+        def: GenericDefId,
+    ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
 
     // region:attrs
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 6f200021baa..d430733fcad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -14,6 +14,7 @@ use span::SyntaxContextId;
 use syntax::{ast, Parse};
 use triomphe::Arc;
 
+use crate::type_ref::{TypesMap, TypesSourceMap};
 use crate::{
     attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
     UnresolvedMacro,
@@ -114,8 +115,19 @@ impl Expander {
         mark.bomb.defuse();
     }
 
-    pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
-        LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
+    pub fn ctx<'a>(
+        &self,
+        db: &'a dyn DefDatabase,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
+    ) -> LowerCtx<'a> {
+        LowerCtx::with_span_map_cell(
+            db,
+            self.current_file_id,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        )
     }
 
     pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
@@ -142,8 +154,20 @@ impl Expander {
         self.current_file_id
     }
 
-    pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
-        let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
+    pub(crate) fn parse_path(
+        &mut self,
+        db: &dyn DefDatabase,
+        path: ast::Path,
+        types_map: &mut TypesMap,
+        types_source_map: &mut TypesSourceMap,
+    ) -> Option<Path> {
+        let ctx = LowerCtx::with_span_map_cell(
+            db,
+            self.current_file_id,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        );
         Path::from_src(&ctx, path)
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 6c34ee086aa..6b79850e9c4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -3,16 +3,18 @@
 //! generic parameters. See also the `Generics` type and the `generics_of` query
 //! in rustc.
 
-use std::ops;
+use std::{ops, sync::LazyLock};
 
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
     ExpandResult,
 };
-use intern::Interned;
 use la_arena::{Arena, RawIdx};
-use stdx::impl_from;
+use stdx::{
+    impl_from,
+    thin_vec::{EmptyOptimizedThinVec, ThinVec},
+};
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
 use triomphe::Arc;
 
@@ -22,7 +24,11 @@ use crate::{
     item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
-    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+    path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
+    type_ref::{
+        ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
+        TypesSourceMap,
+    },
     AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
@@ -37,7 +43,7 @@ pub struct TypeParamData {
     /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
     /// make it always be a value, giving impl trait a special name.
     pub name: Option<Name>,
-    pub default: Option<Interned<TypeRef>>,
+    pub default: Option<TypeRefId>,
     pub provenance: TypeParamProvenance,
 }
 
@@ -51,7 +57,7 @@ pub struct LifetimeParamData {
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct ConstParamData {
     pub name: Name,
-    pub ty: Interned<TypeRef>,
+    pub ty: TypeRefId,
     pub default: Option<ConstRef>,
 }
 
@@ -161,6 +167,7 @@ pub struct GenericParams {
     type_or_consts: Arena<TypeOrConstParamData>,
     lifetimes: Arena<LifetimeParamData>,
     where_predicates: Box<[WherePredicate]>,
+    pub types_map: TypesMap,
 }
 
 impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
 /// associated type bindings like `Iterator<Item = u32>`.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum WherePredicate {
-    TypeBound {
-        target: WherePredicateTypeTarget,
-        bound: Interned<TypeBound>,
-    },
-    Lifetime {
-        target: LifetimeRef,
-        bound: LifetimeRef,
-    },
-    ForLifetime {
-        lifetimes: Box<[Name]>,
-        target: WherePredicateTypeTarget,
-        bound: Interned<TypeBound>,
-    },
+    TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
+    Lifetime { target: LifetimeRef, bound: LifetimeRef },
+    ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum WherePredicateTypeTarget {
-    TypeRef(Interned<TypeRef>),
+    TypeRef(TypeRefId),
     /// For desugared where predicates that can directly refer to a type param.
     TypeOrConstParam(LocalTypeOrConstParamId),
 }
@@ -300,7 +297,14 @@ impl GenericParams {
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
         def: GenericDefId,
-    ) -> Interned<GenericParams> {
+    ) -> Arc<GenericParams> {
+        db.generic_params_with_source_map(def).0
+    }
+
+    pub(crate) fn generic_params_with_source_map_query(
+        db: &dyn DefDatabase,
+        def: GenericDefId,
+    ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
         let _p = tracing::info_span!("generic_params_query").entered();
 
         let krate = def.krate(db);
@@ -309,7 +313,7 @@ impl GenericParams {
 
         // Returns the generic parameters that are enabled under the current `#[cfg]` options
         let enabled_params =
-            |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+            |params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
                 let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
                 let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
                 let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@@ -325,7 +329,7 @@ impl GenericParams {
                 if all_type_or_consts_enabled && all_lifetimes_enabled {
                     params.clone()
                 } else {
-                    Interned::new(GenericParams {
+                    Arc::new(GenericParams {
                         type_or_consts: all_type_or_consts_enabled
                             .then(|| params.type_or_consts.clone())
                             .unwrap_or_else(|| {
@@ -347,6 +351,7 @@ impl GenericParams {
                                     .collect()
                             }),
                         where_predicates: params.where_predicates.clone(),
+                        types_map: params.types_map.clone(),
                     })
                 }
             };
@@ -357,18 +362,18 @@ impl GenericParams {
                 Data = impl ItemTreeLoc<Id = Id>,
             >,
             enabled_params: impl Fn(
-                &Interned<GenericParams>,
+                &Arc<GenericParams>,
                 &ItemTree,
                 GenericModItem,
-            ) -> Interned<GenericParams>,
-        ) -> Interned<GenericParams>
+            ) -> Arc<GenericParams>,
+        ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
         where
             FileItemTreeId<Id>: Into<GenericModItem>,
         {
             let id = id.lookup(db).item_tree_id();
             let tree = id.item_tree(db);
             let item = &tree[id.value];
-            enabled_params(item.generic_params(), &tree, id.value.into())
+            (enabled_params(item.generic_params(), &tree, id.value.into()), None)
         }
 
         match def {
@@ -383,28 +388,37 @@ impl GenericParams {
                 let module = loc.container.module(db);
                 let func_data = db.function_data(id);
                 if func_data.params.is_empty() {
-                    enabled_params
+                    (enabled_params, None)
                 } else {
+                    let source_maps = loc.id.item_tree_with_source_map(db).1;
+                    let item_source_maps = source_maps.function(loc.id.value);
                     let mut generic_params = GenericParamsCollector {
                         type_or_consts: enabled_params.type_or_consts.clone(),
                         lifetimes: enabled_params.lifetimes.clone(),
                         where_predicates: enabled_params.where_predicates.clone().into(),
                     };
 
+                    let (mut types_map, mut types_source_maps) =
+                        (enabled_params.types_map.clone(), item_source_maps.generics().clone());
                     // Don't create an `Expander` if not needed since this
                     // could cause a reparse after the `ItemTree` has been created due to the spanmap.
                     let mut expander = None;
-                    for param in func_data.params.iter() {
+                    for &param in func_data.params.iter() {
                         generic_params.fill_implicit_impl_trait_args(
                             db,
+                            &mut types_map,
+                            &mut types_source_maps,
                             &mut expander,
                             &mut || {
                                 (module.def_map(db), Expander::new(db, loc.id.file_id(), module))
                             },
                             param,
+                            &item.types_map,
+                            item_source_maps.item(),
                         );
                     }
-                    Interned::new(generic_params.finish())
+                    let generics = generic_params.finish(types_map, &mut types_source_maps);
+                    (generics, Some(Arc::new(types_source_maps)))
                 }
             }
             GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@@ -414,11 +428,15 @@ impl GenericParams {
             GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
-            GenericDefId::ConstId(_) => Interned::new(GenericParams {
-                type_or_consts: Default::default(),
-                lifetimes: Default::default(),
-                where_predicates: Default::default(),
-            }),
+            GenericDefId::ConstId(_) => (
+                Arc::new(GenericParams {
+                    type_or_consts: Default::default(),
+                    lifetimes: Default::default(),
+                    where_predicates: Default::default(),
+                    types_map: Default::default(),
+                }),
+                None,
+            ),
         }
     }
 }
@@ -452,7 +470,7 @@ impl GenericParamsCollector {
         &mut self,
         lower_ctx: &LowerCtx<'_>,
         type_bounds: Option<ast::TypeBoundList>,
-        target: Either<TypeRef, LifetimeRef>,
+        target: Either<TypeRefId, LifetimeRef>,
     ) {
         for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
             self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
@@ -473,16 +491,15 @@ impl GenericParamsCollector {
                 ast::TypeOrConstParam::Type(type_param) => {
                     let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
                     // FIXME: Use `Path::from_src`
-                    let default = type_param
-                        .default_type()
-                        .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
+                    let default =
+                        type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
                     let param = TypeParamData {
                         name: Some(name.clone()),
                         default,
                         provenance: TypeParamProvenance::TypeParamList,
                     };
                     let idx = self.type_or_consts.alloc(param.into());
-                    let type_ref = TypeRef::Path(name.into());
+                    let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
                     self.fill_bounds(
                         lower_ctx,
                         type_param.type_bound_list(),
@@ -492,12 +509,10 @@ impl GenericParamsCollector {
                 }
                 ast::TypeOrConstParam::Const(const_param) => {
                     let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
-                    let ty = const_param
-                        .ty()
-                        .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+                    let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
                     let param = ConstParamData {
                         name,
-                        ty: Interned::new(ty),
+                        ty,
                         default: ConstRef::from_const_param(lower_ctx, &const_param),
                     };
                     let idx = self.type_or_consts.alloc(param.into());
@@ -557,7 +572,7 @@ impl GenericParamsCollector {
         lower_ctx: &LowerCtx<'_>,
         bound: ast::TypeBound,
         hrtb_lifetimes: Option<&[Name]>,
-        target: Either<TypeRef, LifetimeRef>,
+        target: Either<TypeRefId, LifetimeRef>,
     ) {
         let bound = TypeBound::from_ast(lower_ctx, bound);
         self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@@ -565,12 +580,12 @@ impl GenericParamsCollector {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
                 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
                     lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
-                    target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
-                    bound: Interned::new(bound),
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
                 },
                 None => WherePredicate::TypeBound {
-                    target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
-                    bound: Interned::new(bound),
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
                 },
             },
             (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@@ -581,7 +596,7 @@ impl GenericParamsCollector {
         self.where_predicates.push(predicate);
     }
 
-    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
         for bounds in impl_bounds {
             let param = TypeParamData {
                 name: None,
@@ -589,10 +604,10 @@ impl GenericParamsCollector {
                 provenance: TypeParamProvenance::ArgumentImplTrait,
             };
             let param_id = self.type_or_consts.alloc(param.into());
-            for bound in bounds {
+            for bound in &bounds {
                 self.where_predicates.push(WherePredicate::TypeBound {
                     target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
-                    bound,
+                    bound: bound.clone(),
                 });
             }
         }
@@ -601,12 +616,16 @@ impl GenericParamsCollector {
     fn fill_implicit_impl_trait_args(
         &mut self,
         db: &dyn DefDatabase,
+        generics_types_map: &mut TypesMap,
+        generics_types_source_map: &mut TypesSourceMap,
         // FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
         exp: &mut Option<(Arc<DefMap>, Expander)>,
         exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
-        type_ref: &TypeRef,
+        type_ref: TypeRefId,
+        types_map: &TypesMap,
+        types_source_map: &TypesSourceMap,
     ) {
-        type_ref.walk(&mut |type_ref| {
+        TypeRef::walk(type_ref, types_map, &mut |type_ref| {
             if let TypeRef::ImplTrait(bounds) = type_ref {
                 let param = TypeParamData {
                     name: None,
@@ -615,12 +634,20 @@ impl GenericParamsCollector {
                 };
                 let param_id = self.type_or_consts.alloc(param.into());
                 for bound in bounds {
+                    let bound = copy_type_bound(
+                        bound,
+                        types_map,
+                        types_source_map,
+                        generics_types_map,
+                        generics_types_source_map,
+                    );
                     self.where_predicates.push(WherePredicate::TypeBound {
                         target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
-                        bound: bound.clone(),
+                        bound,
                     });
                 }
             }
+
             if let TypeRef::Macro(mc) = type_ref {
                 let macro_call = mc.to_node(db.upcast());
                 let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@@ -641,23 +668,217 @@ impl GenericParamsCollector {
                 if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
                     expander.enter_expand(db, macro_call, resolver)
                 {
-                    let ctx = expander.ctx(db);
+                    let (mut macro_types_map, mut macro_types_source_map) =
+                        (TypesMap::default(), TypesSourceMap::default());
+                    let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
                     let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
-                    self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
+                    self.fill_implicit_impl_trait_args(
+                        db,
+                        generics_types_map,
+                        generics_types_source_map,
+                        &mut *exp,
+                        exp_fill,
+                        type_ref,
+                        &macro_types_map,
+                        &macro_types_source_map,
+                    );
                     exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
                 }
             }
         });
     }
 
-    pub(crate) fn finish(self) -> GenericParams {
-        let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
+    pub(crate) fn finish(
+        self,
+        mut generics_types_map: TypesMap,
+        generics_types_source_map: &mut TypesSourceMap,
+    ) -> Arc<GenericParams> {
+        let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
+
+        if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
+            static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
+                Arc::new(GenericParams {
+                    lifetimes: Arena::new(),
+                    type_or_consts: Arena::new(),
+                    where_predicates: Box::default(),
+                    types_map: TypesMap::default(),
+                })
+            });
+            return Arc::clone(&EMPTY);
+        }
+
         lifetimes.shrink_to_fit();
         type_or_consts.shrink_to_fit();
-        GenericParams {
+        where_predicates.shrink_to_fit();
+        generics_types_map.shrink_to_fit();
+        generics_types_source_map.shrink_to_fit();
+        Arc::new(GenericParams {
             type_or_consts,
             lifetimes,
             where_predicates: where_predicates.into_boxed_slice(),
+            types_map: generics_types_map,
+        })
+    }
+}
+
+/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
+/// (and `TypesSourceMap`).
+fn copy_type_ref(
+    type_ref: TypeRefId,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> TypeRefId {
+    let result = match &from[type_ref] {
+        TypeRef::Fn(fn_) => {
+            let params = fn_.params().iter().map(|(name, param_type)| {
+                (name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
+            });
+            TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
         }
+        TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+            types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
+        )),
+        &TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
+            copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
+            mutbl,
+        ),
+        TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
+            ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
+            lifetime: ref_.lifetime.clone(),
+            mutability: ref_.mutability,
+        })),
+        TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
+            ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
+            len: array.len.clone(),
+        })),
+        &TypeRef::Slice(type_ref) => {
+            TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
+        }
+        TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
+            bounds,
+            from,
+            from_source_map,
+            to,
+            to_source_map,
+        ))),
+        TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
+            bounds,
+            from,
+            from_source_map,
+            to,
+            to_source_map,
+        ))),
+        TypeRef::Path(path) => {
+            TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
+        }
+        TypeRef::Never => TypeRef::Never,
+        TypeRef::Placeholder => TypeRef::Placeholder,
+        TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
+        TypeRef::Error => TypeRef::Error,
+    };
+    let id = to.types.alloc(result);
+    if let Some(&ptr) = from_source_map.types_map_back.get(id) {
+        to_source_map.types_map_back.insert(id, ptr);
+    }
+    id
+}
+
+fn copy_path(
+    path: &Path,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> Path {
+    match path {
+        Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
+        Path::Normal(path) => {
+            let type_anchor = path
+                .type_anchor()
+                .map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
+            let mod_path = path.mod_path().clone();
+            let generic_args = path.generic_args().iter().map(|generic_args| {
+                copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
+            });
+            Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
+        }
+        Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
+    }
+}
+
+fn copy_generic_args(
+    generic_args: &Option<GenericArgs>,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> Option<GenericArgs> {
+    generic_args.as_ref().map(|generic_args| {
+        let args = generic_args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                &GenericArg::Type(ty) => {
+                    GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
+                }
+                GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
+                GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
+            })
+            .collect();
+        let bindings = generic_args
+            .bindings
+            .iter()
+            .map(|binding| {
+                let name = binding.name.clone();
+                let args =
+                    copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
+                let type_ref = binding.type_ref.map(|type_ref| {
+                    copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
+                });
+                let bounds =
+                    copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
+                        .collect();
+                AssociatedTypeBinding { name, args, type_ref, bounds }
+            })
+            .collect();
+        GenericArgs {
+            args,
+            has_self_type: generic_args.has_self_type,
+            bindings,
+            desugared_from_fn: generic_args.desugared_from_fn,
+        }
+    })
+}
+
+fn copy_type_bounds<'a>(
+    bounds: &'a [TypeBound],
+    from: &'a TypesMap,
+    from_source_map: &'a TypesSourceMap,
+    to: &'a mut TypesMap,
+    to_source_map: &'a mut TypesSourceMap,
+) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
+    bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
+}
+
+fn copy_type_bound(
+    bound: &TypeBound,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> TypeBound {
+    match bound {
+        TypeBound::Path(path, modifier) => {
+            TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
+        }
+        TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
+            lifetimes.clone(),
+            copy_path(path, from, from_source_map, to, to_source_map),
+        ),
+        TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
+        TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
+        TypeBound::Error => TypeBound::Error,
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index c1d3e255bb5..85963469430 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -18,15 +18,16 @@ pub mod type_ref;
 use std::fmt;
 
 use hir_expand::{name::Name, MacroDefId};
-use intern::{Interned, Symbol};
+use intern::Symbol;
 use la_arena::{Idx, RawIdx};
 use rustc_apfloat::ieee::{Half as f16, Quad as f128};
 use syntax::ast;
+use type_ref::TypeRefId;
 
 use crate::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     path::{GenericArgs, Path},
-    type_ref::{Mutability, Rawness, TypeRef},
+    type_ref::{Mutability, Rawness},
     BlockId, ConstBlockId,
 };
 
@@ -264,7 +265,7 @@ pub enum Expr {
     },
     Cast {
         expr: ExprId,
-        type_ref: Interned<TypeRef>,
+        type_ref: TypeRefId,
     },
     Ref {
         expr: ExprId,
@@ -300,8 +301,8 @@ pub enum Expr {
     },
     Closure {
         args: Box<[PatId]>,
-        arg_types: Box<[Option<Interned<TypeRef>>]>,
-        ret_type: Option<Interned<TypeRef>>,
+        arg_types: Box<[Option<TypeRefId>]>,
+        ret_type: Option<TypeRefId>,
         body: ExprId,
         closure_kind: ClosureKind,
         capture_by: CaptureBy,
@@ -318,7 +319,7 @@ pub enum Expr {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct OffsetOf {
-    pub container: Interned<TypeRef>,
+    pub container: TypeRefId,
     pub fields: Box<[Name]>,
 }
 
@@ -484,7 +485,7 @@ pub struct RecordLitField {
 pub enum Statement {
     Let {
         pat: PatId,
-        type_ref: Option<Interned<TypeRef>>,
+        type_ref: Option<TypeRefId>,
         initializer: Option<ExprId>,
         else_branch: Option<ExprId>,
     },
@@ -582,7 +583,7 @@ pub enum Pat {
         suffix: Box<[PatId]>,
     },
     /// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
-    Path(Box<Path>),
+    Path(Path),
     Lit(ExprId),
     Bind {
         id: BindingId,
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 5fba2066932..2582340c0f8 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
@@ -2,22 +2,27 @@
 //! be directly created from an ast::TypeRef, without further queries.
 
 use core::fmt;
-use std::fmt::Write;
+use std::{fmt::Write, ops::Index};
 
 use hir_expand::{
     db::ExpandDatabase,
     name::{AsName, Name},
-    AstId,
+    AstId, InFile,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
+use la_arena::{Arena, ArenaMap, Idx};
 use span::Edition;
-use syntax::ast::{self, HasGenericArgs, HasName, IsString};
+use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
+use syntax::{
+    ast::{self, HasGenericArgs, HasName, IsString},
+    AstPtr,
+};
 
 use crate::{
     builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
     hir::Literal,
     lower::LowerCtx,
-    path::Path,
+    path::{GenericArg, Path},
 };
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -104,35 +109,90 @@ impl TraitRef {
     }
 }
 
+thin_vec_with_header_struct! {
+    pub new(pub(crate)) struct FnType, FnTypeHeader {
+        pub params: [(Option<Name>, TypeRefId)],
+        pub is_varargs: bool,
+        pub is_unsafe: bool,
+        pub abi: Option<Symbol>; ref,
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ArrayType {
+    pub ty: TypeRefId,
+    // FIXME: This should be Ast<ConstArg>
+    pub len: ConstRef,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct RefType {
+    pub ty: TypeRefId,
+    pub lifetime: Option<LifetimeRef>,
+    pub mutability: Mutability,
+}
+
 /// Compare ty::Ty
-///
-/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
-/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
-/// does not seem to save any noticeable amount of memory.
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum TypeRef {
     Never,
     Placeholder,
-    Tuple(Vec<TypeRef>),
+    Tuple(EmptyOptimizedThinVec<TypeRefId>),
     Path(Path),
-    RawPtr(Box<TypeRef>, Mutability),
-    Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
-    // FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
-    Array(Box<TypeRef>, ConstRef),
-    Slice(Box<TypeRef>),
+    RawPtr(TypeRefId, Mutability),
+    Reference(Box<RefType>),
+    Array(Box<ArrayType>),
+    Slice(TypeRefId),
     /// A fn pointer. Last element of the vector is the return type.
-    Fn(
-        Box<[(Option<Name>, TypeRef)]>,
-        bool,           /*varargs*/
-        bool,           /*is_unsafe*/
-        Option<Symbol>, /* abi */
-    ),
-    ImplTrait(Vec<Interned<TypeBound>>),
-    DynTrait(Vec<Interned<TypeBound>>),
+    Fn(FnType),
+    ImplTrait(ThinVec<TypeBound>),
+    DynTrait(ThinVec<TypeBound>),
     Macro(AstId<ast::MacroCall>),
     Error,
 }
 
+#[cfg(target_arch = "x86_64")]
+const _: () = assert!(size_of::<TypeRef>() == 16);
+
+pub type TypeRefId = Idx<TypeRef>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesMap {
+    pub(crate) types: Arena<TypeRef>,
+}
+
+impl TypesMap {
+    pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
+
+    pub(crate) fn shrink_to_fit(&mut self) {
+        let TypesMap { types } = self;
+        types.shrink_to_fit();
+    }
+}
+
+impl Index<TypeRefId> for TypesMap {
+    type Output = TypeRef;
+
+    fn index(&self, index: TypeRefId) -> &Self::Output {
+        &self.types[index]
+    }
+}
+
+pub type TypePtr = AstPtr<ast::Type>;
+pub type TypeSource = InFile<TypePtr>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesSourceMap {
+    pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
+}
+
+impl TypesSourceMap {
+    pub(crate) fn shrink_to_fit(&mut self) {
+        let TypesSourceMap { types_map_back } = self;
+        types_map_back.shrink_to_fit();
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct LifetimeRef {
     pub name: Name,
@@ -162,7 +222,7 @@ pub enum TypeBound {
 }
 
 #[cfg(target_pointer_width = "64")]
-const _: [(); 56] = [(); ::std::mem::size_of::<TypeBound>()];
+const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum UseArgRef {
@@ -172,7 +232,7 @@ pub enum UseArgRef {
 
 /// A modifier on a bound, currently this is only used for `?Sized`, where the
 /// modifier is `Maybe`.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum TraitBoundModifier {
     None,
     Maybe,
@@ -180,12 +240,12 @@ pub enum TraitBoundModifier {
 
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
-    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
-        match node {
-            ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
-            ast::Type::TupleType(inner) => {
-                TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
-            }
+    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
+        let ty = match &node {
+            ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
+            ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+                Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))),
+            )),
             ast::Type::NeverType(..) => TypeRef::Never,
             ast::Type::PathType(inner) => {
                 // FIXME: Use `Path::from_src`
@@ -198,20 +258,21 @@ impl TypeRef {
             ast::Type::PtrType(inner) => {
                 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
-                TypeRef::RawPtr(Box::new(inner_ty), mutability)
+                TypeRef::RawPtr(inner_ty, mutability)
             }
             ast::Type::ArrayType(inner) => {
                 let len = ConstRef::from_const_arg(ctx, inner.const_arg());
-                TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
-            }
-            ast::Type::SliceType(inner) => {
-                TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
+                TypeRef::Array(Box::new(ArrayType {
+                    ty: TypeRef::from_ast_opt(ctx, inner.ty()),
+                    len,
+                }))
             }
+            ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
             ast::Type::RefType(inner) => {
                 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
                 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
-                TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
+                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
             }
             ast::Type::InferType(_inner) => TypeRef::Placeholder,
             ast::Type::FnPtrType(inner) => {
@@ -219,7 +280,7 @@ impl TypeRef {
                     .ret_type()
                     .and_then(|rt| rt.ty())
                     .map(|it| TypeRef::from_ast(ctx, it))
-                    .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
+                    .unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
                 let mut is_varargs = false;
                 let mut params = if let Some(pl) = inner.param_list() {
                     if let Some(param) = pl.params().last() {
@@ -251,10 +312,10 @@ impl TypeRef {
 
                 let abi = inner.abi().map(lower_abi);
                 params.push((None, ret_ty));
-                TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
+                TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
             }
             // for types are close enough for our purposes to the inner type for now...
-            ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
+            ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
             ast::Type::ImplTraitType(inner) => {
                 if ctx.outer_impl_trait() {
                     // Disallow nested impl traits
@@ -271,72 +332,72 @@ impl TypeRef {
                 Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
                 None => TypeRef::Error,
             },
-        }
+        };
+        ctx.alloc_type_ref(ty, AstPtr::new(&node))
     }
 
-    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
+    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
         match node {
             Some(node) => TypeRef::from_ast(ctx, node),
-            None => TypeRef::Error,
+            None => ctx.alloc_error_type(),
         }
     }
 
     pub(crate) fn unit() -> TypeRef {
-        TypeRef::Tuple(Vec::new())
+        TypeRef::Tuple(EmptyOptimizedThinVec::empty())
     }
 
-    pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
-        go(self, f);
+    pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
+        go(this, f, map);
 
-        fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
+        fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
+            let type_ref = &map[type_ref];
             f(type_ref);
             match type_ref {
-                TypeRef::Fn(params, _, _, _) => {
-                    params.iter().for_each(|(_, param_type)| go(param_type, f))
+                TypeRef::Fn(fn_) => {
+                    fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
                 }
-                TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
-                TypeRef::RawPtr(type_ref, _)
-                | TypeRef::Reference(type_ref, ..)
-                | TypeRef::Array(type_ref, _)
-                | TypeRef::Slice(type_ref) => go(type_ref, f),
+                TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
+                TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
+                TypeRef::Reference(it) => go(it.ty, f, map),
+                TypeRef::Array(it) => go(it.ty, f, map),
                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
                     for bound in bounds {
-                        match bound.as_ref() {
+                        match bound {
                             TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                go_path(path, f)
+                                go_path(path, f, map)
                             }
                             TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                         }
                     }
                 }
-                TypeRef::Path(path) => go_path(path, f),
+                TypeRef::Path(path) => go_path(path, f, map),
                 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
             };
         }
 
-        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
+        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
             if let Some(type_ref) = path.type_anchor() {
-                go(type_ref, f);
+                go(type_ref, f, map);
             }
             for segment in path.segments().iter() {
                 if let Some(args_and_bindings) = segment.args_and_bindings {
                     for arg in args_and_bindings.args.iter() {
                         match arg {
-                            crate::path::GenericArg::Type(type_ref) => {
-                                go(type_ref, f);
+                            GenericArg::Type(type_ref) => {
+                                go(*type_ref, f, map);
                             }
-                            crate::path::GenericArg::Const(_)
-                            | crate::path::GenericArg::Lifetime(_) => {}
+                            GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
                         }
                     }
                     for binding in args_and_bindings.bindings.iter() {
-                        if let Some(type_ref) = &binding.type_ref {
-                            go(type_ref, f);
+                        if let Some(type_ref) = binding.type_ref {
+                            go(type_ref, f, map);
                         }
                         for bound in binding.bounds.iter() {
-                            match bound.as_ref() {
+                            match bound {
                                 TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                    go_path(path, f)
+                                    go_path(path, f, map)
                                 }
                                 TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                             }
@@ -351,11 +412,13 @@ impl TypeRef {
 pub(crate) fn type_bounds_from_ast(
     lower_ctx: &LowerCtx<'_>,
     type_bounds_opt: Option<ast::TypeBoundList>,
-) -> Vec<Interned<TypeBound>> {
+) -> ThinVec<TypeBound> {
     if let Some(type_bounds) = type_bounds_opt {
-        type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
+        ThinVec::from_iter(Vec::from_iter(
+            type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
+        ))
     } else {
-        vec![]
+        ThinVec::from_iter([])
     }
 }
 
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 91a8cbab1a2..b39a3fece62 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
@@ -61,7 +61,7 @@ use crate::{
     db::DefDatabase,
     generics::GenericParams,
     path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
-    type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
+    type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
     visibility::{RawVisibility, VisibilityExplicitness},
     BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
 };
@@ -100,13 +100,20 @@ pub struct ItemTree {
 
 impl ItemTree {
     pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+        db.file_item_tree_with_source_map(file_id).0
+    }
+
+    pub(crate) fn file_item_tree_with_source_map_query(
+        db: &dyn DefDatabase,
+        file_id: HirFileId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
         let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+        static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
 
         let ctx = lower::Ctx::new(db, file_id);
         let syntax = db.parse_or_expand(file_id);
         let mut top_attrs = None;
-        let mut item_tree = match_ast! {
+        let (mut item_tree, source_maps) = match_ast! {
             match syntax {
                 ast::SourceFile(file) => {
                     top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@@ -136,42 +143,55 @@ impl ItemTree {
         {
             EMPTY
                 .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+                    (
+                        Arc::new(ItemTree {
+                            top_level: SmallVec::new_const(),
+                            attrs: FxHashMap::default(),
+                            data: None,
+                        }),
+                        Arc::default(),
+                    )
                 })
                 .clone()
         } else {
             item_tree.shrink_to_fit();
-            Arc::new(item_tree)
+            (Arc::new(item_tree), Arc::new(source_maps))
         }
     }
 
     pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+        db.block_item_tree_with_source_map(block).0
+    }
+
+    pub(crate) fn block_item_tree_with_source_map_query(
+        db: &dyn DefDatabase,
+        block: BlockId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
         let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+        static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
 
         let loc = block.lookup(db);
         let block = loc.ast_id.to_node(db.upcast());
 
         let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
-        let mut item_tree = ctx.lower_block(&block);
+        let (mut item_tree, source_maps) = ctx.lower_block(&block);
         if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
         {
             EMPTY
                 .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+                    (
+                        Arc::new(ItemTree {
+                            top_level: SmallVec::new_const(),
+                            attrs: FxHashMap::default(),
+                            data: None,
+                        }),
+                        Arc::default(),
+                    )
                 })
                 .clone()
         } else {
             item_tree.shrink_to_fit();
-            Arc::new(item_tree)
+            (Arc::new(item_tree), Arc::new(source_maps))
         }
     }
 
@@ -308,6 +328,160 @@ struct ItemTreeData {
     vis: ItemVisibilities,
 }
 
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct ItemTreeSourceMaps {
+    all_concatenated: Box<[TypesSourceMap]>,
+    structs_offset: u32,
+    unions_offset: u32,
+    enum_generics_offset: u32,
+    variants_offset: u32,
+    consts_offset: u32,
+    statics_offset: u32,
+    trait_generics_offset: u32,
+    trait_alias_generics_offset: u32,
+    impls_offset: u32,
+    type_aliases_offset: u32,
+}
+
+#[derive(Clone, Copy)]
+pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
+
+impl<'a> GenericItemSourceMap<'a> {
+    #[inline]
+    pub fn item(self) -> &'a TypesSourceMap {
+        &self.0[0]
+    }
+
+    #[inline]
+    pub fn generics(self) -> &'a TypesSourceMap {
+        &self.0[1]
+    }
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct GenericItemSourceMapBuilder {
+    pub item: TypesSourceMap,
+    pub generics: TypesSourceMap,
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+struct ItemTreeSourceMapsBuilder {
+    functions: Vec<GenericItemSourceMapBuilder>,
+    structs: Vec<GenericItemSourceMapBuilder>,
+    unions: Vec<GenericItemSourceMapBuilder>,
+    enum_generics: Vec<TypesSourceMap>,
+    variants: Vec<TypesSourceMap>,
+    consts: Vec<TypesSourceMap>,
+    statics: Vec<TypesSourceMap>,
+    trait_generics: Vec<TypesSourceMap>,
+    trait_alias_generics: Vec<TypesSourceMap>,
+    impls: Vec<GenericItemSourceMapBuilder>,
+    type_aliases: Vec<GenericItemSourceMapBuilder>,
+}
+
+impl ItemTreeSourceMapsBuilder {
+    fn build(self) -> ItemTreeSourceMaps {
+        let ItemTreeSourceMapsBuilder {
+            functions,
+            structs,
+            unions,
+            enum_generics,
+            variants,
+            consts,
+            statics,
+            trait_generics,
+            trait_alias_generics,
+            impls,
+            type_aliases,
+        } = self;
+        let structs_offset = functions.len() as u32 * 2;
+        let unions_offset = structs_offset + (structs.len() as u32 * 2);
+        let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
+        let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
+        let consts_offset = variants_offset + (variants.len() as u32);
+        let statics_offset = consts_offset + (consts.len() as u32);
+        let trait_generics_offset = statics_offset + (statics.len() as u32);
+        let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
+        let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
+        let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
+        let all_concatenated = generics_concat(functions)
+            .chain(generics_concat(structs))
+            .chain(generics_concat(unions))
+            .chain(enum_generics)
+            .chain(variants)
+            .chain(consts)
+            .chain(statics)
+            .chain(trait_generics)
+            .chain(trait_alias_generics)
+            .chain(generics_concat(impls))
+            .chain(generics_concat(type_aliases))
+            .collect();
+        return ItemTreeSourceMaps {
+            all_concatenated,
+            structs_offset,
+            unions_offset,
+            enum_generics_offset,
+            variants_offset,
+            consts_offset,
+            statics_offset,
+            trait_generics_offset,
+            trait_alias_generics_offset,
+            impls_offset,
+            type_aliases_offset,
+        };
+
+        fn generics_concat(
+            source_maps: Vec<GenericItemSourceMapBuilder>,
+        ) -> impl Iterator<Item = TypesSourceMap> {
+            source_maps.into_iter().flat_map(|it| [it.item, it.generics])
+        }
+    }
+}
+
+impl ItemTreeSourceMaps {
+    #[inline]
+    fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
+        GenericItemSourceMap(
+            self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
+        )
+    }
+
+    #[inline]
+    fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
+        &self.all_concatenated[(offset + index) as usize]
+    }
+
+    #[inline]
+    pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
+        self.generic_item(0, index.0.into_raw().into_u32())
+    }
+}
+
+macro_rules! index_item_source_maps {
+    ( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
+        impl ItemTreeSourceMaps {
+            $(
+                #[inline]
+                pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
+                    self.$fn(self.$field, index.0.into_raw().into_u32())
+                }
+            )*
+        }
+    };
+}
+index_item_source_maps! {
+    strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
+    union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
+    enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
+    variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
+    konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
+    statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
+    trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
+    trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
+    impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
+    type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub enum AttrOwner {
     /// Attributes on an item.
@@ -363,7 +537,7 @@ pub trait ItemTreeNode: Clone {
     fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
 }
 pub trait GenericsItemTreeNode: ItemTreeNode {
-    fn generic_params(&self) -> &Interned<GenericParams>;
+    fn generic_params(&self) -> &Arc<GenericParams>;
 }
 
 pub struct FileItemTreeId<N>(Idx<N>);
@@ -428,6 +602,16 @@ impl TreeId {
         }
     }
 
+    pub fn item_tree_with_source_map(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+        match self.block {
+            Some(block) => db.block_item_tree_with_source_map(block),
+            None => db.file_item_tree_with_source_map(self.file),
+        }
+    }
+
     pub fn file_id(self) -> HirFileId {
         self.file
     }
@@ -460,6 +644,13 @@ impl<N> ItemTreeId<N> {
         self.tree.item_tree(db)
     }
 
+    pub fn item_tree_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+        self.tree.item_tree_with_source_map(db)
+    }
+
     pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
     where
         ItemTree: Index<FileItemTreeId<N>, Output = N>,
@@ -592,7 +783,7 @@ macro_rules! mod_items {
 
             $(
                 impl GenericsItemTreeNode for $typ {
-                    fn generic_params(&self) -> &Interned<GenericParams> {
+                    fn generic_params(&self) -> &Arc<GenericParams> {
                         &self.$generic_params
                     }
                 }
@@ -730,17 +921,18 @@ pub struct ExternBlock {
 pub struct Function {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub explicit_generic_params: Interned<GenericParams>,
+    pub explicit_generic_params: Arc<GenericParams>,
     pub abi: Option<Symbol>,
     pub params: Box<[Param]>,
-    pub ret_type: Interned<TypeRef>,
+    pub ret_type: TypeRefId,
     pub ast_id: FileAstId<ast::Fn>,
+    pub types_map: Arc<TypesMap>,
     pub(crate) flags: FnFlags,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Param {
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub type_ref: Option<TypeRefId>,
 }
 
 bitflags::bitflags! {
@@ -761,26 +953,28 @@ bitflags::bitflags! {
 pub struct Struct {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub fields: Box<[Field]>,
     pub shape: FieldsShape,
     pub ast_id: FileAstId<ast::Struct>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Union {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub fields: Box<[Field]>,
     pub ast_id: FileAstId<ast::Union>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Enum {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub variants: Range<FileItemTreeId<Variant>>,
     pub ast_id: FileAstId<ast::Enum>,
 }
@@ -791,6 +985,7 @@ pub struct Variant {
     pub fields: Box<[Field]>,
     pub shape: FieldsShape,
     pub ast_id: FileAstId<ast::Variant>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -804,7 +999,7 @@ pub enum FieldsShape {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Field {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibilityId,
 }
 
@@ -813,9 +1008,10 @@ pub struct Const {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
     pub visibility: RawVisibilityId,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub ast_id: FileAstId<ast::Const>,
     pub has_body: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -826,15 +1022,16 @@ pub struct Static {
     pub mutable: bool,
     pub has_safe_kw: bool,
     pub has_unsafe_kw: bool,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub ast_id: FileAstId<ast::Static>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Trait {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub is_auto: bool,
     pub is_unsafe: bool,
     pub items: Box<[AssocItem]>,
@@ -845,19 +1042,20 @@ pub struct Trait {
 pub struct TraitAlias {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub ast_id: FileAstId<ast::TraitAlias>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Impl {
-    pub generic_params: Interned<GenericParams>,
-    pub target_trait: Option<Interned<TraitRef>>,
-    pub self_ty: Interned<TypeRef>,
+    pub generic_params: Arc<GenericParams>,
+    pub target_trait: Option<TraitRef>,
+    pub self_ty: TypeRefId,
     pub is_negative: bool,
     pub is_unsafe: bool,
     pub items: Box<[AssocItem]>,
     pub ast_id: FileAstId<ast::Impl>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -865,10 +1063,11 @@ pub struct TypeAlias {
     pub name: Name,
     pub visibility: RawVisibilityId,
     /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
-    pub bounds: Box<[Interned<TypeBound>]>,
-    pub generic_params: Interned<GenericParams>,
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub bounds: Box<[TypeBound]>,
+    pub generic_params: Arc<GenericParams>,
+    pub type_ref: Option<TypeRefId>,
     pub ast_id: FileAstId<ast::TypeAlias>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 431a7f66f40..bd17fce37b7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -1,12 +1,18 @@
 //! AST -> `ItemTree` lowering code.
 
-use std::collections::hash_map::Entry;
+use std::{cell::OnceCell, collections::hash_map::Entry};
 
-use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
+use hir_expand::{
+    mod_path::path,
+    name::AsName,
+    span_map::{SpanMap, SpanMapRef},
+    HirFileId,
+};
 use intern::{sym, Symbol};
 use la_arena::Arena;
 use rustc_hash::FxHashMap;
 use span::{AstIdMap, SyntaxContextId};
+use stdx::thin_vec::ThinVec;
 use syntax::{
     ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
     AstNode,
@@ -18,14 +24,19 @@ use crate::{
     generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
     item_tree::{
         AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
-        FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
-        ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
+        FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
+        GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
+        ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
         ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
         Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
         Variant,
     },
+    lower::LowerCtx,
     path::AssociatedTypeBinding,
-    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
+    type_ref::{
+        LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
+        TypesMap, TypesSourceMap,
+    },
     visibility::RawVisibility,
     LocalLifetimeParamId, LocalTypeOrConstParamId,
 };
@@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> {
     source_ast_id_map: Arc<AstIdMap>,
     generic_param_attr_buffer:
         FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
-    body_ctx: crate::lower::LowerCtx<'a>,
+    span_map: OnceCell<SpanMap>,
+    file: HirFileId,
+    source_maps: ItemTreeSourceMapsBuilder,
 }
 
 impl<'a> Ctx<'a> {
@@ -50,22 +63,49 @@ impl<'a> Ctx<'a> {
             tree: ItemTree::default(),
             generic_param_attr_buffer: FxHashMap::default(),
             source_ast_id_map: db.ast_id_map(file),
-            body_ctx: crate::lower::LowerCtx::new(db, file),
+            file,
+            span_map: OnceCell::new(),
+            source_maps: ItemTreeSourceMapsBuilder::default(),
         }
     }
 
     pub(super) fn span_map(&self) -> SpanMapRef<'_> {
-        self.body_ctx.span_map()
+        self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
+    }
+
+    fn body_ctx<'b, 'c>(
+        &self,
+        types_map: &'b mut TypesMap,
+        types_source_map: &'b mut TypesSourceMap,
+    ) -> LowerCtx<'c>
+    where
+        'a: 'c,
+        'b: 'c,
+    {
+        // FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
+        LowerCtx::with_span_map_cell(
+            self.db,
+            self.file,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        )
     }
 
-    pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
+    pub(super) fn lower_module_items(
+        mut self,
+        item_owner: &dyn HasModuleItem,
+    ) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
-    pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
+    pub(super) fn lower_macro_stmts(
+        mut self,
+        stmts: ast::MacroStmts,
+    ) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree.top_level = stmts
             .statements()
             .filter_map(|stmt| {
@@ -96,10 +136,10 @@ impl<'a> Ctx<'a> {
         }
 
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
-    pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
+    pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree
             .attrs
             .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@@ -125,7 +165,7 @@ impl<'a> Ctx<'a> {
         }
 
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
     fn data(&mut self) -> &mut ItemTreeData {
@@ -144,7 +184,7 @@ impl<'a> Ctx<'a> {
             ast::Item::Module(ast) => self.lower_module(ast)?.into(),
             ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
             ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
-            ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
+            ast::Item::Impl(ast) => self.lower_impl(ast).into(),
             ast::Item::Use(ast) => self.lower_use(ast)?.into(),
             ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
             ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@@ -159,12 +199,14 @@ impl<'a> Ctx<'a> {
     }
 
     fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
-        match self.tree.attrs.entry(item) {
-            Entry::Occupied(mut entry) => {
-                *entry.get_mut() = entry.get().merge(attrs);
-            }
-            Entry::Vacant(entry) => {
-                entry.insert(attrs);
+        if !attrs.is_empty() {
+            match self.tree.attrs.entry(item) {
+                Entry::Occupied(mut entry) => {
+                    *entry.get_mut() = entry.get().merge(attrs);
+                }
+                Entry::Vacant(entry) => {
+                    entry.insert(attrs);
+                }
             }
         }
     }
@@ -190,13 +232,31 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
-        let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
+        let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, strukt);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Struct {
+            name,
+            visibility,
+            generic_params,
+            fields,
+            shape: kind,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().structs.alloc(res));
+        self.source_maps.structs.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -213,6 +273,7 @@ impl<'a> Ctx<'a> {
     fn lower_fields(
         &mut self,
         strukt_kind: &ast::StructKind,
+        body_ctx: &LowerCtx<'_>,
     ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
         match strukt_kind {
             ast::StructKind::Record(it) => {
@@ -220,7 +281,7 @@ impl<'a> Ctx<'a> {
                 let mut attrs = vec![];
 
                 for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_record_field(&field);
+                    let data = self.lower_record_field(&field, body_ctx);
                     fields.push(data);
                     let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
                     if !attr.is_empty() {
@@ -234,7 +295,7 @@ impl<'a> Ctx<'a> {
                 let mut attrs = vec![];
 
                 for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_tuple_field(i, &field);
+                    let data = self.lower_tuple_field(i, &field, body_ctx);
                     fields.push(data);
                     let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
                     if !attr.is_empty() {
@@ -247,35 +308,59 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
+    fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
         let name = match field.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
         };
         let visibility = self.lower_visibility(field);
-        let type_ref = self.lower_type_ref_opt(field.ty());
+        let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
 
         Field { name, type_ref, visibility }
     }
 
-    fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
+    fn lower_tuple_field(
+        &mut self,
+        idx: usize,
+        field: &ast::TupleField,
+        body_ctx: &LowerCtx<'_>,
+    ) -> Field {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
-        let type_ref = self.lower_type_ref_opt(field.ty());
+        let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
         Field { name, type_ref, visibility }
     }
 
     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
         let (fields, _, attrs) = match union.record_field_list() {
-            Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
+            Some(record_field_list) => {
+                self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
+            }
             None => (Box::default(), FieldsShape::Record, Vec::default()),
         };
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
-        let res = Union { name, visibility, generic_params, fields, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, union);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Union {
+            name,
+            visibility,
+            generic_params,
+            fields,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().unions.alloc(res));
+        self.source_maps.unions.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -299,9 +384,11 @@ impl<'a> Ctx<'a> {
                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
             }
         };
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
         let id = id(self.data().enums.alloc(res));
+        self.source_maps.enum_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
@@ -320,14 +407,20 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = match variant.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
         };
-        let (fields, kind, attrs) = self.lower_fields(&variant.kind());
+        let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(variant);
-        let res = Variant { name, fields, shape: kind, ast_id };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
         let id = self.data().variants.alloc(res);
+        self.source_maps.variants.push(types_source_map);
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -341,6 +434,10 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
 
@@ -360,27 +457,31 @@ impl<'a> Ctx<'a> {
                     RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
                 );
                 let self_type = match self_param.ty() {
-                    Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
+                    Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
                     None => {
-                        let self_type =
-                            TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
+                        let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                            Name::new_symbol_root(sym::Self_.clone()).into(),
+                        ));
                         match self_param.kind() {
                             ast::SelfParamKind::Owned => self_type,
-                            ast::SelfParamKind::Ref => TypeRef::Reference(
-                                Box::new(self_type),
-                                self_param.lifetime().as_ref().map(LifetimeRef::new),
-                                Mutability::Shared,
+                            ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
+                                TypeRef::Reference(Box::new(RefType {
+                                    ty: self_type,
+                                    lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+                                    mutability: Mutability::Shared,
+                                })),
                             ),
-                            ast::SelfParamKind::MutRef => TypeRef::Reference(
-                                Box::new(self_type),
-                                self_param.lifetime().as_ref().map(LifetimeRef::new),
-                                Mutability::Mut,
+                            ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
+                                TypeRef::Reference(Box::new(RefType {
+                                    ty: self_type,
+                                    lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+                                    mutability: Mutability::Mut,
+                                })),
                             ),
                         }
                     }
                 };
-                let type_ref = Interned::new(self_type);
-                params.push(Param { type_ref: Some(type_ref) });
+                params.push(Param { type_ref: Some(self_type) });
                 has_self_param = true;
             }
             for param in param_list.params() {
@@ -391,9 +492,8 @@ impl<'a> Ctx<'a> {
                         Param { type_ref: None }
                     }
                     None => {
-                        let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
-                        let ty = Interned::new(type_ref);
-                        Param { type_ref: Some(ty) }
+                        let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
+                        Param { type_ref: Some(type_ref) }
                     }
                 };
                 params.push(param);
@@ -402,17 +502,17 @@ impl<'a> Ctx<'a> {
 
         let ret_type = match func.ret_type() {
             Some(rt) => match rt.ty() {
-                Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
-                None if rt.thin_arrow_token().is_some() => TypeRef::Error,
-                None => TypeRef::unit(),
+                Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+                None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
+                None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
             },
-            None => TypeRef::unit(),
+            None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
         };
 
         let ret_type = if func.async_token().is_some() {
             let future_impl = desugar_future_path(ret_type);
-            let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
-            TypeRef::ImplTrait(vec![ty_bound])
+            let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
+            body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
         } else {
             ret_type
         };
@@ -447,18 +547,27 @@ impl<'a> Ctx<'a> {
             flags |= FnFlags::IS_VARARGS;
         }
 
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, func);
         let res = Function {
             name,
             visibility,
-            explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
+            explicit_generic_params: generic_params,
             abi,
             params: params.into_boxed_slice(),
-            ret_type: Interned::new(ret_type),
+            ret_type,
             ast_id,
+            types_map: Arc::new(types_map),
             flags,
         };
 
         let id = id(self.data().functions.alloc(res));
+        self.source_maps.functions.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
         }
@@ -470,37 +579,82 @@ impl<'a> Ctx<'a> {
         &mut self,
         type_alias: &ast::TypeAlias,
     ) -> Option<FileItemTreeId<TypeAlias>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = type_alias.name()?.as_name();
-        let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
+        let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
         let visibility = self.lower_visibility(type_alias);
-        let bounds = self.lower_type_bounds(type_alias);
+        let bounds = self.lower_type_bounds(type_alias, &body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
-        let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, type_alias);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = TypeAlias {
+            name,
+            visibility,
+            bounds,
+            generic_params,
+            type_ref,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().type_aliases.alloc(res));
+        self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
 
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = static_.name()?.as_name();
-        let type_ref = self.lower_type_ref_opt(static_.ty());
+        let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
         let has_safe_kw = static_.safe_token().is_some();
         let has_unsafe_kw = static_.unsafe_token().is_some();
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res =
-            Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Static {
+            name,
+            visibility,
+            mutable,
+            type_ref,
+            ast_id,
+            has_safe_kw,
+            has_unsafe_kw,
+            types_map: Arc::new(types_map),
+        };
+        self.source_maps.statics.push(types_source_map);
         Some(id(self.data().statics.alloc(res)))
     }
 
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = konst.name().map(|it| it.as_name());
-        let type_ref = self.lower_type_ref_opt(konst.ty());
+        let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
-        let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Const {
+            name,
+            visibility,
+            type_ref,
+            ast_id,
+            has_body: konst.body().is_some(),
+            types_map: Arc::new(types_map),
+        };
+        self.source_maps.consts.push(types_source_map);
         id(self.data().consts.alloc(res))
     }
 
@@ -539,10 +693,11 @@ impl<'a> Ctx<'a> {
             .filter_map(|item_node| self.lower_assoc_item(&item_node))
             .collect();
 
-        let generic_params =
+        let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
         let id = id(self.data().traits.alloc(def));
+        self.source_maps.trait_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
@@ -554,24 +709,29 @@ impl<'a> Ctx<'a> {
         let name = trait_alias_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_alias_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
-        let generic_params = self.lower_generic_params(
+        let (generic_params, generics_source_map) = self.lower_generic_params(
             HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
             trait_alias_def,
         );
 
         let alias = TraitAlias { name, visibility, generic_params, ast_id };
         let id = id(self.data().trait_aliases.alloc(alias));
+        self.source_maps.trait_alias_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
 
-    fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
+    fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
-        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
+        let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
+        let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -584,12 +744,27 @@ impl<'a> Ctx<'a> {
             .collect();
         // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
         // type alias rather than a type parameter, so this is handled by the resolver.
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
-        let res =
-            Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, impl_def);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Impl {
+            generic_params,
+            target_trait,
+            self_ty,
+            is_negative,
+            is_unsafe,
+            items,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().impls.alloc(res));
+        self.source_maps.impls.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         self.write_generic_params_attributes(id.into());
-        Some(id)
+        id
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -692,14 +867,17 @@ impl<'a> Ctx<'a> {
         &mut self,
         has_implicit_self: HasImplicitSelf,
         node: &dyn ast::HasGenericParams,
-    ) -> Interned<GenericParams> {
+    ) -> (Arc<GenericParams>, TypesSourceMap) {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         debug_assert!(self.generic_param_attr_buffer.is_empty(),);
         let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
                                param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
+            let attrs = RawAttrs::new(self.db.upcast(), &param, body_ctx.span_map());
             debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
         };
-        self.body_ctx.take_impl_traits_bounds();
+        body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
         if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -715,23 +893,29 @@ impl<'a> Ctx<'a> {
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
             generics.fill_bounds(
-                &self.body_ctx,
+                &body_ctx,
                 bounds,
-                Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
+                Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                    Name::new_symbol_root(sym::Self_.clone()).into(),
+                ))),
             );
         }
 
-        generics.fill(&self.body_ctx, node, add_param_attrs);
+        generics.fill(&body_ctx, node, add_param_attrs);
 
-        Interned::new(generics.finish())
+        let generics = generics.finish(types_map, &mut types_source_map);
+        (generics, types_source_map)
     }
 
-    fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
+    fn lower_type_bounds(
+        &mut self,
+        node: &dyn ast::HasTypeBounds,
+        body_ctx: &LowerCtx<'_>,
+    ) -> Box<[TypeBound]> {
         match node.type_bound_list() {
-            Some(bound_list) => bound_list
-                .bounds()
-                .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
-                .collect(),
+            Some(bound_list) => {
+                bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
+            }
             None => Box::default(),
         }
     }
@@ -743,23 +927,6 @@ impl<'a> Ctx<'a> {
         self.data().vis.alloc(vis)
     }
 
-    fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
-        let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
-        Some(Interned::new(trait_ref))
-    }
-
-    fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
-        let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
-        Interned::new(tyref)
-    }
-
-    fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
-        match type_ref.map(|ty| self.lower_type_ref(&ty)) {
-            Some(it) => it,
-            None => Interned::new(TypeRef::Error),
-        }
-    }
-
     fn next_variant_idx(&self) -> Idx<Variant> {
         Idx::from_raw(RawIdx::from(
             self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@@ -767,7 +934,7 @@ impl<'a> Ctx<'a> {
     }
 }
 
-fn desugar_future_path(orig: TypeRef) -> Path {
+fn desugar_future_path(orig: TypeRefId) -> Path {
     let path = path![core::future::Future];
     let mut generic_args: Vec<_> =
         std::iter::repeat(None).take(path.segments().len() - 1).collect();
@@ -777,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
         type_ref: Some(orig),
         bounds: Box::default(),
     };
-    generic_args.push(Some(Interned::new(GenericArgs {
-        bindings: Box::new([binding]),
-        ..GenericArgs::empty()
-    })));
+    generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
 
     Path::from_known_path(path, generic_args)
 }
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 9dce28b2e49..b6816a1f968 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
@@ -10,11 +10,12 @@ use crate::{
     item_tree::{
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
         FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
-        Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
-        RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
-        TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
+        ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
+        RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
+        UseTree, UseTreeKind, Variant,
     },
     pretty::{print_path, print_type_bounds, print_type_ref},
+    type_ref::{TypeRefId, TypesMap},
     visibility::RawVisibility,
 };
 
@@ -121,7 +122,13 @@ impl Printer<'_> {
         };
     }
 
-    fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
+    fn print_fields(
+        &mut self,
+        parent: FieldParent,
+        kind: FieldsShape,
+        fields: &[Field],
+        map: &TypesMap,
+    ) {
         let edition = self.edition;
         match kind {
             FieldsShape::Record => {
@@ -135,7 +142,7 @@ impl Printer<'_> {
                         );
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name.display(self.db.upcast(), edition));
-                        this.print_type_ref(type_ref);
+                        this.print_type_ref(*type_ref, map);
                         wln!(this, ",");
                     }
                 });
@@ -151,7 +158,7 @@ impl Printer<'_> {
                         );
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name.display(self.db.upcast(), edition));
-                        this.print_type_ref(type_ref);
+                        this.print_type_ref(*type_ref, map);
                         wln!(this, ",");
                     }
                 });
@@ -167,20 +174,21 @@ impl Printer<'_> {
         kind: FieldsShape,
         fields: &[Field],
         params: &GenericParams,
+        map: &TypesMap,
     ) {
         match kind {
             FieldsShape::Record => {
                 if self.print_where_clause(params) {
                     wln!(self);
                 }
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
             }
             FieldsShape::Unit => {
                 self.print_where_clause(params);
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
             }
             FieldsShape::Tuple => {
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
                 self.print_where_clause(params);
             }
         }
@@ -262,6 +270,7 @@ impl Printer<'_> {
                     params,
                     ret_type,
                     ast_id,
+                    types_map,
                     flags,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
@@ -298,7 +307,7 @@ impl Printer<'_> {
                                 w!(this, "self: ");
                             }
                             if let Some(type_ref) = type_ref {
-                                this.print_type_ref(type_ref);
+                                this.print_type_ref(*type_ref, types_map);
                             } else {
                                 wln!(this, "...");
                             }
@@ -307,7 +316,7 @@ impl Printer<'_> {
                     });
                 }
                 w!(self, ") -> ");
-                self.print_type_ref(ret_type);
+                self.print_type_ref(*ret_type, types_map);
                 self.print_where_clause(explicit_generic_params);
                 if flags.contains(FnFlags::HAS_BODY) {
                     wln!(self, " {{ ... }}");
@@ -316,8 +325,15 @@ impl Printer<'_> {
                 }
             }
             ModItem::Struct(it) => {
-                let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
-                    &self.tree[it];
+                let Struct {
+                    visibility,
+                    name,
+                    fields,
+                    shape: kind,
+                    generic_params,
+                    ast_id,
+                    types_map,
+                } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
@@ -327,6 +343,7 @@ impl Printer<'_> {
                     *kind,
                     fields,
                     generic_params,
+                    types_map,
                 );
                 if matches!(kind, FieldsShape::Record) {
                     wln!(self);
@@ -335,7 +352,8 @@ impl Printer<'_> {
                 }
             }
             ModItem::Union(it) => {
-                let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
+                let Union { name, visibility, fields, generic_params, ast_id, types_map } =
+                    &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db.upcast(), self.edition));
@@ -345,6 +363,7 @@ impl Printer<'_> {
                     FieldsShape::Record,
                     fields,
                     generic_params,
+                    types_map,
                 );
                 wln!(self);
             }
@@ -358,18 +377,20 @@ impl Printer<'_> {
                 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];
+                        let Variant { name, fields, shape: kind, ast_id, types_map } =
+                            &this.tree[variant];
                         this.print_ast_id(ast_id.erase());
                         this.print_attrs_of(variant, "\n");
                         w!(this, "{}", name.display(self.db.upcast(), edition));
-                        this.print_fields(FieldParent::Variant(variant), *kind, fields);
+                        this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
                         wln!(this, ",");
                     }
                 });
                 wln!(self, "}}");
             }
             ModItem::Const(it) => {
-                let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
+                let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
+                    &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "const ");
@@ -378,7 +399,7 @@ impl Printer<'_> {
                     None => w!(self, "_"),
                 }
                 w!(self, ": ");
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, types_map);
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
@@ -390,6 +411,7 @@ impl Printer<'_> {
                     ast_id,
                     has_safe_kw,
                     has_unsafe_kw,
+                    types_map,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
@@ -404,7 +426,7 @@ impl Printer<'_> {
                     w!(self, "mut ");
                 }
                 w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, types_map);
                 w!(self, " = _;");
                 wln!(self);
             }
@@ -449,6 +471,7 @@ impl Printer<'_> {
                     items,
                     generic_params,
                     ast_id,
+                    types_map,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 if *is_unsafe {
@@ -461,10 +484,10 @@ impl Printer<'_> {
                     w!(self, "!");
                 }
                 if let Some(tr) = target_trait {
-                    self.print_path(&tr.path);
+                    self.print_path(&tr.path, types_map);
                     w!(self, " for ");
                 }
-                self.print_type_ref(self_ty);
+                self.print_type_ref(*self_ty, types_map);
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
@@ -474,19 +497,26 @@ impl Printer<'_> {
                 wln!(self, "}}");
             }
             ModItem::TypeAlias(it) => {
-                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
-                    &self.tree[it];
+                let TypeAlias {
+                    name,
+                    visibility,
+                    bounds,
+                    type_ref,
+                    generic_params,
+                    ast_id,
+                    types_map,
+                } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
-                    self.print_type_bounds(bounds);
+                    self.print_type_bounds(bounds, types_map);
                 }
                 if let Some(ty) = type_ref {
                     w!(self, " = ");
-                    self.print_type_ref(ty);
+                    self.print_type_ref(*ty, types_map);
                 }
                 self.print_where_clause(generic_params);
                 w!(self, ";");
@@ -543,19 +573,19 @@ impl Printer<'_> {
         self.blank();
     }
 
-    fn print_type_ref(&mut self, type_ref: &TypeRef) {
+    fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
         let edition = self.edition;
-        print_type_ref(self.db, type_ref, self, edition).unwrap();
+        print_type_ref(self.db, type_ref, map, self, edition).unwrap();
     }
 
-    fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
+    fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
         let edition = self.edition;
-        print_type_bounds(self.db, bounds, self, edition).unwrap();
+        print_type_bounds(self.db, bounds, map, self, edition).unwrap();
     }
 
-    fn print_path(&mut self, path: &Path) {
+    fn print_path(&mut self, path: &Path, map: &TypesMap) {
         let edition = self.edition;
-        print_path(self.db, path, self, edition).unwrap();
+        print_path(self.db, path, map, self, edition).unwrap();
     }
 
     fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@@ -586,7 +616,7 @@ impl Printer<'_> {
                 },
                 TypeOrConstParamData::ConstParamData(konst) => {
                     w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
-                    self.print_type_ref(&konst.ty);
+                    self.print_type_ref(konst.ty, &params.types_map);
                 }
             }
         }
@@ -640,14 +670,16 @@ impl Printer<'_> {
                 };
 
                 match target {
-                    WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
+                    WherePredicateTypeTarget::TypeRef(ty) => {
+                        this.print_type_ref(*ty, &params.types_map)
+                    }
                     WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
                         Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
                         None => w!(this, "_anon_{}", id.into_raw()),
                     },
                 }
                 w!(this, ": ");
-                this.print_type_bounds(std::slice::from_ref(bound));
+                this.print_type_bounds(std::slice::from_ref(bound), &params.types_map);
             }
         });
         true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 157c9ef0805..f6ed826f04c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
 pub struct UnresolvedMacro {
     pub path: hir_expand::mod_path::ModPath,
 }
-
-intern::impl_internable!(
-    crate::type_ref::TypeRef,
-    crate::type_ref::TraitRef,
-    crate::type_ref::TypeBound,
-    crate::path::GenericArgs,
-    generics::GenericParams,
-);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index 8e521460c35..df5847929c5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -5,43 +5,53 @@ use hir_expand::{
     span_map::{SpanMap, SpanMapRef},
     AstId, HirFileId, InFile,
 };
-use intern::Interned;
 use span::{AstIdMap, AstIdNode};
+use stdx::thin_vec::ThinVec;
 use syntax::ast;
 use triomphe::Arc;
 
-use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
+use crate::{
+    db::DefDatabase,
+    path::Path,
+    type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
+};
 
 pub struct LowerCtx<'a> {
     pub db: &'a dyn DefDatabase,
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
-    impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
+    impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
     // Prevent nested impl traits like `impl Foo<impl Bar>`.
     outer_impl_trait: RefCell<bool>,
+    types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
 }
 
-pub(crate) struct OuterImplTraitGuard<'a> {
-    ctx: &'a LowerCtx<'a>,
+pub(crate) struct OuterImplTraitGuard<'a, 'b> {
+    ctx: &'a LowerCtx<'b>,
     old: bool,
 }
 
-impl<'a> OuterImplTraitGuard<'a> {
-    fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
+impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
+    fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
         let old = ctx.outer_impl_trait.replace(impl_trait);
         Self { ctx, old }
     }
 }
 
-impl Drop for OuterImplTraitGuard<'_> {
+impl Drop for OuterImplTraitGuard<'_, '_> {
     fn drop(&mut self) {
         self.ctx.outer_impl_trait.replace(self.old);
     }
 }
 
 impl<'a> LowerCtx<'a> {
-    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
+    pub fn new(
+        db: &'a dyn DefDatabase,
+        file_id: HirFileId,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
+    ) -> Self {
         LowerCtx {
             db,
             file_id,
@@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> {
             ast_id_map: OnceCell::new(),
             impl_trait_bounds: RefCell::new(Vec::new()),
             outer_impl_trait: RefCell::default(),
+            types_map: RefCell::new((types_map, types_source_map)),
         }
     }
 
@@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> {
         db: &'a dyn DefDatabase,
         file_id: HirFileId,
         span_map: OnceCell<SpanMap>,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
     ) -> Self {
         LowerCtx {
             db,
@@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> {
             ast_id_map: OnceCell::new(),
             impl_trait_bounds: RefCell::new(Vec::new()),
             outer_impl_trait: RefCell::default(),
+            types_map: RefCell::new((types_map, types_source_map)),
         }
     }
 
@@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> {
         )
     }
 
-    pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
+    pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
         self.impl_trait_bounds.borrow_mut().push(bounds);
     }
 
-    pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
+    pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
         self.impl_trait_bounds.take()
     }
 
@@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> {
         *self.outer_impl_trait.borrow()
     }
 
-    pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
+    pub(crate) fn outer_impl_trait_scope<'b>(
+        &'b self,
+        impl_trait: bool,
+    ) -> OuterImplTraitGuard<'b, 'a> {
         OuterImplTraitGuard::new(self, impl_trait)
     }
+
+    pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
+        let mut types_map = self.types_map.borrow_mut();
+        let (types_map, types_source_map) = &mut *types_map;
+        let id = types_map.types.alloc(type_ref);
+        types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
+        id
+    }
+
+    pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
+        self.types_map.borrow_mut().0.types.alloc(type_ref)
+    }
+
+    pub(crate) fn alloc_error_type(&self) -> TypeRefId {
+        self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
+    }
+
+    // FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
+    // to use proper mutability instead of interior mutability.
+    pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
+        std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index d319831867c..d920c108266 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -253,7 +253,8 @@ m!(Z);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
         });
-        let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        let n_recalculated_item_trees =
+            events.iter().filter(|it| it.contains("item_tree(")).count();
         assert_eq!(n_recalculated_item_trees, 6);
         let n_reparsed_macros =
             events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@@ -308,7 +309,7 @@ pub type Ty = ();
         let events = db.log_executed(|| {
             db.file_item_tree(pos.file_id.into());
         });
-        let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
         assert_eq!(n_calculated_item_trees, 1);
         let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
         assert_eq!(n_parsed_files, 1);
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 077863c0c93..dc6947c5b56 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -9,11 +9,12 @@ use std::{
 use crate::{
     lang_item::LangItemTarget,
     lower::LowerCtx,
-    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
 };
 use hir_expand::name::Name;
 use intern::Interned;
 use span::Edition;
+use stdx::thin_vec::thin_vec_with_header_struct;
 use syntax::ast;
 
 pub use hir_expand::mod_path::{path, ModPath, PathKind};
@@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Path {
-    /// A normal path
-    Normal {
-        /// Type based path like `<T>::foo`.
-        /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
-        type_anchor: Option<Interned<TypeRef>>,
-        mod_path: Interned<ModPath>,
-        /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
-        generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
-    },
+    /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
+    /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
+    /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
+    /// this is not a problem since many more paths have generics than a type anchor).
+    BarePath(Interned<ModPath>),
+    /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
+    Normal(NormalPath),
     /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
     /// links via a normal path since they might be private and not accessible in the usage place.
     LangItem(LangItemTarget, Option<Name>),
 }
 
+// This type is being used a lot, make sure it doesn't grow unintentionally.
+#[cfg(target_arch = "x86_64")]
+const _: () = {
+    assert!(size_of::<Path>() == 16);
+    assert!(size_of::<Option<Path>>() == 16);
+};
+
+thin_vec_with_header_struct! {
+    pub new(pub(crate)) struct NormalPath, NormalPathHeader {
+        pub generic_args: [Option<GenericArgs>],
+        pub type_anchor: Option<TypeRefId>,
+        pub mod_path: Interned<ModPath>; ref,
+    }
+}
+
 /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
 /// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding {
     pub name: Name,
     /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
     /// would be `['a, T]`.
-    pub args: Option<Interned<GenericArgs>>,
+    pub args: Option<GenericArgs>,
     /// The type bound to this associated type (in `Item = T`, this would be the
     /// `T`). This can be `None` if there are bounds instead.
-    pub type_ref: Option<TypeRef>,
+    pub type_ref: Option<TypeRefId>,
     /// Bounds for the associated type, like in `Iterator<Item:
     /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
     /// feature.)
-    pub bounds: Box<[Interned<TypeBound>]>,
+    pub bounds: Box<[TypeBound]>,
 }
 
 /// A single generic argument.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum GenericArg {
-    Type(TypeRef),
+    Type(TypeRefId),
     Lifetime(LifetimeRef),
     Const(ConstRef),
 }
@@ -112,50 +126,49 @@ impl Path {
     }
 
     /// Converts a known mod path to `Path`.
-    pub fn from_known_path(
-        path: ModPath,
-        generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
-    ) -> Path {
-        let generic_args = generic_args.into();
-        assert_eq!(path.len(), generic_args.len());
-        Path::Normal {
-            type_anchor: None,
-            mod_path: Interned::new(path),
-            generic_args: Some(generic_args),
-        }
+    pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
+        Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
     }
 
     /// Converts a known mod path to `Path`.
     pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
-        Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
+        Path::BarePath(Interned::new(path))
     }
 
+    #[inline]
     pub fn kind(&self) -> &PathKind {
         match self {
-            Path::Normal { mod_path, .. } => &mod_path.kind,
+            Path::BarePath(mod_path) => &mod_path.kind,
+            Path::Normal(path) => &path.mod_path().kind,
             Path::LangItem(..) => &PathKind::Abs,
         }
     }
 
-    pub fn type_anchor(&self) -> Option<&TypeRef> {
+    #[inline]
+    pub fn type_anchor(&self) -> Option<TypeRefId> {
         match self {
-            Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
-            Path::LangItem(..) => None,
+            Path::Normal(path) => path.type_anchor(),
+            Path::LangItem(..) | Path::BarePath(_) => None,
+        }
+    }
+
+    #[inline]
+    pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
+        match self {
+            Path::Normal(path) => Some(path.generic_args()),
+            Path::LangItem(..) | Path::BarePath(_) => None,
         }
     }
 
     pub fn segments(&self) -> PathSegments<'_> {
         match self {
-            Path::Normal { mod_path, generic_args, .. } => {
-                let s = PathSegments {
-                    segments: mod_path.segments(),
-                    generic_args: generic_args.as_deref(),
-                };
-                if let Some(generic_args) = s.generic_args {
-                    assert_eq!(s.segments.len(), generic_args.len());
-                }
-                s
+            Path::BarePath(mod_path) => {
+                PathSegments { segments: mod_path.segments(), generic_args: None }
             }
+            Path::Normal(path) => PathSegments {
+                segments: path.mod_path().segments(),
+                generic_args: Some(path.generic_args()),
+            },
             Path::LangItem(_, seg) => PathSegments {
                 segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
                 generic_args: None,
@@ -165,34 +178,55 @@ impl Path {
 
     pub fn mod_path(&self) -> Option<&ModPath> {
         match self {
-            Path::Normal { mod_path, .. } => Some(mod_path),
+            Path::BarePath(mod_path) => Some(mod_path),
+            Path::Normal(path) => Some(path.mod_path()),
             Path::LangItem(..) => None,
         }
     }
 
     pub fn qualifier(&self) -> Option<Path> {
-        let Path::Normal { mod_path, generic_args, type_anchor } = self else {
-            return None;
-        };
-        if mod_path.is_ident() {
-            return None;
+        match self {
+            Path::BarePath(mod_path) => {
+                if mod_path.is_ident() {
+                    return None;
+                }
+                Some(Path::BarePath(Interned::new(ModPath::from_segments(
+                    mod_path.kind,
+                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+                ))))
+            }
+            Path::Normal(path) => {
+                let mod_path = path.mod_path();
+                if mod_path.is_ident() {
+                    return None;
+                }
+                let type_anchor = path.type_anchor();
+                let generic_args = path.generic_args();
+                let qualifier_mod_path = Interned::new(ModPath::from_segments(
+                    mod_path.kind,
+                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+                ));
+                let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
+                Some(Path::Normal(NormalPath::new(
+                    type_anchor,
+                    qualifier_mod_path,
+                    qualifier_generic_args.iter().cloned(),
+                )))
+            }
+            Path::LangItem(..) => None,
         }
-        let res = Path::Normal {
-            type_anchor: type_anchor.clone(),
-            mod_path: Interned::new(ModPath::from_segments(
-                mod_path.kind,
-                mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
-            )),
-            generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
-        };
-        Some(res)
     }
 
     pub fn is_self_type(&self) -> bool {
-        let Path::Normal { mod_path, generic_args, type_anchor } = self else {
-            return false;
-        };
-        type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
+        match self {
+            Path::BarePath(mod_path) => mod_path.is_Self(),
+            Path::Normal(path) => {
+                path.type_anchor().is_none()
+                    && path.mod_path().is_Self()
+                    && path.generic_args().iter().all(|args| args.is_none())
+            }
+            Path::LangItem(..) => false,
+        }
     }
 }
 
@@ -204,7 +238,7 @@ pub struct PathSegment<'a> {
 
 pub struct PathSegments<'a> {
     segments: &'a [Name],
-    generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
+    generic_args: Option<&'a [Option<GenericArgs>]>,
 }
 
 impl<'a> PathSegments<'a> {
@@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> {
     pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
         let res = PathSegment {
             name: self.segments.get(idx)?,
-            args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
+            args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
         };
         Some(res)
     }
@@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> {
         self.segments
             .iter()
             .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
-            .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
+            .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
     }
 }
 
@@ -268,16 +302,6 @@ impl GenericArgs {
 
 impl From<Name> for Path {
     fn from(name: Name) -> Path {
-        Path::Normal {
-            type_anchor: None,
-            mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
-            generic_args: None,
-        }
-    }
-}
-
-impl From<Name> for Box<Path> {
-    fn from(name: Name) -> Box<Path> {
-        Box::new(Path::from(name))
+        Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 70918a9358e..c328b9c6ce2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -2,13 +2,14 @@
 
 use std::iter;
 
-use crate::{lower::LowerCtx, type_ref::ConstRef};
+use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
 
 use hir_expand::{
     mod_path::resolve_crate_root,
     name::{AsName, Name},
 };
 use intern::{sym, Interned};
+use stdx::thin_vec::EmptyOptimizedThinVec;
 use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
 
 use crate::{
@@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                             segment.param_list(),
                             segment.ret_type(),
                         )
-                    })
-                    .map(Interned::new);
+                    });
                 if args.is_some() {
                     generic_args.resize(segments.len(), None);
                     generic_args.push(args);
@@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                 match trait_ref {
                     // <T>::foo
                     None => {
-                        type_anchor = Some(Interned::new(self_type));
+                        type_anchor = Some(self_type);
                         kind = PathKind::Plain;
                     }
                     // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
                     Some(trait_ref) => {
-                        let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
-                            Path::from_src(ctx, trait_ref.path()?)?
-                        else {
-                            return None;
-                        };
+                        let path = Path::from_src(ctx, trait_ref.path()?)?;
+                        let mod_path = path.mod_path()?;
+                        let path_generic_args = path.generic_args();
                         let num_segments = mod_path.segments().len();
                         kind = mod_path.kind;
 
@@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
 
                         // Insert the type reference (T in the above example) as Self parameter for the trait
                         let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
-                        *last_segment = Some(Interned::new(match last_segment.take() {
+                        *last_segment = Some(match last_segment.take() {
                             Some(it) => GenericArgs {
                                 args: iter::once(self_type)
                                     .chain(it.args.iter().cloned())
@@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                                 has_self_type: true,
                                 ..GenericArgs::empty()
                             },
-                        }));
+                        });
                     }
                 }
             }
@@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
         };
     }
     segments.reverse();
-    if !generic_args.is_empty() {
+    if !generic_args.is_empty() || type_anchor.is_some() {
         generic_args.resize(segments.len(), None);
         generic_args.reverse();
     }
@@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
     }
 
     let mod_path = Interned::new(ModPath::from_segments(kind, segments));
-    return Some(Path::Normal {
-        type_anchor,
-        mod_path,
-        generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
-    });
+    if type_anchor.is_none() && generic_args.is_empty() {
+        return Some(Path::BarePath(mod_path));
+    } else {
+        return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
+    }
 
     fn qualifier(path: &ast::Path) -> Option<ast::Path> {
         if let Some(q) = path.qualifier() {
@@ -194,11 +192,13 @@ pub(super) fn lower_generic_args(
         match generic_arg {
             ast::GenericArg::TypeArg(type_arg) => {
                 let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
-                type_ref.walk(&mut |tr| {
+                let types_map = lower_ctx.types_map();
+                TypeRef::walk(type_ref, &types_map, &mut |tr| {
                     if let TypeRef::ImplTrait(bounds) = tr {
                         lower_ctx.update_impl_traits_bounds(bounds.clone());
                     }
                 });
+                drop(types_map);
                 args.push(GenericArg::Type(type_ref));
             }
             ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@@ -212,20 +212,19 @@ pub(super) fn lower_generic_args(
                     let name = name_ref.as_name();
                     let args = assoc_type_arg
                         .generic_arg_list()
-                        .and_then(|args| lower_generic_args(lower_ctx, args))
-                        .map(Interned::new);
+                        .and_then(|args| lower_generic_args(lower_ctx, args));
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
-                    let type_ref = type_ref.inspect(|tr| {
-                        tr.walk(&mut |tr| {
+                    let type_ref = type_ref.inspect(|&tr| {
+                        let types_map = lower_ctx.types_map();
+                        TypeRef::walk(tr, &types_map, &mut |tr| {
                             if let TypeRef::ImplTrait(bounds) = tr {
                                 lower_ctx.update_impl_traits_bounds(bounds.clone());
                             }
                         });
+                        drop(types_map);
                     });
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                        l.bounds()
-                            .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
-                            .collect()
+                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
                     } else {
                         Box::default()
                     };
@@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path(
         let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
         param_types.push(type_ref);
     }
-    let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
+    let args = Box::new([GenericArg::Type(
+        ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))),
+    )]);
     let bindings = if let Some(ret_type) = ret_type {
         let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
         Box::new([AssociatedTypeBinding {
@@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
         }])
     } else {
         // -> ()
-        let type_ref = TypeRef::Tuple(Vec::new());
+        let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
         Box::new([AssociatedTypeBinding {
             name: Name::new_symbol_root(sym::Output.clone()),
             args: None,
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 49c0ad41249..9ceb82d5fd6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -6,7 +6,6 @@ use std::{
 };
 
 use hir_expand::mod_path::PathKind;
-use intern::Interned;
 use itertools::Itertools;
 use span::Edition;
 
@@ -14,12 +13,15 @@ use crate::{
     db::DefDatabase,
     lang_item::LangItemTarget,
     path::{GenericArg, GenericArgs, Path},
-    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
+    type_ref::{
+        Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
+    },
 };
 
 pub(crate) fn print_path(
     db: &dyn DefDatabase,
     path: &Path,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -61,7 +63,7 @@ pub(crate) fn print_path(
     match path.type_anchor() {
         Some(anchor) => {
             write!(buf, "<")?;
-            print_type_ref(db, anchor, buf, edition)?;
+            print_type_ref(db, anchor, map, buf, edition)?;
             write!(buf, ">::")?;
         }
         None => match path.kind() {
@@ -90,7 +92,7 @@ pub(crate) fn print_path(
         write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
         if let Some(generics) = segment.args_and_bindings {
             write!(buf, "::<")?;
-            print_generic_args(db, generics, buf, edition)?;
+            print_generic_args(db, generics, map, buf, edition)?;
 
             write!(buf, ">")?;
         }
@@ -102,6 +104,7 @@ pub(crate) fn print_path(
 pub(crate) fn print_generic_args(
     db: &dyn DefDatabase,
     generics: &GenericArgs,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -109,7 +112,7 @@ pub(crate) fn print_generic_args(
     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, edition)?;
+        print_generic_arg(db, self_ty, map, buf, edition)?;
         first = false;
         args
     } else {
@@ -120,7 +123,7 @@ pub(crate) fn print_generic_args(
             write!(buf, ", ")?;
         }
         first = false;
-        print_generic_arg(db, arg, buf, edition)?;
+        print_generic_arg(db, arg, map, buf, edition)?;
     }
     for binding in generics.bindings.iter() {
         if !first {
@@ -130,11 +133,11 @@ pub(crate) fn print_generic_args(
         write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
         if !binding.bounds.is_empty() {
             write!(buf, ": ")?;
-            print_type_bounds(db, &binding.bounds, buf, edition)?;
+            print_type_bounds(db, &binding.bounds, map, buf, edition)?;
         }
-        if let Some(ty) = &binding.type_ref {
+        if let Some(ty) = binding.type_ref {
             write!(buf, " = ")?;
-            print_type_ref(db, ty, buf, edition)?;
+            print_type_ref(db, ty, map, buf, edition)?;
         }
     }
     Ok(())
@@ -143,11 +146,12 @@ pub(crate) fn print_generic_args(
 pub(crate) fn print_generic_arg(
     db: &dyn DefDatabase,
     arg: &GenericArg,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
     match arg {
-        GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
+        GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
         GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
         GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
     }
@@ -155,12 +159,13 @@ pub(crate) fn print_generic_arg(
 
 pub(crate) fn print_type_ref(
     db: &dyn DefDatabase,
-    type_ref: &TypeRef,
+    type_ref: TypeRefId,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
     // FIXME: deduplicate with `HirDisplay` impl
-    match type_ref {
+    match &map[type_ref] {
         TypeRef::Never => write!(buf, "!")?,
         TypeRef::Placeholder => write!(buf, "_")?,
         TypeRef::Tuple(fields) => {
@@ -169,48 +174,48 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, field, buf, edition)?;
+                print_type_ref(db, *field, map, buf, edition)?;
             }
             write!(buf, ")")?;
         }
-        TypeRef::Path(path) => print_path(db, path, buf, edition)?,
+        TypeRef::Path(path) => print_path(db, path, map, 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, edition)?;
+            print_type_ref(db, *pointee, map, buf, edition)?;
         }
-        TypeRef::Reference(pointee, lt, mtbl) => {
-            let mtbl = match mtbl {
+        TypeRef::Reference(ref_) => {
+            let mtbl = match ref_.mutability {
                 Mutability::Shared => "",
                 Mutability::Mut => "mut ",
             };
             write!(buf, "&")?;
-            if let Some(lt) = lt {
+            if let Some(lt) = &ref_.lifetime {
                 write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
             }
             write!(buf, "{mtbl}")?;
-            print_type_ref(db, pointee, buf, edition)?;
+            print_type_ref(db, ref_.ty, map, buf, edition)?;
         }
-        TypeRef::Array(elem, len) => {
+        TypeRef::Array(array) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf, edition)?;
-            write!(buf, "; {}]", len.display(db.upcast(), edition))?;
+            print_type_ref(db, array.ty, map, buf, edition)?;
+            write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
         }
         TypeRef::Slice(elem) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf, edition)?;
+            print_type_ref(db, *elem, map, buf, edition)?;
             write!(buf, "]")?;
         }
-        TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
+        TypeRef::Fn(fn_) => {
             let ((_, return_type), args) =
-                args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
-            if *is_unsafe {
+                fn_.params().split_last().expect("TypeRef::Fn is missing return type");
+            if fn_.is_unsafe() {
                 write!(buf, "unsafe ")?;
             }
-            if let Some(abi) = abi {
+            if let Some(abi) = fn_.abi() {
                 buf.write_str("extern ")?;
                 buf.write_str(abi.as_str())?;
                 buf.write_char(' ')?;
@@ -220,16 +225,16 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, typeref, buf, edition)?;
+                print_type_ref(db, *typeref, map, buf, edition)?;
             }
-            if *varargs {
+            if fn_.is_varargs() {
                 if !args.is_empty() {
                     write!(buf, ", ")?;
                 }
                 write!(buf, "...")?;
             }
             write!(buf, ") -> ")?;
-            print_type_ref(db, return_type, buf, edition)?;
+            print_type_ref(db, *return_type, map, buf, edition)?;
         }
         TypeRef::Macro(_ast_id) => {
             write!(buf, "<macro>")?;
@@ -237,11 +242,11 @@ pub(crate) fn print_type_ref(
         TypeRef::Error => write!(buf, "{{unknown}}")?,
         TypeRef::ImplTrait(bounds) => {
             write!(buf, "impl ")?;
-            print_type_bounds(db, bounds, buf, edition)?;
+            print_type_bounds(db, bounds, map, buf, edition)?;
         }
         TypeRef::DynTrait(bounds) => {
             write!(buf, "dyn ")?;
-            print_type_bounds(db, bounds, buf, edition)?;
+            print_type_bounds(db, bounds, map, buf, edition)?;
         }
     }
 
@@ -250,7 +255,8 @@ pub(crate) fn print_type_ref(
 
 pub(crate) fn print_type_bounds(
     db: &dyn DefDatabase,
-    bounds: &[Interned<TypeBound>],
+    bounds: &[TypeBound],
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -259,13 +265,13 @@ pub(crate) fn print_type_bounds(
             write!(buf, " + ")?;
         }
 
-        match bound.as_ref() {
+        match bound {
             TypeBound::Path(path, modifier) => {
                 match modifier {
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(buf, "?")?,
                 }
-                print_path(db, path, buf, edition)?;
+                print_path(db, path, map, buf, edition)?;
             }
             TypeBound::ForLifetime(lifetimes, path) => {
                 write!(
@@ -273,7 +279,7 @@ pub(crate) fn print_type_bounds(
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
                 )?;
-                print_path(db, path, buf, edition)?;
+                print_path(db, path, map, buf, edition)?;
             }
             TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
             TypeBound::Use(args) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index d491042eabf..26655e40ca7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -3,7 +3,7 @@ use std::{fmt, iter, mem};
 
 use base_db::CrateId;
 use hir_expand::{name::Name, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
 use itertools::Itertools as _;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -24,7 +24,7 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     path::{ModPath, Path, PathKind},
     per_ns::PerNs,
-    type_ref::LifetimeRef,
+    type_ref::{LifetimeRef, TypesMap},
     visibility::{RawVisibility, Visibility},
     AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
     ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@@ -76,7 +76,7 @@ enum Scope {
     /// All the items and imported names of a module
     BlockScope(ModuleItemMap),
     /// Brings the generic parameters of an item into scope
-    GenericParams { def: GenericDefId, params: Interned<GenericParams> },
+    GenericParams { def: GenericDefId, params: Arc<GenericParams> },
     /// Brings `Self` in `impl` block into scope
     ImplDefScope(ImplId),
     /// Brings `Self` in enum, struct and union definitions into scope
@@ -167,7 +167,8 @@ impl Resolver {
         path: &Path,
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
         let path = match path {
-            Path::Normal { mod_path, .. } => mod_path,
+            Path::BarePath(mod_path) => mod_path,
+            Path::Normal(it) => it.mod_path(),
             Path::LangItem(l, seg) => {
                 let type_ns = match *l {
                     LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
@@ -265,7 +266,8 @@ impl Resolver {
         mut hygiene_id: HygieneId,
     ) -> Option<ResolveValueResult> {
         let path = match path {
-            Path::Normal { mod_path, .. } => mod_path,
+            Path::BarePath(mod_path) => mod_path,
+            Path::Normal(it) => it.mod_path(),
             Path::LangItem(l, None) => {
                 return Some(ResolveValueResult::ValueNs(
                     match *l {
@@ -620,13 +622,15 @@ impl Resolver {
 
     pub fn where_predicates_in_scope(
         &self,
-    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
+    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
         self.scopes()
             .filter_map(|scope| match scope {
                 Scope::GenericParams { params, def } => Some((params, def)),
                 _ => None,
             })
-            .flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def)))
+            .flat_map(|(params, def)| {
+                params.where_predicates().zip(iter::repeat((def, &params.types_map)))
+            })
     }
 
     pub fn generic_def(&self) -> Option<GenericDefId> {
@@ -636,13 +640,20 @@ impl Resolver {
         })
     }
 
-    pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
+    pub fn generic_params(&self) -> Option<&Arc<GenericParams>> {
         self.scopes().find_map(|scope| match scope {
             Scope::GenericParams { params, .. } => Some(params),
             _ => None,
         })
     }
 
+    pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> {
+        self.scopes().filter_map(|scope| match scope {
+            Scope::GenericParams { params, def } => Some((&**params, def)),
+            _ => None,
+        })
+    }
+
     pub fn body_owner(&self) -> Option<DefWithBodyId> {
         self.scopes().find_map(|scope| match scope {
             Scope::ExprScope(it) => Some(it.owner),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 79cfeb4cf18..12df3cf2188 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -26,6 +26,7 @@ use crate::{
 /// Syntactical attributes, without filtering of `cfg_attr`s.
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct RawAttrs {
+    // FIXME: This can become `Box<[Attr]>` if https://internals.rust-lang.org/t/layout-of-dst-box/21728?u=chrefr is accepted.
     entries: Option<ThinArc<(), Attr>>,
 }
 
@@ -169,6 +170,10 @@ impl RawAttrs {
         };
         RawAttrs { entries }
     }
+
+    pub fn is_empty(&self) -> bool {
+        self.entries.is_none()
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
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 8a616956de2..4bc78afacc0 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
@@ -615,8 +615,9 @@ pub(crate) fn associated_ty_data_query(
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
-    let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
-        .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
+    let ctx =
+        crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
+            .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
 
     let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
         .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
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 7f6b7e392b3..c9ab0acc084 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
@@ -309,7 +309,7 @@ impl<'a> DeclValidator<'a> {
     /// Check incorrect names for struct fields.
     fn validate_struct_fields(&mut self, struct_id: StructId) {
         let data = self.db.struct_data(struct_id);
-        let VariantData::Record(fields) = data.variant_data.as_ref() else {
+        let VariantData::Record { fields, .. } = data.variant_data.as_ref() else {
             return;
         };
         let edition = self.edition(struct_id);
@@ -469,7 +469,7 @@ impl<'a> DeclValidator<'a> {
     /// Check incorrect names for fields of enum variant.
     fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
         let variant_data = self.db.enum_variant_data(variant_id);
-        let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
+        let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else {
             return;
         };
         let edition = self.edition(variant_id);
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 4bc07bc9ec8..c5d8c956615 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
@@ -341,7 +341,7 @@ impl HirDisplay for Pat {
                     };
 
                     let variant_data = variant.variant_data(f.db.upcast());
-                    if let VariantData::Record(rec_fields) = &*variant_data {
+                    if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
                         write!(f, " {{ ")?;
 
                         let mut printed = 0;
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 79861345b8c..277dabe9aa3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -19,7 +19,9 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     nameres::DefMap,
     path::{Path, PathKind},
-    type_ref::{TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
+    type_ref::{
+        TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
+    },
     visibility::Visibility,
     GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
     ModuleId, TraitId,
@@ -806,7 +808,7 @@ fn render_variant_after_name(
     memory_map: &MemoryMap,
 ) -> Result<(), HirDisplayError> {
     match data {
-        VariantData::Record(fields) | VariantData::Tuple(fields) => {
+        VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
             let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
                 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
                 let ty = field_types[id].clone().substitute(Interner, subst);
@@ -817,7 +819,7 @@ fn render_variant_after_name(
                 render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
             };
             let mut it = fields.iter();
-            if matches!(data, VariantData::Record(_)) {
+            if matches!(data, VariantData::Record { .. }) {
                 write!(f, " {{")?;
                 if let Some((id, data)) = it.next() {
                     write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
@@ -1897,100 +1899,150 @@ pub fn write_visibility(
     }
 }
 
-impl HirDisplay for TypeRef {
+pub trait HirDisplayWithTypesMap {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError>;
+}
+
+impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
+        T::hir_fmt(&**self, f, types_map)
+    }
+}
+
+pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
+    value: T,
+    types_map: &'a TypesMap,
+) -> impl HirDisplay + 'a {
+    TypesMapAdapter(value, types_map)
+}
+
+struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
+
+impl<'a, T> TypesMapAdapter<'a, T> {
+    fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
+        move |value| TypesMapAdapter(value, types_map)
+    }
+}
+
+impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self {
+        T::hir_fmt(&self.0, f, self.1)
+    }
+}
+
+impl HirDisplayWithTypesMap for TypeRefId {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
+        match &types_map[*self] {
             TypeRef::Never => write!(f, "!")?,
             TypeRef::Placeholder => write!(f, "_")?,
             TypeRef::Tuple(elems) => {
                 write!(f, "(")?;
-                f.write_joined(elems, ", ")?;
+                f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
                 if elems.len() == 1 {
                     write!(f, ",")?;
                 }
                 write!(f, ")")?;
             }
-            TypeRef::Path(path) => path.hir_fmt(f)?,
+            TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
             TypeRef::RawPtr(inner, mutability) => {
                 let mutability = match mutability {
                     hir_def::type_ref::Mutability::Shared => "*const ",
                     hir_def::type_ref::Mutability::Mut => "*mut ",
                 };
                 write!(f, "{mutability}")?;
-                inner.hir_fmt(f)?;
+                inner.hir_fmt(f, types_map)?;
             }
-            TypeRef::Reference(inner, lifetime, mutability) => {
-                let mutability = match mutability {
+            TypeRef::Reference(ref_) => {
+                let mutability = match ref_.mutability {
                     hir_def::type_ref::Mutability::Shared => "",
                     hir_def::type_ref::Mutability::Mut => "mut ",
                 };
                 write!(f, "&")?;
-                if let Some(lifetime) = lifetime {
+                if let Some(lifetime) = &ref_.lifetime {
                     write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
                 write!(f, "{mutability}")?;
-                inner.hir_fmt(f)?;
+                ref_.ty.hir_fmt(f, types_map)?;
             }
-            TypeRef::Array(inner, len) => {
+            TypeRef::Array(array) => {
                 write!(f, "[")?;
-                inner.hir_fmt(f)?;
-                write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
+                array.ty.hir_fmt(f, types_map)?;
+                write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
             }
             TypeRef::Slice(inner) => {
                 write!(f, "[")?;
-                inner.hir_fmt(f)?;
+                inner.hir_fmt(f, types_map)?;
                 write!(f, "]")?;
             }
-            &TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => {
-                if is_unsafe {
+            TypeRef::Fn(fn_) => {
+                if fn_.is_unsafe() {
                     write!(f, "unsafe ")?;
                 }
-                if let Some(abi) = abi {
+                if let Some(abi) = fn_.abi() {
                     f.write_str("extern \"")?;
                     f.write_str(abi.as_str())?;
                     f.write_str("\" ")?;
                 }
                 write!(f, "fn(")?;
-                if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
+                if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() {
                     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(), f.edition()))?;
                         }
 
-                        param_type.hir_fmt(f)?;
+                        param_type.hir_fmt(f, types_map)?;
 
                         if index != function_parameters.len() - 1 {
                             write!(f, ", ")?;
                         }
                     }
-                    if is_varargs {
-                        write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
+                    if fn_.is_varargs() {
+                        write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?;
                     }
                     write!(f, ")")?;
-                    match &return_type {
+                    match &types_map[*return_type] {
                         TypeRef::Tuple(tup) if tup.is_empty() => {}
                         _ => {
                             write!(f, " -> ")?;
-                            return_type.hir_fmt(f)?;
+                            return_type.hir_fmt(f, types_map)?;
                         }
                     }
                 }
             }
             TypeRef::ImplTrait(bounds) => {
                 write!(f, "impl ")?;
-                f.write_joined(bounds, " + ")?;
+                f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
             }
             TypeRef::DynTrait(bounds) => {
                 write!(f, "dyn ")?;
-                f.write_joined(bounds, " + ")?;
+                f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
             }
             TypeRef::Macro(macro_call) => {
-                let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id);
+                let (mut types_map, mut types_source_map) =
+                    (TypesMap::default(), TypesSourceMap::default());
+                let ctx = hir_def::lower::LowerCtx::new(
+                    f.db.upcast(),
+                    macro_call.file_id,
+                    &mut types_map,
+                    &mut types_source_map,
+                );
                 let macro_call = macro_call.to_node(f.db.upcast());
                 match macro_call.path() {
                     Some(path) => match Path::from_src(&ctx, path) {
-                        Some(path) => path.hir_fmt(f)?,
+                        Some(path) => path.hir_fmt(f, &types_map)?,
                         None => write!(f, "{{macro}}")?,
                     },
                     None => write!(f, "{{macro}}")?,
@@ -2003,15 +2055,19 @@ impl HirDisplay for TypeRef {
     }
 }
 
-impl HirDisplay for TypeBound {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for TypeBound {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match self {
             TypeBound::Path(path, modifier) => {
                 match modifier {
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(f, "?")?,
                 }
-                path.hir_fmt(f)
+                path.hir_fmt(f, types_map)
             }
             TypeBound::Lifetime(lifetime) => {
                 write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@@ -2023,7 +2079,7 @@ impl HirDisplay for TypeBound {
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
                 )?;
-                path.hir_fmt(f)
+                path.hir_fmt(f, types_map)
             }
             TypeBound::Use(args) => {
                 let edition = f.edition();
@@ -2043,12 +2099,16 @@ impl HirDisplay for TypeBound {
     }
 }
 
-impl HirDisplay for Path {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for Path {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match (self.type_anchor(), self.kind()) {
             (Some(anchor), _) => {
                 write!(f, "<")?;
-                anchor.hir_fmt(f)?;
+                anchor.hir_fmt(f, types_map)?;
                 write!(f, ">")?;
             }
             (_, PathKind::Plain) => {}
@@ -2091,7 +2151,7 @@ impl HirDisplay for Path {
         });
         if let Some(ty) = trait_self_ty {
             write!(f, "<")?;
-            ty.hir_fmt(f)?;
+            ty.hir_fmt(f, types_map)?;
             write!(f, " as ")?;
             // Now format the path of the trait...
         }
@@ -2107,21 +2167,26 @@ impl HirDisplay for Path {
                 if generic_args.desugared_from_fn {
                     // First argument will be a tuple, which already includes the parentheses.
                     // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
-                    if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
-                        &generic_args.args[0]
-                    {
+                    let tuple = match generic_args.args[0] {
+                        hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
+                            TypeRef::Tuple(it) => Some(it),
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+                    if let Some(v) = tuple {
                         if v.len() == 1 {
                             write!(f, "(")?;
-                            v[0].hir_fmt(f)?;
+                            v[0].hir_fmt(f, types_map)?;
                             write!(f, ")")?;
                         } else {
-                            generic_args.args[0].hir_fmt(f)?;
+                            generic_args.args[0].hir_fmt(f, types_map)?;
                         }
                     }
-                    if let Some(ret) = &generic_args.bindings[0].type_ref {
-                        if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
+                    if let Some(ret) = generic_args.bindings[0].type_ref {
+                        if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
                             write!(f, " -> ")?;
-                            ret.hir_fmt(f)?;
+                            ret.hir_fmt(f, types_map)?;
                         }
                     }
                     return Ok(());
@@ -2136,7 +2201,7 @@ impl HirDisplay for Path {
                     } else {
                         write!(f, ", ")?;
                     }
-                    arg.hir_fmt(f)?;
+                    arg.hir_fmt(f, types_map)?;
                 }
                 for binding in generic_args.bindings.iter() {
                     if first {
@@ -2149,11 +2214,14 @@ impl HirDisplay for Path {
                     match &binding.type_ref {
                         Some(ty) => {
                             write!(f, " = ")?;
-                            ty.hir_fmt(f)?
+                            ty.hir_fmt(f, types_map)?
                         }
                         None => {
                             write!(f, ": ")?;
-                            f.write_joined(binding.bounds.iter(), " + ")?;
+                            f.write_joined(
+                                binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
+                                " + ",
+                            )?;
                         }
                     }
                 }
@@ -2175,10 +2243,14 @@ impl HirDisplay for Path {
     }
 }
 
-impl HirDisplay for hir_def::path::GenericArg {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match self {
-            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
+            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
             hir_def::path::GenericArg::Const(c) => {
                 write!(f, "{}", c.display(f.db.upcast(), f.edition()))
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index 89ca707c2e6..c094bc39512 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -16,12 +16,13 @@ use hir_def::{
         GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
         TypeParamProvenance,
     },
+    type_ref::TypesMap,
     ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
-use intern::Interned;
 use itertools::chain;
 use stdx::TupleExt;
+use triomphe::Arc;
 
 use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
 
@@ -34,7 +35,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
 #[derive(Clone, Debug)]
 pub(crate) struct Generics {
     def: GenericDefId,
-    params: Interned<GenericParams>,
+    params: Arc<GenericParams>,
     parent_generics: Option<Box<Generics>>,
     has_trait_self_param: bool,
 }
@@ -85,6 +86,18 @@ impl Generics {
         self.iter_self().chain(self.iter_parent())
     }
 
+    pub(crate) fn iter_with_types_map(
+        &self,
+    ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
+        self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
+            self.iter_parent().zip(
+                self.parent_generics()
+                    .into_iter()
+                    .flat_map(|it| std::iter::repeat(&it.params.types_map)),
+            ),
+        )
+    }
+
     /// Iterate over the params without parent params.
     pub(crate) fn iter_self(
         &self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 3cb0d89e01c..3685ed56964 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -41,7 +41,7 @@ use hir_def::{
     layout::Integer,
     path::{ModPath, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
-    type_ref::{LifetimeRef, TypeRef},
+    type_ref::{LifetimeRef, TypeRefId, TypesMap},
     AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
     TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
 };
@@ -858,7 +858,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_const(&mut self, data: &ConstData) {
-        let return_ty = self.make_ty(&data.type_ref);
+        let return_ty = self.make_ty(data.type_ref, &data.types_map);
 
         // Constants might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -867,7 +867,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_static(&mut self, data: &StaticData) {
-        let return_ty = self.make_ty(&data.type_ref);
+        let return_ty = self.make_ty(data.type_ref, &data.types_map);
 
         // Statics might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -877,11 +877,11 @@ impl<'a> InferenceContext<'a> {
 
     fn collect_fn(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
-        let mut param_tys =
-            data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+        let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
+            ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                .impl_trait_mode(ImplTraitLoweringMode::Param);
+            data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
+        });
         // Check if function contains a va_list, if it does then we append it to the parameter types
         // that are collected from the function data
         if data.is_varargs() {
@@ -916,12 +916,13 @@ impl<'a> InferenceContext<'a> {
                 tait_candidates.insert(ty);
             }
         }
-        let return_ty = &*data.ret_type;
+        let return_ty = data.ret_type;
 
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-        let return_ty = ctx.lower_ty(return_ty);
+        let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
+            ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                .impl_trait_mode(ImplTraitLoweringMode::Opaque)
+                .lower_ty(return_ty)
+        });
         let return_ty = self.insert_type_vars(return_ty);
 
         let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@@ -1225,20 +1226,43 @@ impl<'a> InferenceContext<'a> {
         self.result.diagnostics.push(diagnostic);
     }
 
-    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let ty = ctx.lower_ty(type_ref);
+    fn with_ty_lowering<R>(
+        &self,
+        types_map: &TypesMap,
+        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+    ) -> R {
+        let mut ctx = crate::lower::TyLoweringContext::new(
+            self.db,
+            &self.resolver,
+            types_map,
+            self.owner.into(),
+        );
+        f(&mut ctx)
+    }
+
+    fn with_body_ty_lowering<R>(
+        &self,
+        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+    ) -> R {
+        self.with_ty_lowering(&self.body.types, f)
+    }
+
+    fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
+        let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
         let ty = self.insert_type_vars(ty);
         self.normalize_associated_types_in(ty)
     }
 
+    fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
+        self.make_ty(type_ref, &self.body.types)
+    }
+
     fn err_ty(&self) -> Ty {
         self.result.standard_types.unknown.clone()
     }
 
     fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let lt = ctx.lower_lifetime(lifetime_ref);
+        let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
         self.insert_type_vars(lt)
     }
 
@@ -1396,7 +1420,12 @@ impl<'a> InferenceContext<'a> {
             Some(path) => path,
             None => return (self.err_ty(), None),
         };
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+        let ctx = crate::lower::TyLoweringContext::new(
+            self.db,
+            &self.resolver,
+            &self.body.types,
+            self.owner.into(),
+        );
         let (resolution, unresolved) = if value_ns {
             match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
                 Some(ResolveValueResult::ValueNs(value, _)) => match value {
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 f5face07d86..5a251683b96 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
@@ -283,11 +283,11 @@ impl CapturedItem {
                 ProjectionElem::Deref => {}
                 ProjectionElem::Field(Either::Left(f)) => {
                     match &*f.parent.variant_data(db.upcast()) {
-                        VariantData::Record(fields) => {
+                        VariantData::Record { fields, .. } => {
                             result.push('_');
                             result.push_str(fields[f.local_id].name.as_str())
                         }
-                        VariantData::Tuple(fields) => {
+                        VariantData::Tuple { fields, .. } => {
                             let index = fields.iter().position(|it| it.0 == f.local_id);
                             if let Some(index) = index {
                                 format_to!(result, "_{index}");
@@ -325,12 +325,12 @@ impl CapturedItem {
                 ProjectionElem::Field(Either::Left(f)) => {
                     let variant_data = f.parent.variant_data(db.upcast());
                     match &*variant_data {
-                        VariantData::Record(fields) => format_to!(
+                        VariantData::Record { fields, .. } => format_to!(
                             result,
                             ".{}",
                             fields[f.local_id].name.display(db.upcast(), edition)
                         ),
-                        VariantData::Tuple(fields) => format_to!(
+                        VariantData::Tuple { fields, .. } => format_to!(
                             result,
                             ".{}",
                             fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@@ -383,8 +383,10 @@ impl CapturedItem {
                     }
                     let variant_data = f.parent.variant_data(db.upcast());
                     let field = match &*variant_data {
-                        VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
-                        VariantData::Tuple(fields) => fields
+                        VariantData::Record { fields, .. } => {
+                            fields[f.local_id].name.as_str().to_owned()
+                        }
+                        VariantData::Tuple { fields, .. } => fields
                             .iter()
                             .position(|it| it.0 == f.local_id)
                             .unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index e55ddad4e96..32b4ea2f28b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -198,7 +198,7 @@ impl InferenceContext<'_> {
         match &self.body[expr] {
             // Lang item paths cannot currently be local variables or statics.
             Expr::Path(Path::LangItem(_, _)) => false,
-            Expr::Path(Path::Normal { type_anchor: Some(_), .. }) => false,
+            Expr::Path(Path::Normal(path)) => path.type_anchor().is_none(),
             Expr::Path(path) => self
                 .resolver
                 .resolve_path_in_value_ns_fully(
@@ -382,7 +382,7 @@ impl InferenceContext<'_> {
                 // collect explicitly written argument types
                 for arg_type in arg_types.iter() {
                     let arg_ty = match arg_type {
-                        Some(type_ref) => self.make_ty(type_ref),
+                        Some(type_ref) => self.make_body_ty(*type_ref),
                         None => self.table.new_type_var(),
                     };
                     sig_tys.push(arg_ty);
@@ -390,7 +390,7 @@ impl InferenceContext<'_> {
 
                 // add return type
                 let ret_ty = match ret_type {
-                    Some(type_ref) => self.make_ty(type_ref),
+                    Some(type_ref) => self.make_body_ty(*type_ref),
                     None => self.table.new_type_var(),
                 };
                 if let ClosureKind::Async = closure_kind {
@@ -786,7 +786,7 @@ impl InferenceContext<'_> {
                 self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
             }
             Expr::Cast { expr, type_ref } => {
-                let cast_ty = self.make_ty(type_ref);
+                let cast_ty = self.make_body_ty(*type_ref);
                 let expr_ty = self.infer_expr(
                     *expr,
                     &Expectation::Castable(cast_ty.clone()),
@@ -1214,7 +1214,7 @@ impl InferenceContext<'_> {
         let ty = match self.infer_path(path, id) {
             Some(ty) => ty,
             None => {
-                if matches!(path, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self())
+                if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self())
                 {
                     self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { id });
                 }
@@ -1598,7 +1598,7 @@ impl InferenceContext<'_> {
                         Statement::Let { pat, type_ref, initializer, else_branch } => {
                             let decl_ty = type_ref
                                 .as_ref()
-                                .map(|tr| this.make_ty(tr))
+                                .map(|&tr| this.make_body_ty(tr))
                                 .unwrap_or_else(|| this.table.new_type_var());
 
                             let ty = if let Some(expr) = initializer {
@@ -2141,7 +2141,8 @@ impl InferenceContext<'_> {
                         kind_id,
                         args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
                         self,
-                        |this, type_ref| this.make_ty(type_ref),
+                        &self.body.types,
+                        |this, type_ref| this.make_body_ty(type_ref),
                         |this, c, ty| {
                             const_or_path_to_chalk(
                                 this.db,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 44c496c0542..442daa9f9ee 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -94,8 +94,7 @@ impl InferenceContext<'_> {
             return Some(ValuePathResolution::NonGeneric(ty));
         };
 
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let substs = ctx.substs_from_path(path, value_def, true);
+        let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
         let substs = substs.as_slice(Interner);
 
         if let ValueNs::EnumVariantId(_) = value {
@@ -152,8 +151,12 @@ impl InferenceContext<'_> {
             let last = path.segments().last()?;
 
             // Don't use `self.make_ty()` here as we need `orig_ns`.
-            let ctx =
-                crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+            let ctx = crate::lower::TyLoweringContext::new(
+                self.db,
+                &self.resolver,
+                &self.body.types,
+                self.owner.into(),
+            );
             let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
@@ -219,7 +222,7 @@ impl InferenceContext<'_> {
 
         let _d;
         let (resolved_segment, remaining_segments) = match path {
-            Path::Normal { .. } => {
+            Path::Normal { .. } | Path::BarePath(_) => {
                 assert!(remaining_index < path.segments().len());
                 (
                     path.segments().get(remaining_index - 1).unwrap(),
@@ -243,17 +246,10 @@ impl InferenceContext<'_> {
             (TypeNs::TraitId(trait_), true) => {
                 let segment =
                     remaining_segments.last().expect("there should be at least one segment here");
-                let ctx = crate::lower::TyLoweringContext::new(
-                    self.db,
-                    &self.resolver,
-                    self.owner.into(),
-                );
-                let trait_ref = ctx.lower_trait_ref_from_resolved_path(
-                    trait_,
-                    resolved_segment,
-                    self.table.new_type_var(),
-                );
-
+                let self_ty = self.table.new_type_var();
+                let trait_ref = self.with_body_ty_lowering(|ctx| {
+                    ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
+                });
                 self.resolve_trait_assoc_item(trait_ref, segment, id)
             }
             (def, _) => {
@@ -263,17 +259,14 @@ impl InferenceContext<'_> {
                 // as Iterator>::Item::default`)
                 let remaining_segments_for_ty =
                     remaining_segments.take(remaining_segments.len() - 1);
-                let ctx = crate::lower::TyLoweringContext::new(
-                    self.db,
-                    &self.resolver,
-                    self.owner.into(),
-                );
-                let (ty, _) = ctx.lower_partly_resolved_path(
-                    def,
-                    resolved_segment,
-                    remaining_segments_for_ty,
-                    true,
-                );
+                let (ty, _) = self.with_body_ty_lowering(|ctx| {
+                    ctx.lower_partly_resolved_path(
+                        def,
+                        resolved_segment,
+                        remaining_segments_for_ty,
+                        true,
+                    )
+                });
                 if ty.is_unknown() {
                     return None;
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index f7db9489980..e3a92e52f61 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -34,6 +34,7 @@ use hir_def::{
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
     type_ref::{
         ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
+        TypeRefId, TypesMap, TypesSourceMap,
     },
     AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
     FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@@ -41,7 +42,6 @@ use hir_def::{
     TypeOwnerId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
-use intern::Interned;
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::Captures;
@@ -122,6 +122,11 @@ pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
     resolver: &'a Resolver,
     generics: OnceCell<Option<Generics>>,
+    types_map: &'a TypesMap,
+    /// If this is set, that means we're in a context of a freshly expanded macro, and that means
+    /// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`,
+    /// instead we need to put `TypeSource` from the source map.
+    types_source_map: Option<&'a TypesSourceMap>,
     in_binders: DebruijnIndex,
     // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
     // where expected
@@ -138,13 +143,20 @@ pub struct TyLoweringContext<'a> {
 }
 
 impl<'a> TyLoweringContext<'a> {
-    pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
-        Self::new_maybe_unowned(db, resolver, Some(owner))
+    pub fn new(
+        db: &'a dyn HirDatabase,
+        resolver: &'a Resolver,
+        types_map: &'a TypesMap,
+        owner: TypeOwnerId,
+    ) -> Self {
+        Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner))
     }
 
     pub fn new_maybe_unowned(
         db: &'a dyn HirDatabase,
         resolver: &'a Resolver,
+        types_map: &'a TypesMap,
+        types_source_map: Option<&'a TypesSourceMap>,
         owner: Option<TypeOwnerId>,
     ) -> Self {
         let impl_trait_mode = ImplTraitLoweringState::Disallowed;
@@ -154,6 +166,8 @@ impl<'a> TyLoweringContext<'a> {
             db,
             resolver,
             generics: OnceCell::new(),
+            types_map,
+            types_source_map,
             owner,
             in_binders,
             impl_trait_mode,
@@ -201,6 +215,16 @@ impl<'a> TyLoweringContext<'a> {
     pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
         Self { type_param_mode, ..self }
     }
+
+    pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+        self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
+        self
+    }
+
+    pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
+        self.type_param_mode = type_param_mode;
+        self
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -230,7 +254,7 @@ pub enum ParamLoweringMode {
 }
 
 impl<'a> TyLoweringContext<'a> {
-    pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
+    pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty {
         self.lower_ty_ext(type_ref).0
     }
 
@@ -254,12 +278,13 @@ impl<'a> TyLoweringContext<'a> {
             .as_ref()
     }
 
-    pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
+    pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
         let mut res = None;
+        let type_ref = &self.types_map[type_ref_id];
         let ty = match type_ref {
             TypeRef::Never => TyKind::Never.intern(Interner),
             TypeRef::Tuple(inner) => {
-                let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
+                let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
                 TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
                     .intern(Interner)
             }
@@ -268,38 +293,43 @@ impl<'a> TyLoweringContext<'a> {
                 res = res_;
                 ty
             }
-            TypeRef::RawPtr(inner, mutability) => {
+            &TypeRef::RawPtr(inner, mutability) => {
                 let inner_ty = self.lower_ty(inner);
-                TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
+                TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
             }
-            TypeRef::Array(inner, len) => {
-                let inner_ty = self.lower_ty(inner);
-                let const_len = self.lower_const(len, TyBuilder::usize());
+            TypeRef::Array(array) => {
+                let inner_ty = self.lower_ty(array.ty);
+                let const_len = self.lower_const(&array.len, TyBuilder::usize());
                 TyKind::Array(inner_ty, const_len).intern(Interner)
             }
-            TypeRef::Slice(inner) => {
+            &TypeRef::Slice(inner) => {
                 let inner_ty = self.lower_ty(inner);
                 TyKind::Slice(inner_ty).intern(Interner)
             }
-            TypeRef::Reference(inner, lifetime, mutability) => {
-                let inner_ty = self.lower_ty(inner);
+            TypeRef::Reference(ref_) => {
+                let inner_ty = self.lower_ty(ref_.ty);
                 // FIXME: It should infer the eldided lifetimes instead of stubbing with static
-                let lifetime =
-                    lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
-                TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
+                let lifetime = ref_
+                    .lifetime
+                    .as_ref()
+                    .map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
+                TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
                     .intern(Interner)
             }
             TypeRef::Placeholder => TyKind::Error.intern(Interner),
-            &TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => {
+            TypeRef::Fn(fn_) => {
                 let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                    Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
+                    Substitution::from_iter(
+                        Interner,
+                        fn_.params().iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+                    )
                 });
                 TyKind::Function(FnPointer {
                     num_binders: 0, // FIXME lower `for<'a> fn()` correctly
                     sig: FnSig {
-                        abi: abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-                        safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
-                        variadic,
+                        abi: fn_.abi().as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+                        safety: if fn_.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+                        variadic: fn_.is_varargs(),
                     },
                     substitution: FnSubst(substs),
                 })
@@ -351,8 +381,8 @@ impl<'a> TyLoweringContext<'a> {
                     ImplTraitLoweringState::Param(counter) => {
                         let idx = counter.get();
                         // Count the number of `impl Trait` things that appear within our bounds.
-                        // Since t hose have been emitted as implicit type args already.
-                        counter.set(idx + count_impl_traits(type_ref) as u16);
+                        // Since those have been emitted as implicit type args already.
+                        counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
                         let kind = self
                             .generics()
                             .expect("param impl trait lowering must be in a generic def")
@@ -376,7 +406,7 @@ impl<'a> TyLoweringContext<'a> {
                         let idx = counter.get();
                         // Count the number of `impl Trait` things that appear within our bounds.
                         // Since t hose have been emitted as implicit type args already.
-                        counter.set(idx + count_impl_traits(type_ref) as u16);
+                        counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
                         let kind = self
                             .generics()
                             .expect("variable impl trait lowering must be in a generic def")
@@ -432,12 +462,40 @@ impl<'a> TyLoweringContext<'a> {
                     match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
                     {
                         Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
-                            let ctx = expander.ctx(self.db.upcast());
+                            let (mut types_map, mut types_source_map) =
+                                (TypesMap::default(), TypesSourceMap::default());
+
+                            let ctx = expander.ctx(
+                                self.db.upcast(),
+                                &mut types_map,
+                                &mut types_source_map,
+                            );
                             // FIXME: Report syntax errors in expansion here
                             let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
 
                             drop(expander);
-                            let ty = self.lower_ty(&type_ref);
+
+                            // FIXME: That may be better served by mutating `self` then restoring, but this requires
+                            // making it `&mut self`.
+                            let inner_ctx = TyLoweringContext {
+                                db: self.db,
+                                resolver: self.resolver,
+                                generics: self.generics.clone(),
+                                types_map: &types_map,
+                                types_source_map: Some(&types_source_map),
+                                in_binders: self.in_binders,
+                                owner: self.owner,
+                                type_param_mode: self.type_param_mode,
+                                impl_trait_mode: self.impl_trait_mode.take(),
+                                expander: RefCell::new(self.expander.take()),
+                                unsized_types: RefCell::new(self.unsized_types.take()),
+                            };
+
+                            let ty = inner_ctx.lower_ty(type_ref);
+
+                            self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode);
+                            *self.expander.borrow_mut() = inner_ctx.expander.into_inner();
+                            *self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner();
 
                             self.expander.borrow_mut().as_mut().unwrap().exit(mark);
                             Some(ty)
@@ -463,7 +521,8 @@ impl<'a> TyLoweringContext<'a> {
     /// This is only for `generic_predicates_for_param`, where we can't just
     /// lower the self types of the predicates since that could lead to cycles.
     /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
+    fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+        let type_ref = &self.types_map[type_ref];
         let path = match type_ref {
             TypeRef::Path(path) => path,
             _ => return None,
@@ -663,7 +722,7 @@ impl<'a> TyLoweringContext<'a> {
         if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
             // trait object type without dyn
             let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
-            let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
+            let ty = self.lower_dyn_trait(&[bound]);
             return (ty, None);
         }
 
@@ -864,7 +923,7 @@ impl<'a> TyLoweringContext<'a> {
                     assert!(matches!(id, GenericParamId::TypeParamId(_)));
                     had_explicit_args = true;
                     if let GenericArg::Type(ty) = &args[0] {
-                        substs.push(self.lower_ty(ty).cast(Interner));
+                        substs.push(self.lower_ty(*ty).cast(Interner));
                     }
                 }
             } else {
@@ -901,6 +960,7 @@ impl<'a> TyLoweringContext<'a> {
                     id,
                     arg,
                     &mut (),
+                    self.types_map,
                     |_, type_ref| self.lower_ty(type_ref),
                     |_, const_ref, ty| self.lower_const(const_ref, ty),
                     |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
@@ -998,7 +1058,7 @@ impl<'a> TyLoweringContext<'a> {
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
                 let self_ty = match target {
-                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
+                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
                     &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
                         let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
                         match self.type_param_mode {
@@ -1029,12 +1089,12 @@ impl<'a> TyLoweringContext<'a> {
 
     pub(crate) fn lower_type_bound(
         &'a self,
-        bound: &'a Interned<TypeBound>,
+        bound: &'a TypeBound,
         self_ty: Ty,
         ignore_bindings: bool,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
         let mut trait_ref = None;
-        let clause = match bound.as_ref() {
+        let clause = match bound {
             TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@@ -1079,10 +1139,10 @@ impl<'a> TyLoweringContext<'a> {
 
     fn assoc_type_bindings_from_type_bound(
         &'a self,
-        bound: &'a Interned<TypeBound>,
+        bound: &'a TypeBound,
         trait_ref: TraitRef,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
-        let last_segment = match bound.as_ref() {
+        let last_segment = match bound {
             TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
                 path.segments().last()
             }
@@ -1111,7 +1171,7 @@ impl<'a> TyLoweringContext<'a> {
                 // this point (`super_trait_ref.substitution`).
                 let substitution = self.substs_from_path_segment(
                     // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
-                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
                     Some(associated_ty.into()),
                     false, // this is not relevant
                     Some(super_trait_ref.self_type_parameter(Interner)),
@@ -1131,8 +1191,8 @@ impl<'a> TyLoweringContext<'a> {
                 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
-                if let Some(type_ref) = &binding.type_ref {
-                    match (type_ref, &self.impl_trait_mode) {
+                if let Some(type_ref) = binding.type_ref {
+                    match (&self.types_map[type_ref], &self.impl_trait_mode) {
                         (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
                         (
                             _,
@@ -1179,6 +1239,8 @@ impl<'a> TyLoweringContext<'a> {
                                 let mut ext = TyLoweringContext::new_maybe_unowned(
                                     self.db,
                                     self.resolver,
+                                    self.types_map,
+                                    self.types_source_map,
                                     self.owner,
                                 )
                                 .with_type_param_mode(self.type_param_mode);
@@ -1216,7 +1278,7 @@ impl<'a> TyLoweringContext<'a> {
             })
     }
 
-    fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
+    fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty {
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
         // order but should be in the same order for the same set but possibly different order of
@@ -1314,7 +1376,7 @@ impl<'a> TyLoweringContext<'a> {
         }
     }
 
-    fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
+    fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait {
         cov_mark::hit!(lower_rpit);
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
@@ -1366,6 +1428,17 @@ impl<'a> TyLoweringContext<'a> {
             None => error_lifetime(),
         }
     }
+
+    // FIXME: This does not handle macros!
+    fn count_impl_traits(&self, type_ref: TypeRefId) -> usize {
+        let mut count = 0;
+        TypeRef::walk(type_ref, self.types_map, &mut |type_ref| {
+            if matches!(type_ref, TypeRef::ImplTrait(_)) {
+                count += 1;
+            }
+        });
+        count
+    }
 }
 
 /// Build the signature of a callable item (function, struct or enum variant).
@@ -1386,17 +1459,6 @@ pub fn associated_type_shorthand_candidates<R>(
     named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
 }
 
-// FIXME: This does not handle macros!
-fn count_impl_traits(type_ref: &TypeRef) -> usize {
-    let mut count = 0;
-    type_ref.walk(&mut |type_ref| {
-        if matches!(type_ref, TypeRef::ImplTrait(_)) {
-            count += 1;
-        }
-    });
-    count
-}
-
 fn named_associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     // If the type parameter is defined in an impl and we're in a method, there
@@ -1500,10 +1562,10 @@ pub(crate) fn field_types_query(
     };
     let generics = generics(db.upcast(), def);
     let mut res = ArenaMap::default();
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
+        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
     }
     Arc::new(res)
 }
@@ -1523,38 +1585,38 @@ pub(crate) fn generic_predicates_for_param_query(
     assoc_name: Option<Name>,
 ) -> GenericPredicates {
     let resolver = def.resolver(db.upcast());
-    let ctx = if let GenericDefId::FunctionId(_) = def {
-        TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = if let GenericDefId::FunctionId(_) = def {
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
             .with_type_param_mode(ParamLoweringMode::Variable)
     } else {
-        TyLoweringContext::new(db, &resolver, def.into())
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_type_param_mode(ParamLoweringMode::Variable)
     };
     let generics = generics(db.upcast(), def);
 
     // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |(pred, &def): &(&_, _)| match pred {
+    let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred {
         WherePredicate::ForLifetime { target, bound, .. }
         | WherePredicate::TypeBound { target, bound, .. } => {
             let invalid_target = match target {
                 WherePredicateTypeTarget::TypeRef(type_ref) => {
-                    ctx.lower_ty_only_param(type_ref) != Some(param_id)
+                    ctx.lower_ty_only_param(*type_ref) != Some(param_id)
                 }
                 &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
-                    let target_id = TypeOrConstParamId { parent: def, local_id };
+                    let target_id = TypeOrConstParamId { parent: *def, local_id };
                     target_id != param_id
                 }
             };
             if invalid_target {
                 // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
-                if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound {
-                    ctx.lower_where_predicate(pred, &def, true).for_each(drop);
+                if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
+                    ctx.lower_where_predicate(pred, def, true).for_each(drop);
                 }
                 return false;
             }
 
-            match &**bound {
+            match bound {
                 TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
                     // Only lower the bound if the trait could possibly define the associated
                     // type we're looking for.
@@ -1577,13 +1639,15 @@ pub(crate) fn generic_predicates_for_param_query(
         }
         WherePredicate::Lifetime { .. } => false,
     };
-    let mut predicates: Vec<_> = resolver
-        .where_predicates_in_scope()
-        .filter(predicate)
-        .flat_map(|(pred, def)| {
-            ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
-        })
-        .collect();
+    let mut predicates = Vec::new();
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        predicates.extend(
+            params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| {
+                ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
+            }),
+        );
+    }
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
     if !subst.is_empty(Interner) {
@@ -1630,23 +1694,27 @@ pub(crate) fn trait_environment_query(
     def: GenericDefId,
 ) -> Arc<TraitEnvironment> {
     let resolver = def.resolver(db.upcast());
-    let ctx = if let GenericDefId::FunctionId(_) = def {
-        TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = if let GenericDefId::FunctionId(_) = def {
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_impl_trait_mode(ImplTraitLoweringMode::Param)
             .with_type_param_mode(ParamLoweringMode::Placeholder)
     } else {
-        TyLoweringContext::new(db, &resolver, def.into())
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_type_param_mode(ParamLoweringMode::Placeholder)
     };
     let mut traits_in_scope = Vec::new();
     let mut clauses = Vec::new();
-    for (pred, def) in resolver.where_predicates_in_scope() {
-        for pred in ctx.lower_where_predicate(pred, def, false) {
-            if let WhereClause::Implemented(tr) = &pred.skip_binders() {
-                traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        for pred in params.where_predicates() {
+            for pred in ctx.lower_where_predicate(pred, def, false) {
+                if let WhereClause::Implemented(tr) = pred.skip_binders() {
+                    traits_in_scope
+                        .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
+                }
+                let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
+                clauses.push(program_clause.into_from_env_clause(Interner));
             }
-            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
-            clauses.push(program_clause.into_from_env_clause(Interner));
         }
     }
 
@@ -1725,18 +1793,20 @@ where
         }
         _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
     };
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
         .with_impl_trait_mode(impl_trait_lowering)
         .with_type_param_mode(param_lowering);
     let generics = generics(db.upcast(), def);
 
-    let mut predicates = resolver
-        .where_predicates_in_scope()
-        .filter(|(pred, def)| filter(pred, def))
-        .flat_map(|(pred, def)| {
-            ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
-        })
-        .collect::<Vec<_>>();
+    let mut predicates = Vec::new();
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map(
+            |pred| {
+                ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
+            },
+        ));
+    }
 
     if generics.len() > 0 {
         let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@@ -1812,18 +1882,19 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
     let resolver = def.resolver(db.upcast());
     let parent_start_idx = generic_params.len_self();
 
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
-        |(idx, (id, p))| {
+    GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
+        |(idx, ((id, p), types_map))| {
+            ctx.types_map = types_map;
             match p {
                 GenericParamDataRef::TypeParamData(p) => {
                     let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
                         // Each default can only refer to previous parameters.
                         // Type variable default referring to parameter coming
                         // after it is forbidden (FIXME: report diagnostic)
-                        fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx)
+                        fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
                     });
                     crate::make_binders(db, &generic_params, ty.cast(Interner))
                 }
@@ -1835,7 +1906,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
                     let mut val = p.default.as_ref().map_or_else(
                         || unknown_const_as_generic(db.const_param_ty(id)),
                         |c| {
-                            let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+                            let c = ctx.lower_const(c, ctx.lower_ty(p.ty));
                             c.cast(Interner)
                         },
                     );
@@ -1875,14 +1946,14 @@ pub(crate) fn generic_defaults_recover(
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
-    let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
+    let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let ret = ctx_ret.lower_ty(&data.ret_type);
+    let ret = ctx_ret.lower_ty(data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let sig = CallableSig::from_params_and_return(
         params,
@@ -1911,28 +1982,33 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
     let data = db.const_data(def);
     let generics = generics(db.upcast(), def.into());
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
 
-    make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
+    make_binders(db, &generics, ctx.lower_ty(data.type_ref))
 }
 
 /// Build the declared type of a static.
 fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
     let data = db.static_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into());
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into());
 
-    Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
+    Binders::empty(Interner, ctx.lower_ty(data.type_ref))
 }
 
 fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
     let struct_data = db.struct_data(def);
     let fields = struct_data.variant_data.fields();
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
-        .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        struct_data.variant_data.types_map(),
+        AdtId::from(def).into(),
+    )
+    .with_type_param_mode(ParamLoweringMode::Variable);
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
     Binders::new(
         binders,
@@ -1962,9 +2038,14 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let var_data = db.enum_variant_data(def);
     let fields = var_data.variant_data.fields();
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
-        .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        var_data.variant_data.types_map(),
+        DefWithBodyId::VariantId(def).into(),
+    )
+    .with_type_param_mode(ParamLoweringMode::Variable);
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
     let (ret, binders) =
         type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
     Binders::new(
@@ -2005,15 +2086,17 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
 fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     let generics = generics(db.upcast(), t.into());
     let resolver = t.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, t.into())
+    let type_alias_data = db.type_alias_data(t);
+    let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let type_alias_data = db.type_alias_data(t);
     let inner = if type_alias_data.is_extern {
         TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
     } else {
-        let type_ref = &type_alias_data.type_ref;
-        ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error))
+        type_alias_data
+            .type_ref
+            .map(|type_ref| ctx.lower_ty(type_ref))
+            .unwrap_or_else(|| TyKind::Error.intern(Interner))
     };
     make_binders(db, &generics, inner)
 }
@@ -2086,9 +2169,9 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
     let generics = generics(db.upcast(), impl_id.into());
-    let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
+    make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
 }
 
 // returns None if def is a type arg
@@ -2096,13 +2179,13 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T
     let parent_data = db.generic_params(def.parent());
     let data = &parent_data[def.local_id()];
     let resolver = def.parent().resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.parent().into());
+    let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
     match data {
         TypeOrConstParamData::TypeParamData(_) => {
             never!();
             Ty::new(Interner, TyKind::Error)
         }
-        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
+        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
     }
 }
 
@@ -2118,7 +2201,7 @@ pub(crate) fn impl_self_ty_recover(
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
     let target_trait = impl_data.target_trait.as_ref()?;
@@ -2132,10 +2215,10 @@ pub(crate) fn return_type_impl_traits(
     // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let _ret = ctx_ret.lower_ty(&data.ret_type);
+    let _ret = ctx_ret.lower_ty(data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let return_type_impl_traits = ImplTraits {
         impl_traits: match ctx_ret.impl_trait_mode {
@@ -2156,10 +2239,10 @@ pub(crate) fn type_alias_impl_traits(
 ) -> Option<Arc<Binders<ImplTraits>>> {
     let data = db.type_alias_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    if let Some(type_ref) = &data.type_ref {
+    if let Some(type_ref) = data.type_ref {
         let _ty = ctx.lower_ty(type_ref);
     }
     let type_alias_impl_traits = ImplTraits {
@@ -2191,7 +2274,8 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
     kind_id: GenericParamId,
     arg: &'a GenericArg,
     this: &mut T,
-    for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
+    types_map: &TypesMap,
+    for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
     for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
     for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
 ) -> crate::GenericArg {
@@ -2204,7 +2288,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
     };
     match (arg, kind) {
-        (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
+        (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
         (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
         (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
             for_lifetime(this, lifetime_ref).cast(Interner)
@@ -2215,7 +2299,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             // We want to recover simple idents, which parser detects them
             // as types. Maybe here is not the best place to do it, but
             // it works.
-            if let TypeRef::Path(p) = t {
+            if let TypeRef::Path(p) = &types_map[*t] {
                 if let Some(p) = p.mod_path() {
                     if p.kind == PathKind::Plain {
                         if let [n] = p.segments() {
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 b7b565dece8..e73b9dc27d1 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
@@ -2849,7 +2849,8 @@ impl Evaluator<'_> {
                         }
                         let layout = self.layout_adt(id.0, subst.clone())?;
                         match data.variant_data.as_ref() {
-                            VariantData::Record(fields) | VariantData::Tuple(fields) => {
+                            VariantData::Record { fields, .. }
+                            | VariantData::Tuple { fields, .. } => {
                                 let field_types = self.db.field_types(s.into());
                                 for (field, _) in fields.iter() {
                                     let offset = layout
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 99a4e112f8b..c4e06400510 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
@@ -14,6 +14,7 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     path::Path,
     resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
+    type_ref::TypesMap,
     AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
     Lookup, TraitId, TupleId, TypeOrConstParamId,
 };
@@ -28,7 +29,7 @@ use triomphe::Arc;
 use crate::{
     consteval::ConstEvalError,
     db::{HirDatabase, InternedClosure},
-    display::HirDisplay,
+    display::{hir_display_with_types_map, HirDisplay},
     error_lifetime,
     generics::generics,
     infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@@ -247,8 +248,15 @@ impl From<LayoutError> for MirLowerError {
 }
 
 impl MirLowerError {
-    fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
-        Self::UnresolvedName(p.display(db, edition).to_string())
+    fn unresolved_path(
+        db: &dyn HirDatabase,
+        p: &Path,
+        edition: Edition,
+        types_map: &TypesMap,
+    ) -> Self {
+        Self::UnresolvedName(
+            hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
+        )
     }
 }
 
@@ -451,7 +459,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         .resolver
                         .resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene)
                         .ok_or_else(|| {
-                            MirLowerError::unresolved_path(self.db, p, self.edition())
+                            MirLowerError::unresolved_path(
+                                self.db,
+                                p,
+                                self.edition(),
+                                &self.body.types,
+                            )
                         })?;
                     self.resolver.reset_to_guard(resolver_guard);
                     result
@@ -824,7 +837,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, self.edition()).to_string(),
+                            hir_display_with_types_map(&**p, &self.body.types)
+                                .display(self.db, self.edition())
+                                .to_string(),
                         ),
                         None => MirLowerError::RecordLiteralWithoutPath,
                     })?;
@@ -1359,10 +1374,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 };
                 let edition = self.edition();
                 let unresolved_name =
-                    || MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
+                    || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
                 let pr = self
                     .resolver
-                    .resolve_path_in_value_ns(self.db.upcast(), c.as_ref(), HygieneId::ROOT)
+                    .resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
                     .ok_or_else(unresolved_name)?;
                 match pr {
                     ResolveValueResult::ValueNs(v, _) => {
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 d985a6451b7..2ffea34c85a 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
@@ -349,8 +349,9 @@ impl MirLowerCtx<'_> {
                     mode,
                 )?,
                 None => {
-                    let unresolved_name =
-                        || MirLowerError::unresolved_path(self.db, p, self.edition());
+                    let unresolved_name = || {
+                        MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
+                    };
                     let hygiene = self.body.pat_path_hygiene(pattern);
                     let pr = self
                         .resolver
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 98e8feceb06..0a436ff2b41 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -163,10 +163,12 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
                 let is_trait = match target {
-                    WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
-                        TypeRef::Path(p) => p.is_self_type(),
-                        _ => false,
-                    },
+                    WherePredicateTypeTarget::TypeRef(type_ref) => {
+                        match &generic_params.types_map[*type_ref] {
+                            TypeRef::Path(p) => p.is_self_type(),
+                            _ => false,
+                        }
+                    }
                     WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
                         Some(*local_id) == trait_self
                     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index cb5f5b06aef..22760c41aae 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -4,35 +4,43 @@
 //!
 //! But we need this for at least LRU caching at the query level.
 pub use hir_def::db::{
-    AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BodyQuery, BodyWithSourceMapQuery,
-    ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, CrateLangItemsQuery,
-    CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage,
-    EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
-    FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery,
-    FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery,
-    ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase,
-    InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery,
-    InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query,
-    InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery,
-    InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
-    InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery,
-    StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery,
-    TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
+    AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
+    BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
+    CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
+    DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
+    ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
+    FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
+    FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
+    GenericParamsWithSourceMapQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery,
+    IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
+    InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
+    InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
+    InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
+    InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
+    InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
+    MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
+    StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataWithDiagnosticsQuery,
+    TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
 };
 pub use hir_expand::db::{
     AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
     ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
-    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery,
+    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
+    RealSpanMapQuery,
 };
 pub use hir_ty::db::{
     AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
     CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
-    ConstParamTyQuery, FieldTypesQuery, FnDefDatumQuery, FnDefVarianceQuery, GenericDefaultsQuery,
-    GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage,
-    ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery,
+    ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
+    FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
+    GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
+    ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
     InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
     InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
-    InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, MirBodyQuery, ProgramClausesForChalkEnvQuery,
-    ReturnTypeImplTraitsQuery, TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery,
-    TraitImplsInBlockQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TyQuery, ValueTyQuery,
+    InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
+    MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
+    MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
+    TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
+    TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
+    TypeAliasImplTraitsQuery, ValueTyQuery,
 };
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index c2b2fbef751..9275f45d881 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -12,12 +12,11 @@ use hir_def::{
 };
 use hir_ty::{
     display::{
-        write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
-        HirFormatter, SizedByDefault,
+        hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
+        HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
     },
     AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
 };
-use intern::Interned;
 use itertools::Itertools;
 
 use crate::{
@@ -113,7 +112,7 @@ impl HirDisplay for Function {
             f.write_str(&pat_str)?;
 
             f.write_str(": ")?;
-            type_ref.hir_fmt(f)?;
+            type_ref.hir_fmt(f, &data.types_map)?;
         }
 
         if data.is_varargs() {
@@ -129,28 +128,30 @@ impl HirDisplay for Function {
         // Use ugly pattern match to strip the Future trait.
         // Better way?
         let ret_type = if !data.is_async() {
-            &data.ret_type
+            Some(data.ret_type)
         } else {
-            match &*data.ret_type {
-                TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
-                    TypeBound::Path(path, _) => {
-                        path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
+            match &data.types_map[data.ret_type] {
+                TypeRef::ImplTrait(bounds) => match &bounds[0] {
+                    TypeBound::Path(path, _) => Some(
+                        *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
                             [0]
                         .type_ref
                         .as_ref()
-                        .unwrap()
-                    }
-                    _ => &TypeRef::Error,
+                        .unwrap(),
+                    ),
+                    _ => None,
                 },
-                _ => &TypeRef::Error,
+                _ => None,
             }
         };
 
-        match ret_type {
-            TypeRef::Tuple(tup) if tup.is_empty() => {}
-            ty => {
-                f.write_str(" -> ")?;
-                ty.hir_fmt(f)?;
+        if let Some(ret_type) = ret_type {
+            match &data.types_map[ret_type] {
+                TypeRef::Tuple(tup) if tup.is_empty() => {}
+                _ => {
+                    f.write_str(" -> ")?;
+                    ret_type.hir_fmt(f, &data.types_map)?;
+                }
             }
         }
 
@@ -192,23 +193,23 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
 impl HirDisplay for SelfParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         let data = f.db.function_data(self.func);
-        let param = data.params.first().unwrap();
-        match &**param {
+        let param = *data.params.first().unwrap();
+        match &data.types_map[param] {
             TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
-            TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
+            TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
             {
                 f.write_char('&')?;
-                if let Some(lifetime) = lifetime {
+                if let Some(lifetime) = &ref_.lifetime {
                     write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
-                if let hir_def::type_ref::Mutability::Mut = mut_ {
+                if let hir_def::type_ref::Mutability::Mut = ref_.mutability {
                     f.write_str("mut ")?;
                 }
                 f.write_str("self")
             }
-            ty => {
+            _ => {
                 f.write_str("self: ")?;
-                ty.hir_fmt(f)
+                param.hir_fmt(f, &data.types_map)
             }
         }
     }
@@ -393,7 +394,7 @@ impl HirDisplay for Variant {
         let data = self.variant_data(f.db);
         match &*data {
             VariantData::Unit => {}
-            VariantData::Tuple(fields) => {
+            VariantData::Tuple { fields, types_map } => {
                 f.write_char('(')?;
                 let mut first = true;
                 for (_, field) in fields.iter() {
@@ -403,11 +404,11 @@ impl HirDisplay for Variant {
                         f.write_str(", ")?;
                     }
                     // Enum variant fields must be pub.
-                    field.type_ref.hir_fmt(f)?;
+                    field.type_ref.hir_fmt(f, types_map)?;
                 }
                 f.write_char(')')?;
             }
-            VariantData::Record(_) => {
+            VariantData::Record { .. } => {
                 if let Some(limit) = f.entity_limit {
                     write_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
@@ -579,13 +580,13 @@ fn write_generic_params(
                     write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                     if let Some(default) = &ty.default {
                         f.write_str(" = ")?;
-                        default.hir_fmt(f)?;
+                        default.hir_fmt(f, &params.types_map)?;
                     }
                 }
                 TypeOrConstParamData::ConstParamData(c) => {
                     delim(f)?;
                     write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
-                    c.ty.hir_fmt(f)?;
+                    c.ty.hir_fmt(f, &params.types_map)?;
 
                     if let Some(default) = &c.default {
                         f.write_str(" = ")?;
@@ -615,7 +616,7 @@ fn write_where_clause(
     Ok(true)
 }
 
-fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
+fn has_disaplayable_predicates(params: &GenericParams) -> bool {
     params.where_predicates().any(|pred| {
         !matches!(
             pred,
@@ -626,21 +627,20 @@ fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
 }
 
 fn write_where_predicates(
-    params: &Interned<GenericParams>,
+    params: &GenericParams,
     f: &mut HirFormatter<'_>,
 ) -> Result<(), HirDisplayError> {
     use WherePredicate::*;
 
     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
-    let is_unnamed_type_target =
-        |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
-            matches!(target,
-                WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
-            )
-        };
+    let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| {
+        matches!(target,
+            WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
+        )
+    };
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
-        WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
+        WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, &params.types_map),
         WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
             Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
             None => f.write_str("{unnamed}"),
@@ -668,7 +668,7 @@ fn write_where_predicates(
             TypeBound { target, bound } => {
                 write_target(target, f)?;
                 f.write_str(": ")?;
-                bound.hir_fmt(f)?;
+                bound.hir_fmt(f, &params.types_map)?;
             }
             Lifetime { target, bound } => {
                 let target = target.name.display(f.db.upcast(), f.edition());
@@ -681,14 +681,16 @@ fn write_where_predicates(
                 write!(f, "for<{lifetimes}> ")?;
                 write_target(target, f)?;
                 f.write_str(": ")?;
-                bound.hir_fmt(f)?;
+                bound.hir_fmt(f, &params.types_map)?;
             }
         }
 
         while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
             f.write_str(" + ")?;
             match nxt {
-                TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
+                TypeBound { bound, .. } | ForLifetime { bound, .. } => {
+                    bound.hir_fmt(f, &params.types_map)?
+                }
                 Lifetime { bound, .. } => {
                     write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
                 }
@@ -716,7 +718,7 @@ impl HirDisplay for Const {
             Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
             None => f.write_str("_: ")?,
         }
-        data.type_ref.hir_fmt(f)?;
+        data.type_ref.hir_fmt(f, &data.types_map)?;
         Ok(())
     }
 }
@@ -730,7 +732,7 @@ impl HirDisplay for Static {
             f.write_str("mut ")?;
         }
         write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
-        data.type_ref.hir_fmt(f)?;
+        data.type_ref.hir_fmt(f, &data.types_map)?;
         Ok(())
     }
 }
@@ -813,11 +815,14 @@ impl HirDisplay for TypeAlias {
         write_generic_params(def_id, f)?;
         if !data.bounds.is_empty() {
             f.write_str(": ")?;
-            f.write_joined(data.bounds.iter(), " + ")?;
+            f.write_joined(
+                data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
+                " + ",
+            )?;
         }
-        if let Some(ty) = &data.type_ref {
+        if let Some(ty) = data.type_ref {
             f.write_str(" = ")?;
-            ty.hir_fmt(f)?;
+            ty.hir_fmt(f, &data.types_map)?;
         }
         write_where_clause(def_id, f)?;
         Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index f9b51b65709..88eb3b127e0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -2424,8 +2424,8 @@ impl SelfParam {
         func_data
             .params
             .first()
-            .map(|param| match &**param {
-                TypeRef::Reference(.., mutability) => match mutability {
+            .map(|&param| match &func_data.types_map[param] {
+                TypeRef::Reference(ref_) => match ref_.mutability {
                     hir_def::type_ref::Mutability::Shared => Access::Shared,
                     hir_def::type_ref::Mutability::Mut => Access::Exclusive,
                 },
@@ -2751,10 +2751,6 @@ impl TypeAlias {
         Module { id: self.id.module(db.upcast()) }
     }
 
-    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
-        db.type_alias_data(self.id).type_ref.as_deref().cloned()
-    }
-
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         Type::from_def(db, self.id)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 6e298d95862..feb9a344d8a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -16,7 +16,7 @@ use hir_def::{
     nameres::{MacroSubNs, ModuleOrigin},
     path::ModPath,
     resolver::{self, HasResolver, Resolver, TypeNs},
-    type_ref::Mutability,
+    type_ref::{Mutability, TypesMap, TypesSourceMap},
     AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
 };
 use hir_expand::{
@@ -1269,19 +1269,28 @@ impl<'db> SemanticsImpl<'db> {
 
     pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
         let analyze = self.analyze(ty.syntax())?;
-        let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
+        let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
         let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
             self.db,
             &analyze.resolver,
+            &types_map,
+            None,
             analyze.resolver.type_owner(),
         )
-        .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
+        .lower_ty(type_ref);
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
     pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
         let analyze = self.analyze(path.syntax())?;
-        let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
         let hir_path = Path::from_src(&ctx, path.clone())?;
         match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
             TypeNs::TraitId(id) => Some(Trait { id }),
@@ -1963,13 +1972,17 @@ impl SemanticsScope<'_> {
     /// Resolve a path as-if it was written at the given scope. This is
     /// necessary a heuristic, as it doesn't take hygiene into account.
     pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
-        let ctx = LowerCtx::new(self.db.upcast(), self.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
         let path = Path::from_src(&ctx, ast_path.clone())?;
         resolve_hir_path(
             self.db,
             &self.resolver,
             &path,
             name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())),
+            &types_map,
         )
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index f5b57d57dfc..8d6e228e14c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -24,7 +24,7 @@ use hir_def::{
     nameres::MacroSubNs,
     path::{ModPath, Path, PathKind},
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
-    type_ref::Mutability,
+    type_ref::{Mutability, TypesMap, TypesSourceMap},
     AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
     LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
 };
@@ -614,7 +614,10 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<Macro> {
-        let ctx = LowerCtx::new(db.upcast(), macro_call.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
         let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
         self.resolver
             .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
@@ -632,7 +635,7 @@ impl SourceAnalyzer {
             Pat::Path(path) => path,
             _ => return None,
         };
-        let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT)?;
+        let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
         match res {
             PathResolution::Def(def) => Some(def),
             _ => None,
@@ -726,14 +729,16 @@ impl SourceAnalyzer {
             return resolved;
         }
 
-        let ctx = LowerCtx::new(db.upcast(), self.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
         let hir_path = Path::from_src(&ctx, path.clone())?;
 
         // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
         // trying to resolve foo::bar.
         if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
             if use_tree.coloncolon_token().is_some() {
-                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
+                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map);
             }
         }
 
@@ -750,7 +755,7 @@ impl SourceAnalyzer {
         // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
         // trying to resolve foo::bar.
         if path.parent_path().is_some() {
-            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
+            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
                 None if meta_path.is_some() => {
                     path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
                         ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
@@ -821,7 +826,7 @@ impl SourceAnalyzer {
             };
         }
         if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
-            resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
+            resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map)
         } else {
             resolve_hir_path_(
                 db,
@@ -829,6 +834,7 @@ impl SourceAnalyzer {
                 &hir_path,
                 prefer_value_ns,
                 name_hygiene(db, InFile::new(self.file_id, path.syntax())),
+                &types_map,
             )
         }
     }
@@ -1156,8 +1162,9 @@ pub(crate) fn resolve_hir_path(
     resolver: &Resolver,
     path: &Path,
     hygiene: HygieneId,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
-    resolve_hir_path_(db, resolver, path, false, hygiene)
+    resolve_hir_path_(db, resolver, path, false, hygiene, types_map)
 }
 
 #[inline]
@@ -1178,13 +1185,19 @@ fn resolve_hir_path_(
     path: &Path,
     prefer_value_ns: bool,
     hygiene: HygieneId,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
     let types = || {
         let (ty, unresolved) = match path.type_anchor() {
             Some(type_ref) => {
-                let (_, res) =
-                    TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
-                        .lower_ty_ext(type_ref);
+                let (_, res) = TyLoweringContext::new_maybe_unowned(
+                    db,
+                    resolver,
+                    types_map,
+                    None,
+                    resolver.type_owner(),
+                )
+                .lower_ty_ext(type_ref);
                 res.map(|ty_ns| (ty_ns, path.segments().first()))
             }
             None => {
@@ -1305,13 +1318,19 @@ fn resolve_hir_path_qualifier(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
     (|| {
         let (ty, unresolved) = match path.type_anchor() {
             Some(type_ref) => {
-                let (_, res) =
-                    TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
-                        .lower_ty_ext(type_ref);
+                let (_, res) = TyLoweringContext::new_maybe_unowned(
+                    db,
+                    resolver,
+                    types_map,
+                    None,
+                    resolver.type_owner(),
+                )
+                .lower_ty_ext(type_ref);
                 res.map(|ty_ns| (ty_ns, path.segments().first()))
             }
             None => {
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index e2ad0081e3a..f8416f86bf9 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -8,7 +8,10 @@ use hir_def::{
     TraitId,
 };
 use hir_expand::HirFileId;
-use hir_ty::{db::HirDatabase, display::HirDisplay};
+use hir_ty::{
+    db::HirDatabase,
+    display::{hir_display_with_types_map, HirDisplay},
+};
 use span::Edition;
 use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
 
@@ -214,7 +217,11 @@ 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(impl_data.self_ty.display(self.db, self.edition).to_smolstr());
+        let impl_name = Some(
+            hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
+                .display(self.db, self.edition)
+                .to_smolstr(),
+        );
         self.with_container_name(impl_name, |s| {
             for &assoc_item_id in impl_data.items.iter() {
                 s.push_assoc_item(assoc_item_id)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 7474d7bc54d..35e3a8d9bf7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -100,16 +100,19 @@ impl RootDatabase {
             hir::db::ConstEvalQuery
             hir::db::ConstEvalStaticQuery
             hir::db::ConstParamTyQuery
+            hir::db::DynCompatibilityOfTraitQuery
             hir::db::FieldTypesQuery
             hir::db::FnDefDatumQuery
             hir::db::FnDefVarianceQuery
             hir::db::GenericDefaultsQuery
             hir::db::GenericPredicatesForParamQuery
             hir::db::GenericPredicatesQuery
+            hir::db::GenericPredicatesWithoutParentQuery
             hir::db::ImplDatumQuery
             hir::db::ImplSelfTyQuery
             hir::db::ImplTraitQuery
             hir::db::IncoherentInherentImplCratesQuery
+            hir::db::InferQuery
             hir::db::InherentImplsInBlockQuery
             hir::db::InherentImplsInCrateQuery
             hir::db::InternCallableDefQuery
@@ -119,7 +122,12 @@ impl RootDatabase {
             hir::db::InternLifetimeParamIdQuery
             hir::db::InternTypeOrConstParamIdQuery
             hir::db::LayoutOfAdtQuery
+            hir::db::LayoutOfTyQuery
+            hir::db::LookupImplMethodQuery
+            hir::db::MirBodyForClosureQuery
             hir::db::MirBodyQuery
+            hir::db::MonomorphizedMirBodyForClosureQuery
+            hir::db::MonomorphizedMirBodyQuery
             hir::db::ProgramClausesForChalkEnvQuery
             hir::db::ReturnTypeImplTraitsQuery
             hir::db::TargetDataLayoutQuery
@@ -128,13 +136,16 @@ impl RootDatabase {
             hir::db::TraitImplsInBlockQuery
             hir::db::TraitImplsInCrateQuery
             hir::db::TraitImplsInDepsQuery
+            hir::db::TraitSolveQuery
             hir::db::TyQuery
+            hir::db::TypeAliasImplTraitsQuery
             hir::db::ValueTyQuery
 
             // DefDatabase
             hir::db::AttrsQuery
             hir::db::BlockDefMapQuery
             hir::db::BlockItemTreeQuery
+            hir::db::BlockItemTreeWithSourceMapQuery
             hir::db::BodyQuery
             hir::db::BodyWithSourceMapQuery
             hir::db::ConstDataQuery
@@ -145,17 +156,21 @@ impl RootDatabase {
             hir::db::CrateSupportsNoStdQuery
             hir::db::EnumDataQuery
             hir::db::EnumVariantDataWithDiagnosticsQuery
+            hir::db::ExpandProcAttrMacrosQuery
             hir::db::ExprScopesQuery
             hir::db::ExternCrateDeclDataQuery
             hir::db::FieldVisibilitiesQuery
             hir::db::FieldsAttrsQuery
             hir::db::FieldsAttrsSourceMapQuery
             hir::db::FileItemTreeQuery
+            hir::db::FileItemTreeWithSourceMapQuery
             hir::db::FunctionDataQuery
             hir::db::FunctionVisibilityQuery
             hir::db::GenericParamsQuery
+            hir::db::GenericParamsWithSourceMapQuery
             hir::db::ImplDataWithDiagnosticsQuery
             hir::db::ImportMapQuery
+            hir::db::IncludeMacroInvocQuery
             hir::db::InternAnonymousConstQuery
             hir::db::InternBlockQuery
             hir::db::InternConstQuery
@@ -177,7 +192,9 @@ impl RootDatabase {
             hir::db::InternUseQuery
             hir::db::LangItemQuery
             hir::db::Macro2DataQuery
+            hir::db::MacroDefQuery
             hir::db::MacroRulesDataQuery
+            hir::db::NotableTraitsInDepsQuery
             hir::db::ProcMacroDataQuery
             hir::db::StaticDataQuery
             hir::db::StructDataWithDiagnosticsQuery
@@ -212,6 +229,7 @@ impl RootDatabase {
             hir::db::MacroArgQuery
             hir::db::ParseMacroExpansionErrorQuery
             hir::db::ParseMacroExpansionQuery
+            hir::db::ProcMacroSpanQuery
             hir::db::ProcMacrosQuery
             hir::db::RealSpanMapQuery
 
@@ -220,7 +238,9 @@ impl RootDatabase {
 
             // SourceDatabase
             base_db::ParseQuery
+            base_db::ParseErrorsQuery
             base_db::CrateGraphQuery
+            base_db::CrateWorkspaceDataQuery
 
             // SourceDatabaseExt
             base_db::FileTextQuery
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 1c42d198e55..04c2153abf4 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -10,6 +10,7 @@ pub mod non_empty_vec;
 pub mod panic_context;
 pub mod process;
 pub mod rand;
+pub mod thin_vec;
 pub mod thread;
 
 pub use always_assert::{always, never};
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
new file mode 100644
index 00000000000..700220e1d3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
@@ -0,0 +1,472 @@
+use std::alloc::{dealloc, handle_alloc_error, Layout};
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::ptr::{addr_of_mut, slice_from_raw_parts_mut, NonNull};
+
+/// A type that is functionally equivalent to `(Header, Box<[Item]>)`,
+/// but all data is stored in one heap allocation and the pointer is thin,
+/// so the whole thing's size is like a pointer.
+pub struct ThinVecWithHeader<Header, Item> {
+    /// INVARIANT: Points to a valid heap allocation that contains `ThinVecInner<Header>`,
+    /// followed by (suitably aligned) `len` `Item`s.
+    ptr: NonNull<ThinVecInner<Header>>,
+    _marker: PhantomData<(Header, Box<[Item]>)>,
+}
+
+// SAFETY: We essentially own both the header and the items.
+unsafe impl<Header: Send, Item: Send> Send for ThinVecWithHeader<Header, Item> {}
+unsafe impl<Header: Sync, Item: Sync> Sync for ThinVecWithHeader<Header, Item> {}
+
+#[derive(Clone)]
+struct ThinVecInner<Header> {
+    header: Header,
+    len: usize,
+}
+
+impl<Header, Item> ThinVecWithHeader<Header, Item> {
+    /// # Safety
+    ///
+    /// The iterator must produce `len` elements.
+    #[inline]
+    unsafe fn from_trusted_len_iter(
+        header: Header,
+        len: usize,
+        items: impl Iterator<Item = Item>,
+    ) -> Self {
+        let (ptr, layout, items_offset) = Self::allocate(len);
+
+        struct DeallocGuard(*mut u8, Layout);
+        impl Drop for DeallocGuard {
+            fn drop(&mut self) {
+                // SAFETY: We allocated this above.
+                unsafe {
+                    dealloc(self.0, self.1);
+                }
+            }
+        }
+        let _dealloc_guard = DeallocGuard(ptr.as_ptr().cast::<u8>(), layout);
+
+        // INVARIANT: Between `0..1` there are only initialized items.
+        struct ItemsGuard<Item>(*mut Item, *mut Item);
+        impl<Item> Drop for ItemsGuard<Item> {
+            fn drop(&mut self) {
+                // SAFETY: Our invariant.
+                unsafe {
+                    slice_from_raw_parts_mut(self.0, self.1.offset_from(self.0) as usize)
+                        .drop_in_place();
+                }
+            }
+        }
+
+        // SAFETY: We allocated enough space.
+        let mut items_ptr = unsafe { ptr.as_ptr().byte_add(items_offset).cast::<Item>() };
+        // INVARIANT: There are zero elements in this range.
+        let mut items_guard = ItemsGuard(items_ptr, items_ptr);
+        items.for_each(|item| {
+            // SAFETY: Our precondition guarantee we won't get more than `len` items, and we allocated
+            // enough space for `len` items.
+            unsafe {
+                items_ptr.write(item);
+                items_ptr = items_ptr.add(1);
+            }
+            // INVARIANT: We just initialized this item.
+            items_guard.1 = items_ptr;
+        });
+
+        // SAFETY: We allocated enough space.
+        unsafe {
+            ptr.write(ThinVecInner { header, len });
+        }
+
+        std::mem::forget(items_guard);
+
+        std::mem::forget(_dealloc_guard);
+
+        // INVARIANT: We allocated and initialized all fields correctly.
+        Self { ptr, _marker: PhantomData }
+    }
+
+    #[inline]
+    fn allocate(len: usize) -> (NonNull<ThinVecInner<Header>>, Layout, usize) {
+        let (layout, items_offset) = Self::layout(len);
+        // SAFETY: We always have `len`, so our allocation cannot be zero-sized.
+        let ptr = unsafe { std::alloc::alloc(layout).cast::<ThinVecInner<Header>>() };
+        let Some(ptr) = NonNull::<ThinVecInner<Header>>::new(ptr) else {
+            handle_alloc_error(layout);
+        };
+        (ptr, layout, items_offset)
+    }
+
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(header: Header, items: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = Item>,
+    {
+        let items = items.into_iter();
+        // SAFETY: `TrustedLen` guarantees the iterator length is exact.
+        unsafe { Self::from_trusted_len_iter(header, items.len(), items) }
+    }
+
+    #[inline]
+    fn items_offset(&self) -> usize {
+        // SAFETY: We `pad_to_align()` in `layout()`, so at most where accessing past the end of the allocation,
+        // which is allowed.
+        unsafe {
+            Layout::new::<ThinVecInner<Header>>().extend(Layout::new::<Item>()).unwrap_unchecked().1
+        }
+    }
+
+    #[inline]
+    fn header_and_len(&self) -> &ThinVecInner<Header> {
+        // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+        unsafe { &*self.ptr.as_ptr() }
+    }
+
+    #[inline]
+    fn items_ptr(&self) -> *mut [Item] {
+        let len = self.header_and_len().len;
+        // SAFETY: `items_offset()` returns the correct offset of the items, where they are allocated.
+        let ptr = unsafe { self.ptr.as_ptr().byte_add(self.items_offset()).cast::<Item>() };
+        slice_from_raw_parts_mut(ptr, len)
+    }
+
+    #[inline]
+    pub fn header(&self) -> &Header {
+        &self.header_and_len().header
+    }
+
+    #[inline]
+    pub fn header_mut(&mut self) -> &mut Header {
+        // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+        unsafe { &mut *addr_of_mut!((*self.ptr.as_ptr()).header) }
+    }
+
+    #[inline]
+    pub fn items(&self) -> &[Item] {
+        // SAFETY: `items_ptr()` gives a valid pointer.
+        unsafe { &*self.items_ptr() }
+    }
+
+    #[inline]
+    pub fn items_mut(&mut self) -> &mut [Item] {
+        // SAFETY: `items_ptr()` gives a valid pointer.
+        unsafe { &mut *self.items_ptr() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.header_and_len().len
+    }
+
+    #[inline]
+    fn layout(len: usize) -> (Layout, usize) {
+        let (layout, items_offset) = Layout::new::<ThinVecInner<Header>>()
+            .extend(Layout::array::<Item>(len).expect("too big `ThinVec` requested"))
+            .expect("too big `ThinVec` requested");
+        let layout = layout.pad_to_align();
+        (layout, items_offset)
+    }
+}
+
+/// # Safety
+///
+/// The length reported must be exactly the number of items yielded.
+pub unsafe trait TrustedLen: ExactSizeIterator {}
+
+unsafe impl<T> TrustedLen for std::vec::IntoIter<T> {}
+unsafe impl<T> TrustedLen for std::slice::Iter<'_, T> {}
+unsafe impl<'a, T: Clone + 'a, I: TrustedLen<Item = &'a T>> TrustedLen for std::iter::Cloned<I> {}
+unsafe impl<T, I: TrustedLen, F: FnMut(I::Item) -> T> TrustedLen for std::iter::Map<I, F> {}
+unsafe impl<T> TrustedLen for std::vec::Drain<'_, T> {}
+unsafe impl<T, const N: usize> TrustedLen for std::array::IntoIter<T, N> {}
+
+impl<Header: Clone, Item: Clone> Clone for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::from_iter(self.header().clone(), self.items().iter().cloned())
+    }
+}
+
+impl<Header, Item> Drop for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn drop(&mut self) {
+        // This must come before we drop `header`, because after that we cannot make a reference to it in `len()`.
+        let len = self.len();
+
+        // SAFETY: The contents are allocated and initialized.
+        unsafe {
+            addr_of_mut!((*self.ptr.as_ptr()).header).drop_in_place();
+            self.items_ptr().drop_in_place();
+        }
+
+        let (layout, _) = Self::layout(len);
+        // SAFETY: This was allocated in `new()` with the same layout calculation.
+        unsafe {
+            dealloc(self.ptr.as_ptr().cast::<u8>(), layout);
+        }
+    }
+}
+
+impl<Header: fmt::Debug, Item: fmt::Debug> fmt::Debug for ThinVecWithHeader<Header, Item> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ThinVecWithHeader")
+            .field("header", self.header())
+            .field("items", &self.items())
+            .finish()
+    }
+}
+
+impl<Header: PartialEq, Item: PartialEq> PartialEq for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.header() == other.header() && self.items() == other.items()
+    }
+}
+
+impl<Header: Eq, Item: Eq> Eq for ThinVecWithHeader<Header, Item> {}
+
+impl<Header: Hash, Item: Hash> Hash for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.header().hash(state);
+        self.items().hash(state);
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct ThinVec<T>(ThinVecWithHeader<(), T>);
+
+impl<T> ThinVec<T> {
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(values: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = T>,
+    {
+        Self(ThinVecWithHeader::from_iter((), values))
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    #[inline]
+    pub fn iter(&self) -> std::slice::Iter<'_, T> {
+        (**self).iter()
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+        (**self).iter_mut()
+    }
+}
+
+impl<T> Deref for ThinVec<T> {
+    type Target = [T];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.0.items()
+    }
+}
+
+impl<T> DerefMut for ThinVec<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0.items_mut()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a ThinVec<T> {
+    type IntoIter = std::slice::Iter<'a, T>;
+    type Item = &'a T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
+    type IntoIter = std::slice::IterMut<'a, T>;
+    type Item = &'a mut T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for ThinVec<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(&**self).finish()
+    }
+}
+
+/// A [`ThinVec`] that requires no allocation for the empty case.
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct EmptyOptimizedThinVec<T>(Option<ThinVec<T>>);
+
+impl<T> EmptyOptimizedThinVec<T> {
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(values: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = T>,
+    {
+        let values = values.into_iter();
+        if values.len() == 0 {
+            Self::empty()
+        } else {
+            Self(Some(ThinVec::from_iter(values)))
+        }
+    }
+
+    #[inline]
+    pub fn empty() -> Self {
+        Self(None)
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.0.as_ref().map_or(0, ThinVec::len)
+    }
+
+    #[inline]
+    pub fn iter(&self) -> std::slice::Iter<'_, T> {
+        (**self).iter()
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+        (**self).iter_mut()
+    }
+}
+
+impl<T> Default for EmptyOptimizedThinVec<T> {
+    #[inline]
+    fn default() -> Self {
+        Self::empty()
+    }
+}
+
+impl<T> Deref for EmptyOptimizedThinVec<T> {
+    type Target = [T];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.0.as_deref().unwrap_or_default()
+    }
+}
+
+impl<T> DerefMut for EmptyOptimizedThinVec<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0.as_deref_mut().unwrap_or_default()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a EmptyOptimizedThinVec<T> {
+    type IntoIter = std::slice::Iter<'a, T>;
+    type Item = &'a T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut EmptyOptimizedThinVec<T> {
+    type IntoIter = std::slice::IterMut<'a, T>;
+    type Item = &'a mut T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for EmptyOptimizedThinVec<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(&**self).finish()
+    }
+}
+
+/// Syntax:
+///
+/// ```ignore
+/// thin_vec_with_header_struct! {
+///     pub new(pub(crate)) struct MyCoolStruct, MyCoolStructHeader {
+///         pub(crate) variable_length: [Ty],
+///         pub field1: CopyTy,
+///         pub field2: NonCopyTy; ref,
+///     }
+/// }
+/// ```
+#[doc(hidden)]
+#[macro_export]
+macro_rules! thin_vec_with_header_struct_ {
+    (@maybe_ref (ref) $($t:tt)*) => { &$($t)* };
+    (@maybe_ref () $($t:tt)*) => { $($t)* };
+    (
+        $vis:vis new($new_vis:vis) struct $struct:ident, $header:ident {
+            $items_vis:vis $items:ident : [$items_ty:ty],
+            $( $header_var_vis:vis $header_var:ident : $header_var_ty:ty $(; $ref:ident)?, )+
+        }
+    ) => {
+        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+        struct $header {
+            $( $header_var : $header_var_ty, )+
+        }
+
+        #[derive(Clone, Eq, PartialEq, Hash)]
+        $vis struct $struct($crate::thin_vec::ThinVecWithHeader<$header, $items_ty>);
+
+        impl $struct {
+            #[inline]
+            #[allow(unused)]
+            $new_vis fn new<I>(
+                $( $header_var: $header_var_ty, )+
+                $items: I,
+            ) -> Self
+            where
+                I: ::std::iter::IntoIterator,
+                I::IntoIter: $crate::thin_vec::TrustedLen<Item = $items_ty>,
+            {
+                Self($crate::thin_vec::ThinVecWithHeader::from_iter(
+                    $header { $( $header_var, )+ },
+                    $items,
+                ))
+            }
+
+            #[inline]
+            $items_vis fn $items(&self) -> &[$items_ty] {
+                self.0.items()
+            }
+
+            $(
+                #[inline]
+                $header_var_vis fn $header_var(&self) -> $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) $header_var_ty) {
+                    $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) self.0.header().$header_var)
+                }
+            )+
+        }
+
+        impl ::std::fmt::Debug for $struct {
+            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+                f.debug_struct(stringify!($struct))
+                    $( .field(stringify!($header_var), &self.$header_var()) )*
+                    .field(stringify!($items), &self.$items())
+                    .finish()
+            }
+        }
+    };
+}
+pub use crate::thin_vec_with_header_struct_ as thin_vec_with_header_struct;
diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs
index 0268e2473c0..c3d531344a1 100644
--- a/src/tools/rust-analyzer/xtask/src/tidy.rs
+++ b/src/tools/rust-analyzer/xtask/src/tidy.rs
@@ -223,7 +223,7 @@ struct TidyDocs {
 impl TidyDocs {
     fn visit(&mut self, path: &Path, text: &str) {
         // Tests and diagnostic fixes don't need module level comments.
-        if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa"]) {
+        if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa", "stdx"]) {
             return;
         }