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,
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(),
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);
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(),
})
}
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,
macro_defs,
vis,
generics,
+ type_refs,
inner_items,
} = &mut **data;
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();
}
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>,
vis: ItemVisibilities,
generics: GenericParamsStorage,
+ type_refs: TypeRefStorage,
inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
}
}
}
+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 {
/// 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>,
}
/// const _: () = ();
pub name: Option<Name>,
pub visibility: RawVisibilityId,
- pub type_ref: TypeRef,
+ pub type_ref: Idx<TypeRef>,
pub ast_id: FileAstId<ast::Const>,
}
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>,
}
#[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>,
/// 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>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
- pub type_ref: TypeRef,
+ pub type_ref: Idx<TypeRef>,
pub visibility: RawVisibilityId,
}
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() {
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);
has_body,
is_unsafe: func.unsafe_token().is_some(),
is_extern: false,
- params: params.into_boxed_slice(),
+ params,
is_varargs,
ret_type,
ast_id,
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);
}
}
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`.