]> git.lizzy.rs Git - rust.git/commitdiff
Intern `TypeRef`s in the containing `ItemTree`
authorJonas Schievink <jonasschievink@gmail.com>
Thu, 4 Feb 2021 18:19:51 +0000 (19:19 +0100)
committerJonas Schievink <jonasschievink@gmail.com>
Thu, 4 Feb 2021 18:23:56 +0000 (19:23 +0100)
crates/hir_def/src/adt.rs
crates/hir_def/src/data.rs
crates/hir_def/src/item_tree.rs
crates/hir_def/src/item_tree/lower.rs

index 06f0b9b180e10a61a2889809386fa77268f0ede0..ed36c31096ce6b4f84852ad04e2dd8f6e3faf223 100644 (file)
@@ -351,7 +351,7 @@ fn lower_field(
 ) -> FieldData {
     FieldData {
         name: field.name.clone(),
-        type_ref: field.type_ref.clone(),
+        type_ref: item_tree[field.type_ref].clone(),
         visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
     }
 }
index c2b0dc00714a9e1fae5345f439170ce47300c6e7..42fcca386aa75f0e0a3bbfac0932db315f383274 100644 (file)
@@ -41,8 +41,8 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
 
         Arc::new(FunctionData {
             name: func.name.clone(),
-            params: func.params.to_vec(),
-            ret_type: func.ret_type.clone(),
+            params: func.params.iter().map(|id| item_tree[*id].clone()).collect(),
+            ret_type: item_tree[func.ret_type].clone(),
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()).clone(),
             has_self_param: func.has_self_param,
             has_body: func.has_body,
@@ -75,7 +75,7 @@ pub(crate) fn type_alias_data_query(
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
-            type_ref: typ.type_ref.clone(),
+            type_ref: typ.type_ref.map(|id| item_tree[id].clone()),
             visibility: item_tree[typ.visibility].clone(),
             is_extern: typ.is_extern,
             bounds: typ.bounds.to_vec(),
@@ -144,8 +144,8 @@ pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData>
 
         let item_tree = db.item_tree(impl_loc.id.file_id);
         let impl_def = &item_tree[impl_loc.id.value];
-        let target_trait = impl_def.target_trait.clone();
-        let target_type = impl_def.target_type.clone();
+        let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
+        let target_type = item_tree[impl_def.target_type].clone();
         let is_negative = impl_def.is_negative;
         let module_id = impl_loc.container.module(db);
         let container = AssocContainerId::ImplId(id);
@@ -182,7 +182,7 @@ pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<Cons
 
         Arc::new(ConstData {
             name: konst.name.clone(),
-            type_ref: konst.type_ref.clone(),
+            type_ref: item_tree[konst.type_ref].clone(),
             visibility: item_tree[konst.visibility].clone(),
         })
     }
@@ -205,7 +205,7 @@ pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<St
 
         Arc::new(StaticData {
             name: Some(statik.name.clone()),
-            type_ref: statik.type_ref.clone(),
+            type_ref: item_tree[statik.type_ref].clone(),
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
             is_extern: statik.is_extern,
index 4bde676490ec2a613a3cc548dddf0e08b6f790bc..4015569312b6b96064a8f66152af43a0f0e6759e 100644 (file)
@@ -146,6 +146,7 @@ fn shrink_to_fit(&mut self) {
                 macro_defs,
                 vis,
                 generics,
+                type_refs,
                 inner_items,
             } = &mut **data;
 
@@ -169,6 +170,8 @@ fn shrink_to_fit(&mut self) {
 
             vis.arena.shrink_to_fit();
             generics.arena.shrink_to_fit();
+            type_refs.arena.shrink_to_fit();
+            type_refs.map.shrink_to_fit();
 
             inner_items.shrink_to_fit();
         }
@@ -279,6 +282,32 @@ fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
     where_predicates: Vec::new(),
 };
 
+/// `TypeRef` interner.
+#[derive(Default, Debug, Eq, PartialEq)]
+struct TypeRefStorage {
+    arena: Arena<Arc<TypeRef>>,
+    map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
+}
+
+impl TypeRefStorage {
+    // Note: We lie about the `Idx<TypeRef>` to hide the interner details.
+
+    fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
+        if let Some(id) = self.map.get(&ty) {
+            return Idx::from_raw(id.into_raw());
+        }
+
+        let ty = Arc::new(ty);
+        let idx = self.arena.alloc(ty.clone());
+        self.map.insert(ty, idx);
+        Idx::from_raw(idx.into_raw())
+    }
+
+    fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
+        &self.arena[Idx::from_raw(id.into_raw())]
+    }
+}
+
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
     imports: Arena<Import>,
