about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChayim Refael Friedman <chayimfr@gmail.com>2024-10-28 17:38:37 +0200
committerChayim Refael Friedman <chayimfr@gmail.com>2024-10-28 17:38:37 +0200
commitd7615a985417c9ef8994745f58c75de9f0fa5399 (patch)
tree8b9733317412a595e3c71db3164c62b6d5cc910d
parentaf764db2aa36da86e517ad5e06f32795f548b100 (diff)
downloadrust-d7615a985417c9ef8994745f58c75de9f0fa5399.tar.gz
rust-d7615a985417c9ef8994745f58c75de9f0fa5399.zip
Cleanup TypeRef lowering
By removing interior mutability from it.
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs100
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs9
12 files changed, 151 insertions, 170 deletions
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 0b108b54e67..1ab49e91569 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
@@ -407,7 +407,7 @@ impl ExprCollector<'_> {
                 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
                 let generic_args = e
                     .generic_arg_list()
-                    .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
+                    .and_then(|it| GenericArgs::from_ast(&mut self.ctx(), it))
                     .map(Box::new);
                 self.alloc_expr(
                     Expr::MethodCall { receiver, method_name, args, generic_args },
@@ -533,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 = TypeRef::from_ast_opt(&self.ctx(), e.ty());
+                let type_ref = TypeRef::from_ast_opt(&mut self.ctx(), e.ty());
                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
             }
             ast::Expr::RefExpr(e) => {
@@ -572,13 +572,15 @@ 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| TypeRef::from_ast(&this.ctx(), it));
+                        let type_ref = param.ty().map(|it| TypeRef::from_ast(&mut this.ctx(), it));
                         args.push(pat);
                         arg_types.push(type_ref);
                     }
                 }
-                let ret_type =
-                    e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
+                let ret_type = e
+                    .ret_type()
+                    .and_then(|r| r.ty())
+                    .map(|it| TypeRef::from_ast(&mut 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();
@@ -705,7 +707,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 = TypeRef::from_ast_opt(&self.ctx(), e.ty());
+                let container = TypeRef::from_ast_opt(&mut self.ctx(), e.ty());
                 let fields = e.fields().map(|it| it.as_name()).collect();
                 self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
             }
@@ -1317,7 +1319,7 @@ impl ExprCollector<'_> {
                     return;
                 }
                 let pat = self.collect_pat_top(stmt.pat());