@@ -301,6 +330,7 @@ struct ItemTreeData {
 
     vis: ItemVisibilities,
     generics: GenericParamsStorage,
+    type_refs: TypeRefStorage,
 
     inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
 }
@@ -489,6 +519,14 @@ fn index(&self, index: GenericParamsId) -> &Self::Output {
     }
 }
 
+impl Index<Idx<TypeRef>> for ItemTree {
+    type Output = TypeRef;
+
+    fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
+        self.data().type_refs.lookup(id)
+    }
+}
+
 impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
     type Output = N;
     fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -532,9 +570,9 @@ pub struct Function {
     /// Whether the function is located in an `extern` block (*not* whether it is an
     /// `extern "abi" fn`).
     pub is_extern: bool,
-    pub params: Box<[TypeRef]>,
+    pub params: Box<[Idx<TypeRef>]>,
     pub is_varargs: bool,
-    pub ret_type: TypeRef,
+    pub ret_type: Idx<TypeRef>,
     pub ast_id: FileAstId<ast::Fn>,
 }
 
@@ -581,7 +619,7 @@ pub struct Const {
     /// const _: () = ();
     pub name: Option<Name>,
     pub visibility: RawVisibilityId,
-    pub type_ref: TypeRef,
+    pub type_ref: Idx<TypeRef>,
     pub ast_id: FileAstId<ast::Const>,
 }
 
@@ -592,7 +630,7 @@ pub struct Static {
     pub mutable: bool,
     /// Whether the static is in an `extern` block.
     pub is_extern: bool,
-    pub type_ref: TypeRef,
+    pub type_ref: Idx<TypeRef>,
     pub ast_id: FileAstId<ast::Static>,
 }
 
@@ -609,8 +647,8 @@ pub struct Trait {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Impl {
     pub generic_params: GenericParamsId,
-    pub target_trait: Option<TypeRef>,
-    pub target_type: TypeRef,
+    pub target_trait: Option<Idx<TypeRef>>,
+    pub target_type: Idx<TypeRef>,
     pub is_negative: bool,
     pub items: Box<[AssocItem]>,
     pub ast_id: FileAstId<ast::Impl>,
@@ -623,7 +661,7 @@ pub struct TypeAlias {
     /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
     pub bounds: Box<[TypeBound]>,
     pub generic_params: GenericParamsId,
-    pub type_ref: Option<TypeRef>,
+    pub type_ref: Option<Idx<TypeRef>>,
     pub is_extern: bool,
     pub ast_id: FileAstId<ast::TypeAlias>,
 }
@@ -806,6 +844,6 @@ pub enum Fields {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Field {
     pub name: Name,
-    pub type_ref: TypeRef,
+    pub type_ref: Idx<TypeRef>,
     pub visibility: RawVisibilityId,
 }
index de2177933f6cf9d5f73b1c71392b4cea8c4fdb06..93cdca55d2e083afc6b7dc50724406a0955e1798 100644 (file)
@@ -364,6 +364,7 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
                 params.push(type_ref);
             }
         }
+        let params = params.into_iter().map(|param| self.data().type_refs.intern(param)).collect();
 
         let mut is_varargs = false;
         if let Some(params) = func.param_list() {
@@ -385,6 +386,8 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
             ret_type
         };
 
+        let ret_type = self.data().type_refs.intern(ret_type);
+
         let has_body = func.body().is_some();
 
         let ast_id = self.source_ast_id_map.ast_id(func);
@@ -396,7 +399,7 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
             has_body,
             is_unsafe: func.unsafe_token().is_some(),
             is_extern: false,
-            params: params.into_boxed_slice(),
+            params,
             is_varargs,
             ret_type,
             ast_id,
@@ -657,6 +660,7 @@ fn lower_generic_params(
                 generics.fill(&self.body_ctx, sm, node);
                 // lower `impl Trait` in arguments
                 for param in &*func.params {
+                    let param = self.data().type_refs.lookup(*param);
                     generics.fill_implicit_impl_trait_args(param);
                 }
             }
@@ -709,11 +713,15 @@ fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilit
         self.data().vis.alloc(vis)
     }
 
-    fn lower_type_ref(&self, type_ref: &ast::Type) -> TypeRef {
-        TypeRef::from_ast(&self.body_ctx, type_ref.clone())
+    fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> {
+        let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
+        self.data().type_refs.intern(tyref)
     }
-    fn lower_type_ref_opt(&self, type_ref: Option<ast::Type>) -> TypeRef {
-        type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error)
+    fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> {
+        match type_ref.map(|ty| self.lower_type_ref(&ty)) {
+            Some(it) => it,
+            None => self.data().type_refs.intern(TypeRef::Error),
+        }
     }
 
     /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.