-                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&mut self.ctx(), it));
                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
                 let else_branch = stmt
                     .let_else()
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 d430733fcad..5315c1c6fbd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -161,14 +161,14 @@ impl Expander {
         types_map: &mut TypesMap,
         types_source_map: &mut TypesSourceMap,
     ) -> Option<Path> {
-        let ctx = LowerCtx::with_span_map_cell(
+        let mut 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)
+        Path::from_src(&mut ctx, path)
     }
 
     fn within_limit<F, T: ast::AstNode>(
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 6b79850e9c4..11e9bb0d886 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -451,7 +451,7 @@ pub(crate) struct GenericParamsCollector {
 impl GenericParamsCollector {
     pub(crate) fn fill(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         node: &dyn HasGenericParams,
         add_param_attrs: impl FnMut(
             Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
@@ -468,7 +468,7 @@ impl GenericParamsCollector {
 
     pub(crate) fn fill_bounds(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         type_bounds: Option<ast::TypeBoundList>,
         target: Either<TypeRefId, LifetimeRef>,
     ) {
@@ -479,7 +479,7 @@ impl GenericParamsCollector {
 
     fn fill_params(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         params: ast::GenericParamList,
         mut add_param_attrs: impl FnMut(
             Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
@@ -535,7 +535,11 @@ impl GenericParamsCollector {
         }
     }
 
-    fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx<'_>, where_clause: ast::WhereClause) {
+    fn fill_where_predicates(
+        &mut self,
+        lower_ctx: &mut LowerCtx<'_>,
+        where_clause: ast::WhereClause,
+    ) {
         for pred in where_clause.predicates() {
             let target = if let Some(type_ref) = pred.ty() {
                 Either::Left(TypeRef::from_ast(lower_ctx, type_ref))
@@ -569,7 +573,7 @@ impl GenericParamsCollector {
 
     fn add_where_predicate_from_bound(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         bound: ast::TypeBound,
         hrtb_lifetimes: Option<&[Name]>,
         target: Either<TypeRefId, LifetimeRef>,
@@ -670,8 +674,9 @@ impl GenericParamsCollector {
                 {
                     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());
+                    let mut ctx =
+                        expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
+                    let type_ref = TypeRef::from_ast(&mut ctx, expanded.tree());
                     self.fill_implicit_impl_trait_args(
                         db,
                         generics_types_map,
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 2582340c0f8..4d83ef99c84 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
@@ -98,7 +98,7 @@ pub struct TraitRef {
 
 impl TraitRef {
     /// Converts an `ast::PathType` to a `hir::TraitRef`.
-    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Option<Self> {
+    pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> {
         // FIXME: Use `Path::from_src`
         match node {
             ast::Type::PathType(path) => {
@@ -240,7 +240,7 @@ pub enum TraitBoundModifier {
 
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
-    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
+    pub fn from_ast(ctx: &mut 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(
@@ -321,8 +321,9 @@ impl TypeRef {
                     // Disallow nested impl traits
                     TypeRef::Error
                 } else {
-                    let _guard = ctx.outer_impl_trait_scope(true);
-                    TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
+                    ctx.with_outer_impl_trait_scope(true, |ctx| {
+                        TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
+                    })
                 }
             }
             ast::Type::DynTraitType(inner) => {
@@ -336,7 +337,7 @@ impl TypeRef {
         ctx.alloc_type_ref(ty, AstPtr::new(&node))
     }
 
-    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
+    pub(crate) fn from_ast_opt(ctx: &mut LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
         match node {
             Some(node) => TypeRef::from_ast(ctx, node),
             None => ctx.alloc_error_type(),
@@ -410,7 +411,7 @@ impl TypeRef {
 }
 
 pub(crate) fn type_bounds_from_ast(
-    lower_ctx: &LowerCtx<'_>,
+    lower_ctx: &mut LowerCtx<'_>,
     type_bounds_opt: Option<ast::TypeBoundList>,
 ) -> ThinVec<TypeBound> {
     if let Some(type_bounds) = type_bounds_opt {
@@ -423,8 +424,8 @@ pub(crate) fn type_bounds_from_ast(
 }
 
 impl TypeBound {
-    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::TypeBound) -> Self {
-        let lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
+    pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self {
+        let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
 
         match node.kind() {
             ast::TypeBoundKind::PathType(path_type) => {
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 bd17fce37b7..d519c1708b3 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
@@ -234,11 +234,11 @@ 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 mut 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(), &body_ctx);
+        let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &mut body_ctx);
         let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::No, strukt);
         types_map.shrink_to_fit();
@@ -273,7 +273,7 @@ impl<'a> Ctx<'a> {
     fn lower_fields(
         &mut self,
         strukt_kind: &ast::StructKind,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
         match strukt_kind {
             ast::StructKind::Record(it) => {
@@ -308,7 +308,11 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
+    fn lower_record_field(
+        &mut self,
+        field: &ast::RecordField,
+        body_ctx: &mut LowerCtx<'_>,
+    ) -> Field {
         let name = match field.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
@@ -323,7 +327,7 @@ impl<'a> Ctx<'a> {
         &mut self,
         idx: usize,
         field: &ast::TupleField,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> Field {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
@@ -334,13 +338,13 @@ impl<'a> Ctx<'a> {
     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 mut 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), &body_ctx)
+                self.lower_fields(&StructKind::Record(record_field_list), &mut body_ctx)
             }
             None => (Box::default(), FieldsShape::Record, Vec::default()),
         };
@@ -409,12 +413,12 @@ 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 mut 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(), &body_ctx);
+        let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &mut body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(variant);
         types_map.shrink_to_fit();
         types_source_map.shrink_to_fit();
@@ -436,7 +440,7 @@ 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 mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
 
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
@@ -457,7 +461,7 @@ 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(&body_ctx, type_ref),
+                    Some(type_ref) => TypeRef::from_ast(&mut body_ctx, type_ref),
                     None => {
                         let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
                             Name::new_symbol_root(sym::Self_.clone()).into(),
@@ -492,7 +496,7 @@ impl<'a> Ctx<'a> {
                         Param { type_ref: None }
                     }
                     None => {
-                        let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
+                        let type_ref = TypeRef::from_ast_opt(&mut body_ctx, param.ty());
                         Param { type_ref: Some(type_ref) }
                     }
                 };
@@ -502,7 +506,7 @@ impl<'a> Ctx<'a> {
 
         let ret_type = match func.ret_type() {
             Some(rt) => match rt.ty() {
-                Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+                Some(type_ref) => TypeRef::from_ast(&mut 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()),
             },
@@ -581,11 +585,11 @@ impl<'a> Ctx<'a> {
     ) -> 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 mut 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| TypeRef::from_ast(&body_ctx, it));
+        let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&mut body_ctx, it));
         let visibility = self.lower_visibility(type_alias);
-        let bounds = self.lower_type_bounds(type_alias, &body_ctx);
+        let bounds = self.lower_type_bounds(type_alias, &mut body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
         let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::No, type_alias);
@@ -612,9 +616,9 @@ impl<'a> Ctx<'a> {
     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 mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = static_.name()?.as_name();
-        let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
+        let type_ref = TypeRef::from_ast_opt(&mut 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();
@@ -639,9 +643,9 @@ impl<'a> Ctx<'a> {
     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 mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = konst.name().map(|it| it.as_name());
-        let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
+        let type_ref = TypeRef::from_ast_opt(&mut body_ctx, konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
         types_map.shrink_to_fit();
@@ -724,14 +728,14 @@ impl<'a> Ctx<'a> {
     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 mut 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 = 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 self_ty = TypeRef::from_ast_opt(&mut body_ctx, impl_def.self_ty());
+        let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&mut body_ctx, tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -870,13 +874,8 @@ impl<'a> Ctx<'a> {
     ) -> (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);
+        let mut 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, body_ctx.span_map());
-            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
-        };
         body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
@@ -892,16 +891,19 @@ 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(
-                &body_ctx,
-                bounds,
-                Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
-                    Name::new_symbol_root(sym::Self_.clone()).into(),
-                ))),
-            );
+            let bound_target = Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                Name::new_symbol_root(sym::Self_.clone()).into(),
+            )));
+            generics.fill_bounds(&mut body_ctx, bounds, bound_target);
         }
 
-        generics.fill(&body_ctx, node, add_param_attrs);
+        let span_map = body_ctx.span_map().clone();
+        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
+                               param| {
+            let attrs = RawAttrs::new(self.db.upcast(), &param, span_map.as_ref());
+            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
+        };
+        generics.fill(&mut body_ctx, node, add_param_attrs);
 
         let generics = generics.finish(types_map, &mut types_source_map);
         (generics, types_source_map)
@@ -910,7 +912,7 @@ impl<'a> Ctx<'a> {
     fn lower_type_bounds(
         &mut self,
         node: &dyn ast::HasTypeBounds,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> Box<[TypeBound]> {
         match node.type_bound_list() {
             Some(bound_list) => {
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 df5847929c5..6d1a3d17447 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,10 +1,7 @@
 //! Context for lowering paths.
-use std::cell::{OnceCell, RefCell};
+use std::{cell::OnceCell, mem};
 
-use hir_expand::{
-    span_map::{SpanMap, SpanMapRef},
-    AstId, HirFileId, InFile,
-};
+use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile};
 use span::{AstIdMap, AstIdNode};
 use stdx::thin_vec::ThinVec;
 use syntax::ast;
@@ -21,28 +18,11 @@ pub struct LowerCtx<'a> {
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
-    impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
+    impl_trait_bounds: 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, 'b> {
-    ctx: &'a LowerCtx<'b>,
-    old: bool,
-}
-
-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<'_, '_> {
-    fn drop(&mut self) {
-        self.ctx.outer_impl_trait.replace(self.old);
-    }
+    outer_impl_trait: bool,
+    types_map: &'a mut TypesMap,
+    types_source_map: &'a mut TypesSourceMap,
 }
 
 impl<'a> LowerCtx<'a> {
@@ -57,9 +37,10 @@ impl<'a> LowerCtx<'a> {
             file_id,
             span_map: OnceCell::new(),
             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)),
+            impl_trait_bounds: Vec::new(),
+            outer_impl_trait: false,
+            types_map,
+            types_source_map,
         }
     }
 
@@ -75,17 +56,18 @@ impl<'a> LowerCtx<'a> {
             file_id,
             span_map,
             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)),
+            impl_trait_bounds: Vec::new(),
+            outer_impl_trait: false,
+            types_map,
+            types_source_map,
         }
     }
 
-    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
-        self.span_map.get_or_init(|| self.db.span_map(self.file_id)).as_ref()
+    pub(crate) fn span_map(&self) -> &SpanMap {
+        self.span_map.get_or_init(|| self.db.span_map(self.file_id))
     }
 
-    pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
+    pub(crate) fn lower_path(&mut self, ast: ast::Path) -> Option<Path> {
         Path::from_src(self, ast)
     }
 
@@ -96,44 +78,44 @@ impl<'a> LowerCtx<'a> {
         )
     }
 
-    pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
-        self.impl_trait_bounds.borrow_mut().push(bounds);
+    pub fn update_impl_traits_bounds_from_type_ref(&mut self, type_ref: TypeRefId) {
+        TypeRef::walk(type_ref, self.types_map, &mut |tr| {
+            if let TypeRef::ImplTrait(bounds) = tr {
+                self.impl_trait_bounds.push(bounds.clone());
+            }
+        });
     }
 
-    pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
-        self.impl_trait_bounds.take()
+    pub fn take_impl_traits_bounds(&mut self) -> Vec<ThinVec<TypeBound>> {
+        mem::take(&mut self.impl_trait_bounds)
     }
 
     pub(crate) fn outer_impl_trait(&self) -> bool {
-        *self.outer_impl_trait.borrow()
+        self.outer_impl_trait
     }
 
-    pub(crate) fn outer_impl_trait_scope<'b>(
-        &'b self,
+    pub(crate) fn with_outer_impl_trait_scope<R>(
+        &mut self,
         impl_trait: bool,
-    ) -> OuterImplTraitGuard<'b, 'a> {
-        OuterImplTraitGuard::new(self, impl_trait)
+        f: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
+        let result = f(self);
+        self.outer_impl_trait = old;
+        result
     }
 
-    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));
+    pub(crate) fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
+        let id = self.types_map.types.alloc(type_ref);
+        self.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)
+    pub(crate) fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
+        self.types_map.types.alloc(type_ref)
     }
 
-    // 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)
+    pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
+        self.types_map.types.alloc(TypeRef::Error)
     }
 }
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 dc6947c5b56..aa2c4a6f1bc 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -121,7 +121,7 @@ pub enum GenericArg {
 impl Path {
     /// Converts an `ast::Path` to `Path`. Works with use trees.
     /// It correctly handles `$crate` based path from macro call.
-    pub fn from_src(ctx: &LowerCtx<'_>, path: ast::Path) -> Option<Path> {
+    pub fn from_src(ctx: &mut LowerCtx<'_>, path: ast::Path) -> Option<Path> {
         lower::lower_path(ctx, path)
     }
 
@@ -284,7 +284,7 @@ impl<'a> PathSegments<'a> {
 
 impl GenericArgs {
     pub(crate) fn from_ast(
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         node: ast::GenericArgList,
     ) -> Option<GenericArgs> {
         lower::lower_generic_args(lower_ctx, node)
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 c328b9c6ce2..553e615b94f 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
@@ -19,12 +19,11 @@ use crate::{
 
 /// Converts an `ast::Path` to `Path`. Works with use trees.
 /// It correctly handles `$crate` based path from macro call.
-pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
+pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
     let mut kind = PathKind::Plain;
     let mut type_anchor = None;
     let mut segments = Vec::new();
     let mut generic_args = Vec::new();
-    let span_map = ctx.span_map();
     loop {
         let segment = path.segment()?;
 
@@ -37,7 +36,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                 if name_ref.text() == "$crate" {
                     break kind = resolve_crate_root(
                         ctx.db.upcast(),
-                        span_map.span_for_range(name_ref.syntax().text_range()).ctx,
+                        ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx,
                     )
                     .map(PathKind::DollarCrate)
                     .unwrap_or(PathKind::Crate);
@@ -151,7 +150,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            let syn_ctxt = span_map.span_for_range(path.segment()?.syntax().text_range()).ctx;
+            let syn_ctxt = ctx.span_map().span_for_range(path.segment()?.syntax().text_range()).ctx;
             if let Some(macro_call_id) = ctx.db.lookup_intern_syntax_context(syn_ctxt).outer_expn {
                 if ctx.db.lookup_intern_macro_call(macro_call_id).def.local_inner {
                     kind = match resolve_crate_root(ctx.db.upcast(), syn_ctxt) {
@@ -183,7 +182,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
 }
 
 pub(super) fn lower_generic_args(
-    lower_ctx: &LowerCtx<'_>,
+    lower_ctx: &mut LowerCtx<'_>,
     node: ast::GenericArgList,
 ) -> Option<GenericArgs> {
     let mut args = Vec::new();
@@ -192,13 +191,7 @@ 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());
-                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);
+                lower_ctx.update_impl_traits_bounds_from_type_ref(type_ref);
                 args.push(GenericArg::Type(type_ref));
             }
             ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@@ -208,27 +201,22 @@ pub(super) fn lower_generic_args(
                 }
                 if let Some(name_ref) = assoc_type_arg.name_ref() {
                     // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
-                    let _guard = lower_ctx.outer_impl_trait_scope(false);
-                    let name = name_ref.as_name();
-                    let args = assoc_type_arg
-                        .generic_arg_list()
-                        .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| {
-                        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);
+                    lower_ctx.with_outer_impl_trait_scope(false, |lower_ctx| {
+                        let name = name_ref.as_name();
+                        let args = assoc_type_arg
+                            .generic_arg_list()
+                            .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| lower_ctx.update_impl_traits_bounds_from_type_ref(tr));
+                        let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
+                            l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
+                        } else {
+                            Box::default()
+                        };
+                        bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
                     });
-                    let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
-                    } else {
-                        Box::default()
-                    };
-                    bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
                 }
             }
             ast::GenericArg::LifetimeArg(lifetime_arg) => {
@@ -258,7 +246,7 @@ pub(super) fn lower_generic_args(
 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
 fn lower_generic_args_from_fn_path(
-    ctx: &LowerCtx<'_>,
+    ctx: &mut LowerCtx<'_>,
     params: Option<ast::ParamList>,
     ret_type: Option<ast::RetType>,
 ) -> Option<GenericArgs> {
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 277dabe9aa3..4e95bdf219f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -2033,7 +2033,7 @@ impl HirDisplayWithTypesMap for TypeRefId {
             TypeRef::Macro(macro_call) => {
                 let (mut types_map, mut types_source_map) =
                     (TypesMap::default(), TypesSourceMap::default());
-                let ctx = hir_def::lower::LowerCtx::new(
+                let mut ctx = hir_def::lower::LowerCtx::new(
                     f.db.upcast(),
                     macro_call.file_id,
                     &mut types_map,
@@ -2041,7 +2041,7 @@ impl HirDisplayWithTypesMap for TypeRefId {
                 );
                 let macro_call = macro_call.to_node(f.db.upcast());
                 match macro_call.path() {
-                    Some(path) => match Path::from_src(&ctx, path) {
+                    Some(path) => match Path::from_src(&mut ctx, path) {
                         Some(path) => path.hir_fmt(f, &types_map)?,
                         None => write!(f, "{{macro}}")?,
                     },
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 e3a92e52f61..ee9fd02cdf8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -465,13 +465,13 @@ impl<'a> TyLoweringContext<'a> {
                             let (mut types_map, mut types_source_map) =
                                 (TypesMap::default(), TypesSourceMap::default());
 
-                            let ctx = expander.ctx(
+                            let mut 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());
+                            let type_ref = TypeRef::from_ast(&mut ctx, expanded.tree());
 
                             drop(expander);
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index feb9a344d8a..29c2660554b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1271,9 +1271,9 @@ impl<'db> SemanticsImpl<'db> {
         let analyze = self.analyze(ty.syntax())?;
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut 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 type_ref = crate::TypeRef::from_ast(&mut ctx, ty.clone());
         let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
             self.db,
             &analyze.resolver,
@@ -1289,9 +1289,9 @@ impl<'db> SemanticsImpl<'db> {
         let analyze = self.analyze(path.syntax())?;
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut 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())?;
+        let hir_path = Path::from_src(&mut ctx, path.clone())?;
         match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
             TypeNs::TraitId(id) => Some(Trait { id }),
             _ => None,
@@ -1974,9 +1974,9 @@ impl SemanticsScope<'_> {
     pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut 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())?;
+        let path = Path::from_src(&mut ctx, ast_path.clone())?;
         resolve_hir_path(
             self.db,
             &self.resolver,
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 8d6e228e14c..c16454cff68 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -616,9 +616,9 @@ impl SourceAnalyzer {
     ) -> Option<Macro> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut 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))?;
+        let path = macro_call.value.path().and_then(|ast| Path::from_src(&mut ctx, ast))?;
         self.resolver
             .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
             .map(|(it, _)| it.into())
@@ -731,8 +731,9 @@ impl SourceAnalyzer {
 
         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())?;
+        let mut ctx =
+            LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
+        let hir_path = Path::from_src(&mut 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.