From 1d75d11d6cbd8a2d4605fd185237ec2747b0687f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 25 Mar 2020 15:33:01 +0100 Subject: [PATCH 01/34] Start item tree --- crates/ra_hir_def/src/body/lower.rs | 7 +- crates/ra_hir_def/src/item_tree.rs | 511 ++++++++++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 2 + 3 files changed, 517 insertions(+), 3 deletions(-) create mode 100644 crates/ra_hir_def/src/item_tree.rs diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f159f80af0..113ec2b78e 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -3,6 +3,7 @@ use either::Either; use hir_expand::{ + db::AstDatabase, hygiene::Hygiene, name::{name, AsName, Name}, HirFileId, MacroDefId, MacroDefKind, @@ -41,8 +42,8 @@ pub(crate) struct LowerCtx { } impl LowerCtx { - pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { - LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } + pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { + LowerCtx { hygiene: Hygiene::new(db, file_id) } } pub fn with_hygiene(hygiene: &Hygiene) -> Self { LowerCtx { hygiene: hygiene.clone() } @@ -119,7 +120,7 @@ impl ExprCollector<'_> { } fn ctx(&self) -> LowerCtx { - LowerCtx::new(self.db, self.expander.current_file_id) + LowerCtx::new(self.db.upcast(), self.expander.current_file_id) } fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs new file mode 100644 index 0000000000..f4743f0f63 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree.rs @@ -0,0 +1,511 @@ +//! A simplified AST that only contains items. + +use hir_expand::{ + ast_id_map::{AstIdMap, FileAstId}, + hygiene::Hygiene, + name::{name, AsName, Name}, +}; +use ra_arena::{Arena, Idx, RawId}; +use ra_syntax::ast; + +use crate::{ + attr::Attrs, + generics::GenericParams, + path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path}, + type_ref::{Mutability, TypeBound, TypeRef}, + visibility::RawVisibility, +}; +use ast::{NameOwner, StructKind, TypeAscriptionOwner}; +use std::{ + ops::{Index, Range}, + sync::Arc, +}; + +#[derive(Default)] +pub struct ItemTree { + imports: Arena, + functions: Arena, + structs: Arena, + fields: Arena, + unions: Arena, + enums: Arena, + variants: Arena, + consts: Arena, + statics: Arena, + traits: Arena, + impls: Arena, + type_aliases: Arena, + mods: Arena, + macro_calls: Arena, + exprs: Arena, +} + +impl ItemTree { + pub fn query(syntax: &ast::SourceFile) -> ItemTree { + todo!() + } +} + +macro_rules! impl_index { + ( $($fld:ident: $t:ty),+ $(,)? ) => { + $( + impl Index> for ItemTree { + type Output = $t; + + fn index(&self, index: Idx<$t>) -> &Self::Output { + &self.$fld[index] + } + } + )+ + }; +} + +impl_index!( + imports: Import, + functions: Function, + structs: Struct, + fields: Field, + unions: Union, + enums: Enum, + variants: Variant, + consts: Const, + statics: Static, + traits: Trait, + impls: Impl, + type_aliases: TypeAlias, + mods: Mod, + macro_calls: MacroCall, + exprs: Expr, +); + +pub struct Import { + pub path: ModPath, + pub alias: Option, + pub visibility: RawVisibility, + pub is_glob: bool, + pub is_prelude: bool, + pub is_extern_crate: bool, + pub is_macro_use: bool, +} + +pub struct Function { + pub name: Name, + pub attrs: Attrs, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub has_self_param: bool, + pub params: Vec, + pub ret_type: TypeRef, + pub ast: FileAstId, +} + +pub struct Struct { + pub name: Name, + pub attrs: Attrs, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub fields: Fields, + pub ast: FileAstId, +} + +pub struct Union { + pub name: Name, + pub attrs: Attrs, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub fields: Fields, +} + +pub struct Enum { + pub name: Name, + pub attrs: Attrs, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub variants: Range>, +} + +pub struct Const { + /// const _: () = (); + pub name: Option, + pub visibility: RawVisibility, + pub type_ref: TypeRef, +} + +pub struct Static { + pub name: Name, + pub visibility: RawVisibility, + pub type_ref: TypeRef, +} + +pub struct Trait { + pub name: Name, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub auto: bool, + pub items: Vec, +} + +pub struct Impl { + pub generic_params: GenericParams, + pub target_trait: Option, + pub target_type: TypeRef, + pub is_negative: bool, + pub items: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TypeAlias { + pub name: Name, + pub visibility: RawVisibility, + pub generic_params: GenericParams, + pub type_ref: Option, +} + +pub struct Mod { + pub name: Name, + pub visibility: RawVisibility, + pub items: Vec, +} + +pub struct MacroCall { + pub name: Option, + pub path: ModPath, + pub export: bool, + pub builtin: bool, + pub ast_id: FileAstId, +} + +// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array +// lengths, but we don't do much with them yet. +pub struct Expr; + +pub enum ModItem { + Import(Idx), + Function(Idx), + Struct(Idx), + Union(Idx), + Enum(Idx), + Const(Idx), + Static(Idx), + Trait(Idx), + Impl(Idx), + TypeAlias(Idx), + Mod(Idx), + MacroCall(Idx), +} + +pub enum AssocItem { + Function(Idx), + TypeAlias(Idx), + Const(Idx), + MacroCall(Idx), +} + +pub struct Variant { + pub name: Name, + pub fields: Fields, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Fields { + Record(Range>), + Tuple(Range>), + Unit, +} + +/// A single field of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Field { + pub name: Name, + pub type_ref: TypeRef, + pub visibility: RawVisibility, +} + +struct Ctx { + tree: ItemTree, + hygiene: Hygiene, + source_ast_id_map: Arc, + body_ctx: crate::body::LowerCtx, +} + +impl Ctx { + fn lower(&mut self, item_owner: &dyn ast::ModuleItemOwner) { + for item in item_owner.items() { + self.lower_item(&item) + } + } + + fn lower_item(&mut self, item: &ast::ModuleItem) { + match item { + ast::ModuleItem::StructDef(ast) => { + if let Some(data) = self.lower_struct(ast) { + let idx = self.tree.structs.alloc(data); + } + } + ast::ModuleItem::UnionDef(ast) => { + if let Some(data) = self.lower_union(ast) { + let idx = self.tree.unions.alloc(data); + } + } + ast::ModuleItem::EnumDef(ast) => { + if let Some(data) = self.lower_enum(ast) { + let idx = self.tree.enums.alloc(data); + } + } + ast::ModuleItem::FnDef(ast) => { + if let Some(data) = self.lower_function(ast) { + let idx = self.tree.functions.alloc(data); + } + } + ast::ModuleItem::TypeAliasDef(ast) => { + if let Some(data) = self.lower_type_alias(ast) { + let idx = self.tree.type_aliases.alloc(data); + } + } + ast::ModuleItem::StaticDef(ast) => { + if let Some(data) = self.lower_static(ast) { + let idx = self.tree.statics.alloc(data); + } + } + ast::ModuleItem::ConstDef(ast) => { + let data = self.lower_const(ast); + let idx = self.tree.consts.alloc(data); + } + ast::ModuleItem::Module(_) => {} + ast::ModuleItem::TraitDef(_) => {} + ast::ModuleItem::ImplDef(_) => {} + ast::ModuleItem::UseItem(_) => {} + ast::ModuleItem::ExternCrateItem(_) => {} + ast::ModuleItem::MacroCall(_) => {} + ast::ModuleItem::ExternBlock(_) => {} + } + } + + fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option { + let attrs = self.lower_attrs(strukt); + let visibility = self.lower_visibility(strukt); + let name = strukt.name()?.as_name(); + let generic_params = self.lower_generic_params(strukt); + let fields = self.lower_fields(&strukt.kind()); + let ast = self.source_ast_id_map.ast_id(strukt); + let res = Struct { name, attrs, visibility, generic_params, fields, ast }; + Some(res) + } + + fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { + match strukt_kind { + ast::StructKind::Record(it) => { + let range = self.lower_record_fields(it); + Fields::Record(range) + } + ast::StructKind::Tuple(it) => { + let range = self.lower_tuple_fields(it); + Fields::Tuple(range) + } + ast::StructKind::Unit => Fields::Unit, + } + } + + fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range> { + let start = self.next_field_idx(); + for field in fields.fields() { + if let Some(data) = self.lower_record_field(&field) { + let idx = self.tree.fields.alloc(data); + } + } + let end = self.next_field_idx(); + start..end + } + + fn lower_record_field(&self, field: &ast::RecordFieldDef) -> Option { + let name = field.name()?.as_name(); + let visibility = self.lower_visibility(field); + let type_ref = self.lower_type_ref(&field.ascribed_type()?); + let res = Field { name, type_ref, visibility }; + Some(res) + } + + fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range> { + let start = self.next_field_idx(); + for (i, field) in fields.fields().enumerate() { + if let Some(data) = self.lower_tuple_field(i, &field) { + let idx = self.tree.fields.alloc(data); + } + } + let end = self.next_field_idx(); + start..end + } + + fn lower_tuple_field(&self, idx: usize, field: &ast::TupleFieldDef) -> Option { + let name = Name::new_tuple_field(idx); + let visibility = self.lower_visibility(field); + let type_ref = self.lower_type_ref(&field.type_ref()?); + let res = Field { name, type_ref, visibility }; + Some(res) + } + + fn lower_union(&mut self, union: &ast::UnionDef) -> Option { + let attrs = self.lower_attrs(union); + let visibility = self.lower_visibility(union); + let name = union.name()?.as_name(); + let generic_params = self.lower_generic_params(union); + let fields = match union.record_field_def_list() { + Some(record_field_def_list) => { + self.lower_fields(&StructKind::Record(record_field_def_list)) + } + None => Fields::Record(self.next_field_idx()..self.next_field_idx()), + }; + let res = Union { name, attrs, visibility, generic_params, fields }; + Some(res) + } + + fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option { + let attrs = self.lower_attrs(enum_); + let visibility = self.lower_visibility(enum_); + let name = enum_.name()?.as_name(); + let generic_params = self.lower_generic_params(enum_); + let variants = match &enum_.variant_list() { + Some(variant_list) => self.lower_variants(variant_list), + None => self.next_variant_idx()..self.next_variant_idx(), + }; + let res = Enum { name, attrs, visibility, generic_params, variants }; + Some(res) + } + + fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { + let start = self.next_variant_idx(); + for variant in variants.variants() { + if let Some(data) = self.lower_variant(&variant) { + let idx = self.tree.variants.alloc(data); + } + } + let end = self.next_variant_idx(); + start..end + } + + fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option { + let name = variant.name()?.as_name(); + let fields = self.lower_fields(&variant.kind()); + let res = Variant { name, fields }; + Some(res) + } + + fn lower_function(&mut self, func: &ast::FnDef) -> Option { + let attrs = self.lower_attrs(func); + let visibility = self.lower_visibility(func); + let name = func.name()?.as_name(); + let generic_params = self.lower_generic_params(func); + + let mut params = Vec::new(); + let mut has_self_param = false; + if let Some(param_list) = func.param_list() { + if let Some(self_param) = param_list.self_param() { + let self_type = if let Some(type_ref) = self_param.ascribed_type() { + TypeRef::from_ast(&self.body_ctx, type_ref) + } else { + let self_type = TypeRef::Path(name![Self].into()); + match self_param.kind() { + ast::SelfParamKind::Owned => self_type, + ast::SelfParamKind::Ref => { + TypeRef::Reference(Box::new(self_type), Mutability::Shared) + } + ast::SelfParamKind::MutRef => { + TypeRef::Reference(Box::new(self_type), Mutability::Mut) + } + } + }; + params.push(self_type); + has_self_param = true; + } + for param in param_list.params() { + let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); + params.push(type_ref); + } + } + let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { + Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), + _ => TypeRef::unit(), + }; + + let ret_type = if func.async_token().is_some() { + let future_impl = desugar_future_path(ret_type); + let ty_bound = TypeBound::Path(future_impl); + TypeRef::ImplTrait(vec![ty_bound]) + } else { + ret_type + }; + + let ast = self.source_ast_id_map.ast_id(func); + let res = Function { + name, + attrs, + visibility, + generic_params, + has_self_param, + params, + ret_type, + ast, + }; + Some(res) + } + + fn lower_type_alias(&mut self, type_alias: &ast::TypeAliasDef) -> Option { + let name = type_alias.name()?.as_name(); + let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); + let visibility = self.lower_visibility(type_alias); + let generic_params = self.lower_generic_params(type_alias); + let res = TypeAlias { name, visibility, generic_params, type_ref }; + Some(res) + } + + fn lower_static(&mut self, static_: &ast::StaticDef) -> Option { + let name = static_.name()?.as_name(); + let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); + let visibility = self.lower_visibility(static_); + let res = Static { name, visibility, type_ref }; + Some(res) + } + + fn lower_const(&mut self, konst: &ast::ConstDef) -> Const { + let name = konst.name().map(|it| it.as_name()); + let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); + let visibility = self.lower_visibility(konst); + Const { name, visibility, type_ref } + } + + fn lower_generic_params(&mut self, item: &impl ast::TypeParamsOwner) -> GenericParams { + None.unwrap() + } + + fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { + Attrs::new(item, &self.hygiene) + } + fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { + RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) + } + fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { + TypeRef::from_ast(&self.body_ctx, type_ref.clone()) + } + fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { + TypeRef::from_ast_opt(&self.body_ctx, type_ref) + } + + fn next_field_idx(&self) -> Idx { + Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) + } + fn next_variant_idx(&self) -> Idx { + Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) + } +} + +fn desugar_future_path(orig: TypeRef) -> Path { + let path = path![std::future::Future]; + let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); + let mut last = GenericArgs::empty(); + let binding = + AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; + last.bindings.push(binding); + generic_args.push(Some(Arc::new(last))); + + Path::from_known_path(path, generic_args) +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index af2a717c9d..b5500f3707 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -25,6 +25,8 @@ pub mod item_scope; pub mod dyn_map; pub mod keys; +pub mod item_tree; + pub mod adt; pub mod data; pub mod generics; From 34bc80650b93bf422039af31844898f427cc375c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 11 Jun 2020 19:46:56 +0200 Subject: [PATCH 02/34] Hook up query, add impls, lower moar --- crates/ra_hir_def/src/body/lower.rs | 7 +- crates/ra_hir_def/src/db.rs | 4 + crates/ra_hir_def/src/item_tree.rs | 158 +++++++++++++++++++++------- 3 files changed, 128 insertions(+), 41 deletions(-) diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 113ec2b78e..f159f80af0 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -3,7 +3,6 @@ use either::Either; use hir_expand::{ - db::AstDatabase, hygiene::Hygiene, name::{name, AsName, Name}, HirFileId, MacroDefId, MacroDefKind, @@ -42,8 +41,8 @@ pub(crate) struct LowerCtx { } impl LowerCtx { - pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { - LowerCtx { hygiene: Hygiene::new(db, file_id) } + pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { + LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } } pub fn with_hygiene(hygiene: &Hygiene) -> Self { LowerCtx { hygiene: hygiene.clone() } @@ -120,7 +119,7 @@ impl ExprCollector<'_> { } fn ctx(&self) -> LowerCtx { - LowerCtx::new(self.db.upcast(), self.expander.current_file_id) + LowerCtx::new(self.db, self.expander.current_file_id) } fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 10cc26480f..c4c9e10a3d 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -14,6 +14,7 @@ use crate::{ docs::Documentation, generics::GenericParams, import_map::ImportMap, + item_tree::ItemTree, lang_item::{LangItemTarget, LangItems}, nameres::{raw::RawItems, CrateDefMap}, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, @@ -48,6 +49,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { #[salsa::invoke(RawItems::raw_items_query)] fn raw_items(&self, file_id: HirFileId) -> Arc; + #[salsa::invoke(ItemTree::item_tree_query)] + fn item_tree(&self, file_id: HirFileId) -> Arc; + #[salsa::invoke(crate_def_map_wait)] #[salsa::transparent] fn crate_def_map(&self, krate: CrateId) -> Arc; diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index f4743f0f63..7e81bc178d 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -4,25 +4,28 @@ use hir_expand::{ ast_id_map::{AstIdMap, FileAstId}, hygiene::Hygiene, name::{name, AsName, Name}, + HirFileId, }; use ra_arena::{Arena, Idx, RawId}; -use ra_syntax::ast; +use ra_syntax::{ast, match_ast}; use crate::{ attr::Attrs, + db::DefDatabase, generics::GenericParams, path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path}, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; -use ast::{NameOwner, StructKind, TypeAscriptionOwner}; +use ast::{AstNode, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; use std::{ ops::{Index, Range}, sync::Arc, }; -#[derive(Default)] +#[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { + top_level: Vec, imports: Arena, functions: Arena, structs: Arena, @@ -41,8 +44,42 @@ pub struct ItemTree { } impl ItemTree { - pub fn query(syntax: &ast::SourceFile) -> ItemTree { - todo!() + pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { + let syntax = if let Some(node) = db.parse_or_expand(file_id) { + node + } else { + return Default::default(); + }; + + let (macro_storage, file_storage); + let item_owner = match_ast! { + match syntax { + ast::MacroItems(items) => { + macro_storage = items; + ¯o_storage as &dyn ModuleItemOwner + }, + ast::SourceFile(file) => { + file_storage = file; + &file_storage + }, + _ => return Default::default(), + } + }; + + let map = db.ast_id_map(file_id); + let ctx = Ctx { + tree: ItemTree::default(), + hygiene: Hygiene::new(db.upcast(), file_id), + source_ast_id_map: map, + body_ctx: crate::body::LowerCtx::new(db, file_id), + }; + Arc::new(ctx.lower(item_owner)) + } + + /// Returns an iterator over all items located at the top level of the `HirFileId` this + /// `ItemTree` was created from. + pub fn top_level_items(&self) -> impl Iterator + '_ { + self.top_level.iter().copied() } } @@ -78,6 +115,7 @@ impl_index!( exprs: Expr, ); +#[derive(Debug, Eq, PartialEq)] pub struct Import { pub path: ModPath, pub alias: Option, @@ -88,6 +126,7 @@ pub struct Import { pub is_macro_use: bool, } +#[derive(Debug, Eq, PartialEq)] pub struct Function { pub name: Name, pub attrs: Attrs, @@ -99,6 +138,7 @@ pub struct Function { pub ast: FileAstId, } +#[derive(Debug, Eq, PartialEq)] pub struct Struct { pub name: Name, pub attrs: Attrs, @@ -108,6 +148,7 @@ pub struct Struct { pub ast: FileAstId, } +#[derive(Debug, Eq, PartialEq)] pub struct Union { pub name: Name, pub attrs: Attrs, @@ -116,6 +157,7 @@ pub struct Union { pub fields: Fields, } +#[derive(Debug, Eq, PartialEq)] pub struct Enum { pub name: Name, pub attrs: Attrs, @@ -124,6 +166,7 @@ pub struct Enum { pub variants: Range>, } +#[derive(Debug, Eq, PartialEq)] pub struct Const { /// const _: () = (); pub name: Option, @@ -131,12 +174,14 @@ pub struct Const { pub type_ref: TypeRef, } +#[derive(Debug, Eq, PartialEq)] pub struct Static { pub name: Name, pub visibility: RawVisibility, pub type_ref: TypeRef, } +#[derive(Debug, Eq, PartialEq)] pub struct Trait { pub name: Name, pub visibility: RawVisibility, @@ -145,6 +190,7 @@ pub struct Trait { pub items: Vec, } +#[derive(Debug, Eq, PartialEq)] pub struct Impl { pub generic_params: GenericParams, pub target_trait: Option, @@ -161,12 +207,14 @@ pub struct TypeAlias { pub type_ref: Option, } +#[derive(Debug, Eq, PartialEq)] pub struct Mod { pub name: Name, pub visibility: RawVisibility, pub items: Vec, } +#[derive(Debug, Eq, PartialEq)] pub struct MacroCall { pub name: Option, pub path: ModPath, @@ -177,8 +225,22 @@ pub struct MacroCall { // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array // lengths, but we don't do much with them yet. +#[derive(Debug, Eq, PartialEq)] pub struct Expr; +macro_rules! impl_froms { + ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { + $( + impl From<$t> for $e { + fn from(it: $t) -> $e { + $e::$v(it) + } + } + )* + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ModItem { Import(Idx), Function(Idx), @@ -194,6 +256,22 @@ pub enum ModItem { MacroCall(Idx), } +impl_froms!(ModItem { + Import(Idx), + Function(Idx), + Struct(Idx), + Union(Idx), + Enum(Idx), + Const(Idx), + Static(Idx), + Trait(Idx), + Impl(Idx), + TypeAlias(Idx), + Mod(Idx), + MacroCall(Idx), +}); + +#[derive(Debug, Eq, PartialEq)] pub enum AssocItem { Function(Idx), TypeAlias(Idx), @@ -201,6 +279,14 @@ pub enum AssocItem { MacroCall(Idx), } +impl_froms!(AssocItem { + Function(Idx), + TypeAlias(Idx), + Const(Idx), + MacroCall(Idx), +}); + +#[derive(Debug, Eq, PartialEq)] pub struct Variant { pub name: Name, pub fields: Fields, @@ -229,55 +315,44 @@ struct Ctx { } impl Ctx { - fn lower(&mut self, item_owner: &dyn ast::ModuleItemOwner) { - for item in item_owner.items() { - self.lower_item(&item) - } + fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { + self.tree.top_level = item_owner.items().flat_map(|item| self.lower_item(&item)).collect(); + self.tree } - fn lower_item(&mut self, item: &ast::ModuleItem) { + fn lower_item(&mut self, item: &ast::ModuleItem) -> Option { match item { ast::ModuleItem::StructDef(ast) => { - if let Some(data) = self.lower_struct(ast) { - let idx = self.tree.structs.alloc(data); - } + self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) } ast::ModuleItem::UnionDef(ast) => { - if let Some(data) = self.lower_union(ast) { - let idx = self.tree.unions.alloc(data); - } + self.lower_union(ast).map(|data| self.tree.unions.alloc(data).into()) } ast::ModuleItem::EnumDef(ast) => { - if let Some(data) = self.lower_enum(ast) { - let idx = self.tree.enums.alloc(data); - } + self.lower_enum(ast).map(|data| self.tree.enums.alloc(data).into()) } ast::ModuleItem::FnDef(ast) => { - if let Some(data) = self.lower_function(ast) { - let idx = self.tree.functions.alloc(data); - } + self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) } ast::ModuleItem::TypeAliasDef(ast) => { - if let Some(data) = self.lower_type_alias(ast) { - let idx = self.tree.type_aliases.alloc(data); - } + self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) } ast::ModuleItem::StaticDef(ast) => { - if let Some(data) = self.lower_static(ast) { - let idx = self.tree.statics.alloc(data); - } + self.lower_static(ast).map(|data| self.tree.statics.alloc(data).into()) } ast::ModuleItem::ConstDef(ast) => { let data = self.lower_const(ast); - let idx = self.tree.consts.alloc(data); + Some(self.tree.consts.alloc(data).into()) } - ast::ModuleItem::Module(_) => {} - ast::ModuleItem::TraitDef(_) => {} - ast::ModuleItem::ImplDef(_) => {} - ast::ModuleItem::UseItem(_) => {} - ast::ModuleItem::ExternCrateItem(_) => {} - ast::ModuleItem::MacroCall(_) => {} - ast::ModuleItem::ExternBlock(_) => {} + ast::ModuleItem::Module(ast) => { + self.lower_module(ast).map(|data| self.tree.mods.alloc(data).into()) + } + ast::ModuleItem::TraitDef(_) => todo!(), + ast::ModuleItem::ImplDef(_) => todo!(), + ast::ModuleItem::UseItem(_) => todo!(), + ast::ModuleItem::ExternCrateItem(_) => todo!(), + ast::ModuleItem::MacroCall(_) => todo!(), + ast::ModuleItem::ExternBlock(_) => todo!(), } } @@ -473,7 +548,16 @@ impl Ctx { Const { name, visibility, type_ref } } - fn lower_generic_params(&mut self, item: &impl ast::TypeParamsOwner) -> GenericParams { + fn lower_module(&mut self, module: &ast::Module) -> Option { + let name = module.name()?.as_name(); + let visibility = self.lower_visibility(module); + let items = module + .item_list() + .map(move |list| list.items().flat_map(move |item| self.lower_item(&item)).collect()); + Some(Mod { name, visibility, items: items.unwrap_or_default() }) + } + + fn lower_generic_params(&mut self, _item: &impl ast::TypeParamsOwner) -> GenericParams { None.unwrap() } From 696a7a5a410f419cf7f6638d9f4894802640adf8 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 12 Jun 2020 13:58:02 +0200 Subject: [PATCH 03/34] lower traits --- Cargo.lock | 1 + crates/ra_hir_def/Cargo.toml | 1 + crates/ra_hir_def/src/item_tree.rs | 235 +++++++++++++++++++++++++---- 3 files changed, 208 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7bd2144a74..c2d00adebc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1018,6 +1018,7 @@ dependencies = [ "ra_syntax", "ra_tt", "rustc-hash", + "smallvec", "stdx", "test_utils", ] diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index ef1f65ee06..6d43924e30 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -17,6 +17,7 @@ drop_bomb = "0.1.4" fst = { version = "0.4", default-features = false } itertools = "0.9.0" indexmap = "1.4.0" +smallvec = "1.4.0" stdx = { path = "../stdx" } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 7e81bc178d..3ea6e10c98 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -4,7 +4,7 @@ use hir_expand::{ ast_id_map::{AstIdMap, FileAstId}, hygiene::Hygiene, name::{name, AsName, Name}, - HirFileId, + HirFileId, InFile, }; use ra_arena::{Arena, Idx, RawId}; use ra_syntax::{ast, match_ast}; @@ -12,17 +12,20 @@ use ra_syntax::{ast, match_ast}; use crate::{ attr::Attrs, db::DefDatabase, - generics::GenericParams, + generics, path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path}, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; -use ast::{AstNode, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use either::Either; +use smallvec::SmallVec; use std::{ ops::{Index, Range}, sync::Arc, }; +/// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { top_level: Vec, @@ -70,6 +73,7 @@ impl ItemTree { let ctx = Ctx { tree: ItemTree::default(), hygiene: Hygiene::new(db.upcast(), file_id), + file: file_id, source_ast_id_map: map, body_ctx: crate::body::LowerCtx::new(db, file_id), }; @@ -115,6 +119,7 @@ impl_index!( exprs: Expr, ); +/// A desugared `extern crate` or `use` import. #[derive(Debug, Eq, PartialEq)] pub struct Import { pub path: ModPath, @@ -131,11 +136,12 @@ pub struct Function { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub has_self_param: bool, pub params: Vec, pub ret_type: TypeRef, pub ast: FileAstId, + // FIXME inner items } #[derive(Debug, Eq, PartialEq)] @@ -143,7 +149,7 @@ pub struct Struct { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub fields: Fields, pub ast: FileAstId, } @@ -153,7 +159,7 @@ pub struct Union { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub fields: Fields, } @@ -162,7 +168,7 @@ pub struct Enum { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub variants: Range>, } @@ -185,14 +191,14 @@ pub struct Static { pub struct Trait { pub name: Name, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub auto: bool, pub items: Vec, } #[derive(Debug, Eq, PartialEq)] pub struct Impl { - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub target_trait: Option, pub target_type: TypeRef, pub is_negative: bool, @@ -203,7 +209,7 @@ pub struct Impl { pub struct TypeAlias { pub name: Name, pub visibility: RawVisibility, - pub generic_params: GenericParams, + pub generic_params: generics::GenericParams, pub type_ref: Option, } @@ -218,8 +224,12 @@ pub struct Mod { pub struct MacroCall { pub name: Option, pub path: ModPath, - pub export: bool, - pub builtin: bool, + /// Has `#[macro_export]`. + pub is_export: bool, + /// Has `#[macro_export(local_inner_macros)]`. + pub is_local_inner: bool, + /// Has `#[rustc_builtin_macro]`. + pub is_builtin: bool, pub ast_id: FileAstId, } @@ -307,20 +317,36 @@ pub struct Field { pub visibility: RawVisibility, } +struct ModItems(SmallVec<[ModItem; 1]>); + +impl From for ModItems +where + T: Into, +{ + fn from(t: T) -> Self { + ModItems(SmallVec::from_buf([t.into(); 1])) + } +} + struct Ctx { tree: ItemTree, hygiene: Hygiene, + file: HirFileId, source_ast_id_map: Arc, body_ctx: crate::body::LowerCtx, } impl Ctx { fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { - self.tree.top_level = item_owner.items().flat_map(|item| self.lower_item(&item)).collect(); + self.tree.top_level = item_owner + .items() + .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|items| items.0) + .collect(); self.tree } - fn lower_item(&mut self, item: &ast::ModuleItem) -> Option { + fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option { match item { ast::ModuleItem::StructDef(ast) => { self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) @@ -347,12 +373,48 @@ impl Ctx { ast::ModuleItem::Module(ast) => { self.lower_module(ast).map(|data| self.tree.mods.alloc(data).into()) } - ast::ModuleItem::TraitDef(_) => todo!(), - ast::ModuleItem::ImplDef(_) => todo!(), - ast::ModuleItem::UseItem(_) => todo!(), - ast::ModuleItem::ExternCrateItem(_) => todo!(), - ast::ModuleItem::MacroCall(_) => todo!(), - ast::ModuleItem::ExternBlock(_) => todo!(), + ast::ModuleItem::TraitDef(ast) => { + self.lower_trait(ast).map(|data| self.tree.traits.alloc(data).into()) + } + ast::ModuleItem::ImplDef(ast) => { + self.lower_impl(ast).map(|data| self.tree.impls.alloc(data).into()) + } + ast::ModuleItem::UseItem(ast) => Some(ModItems( + self.lower_use(ast) + .into_iter() + .map(|data| self.tree.imports.alloc(data).into()) + .collect::>(), + )), + ast::ModuleItem::ExternCrateItem(ast) => { + self.lower_extern_crate(ast).map(|data| self.tree.imports.alloc(data).into()) + } + ast::ModuleItem::MacroCall(ast) => { + self.lower_macro_call(ast).map(|data| self.tree.macro_calls.alloc(data).into()) + } + ast::ModuleItem::ExternBlock(ast) => Some(ModItems( + self.lower_extern_block(ast) + .into_iter() + .map(|item| match item { + Either::Left(func) => self.tree.functions.alloc(func).into(), + Either::Right(statik) => self.tree.statics.alloc(statik).into(), + }) + .collect::>(), + )), + } + } + + fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { + match item { + ast::AssocItem::FnDef(ast) => { + self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) + } + ast::AssocItem::TypeAliasDef(ast) => { + self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) + } + ast::AssocItem::ConstDef(ast) => { + let data = self.lower_const(ast); + Some(self.tree.consts.alloc(data).into()) + } } } @@ -385,7 +447,7 @@ impl Ctx { let start = self.next_field_idx(); for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { - let idx = self.tree.fields.alloc(data); + self.tree.fields.alloc(data); } } let end = self.next_field_idx(); @@ -404,7 +466,7 @@ impl Ctx { let start = self.next_field_idx(); for (i, field) in fields.fields().enumerate() { if let Some(data) = self.lower_tuple_field(i, &field) { - let idx = self.tree.fields.alloc(data); + self.tree.fields.alloc(data); } } let end = self.next_field_idx(); @@ -451,7 +513,7 @@ impl Ctx { let start = self.next_variant_idx(); for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { - let idx = self.tree.variants.alloc(data); + self.tree.variants.alloc(data); } } let end = self.next_variant_idx(); @@ -551,14 +613,129 @@ impl Ctx { fn lower_module(&mut self, module: &ast::Module) -> Option { let name = module.name()?.as_name(); let visibility = self.lower_visibility(module); - let items = module - .item_list() - .map(move |list| list.items().flat_map(move |item| self.lower_item(&item)).collect()); + let items = module.item_list().map(move |list| { + list.items() + .flat_map(move |item| self.lower_mod_item(&item)) + .flat_map(|items| items.0) + .collect() + }); Some(Mod { name, visibility, items: items.unwrap_or_default() }) } - fn lower_generic_params(&mut self, _item: &impl ast::TypeParamsOwner) -> GenericParams { - None.unwrap() + fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { + let name = trait_def.name()?.as_name(); + let visibility = self.lower_visibility(trait_def); + let generic_params = self.lower_generic_params(trait_def); + let auto = trait_def.auto_token().is_some(); + let items = trait_def.item_list().map(move |list| { + // FIXME: Does not handle macros + list.assoc_items().flat_map(move |item| self.lower_assoc_item(&item)).collect() + }); + Some(Trait { name, visibility, generic_params, auto, items: items.unwrap_or_default() }) + } + + fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { + let generic_params = self.lower_generic_params(impl_def); + let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); + let target_type = self.lower_type_ref(&impl_def.target_type()?); + let is_negative = impl_def.excl_token().is_some(); + let items = impl_def + .item_list()? + .assoc_items() + .filter_map(|item| self.lower_assoc_item(&item)) + .collect(); + Some(Impl { generic_params, target_trait, target_type, is_negative, items }) + } + + fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec { + // FIXME: cfg_attr + let is_prelude = use_item.has_atom_attr("prelude_import"); + let visibility = self.lower_visibility(use_item); + + // Every use item can expand to many `Import`s. + let mut imports = Vec::new(); + ModPath::expand_use_item( + InFile::new(self.file, use_item.clone()), + &self.hygiene, + |path, _tree, is_glob, alias| { + imports.push(Import { + path, + alias, + visibility: visibility.clone(), + is_glob, + is_prelude, + is_extern_crate: false, + is_macro_use: false, + }); + }, + ); + + imports + } + + fn lower_extern_crate(&mut self, extern_crate: &ast::ExternCrateItem) -> Option { + let path = ModPath::from_name_ref(&extern_crate.name_ref()?); + let alias = extern_crate.alias().map(|a| { + a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) + }); + let visibility = self.lower_visibility(extern_crate); + // FIXME: cfg_attr + let is_macro_use = extern_crate.has_atom_attr("macro_use"); + + Some(Import { + path, + alias, + visibility, + is_glob: false, + is_prelude: false, + is_extern_crate: true, + is_macro_use, + }) + } + + fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option { + let name = m.name().map(|it| it.as_name()); + let attrs = Attrs::new(m, &self.hygiene); + let path = ModPath::from_src(m.path()?, &self.hygiene)?; + + let ast_id = self.source_ast_id_map.ast_id(m); + + // FIXME: cfg_attr + let export_attr = attrs.by_key("macro_export"); + + let is_export = export_attr.exists(); + let is_local_inner = if is_export { + export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { + tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { + ident.text.contains("local_inner_macros") + } + _ => false, + }) + } else { + false + }; + + let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); + Some(MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }) + } + + fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec> { + block.extern_item_list().map_or(Vec::new(), |list| { + list.extern_items() + .filter_map(|item| match item { + ast::ExternItem::FnDef(ast) => self.lower_function(&ast).map(Either::Left), + ast::ExternItem::StaticDef(ast) => self.lower_static(&ast).map(Either::Right), + }) + .collect() + }) + } + + fn lower_generic_params( + &mut self, + _item: &impl ast::TypeParamsOwner, + ) -> generics::GenericParams { + // TODO + generics::GenericParams { types: Arena::new(), where_predicates: Vec::new() } } fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { @@ -583,7 +760,7 @@ impl Ctx { } fn desugar_future_path(orig: TypeRef) -> Path { - let path = path![std::future::Future]; + let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); let mut last = GenericArgs::empty(); let binding = From e24de2007fe1850bb5c6c289ea48f7cb4424bb0a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 12 Jun 2020 23:24:26 +0200 Subject: [PATCH 04/34] collector changes WIP --- crates/ra_hir_def/src/item_tree.rs | 12 ++++-- crates/ra_hir_def/src/nameres/collector.rs | 50 +++++++++++----------- crates/ra_hir_def/src/nameres/raw.rs | 1 + 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 3ea6e10c98..9dee4f43d3 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -82,8 +82,8 @@ impl ItemTree { /// Returns an iterator over all items located at the top level of the `HirFileId` this /// `ItemTree` was created from. - pub fn top_level_items(&self) -> impl Iterator + '_ { - self.top_level.iter().copied() + pub fn top_level_items(&self) -> &[ModItem] { + &self.top_level } } @@ -120,7 +120,7 @@ impl_index!( ); /// A desugared `extern crate` or `use` import. -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Import { pub path: ModPath, pub alias: Option, @@ -220,6 +220,12 @@ pub struct Mod { pub items: Vec, } +pub enum ModKind { + Inline { items: Vec }, + + Outline {}, +} + #[derive(Debug, Eq, PartialEq)] pub struct MacroCall { pub name: Option, diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index cbce043159..034f274107 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -19,9 +19,10 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, + item_tree::{Import, ItemTree, Mod, ModItem}, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, - raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, + BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, }, path::{ImportAlias, ModPath, PathKind}, per_ns::PerNs, @@ -30,6 +31,7 @@ use crate::{ FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, }; +use ra_arena::Idx; pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { let crate_graph = db.crate_graph(); @@ -104,8 +106,8 @@ impl PartialResolvedImport { #[derive(Clone, Debug, Eq, PartialEq)] struct ImportDirective { module_id: LocalModuleId, - import_id: raw::Import, - import: raw::ImportData, + import_id: Idx, + import: Import, status: PartialResolvedImport, } @@ -140,7 +142,7 @@ struct DefCollector<'a> { impl DefCollector<'_> { fn collect(&mut self) { let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; - let raw_items = self.db.raw_items(file_id.into()); + let item_tree = self.db.item_tree(file_id.into()); let module_id = self.def_map.root; self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; ModCollector { @@ -148,10 +150,10 @@ impl DefCollector<'_> { macro_depth: 0, module_id, file_id: file_id.into(), - raw_items: &raw_items, + item_tree: &item_tree, mod_dir: ModDir::root(), } - .collect(raw_items.items()); + .collect(item_tree.top_level_items()); // main name resolution fixed-point loop. let mut i = 0; @@ -286,7 +288,7 @@ impl DefCollector<'_> { fn import_macros_from_extern_crate( &mut self, current_module_id: LocalModuleId, - import: &raw::ImportData, + import: &Import, ) { log::debug!( "importing macros from extern crate: {:?} ({:?})", @@ -352,11 +354,7 @@ impl DefCollector<'_> { } } - fn resolve_import( - &self, - module_id: LocalModuleId, - import: &raw::ImportData, - ) -> PartialResolvedImport { + fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); if import.is_extern_crate { let res = self.def_map.resolve_name_in_extern_prelude( @@ -649,17 +647,17 @@ impl DefCollector<'_> { depth: usize, ) { let file_id: HirFileId = macro_call_id.as_file(); - let raw_items = self.db.raw_items(file_id); + let item_tree = self.db.item_tree(file_id); let mod_dir = self.mod_dirs[&module_id].clone(); ModCollector { def_collector: &mut *self, macro_depth: depth, file_id, module_id, - raw_items: &raw_items, + item_tree: &item_tree, mod_dir, } - .collect(raw_items.items()); + .collect(item_tree.top_level_items()); } fn finish(self) -> CrateDefMap { @@ -673,12 +671,12 @@ struct ModCollector<'a, 'b> { macro_depth: usize, module_id: LocalModuleId, file_id: HirFileId, - raw_items: &'a raw::RawItems, + item_tree: &'a ItemTree, mod_dir: ModDir, } impl ModCollector<'_, '_> { - fn collect(&mut self, items: &[raw::RawItem]) { + fn collect(&mut self, items: &[ModItem]) { // Note: don't assert that inserted value is fresh: it's simply not true // for macros. self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); @@ -697,7 +695,7 @@ impl ModCollector<'_, '_> { for item in items { if self.is_cfg_enabled(&item.attrs) { if let raw::RawItemKind::Import(import_id) = item.kind { - let import = self.raw_items[import_id].clone(); + let import = self.item_tree[import_id].clone(); if import.is_extern_crate && import.is_macro_use { self.def_collector.import_macros_from_extern_crate(self.module_id, &import); } @@ -709,27 +707,27 @@ impl ModCollector<'_, '_> { if self.is_cfg_enabled(&item.attrs) { match item.kind { raw::RawItemKind::Module(m) => { - self.collect_module(&self.raw_items[m], &item.attrs) + self.collect_module(&self.item_tree[m], &item.attrs) } raw::RawItemKind::Import(import_id) => { self.def_collector.unresolved_imports.push(ImportDirective { module_id: self.module_id, import_id, - import: self.raw_items[import_id].clone(), + import: self.item_tree[import_id].clone(), status: PartialResolvedImport::Unresolved, }) } raw::RawItemKind::Def(def) => { - self.define_def(&self.raw_items[def], &item.attrs) + self.define_def(&self.item_tree[def], &item.attrs) } - raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), + raw::RawItemKind::Macro(mac) => self.collect_macro(&self.item_tree[mac]), raw::RawItemKind::Impl(imp) => { let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id, }; let container = ContainerId::ModuleId(module); - let ast_id = self.raw_items[imp].ast_id; + let ast_id = self.item_tree[imp].ast_id; let impl_id = ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } .intern(self.def_collector.db); @@ -742,7 +740,7 @@ impl ModCollector<'_, '_> { } } - fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { + fn collect_module(&mut self, module: &Mod, attrs: &Attrs) { let path_attr = attrs.by_key("path").string_value(); let is_macro_use = attrs.by_key("macro_use").exists(); match module { @@ -760,7 +758,7 @@ impl ModCollector<'_, '_> { macro_depth: self.macro_depth, module_id, file_id: self.file_id, - raw_items: self.raw_items, + item_tree: self.item_tree, mod_dir: self.mod_dir.descend_into_definition(name, path_attr), } .collect(&*items); @@ -790,7 +788,7 @@ impl ModCollector<'_, '_> { macro_depth: self.macro_depth, module_id, file_id: file_id.into(), - raw_items: &raw_items, + item_tree: &raw_items, mod_dir, } .collect(raw_items.items()); diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f44baa5794..d83a5b2b56 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -46,6 +46,7 @@ pub struct RawItems { impl RawItems { pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = profile("raw_items_query"); + db.item_tree(file_id); let mut collector = RawItemsCollector { raw_items: RawItems::default(), source_ast_id_map: db.ast_id_map(file_id), From f9417bcf49f531e0382afd405b9163f791f91c85 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Jun 2020 19:16:02 +0200 Subject: [PATCH 05/34] Draw the rest of the owl --- crates/ra_hir_def/src/item_tree.rs | 135 +++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 27 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 9dee4f43d3..71b4158024 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -19,6 +19,7 @@ use crate::{ }; use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; use either::Either; +use rustc_hash::FxHashMap; use smallvec::SmallVec; use std::{ ops::{Index, Range}, @@ -29,6 +30,10 @@ use std::{ #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { top_level: Vec, + top_attrs: Attrs, + attrs: FxHashMap, + empty_attrs: Attrs, + imports: Arena, functions: Arena, structs: Arena, @@ -48,12 +53,15 @@ pub struct ItemTree { impl ItemTree { pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { + let _p = ra_prof::profile("item_tree_query"); let syntax = if let Some(node) = db.parse_or_expand(file_id) { node } else { return Default::default(); }; + let hygiene = Hygiene::new(db.upcast(), file_id); + let mut top_attrs = None; let (macro_storage, file_storage); let item_owner = match_ast! { match syntax { @@ -62,6 +70,7 @@ impl ItemTree { ¯o_storage as &dyn ModuleItemOwner }, ast::SourceFile(file) => { + top_attrs = Some(Attrs::new(&file, &hygiene)); file_storage = file; &file_storage }, @@ -70,13 +79,14 @@ impl ItemTree { }; let map = db.ast_id_map(file_id); - let ctx = Ctx { + let mut ctx = Ctx { tree: ItemTree::default(), - hygiene: Hygiene::new(db.upcast(), file_id), + hygiene, file: file_id, source_ast_id_map: map, body_ctx: crate::body::LowerCtx::new(db, file_id), }; + ctx.tree.top_attrs = top_attrs.unwrap_or_default(); Arc::new(ctx.lower(item_owner)) } @@ -85,6 +95,15 @@ impl ItemTree { pub fn top_level_items(&self) -> &[ModItem] { &self.top_level } + + /// Returns the inner attributes of the source file. + pub fn top_level_attrs(&self) -> &Attrs { + &self.top_attrs + } + + pub fn attrs(&self, of: ModItem) -> &Attrs { + self.attrs.get(&of).unwrap_or(&self.empty_attrs) + } } macro_rules! impl_index { @@ -140,7 +159,7 @@ pub struct Function { pub has_self_param: bool, pub params: Vec, pub ret_type: TypeRef, - pub ast: FileAstId, + pub ast_id: FileAstId, // FIXME inner items } @@ -151,7 +170,18 @@ pub struct Struct { pub visibility: RawVisibility, pub generic_params: generics::GenericParams, pub fields: Fields, - pub ast: FileAstId, + pub ast_id: FileAstId, + pub kind: StructDefKind, +} + +#[derive(Debug, Eq, PartialEq)] +pub enum StructDefKind { + /// `struct S { ... }` - type namespace only. + Record, + /// `struct S(...);` + Tuple, + /// `struct S;` + Unit, } #[derive(Debug, Eq, PartialEq)] @@ -161,6 +191,7 @@ pub struct Union { pub visibility: RawVisibility, pub generic_params: generics::GenericParams, pub fields: Fields, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -170,6 +201,7 @@ pub struct Enum { pub visibility: RawVisibility, pub generic_params: generics::GenericParams, pub variants: Range>, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -178,6 +210,7 @@ pub struct Const { pub name: Option, pub visibility: RawVisibility, pub type_ref: TypeRef, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -185,6 +218,7 @@ pub struct Static { pub name: Name, pub visibility: RawVisibility, pub type_ref: TypeRef, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -194,6 +228,7 @@ pub struct Trait { pub generic_params: generics::GenericParams, pub auto: bool, pub items: Vec, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -203,6 +238,7 @@ pub struct Impl { pub target_type: TypeRef, pub is_negative: bool, pub items: Vec, + pub ast_id: FileAstId, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -211,24 +247,31 @@ pub struct TypeAlias { pub visibility: RawVisibility, pub generic_params: generics::GenericParams, pub type_ref: Option, + pub ast_id: FileAstId, } #[derive(Debug, Eq, PartialEq)] pub struct Mod { pub name: Name, pub visibility: RawVisibility, - pub items: Vec, + pub kind: ModKind, + pub ast_id: FileAstId, } +#[derive(Debug, Eq, PartialEq)] pub enum ModKind { + /// `mod m { ... }` Inline { items: Vec }, + /// `mod m;` Outline {}, } #[derive(Debug, Eq, PartialEq)] pub struct MacroCall { + /// For `macro_rules!` declarations, this is the name of the declared macro. pub name: Option, + /// Path to the called macro. pub path: ModPath, /// Has `#[macro_export]`. pub is_export: bool, @@ -256,7 +299,7 @@ macro_rules! impl_froms { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ModItem { Import(Idx), Function(Idx), @@ -353,7 +396,8 @@ impl Ctx { } fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option { - match item { + let attrs = Attrs::new(item, &self.hygiene); + let items = match item { ast::ModuleItem::StructDef(ast) => { self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) } @@ -406,7 +450,15 @@ impl Ctx { }) .collect::>(), )), + }; + + if !attrs.is_empty() { + for item in items.iter().flat_map(|items| &items.0) { + self.tree.attrs.insert(*item, attrs.clone()); + } } + + items } fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { @@ -430,8 +482,13 @@ impl Ctx { let name = strukt.name()?.as_name(); let generic_params = self.lower_generic_params(strukt); let fields = self.lower_fields(&strukt.kind()); - let ast = self.source_ast_id_map.ast_id(strukt); - let res = Struct { name, attrs, visibility, generic_params, fields, ast }; + let ast_id = self.source_ast_id_map.ast_id(strukt); + let kind = match strukt.kind() { + ast::StructKind::Record(_) => StructDefKind::Record, + ast::StructKind::Tuple(_) => StructDefKind::Tuple, + ast::StructKind::Unit => StructDefKind::Unit, + }; + let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; Some(res) } @@ -498,7 +555,8 @@ impl Ctx { } None => Fields::Record(self.next_field_idx()..self.next_field_idx()), }; - let res = Union { name, attrs, visibility, generic_params, fields }; + let ast_id = self.source_ast_id_map.ast_id(union); + let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; Some(res) } @@ -511,7 +569,8 @@ impl Ctx { Some(variant_list) => self.lower_variants(variant_list), None => self.next_variant_idx()..self.next_variant_idx(), }; - let res = Enum { name, attrs, visibility, generic_params, variants }; + let ast_id = self.source_ast_id_map.ast_id(enum_); + let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; Some(res) } @@ -578,7 +637,7 @@ impl Ctx { ret_type }; - let ast = self.source_ast_id_map.ast_id(func); + let ast_id = self.source_ast_id_map.ast_id(func); let res = Function { name, attrs, @@ -587,7 +646,7 @@ impl Ctx { has_self_param, params, ret_type, - ast, + ast_id, }; Some(res) } @@ -597,7 +656,8 @@ impl Ctx { let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); let generic_params = self.lower_generic_params(type_alias); - let res = TypeAlias { name, visibility, generic_params, type_ref }; + let ast_id = self.source_ast_id_map.ast_id(type_alias); + let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; Some(res) } @@ -605,7 +665,8 @@ impl Ctx { let name = static_.name()?.as_name(); let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); let visibility = self.lower_visibility(static_); - let res = Static { name, visibility, type_ref }; + let ast_id = self.source_ast_id_map.ast_id(static_); + let res = Static { name, visibility, type_ref, ast_id }; Some(res) } @@ -613,19 +674,30 @@ impl Ctx { let name = konst.name().map(|it| it.as_name()); let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); let visibility = self.lower_visibility(konst); - Const { name, visibility, type_ref } + let ast_id = self.source_ast_id_map.ast_id(konst); + Const { name, visibility, type_ref, ast_id } } fn lower_module(&mut self, module: &ast::Module) -> Option { let name = module.name()?.as_name(); let visibility = self.lower_visibility(module); - let items = module.item_list().map(move |list| { - list.items() - .flat_map(move |item| self.lower_mod_item(&item)) - .flat_map(|items| items.0) - .collect() - }); - Some(Mod { name, visibility, items: items.unwrap_or_default() }) + let kind = if module.semicolon_token().is_some() { + ModKind::Outline {} + } else { + ModKind::Inline { + items: module + .item_list() + .map(|list| { + list.items() + .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|items| items.0) + .collect() + }) + .unwrap_or_default(), + } + }; + let ast_id = self.source_ast_id_map.ast_id(module); + Some(Mod { name, visibility, kind, ast_id }) } fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { @@ -633,11 +705,19 @@ impl Ctx { let visibility = self.lower_visibility(trait_def); let generic_params = self.lower_generic_params(trait_def); let auto = trait_def.auto_token().is_some(); - let items = trait_def.item_list().map(move |list| { + let items = trait_def.item_list().map(|list| { // FIXME: Does not handle macros - list.assoc_items().flat_map(move |item| self.lower_assoc_item(&item)).collect() + list.assoc_items().flat_map(|item| self.lower_assoc_item(&item)).collect() }); - Some(Trait { name, visibility, generic_params, auto, items: items.unwrap_or_default() }) + let ast_id = self.source_ast_id_map.ast_id(trait_def); + Some(Trait { + name, + visibility, + generic_params, + auto, + items: items.unwrap_or_default(), + ast_id, + }) } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { @@ -650,7 +730,8 @@ impl Ctx { .assoc_items() .filter_map(|item| self.lower_assoc_item(&item)) .collect(); - Some(Impl { generic_params, target_trait, target_type, is_negative, items }) + let ast_id = self.source_ast_id_map.ast_id(impl_def); + Some(Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }) } fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec { From 9d244129296a1805f890640016719afcee66a320 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Jun 2020 19:16:14 +0200 Subject: [PATCH 06/34] Move collector --- crates/ra_hir_def/src/nameres/collector.rs | 301 +++++++++++++-------- 1 file changed, 193 insertions(+), 108 deletions(-) diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 034f274107..b899a5fb35 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -4,6 +4,7 @@ //! resolves imports and expands macros. use hir_expand::{ + ast_id_map::FileAstId, builtin_derive::find_builtin_derive, builtin_macro::find_builtin_macro, name::{name, AsName, Name}, @@ -19,14 +20,14 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, - item_tree::{Import, ItemTree, Mod, ModItem}, + item_tree::{Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind}, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, }, path::{ImportAlias, ModPath, PathKind}, per_ns::PerNs, - visibility::Visibility, + visibility::{RawVisibility, Visibility}, AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, @@ -125,6 +126,13 @@ struct DeriveDirective { ast_id: AstIdWithPath, } +struct DefData<'a> { + id: ModuleDefId, + name: &'a Name, + visibility: &'a RawVisibility, + has_constructor: bool, +} + /// Walks the tree of module recursively struct DefCollector<'a> { db: &'a dyn DefDatabase, @@ -693,9 +701,9 @@ impl ModCollector<'_, '_> { // `#[macro_use] extern crate` is hoisted to imports macros before collecting // any other items. for item in items { - if self.is_cfg_enabled(&item.attrs) { - if let raw::RawItemKind::Import(import_id) = item.kind { - let import = self.item_tree[import_id].clone(); + if self.is_cfg_enabled(self.item_tree.attrs(*item)) { + if let ModItem::Import(import_id) = item { + let import = self.item_tree[*import_id].clone(); if import.is_extern_crate && import.is_macro_use { self.def_collector.import_macros_from_extern_crate(self.module_id, &import); } @@ -703,13 +711,17 @@ impl ModCollector<'_, '_> { } } - for item in items { - if self.is_cfg_enabled(&item.attrs) { - match item.kind { - raw::RawItemKind::Module(m) => { - self.collect_module(&self.item_tree[m], &item.attrs) - } - raw::RawItemKind::Import(import_id) => { + for &item in items { + let attrs = self.item_tree.attrs(item); + if self.is_cfg_enabled(attrs) { + let module = + ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; + let container = ContainerId::ModuleId(module); + + let mut def = None; + match item { + ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs), + ModItem::Import(import_id) => { self.def_collector.unresolved_imports.push(ImportDirective { module_id: self.module_id, import_id, @@ -717,11 +729,8 @@ impl ModCollector<'_, '_> { status: PartialResolvedImport::Unresolved, }) } - raw::RawItemKind::Def(def) => { - self.define_def(&self.item_tree[def], &item.attrs) - } - raw::RawItemKind::Macro(mac) => self.collect_macro(&self.item_tree[mac]), - raw::RawItemKind::Impl(imp) => { + ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]), + ModItem::Impl(imp) => { let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id, @@ -735,6 +744,147 @@ impl ModCollector<'_, '_> { .scope .define_impl(impl_id) } + ModItem::Function(it) => { + let it = &self.item_tree[it]; + def = Some(DefData { + id: FunctionLoc { + container: container.into(), + ast_id: AstId::new(self.file_id, it.ast_id), + } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::Struct(it) => { + let it = &self.item_tree[it]; + + // FIXME: check attrs to see if this is an attribute macro invocation; + // in which case we don't add the invocation, just a single attribute + // macro invocation + self.collect_derives(attrs, it.ast_id.upcast()); + + def = Some(DefData { + id: StructLoc { + container, + ast_id: AstId::new(self.file_id, it.ast_id), + } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: it.kind != StructDefKind::Record, + }); + } + ModItem::Union(it) => { + let it = &self.item_tree[it]; + + // FIXME: check attrs to see if this is an attribute macro invocation; + // in which case we don't add the invocation, just a single attribute + // macro invocation + self.collect_derives(attrs, it.ast_id.upcast()); + + def = Some(DefData { + id: UnionLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::Enum(it) => { + let it = &self.item_tree[it]; + + // FIXME: check attrs to see if this is an attribute macro invocation; + // in which case we don't add the invocation, just a single attribute + // macro invocation + self.collect_derives(attrs, it.ast_id.upcast()); + + def = Some(DefData { + id: EnumLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::Const(it) => { + let it = &self.item_tree[it]; + + if let Some(name) = &it.name { + def = Some(DefData { + id: ConstLoc { + container: container.into(), + ast_id: AstId::new(self.file_id, it.ast_id), + } + .intern(self.def_collector.db) + .into(), + name, + visibility: &it.visibility, + has_constructor: false, + }); + } + } + ModItem::Static(it) => { + let it = &self.item_tree[it]; + + def = Some(DefData { + id: StaticLoc { + container, + ast_id: AstId::new(self.file_id, it.ast_id), + } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::Trait(it) => { + let it = &self.item_tree[it]; + + def = Some(DefData { + id: TraitLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::TypeAlias(it) => { + let it = &self.item_tree[it]; + + def = Some(DefData { + id: TypeAliasLoc { + container: container.into(), + ast_id: AstId::new(self.file_id, it.ast_id), + } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + } + + if let Some(DefData { id, name, visibility, has_constructor }) = def { + self.def_collector.def_map.modules[self.module_id].scope.define_def(id); + let vis = self + .def_collector + .def_map + .resolve_visibility(self.def_collector.db, self.module_id, visibility) + .unwrap_or(Visibility::Public); + self.def_collector.update( + self.module_id, + &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], + vis, + ) } } } @@ -743,14 +893,14 @@ impl ModCollector<'_, '_> { fn collect_module(&mut self, module: &Mod, attrs: &Attrs) { let path_attr = attrs.by_key("path").string_value(); let is_macro_use = attrs.by_key("macro_use").exists(); - match module { + match &module.kind { // inline module, just recurse - raw::ModuleData::Definition { name, visibility, items, ast_id } => { + ModKind::Inline { items } => { let module_id = self.push_child_module( - name.clone(), - AstId::new(self.file_id, *ast_id), + module.name.clone(), + AstId::new(self.file_id, module.ast_id), None, - &visibility, + &module.visibility, ); ModCollector { @@ -759,7 +909,7 @@ impl ModCollector<'_, '_> { module_id, file_id: self.file_id, item_tree: self.item_tree, - mod_dir: self.mod_dir.descend_into_definition(name, path_attr), + mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr), } .collect(&*items); if is_macro_use { @@ -767,31 +917,31 @@ impl ModCollector<'_, '_> { } } // out of line module, resolve, parse and recurse - raw::ModuleData::Declaration { name, visibility, ast_id } => { - let ast_id = AstId::new(self.file_id, *ast_id); + ModKind::Outline {} => { + let ast_id = AstId::new(self.file_id, module.ast_id); match self.mod_dir.resolve_declaration( self.def_collector.db, self.file_id, - name, + &module.name, path_attr, ) { Ok((file_id, is_mod_rs, mod_dir)) => { let module_id = self.push_child_module( - name.clone(), + module.name.clone(), ast_id, Some((file_id, is_mod_rs)), - &visibility, + &module.visibility, ); - let raw_items = self.def_collector.db.raw_items(file_id.into()); + let item_tree = self.def_collector.db.item_tree(file_id.into()); ModCollector { def_collector: &mut *self.def_collector, macro_depth: self.macro_depth, module_id, file_id: file_id.into(), - item_tree: &raw_items, + item_tree: &item_tree, mod_dir, } - .collect(raw_items.items()); + .collect(item_tree.top_level_items()); if is_macro_use { self.import_all_legacy_macros(module_id); } @@ -840,77 +990,7 @@ impl ModCollector<'_, '_> { res } - fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { - let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; - // FIXME: check attrs to see if this is an attribute macro invocation; - // in which case we don't add the invocation, just a single attribute - // macro invocation - self.collect_derives(attrs, def); - - let name = def.name.clone(); - let container = ContainerId::ModuleId(module); - let vis = &def.visibility; - let mut has_constructor = false; - - let def: ModuleDefId = match def.kind { - raw::DefKind::Function(ast_id) => FunctionLoc { - container: container.into(), - ast_id: AstId::new(self.file_id, ast_id), - } - .intern(self.def_collector.db) - .into(), - raw::DefKind::Struct(ast_id, mode) => { - has_constructor = mode != raw::StructDefKind::Record; - StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::Union(ast_id) => { - UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::Enum(ast_id) => { - EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::Const(ast_id) => { - ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::Static(ast_id) => { - StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::Trait(ast_id) => { - TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db) - .into() - } - raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc { - container: container.into(), - ast_id: AstId::new(self.file_id, ast_id), - } - .intern(self.def_collector.db) - .into(), - }; - self.def_collector.def_map.modules[self.module_id].scope.define_def(def); - let vis = self - .def_collector - .def_map - .resolve_visibility(self.def_collector.db, self.module_id, vis) - .unwrap_or(Visibility::Public); - self.def_collector.update( - self.module_id, - &[(name, PerNs::from_def(def, vis, has_constructor))], - vis, - ) - } - - fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { + fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId) { for derive_subtree in attrs.by_key("derive").tt_values() { // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree for tt in &derive_subtree.token_trees { @@ -921,7 +1001,7 @@ impl ModCollector<'_, '_> { }; let path = ModPath::from_tt_ident(ident); - let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path); + let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); self.def_collector .unexpanded_attribute_macros .push(DeriveDirective { module_id: self.module_id, ast_id }); @@ -929,11 +1009,11 @@ impl ModCollector<'_, '_> { } } - fn collect_macro(&mut self, mac: &raw::MacroData) { + fn collect_macro(&mut self, mac: &MacroCall) { let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); // Case 0: builtin macros - if mac.builtin { + if mac.is_builtin { if let Some(name) = &mac.name { let krate = self.def_collector.def_map.krate; if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { @@ -941,7 +1021,7 @@ impl ModCollector<'_, '_> { self.module_id, name.clone(), macro_id, - mac.export, + mac.is_export, ); return; } @@ -955,9 +1035,14 @@ impl ModCollector<'_, '_> { ast_id: Some(ast_id.ast_id), krate: Some(self.def_collector.def_map.krate), kind: MacroDefKind::Declarative, - local_inner: mac.local_inner, + local_inner: mac.is_local_inner, }; - self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); + self.def_collector.define_macro( + self.module_id, + name.clone(), + macro_id, + mac.is_export, + ); } return; } From 7054e89d187287c0547ef43961bf4969aba57dd6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Jun 2020 19:16:29 +0200 Subject: [PATCH 07/34] Fix test --- crates/ra_hir_def/src/item_tree.rs | 6 +++++- crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 71b4158024..245ee5e629 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -8,6 +8,7 @@ use hir_expand::{ }; use ra_arena::{Arena, Idx, RawId}; use ra_syntax::{ast, match_ast}; +use test_utils::mark; use crate::{ attr::Attrs, @@ -693,7 +694,10 @@ impl Ctx { .flat_map(|items| items.0) .collect() }) - .unwrap_or_default(), + .unwrap_or_else(|| { + mark::hit!(name_res_works_for_broken_modules); + Vec::new() + }), } }; let ast_id = self.source_ast_id_map.ast_id(module); diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index b43b294cab..d42933eed7 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs @@ -20,8 +20,11 @@ fn name_res_works_for_broken_modules() { ", ); assert_snapshot!(map, @r###" - â‹®crate - â‹®Baz: _ +crate +Baz: _ +foo: t + +crate::foo "###); } From 0e2602f75e17b35472637c8ebd8e6e436a5f2af4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Jun 2020 19:16:43 +0200 Subject: [PATCH 08/34] Remove raw item query --- crates/ra_hir/src/db.rs | 4 +- crates/ra_hir_def/src/db.rs | 5 +- crates/ra_hir_def/src/nameres.rs | 1 - crates/ra_hir_def/src/nameres/raw.rs | 483 --------------------------- crates/ra_ide_db/src/change.rs | 1 - 5 files changed, 3 insertions(+), 491 deletions(-) delete mode 100644 crates/ra_hir_def/src/nameres/raw.rs diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index b25dac28ec..309402a5aa 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -6,8 +6,8 @@ pub use hir_def::db::{ ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, - InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, - StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, + InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery, StructDataQuery, + TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index c4c9e10a3d..9c3ede2d79 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -16,7 +16,7 @@ use crate::{ import_map::ImportMap, item_tree::ItemTree, lang_item::{LangItemTarget, LangItems}, - nameres::{raw::RawItems, CrateDefMap}, + nameres::CrateDefMap, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, @@ -46,9 +46,6 @@ pub trait InternDatabase: SourceDatabase { #[salsa::query_group(DefDatabaseStorage)] pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { - #[salsa::invoke(RawItems::raw_items_query)] - fn raw_items(&self, file_id: HirFileId) -> Arc; - #[salsa::invoke(ItemTree::item_tree_query)] fn item_tree(&self, file_id: HirFileId) -> Arc; diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 060273db40..b279bdeef6 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -47,7 +47,6 @@ //! path and, upon success, we run macro expansion and "collect module" phase on //! the result -pub(crate) mod raw; mod collector; mod mod_resolution; mod path_resolution; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs deleted file mode 100644 index d83a5b2b56..0000000000 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ /dev/null @@ -1,483 +0,0 @@ -//! Lowers syntax tree of a rust file into a raw representation of containing -//! items, *without* attaching them to a module structure. -//! -//! That is, raw items don't have semantics, just as syntax, but, unlike syntax, -//! they don't change with trivial source code edits, making them a great tool -//! for building salsa recomputation firewalls. - -use std::{ops::Index, sync::Arc}; - -use hir_expand::{ - ast_id_map::AstIdMap, - hygiene::Hygiene, - name::{AsName, Name}, -}; -use ra_arena::{Arena, Idx}; -use ra_prof::profile; -use ra_syntax::{ - ast::{self, AttrsOwner, NameOwner, VisibilityOwner}, - AstNode, -}; -use test_utils::mark; - -use crate::{ - attr::Attrs, - db::DefDatabase, - path::{ImportAlias, ModPath}, - visibility::RawVisibility, - FileAstId, HirFileId, InFile, -}; - -/// `RawItems` is a set of top-level items in a file (except for impls). -/// -/// It is the input to name resolution algorithm. `RawItems` are not invalidated -/// on most edits. -#[derive(Debug, Default, PartialEq, Eq)] -pub struct RawItems { - modules: Arena, - imports: Arena, - defs: Arena, - macros: Arena, - impls: Arena, - /// items for top-level module - items: Vec, -} - -impl RawItems { - pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = profile("raw_items_query"); - db.item_tree(file_id); - let mut collector = RawItemsCollector { - raw_items: RawItems::default(), - source_ast_id_map: db.ast_id_map(file_id), - file_id, - hygiene: Hygiene::new(db.upcast(), file_id), - }; - if let Some(node) = db.parse_or_expand(file_id) { - if let Some(source_file) = ast::SourceFile::cast(node.clone()) { - collector.process_module(None, source_file); - } else if let Some(item_list) = ast::MacroItems::cast(node) { - collector.process_module(None, item_list); - } - } - let raw_items = collector.raw_items; - Arc::new(raw_items) - } - - pub(super) fn items(&self) -> &[RawItem] { - &self.items - } -} - -impl Index> for RawItems { - type Output = ModuleData; - fn index(&self, idx: Idx) -> &ModuleData { - &self.modules[idx] - } -} - -impl Index for RawItems { - type Output = ImportData; - fn index(&self, idx: Import) -> &ImportData { - &self.imports[idx] - } -} - -impl Index> for RawItems { - type Output = DefData; - fn index(&self, idx: Idx) -> &DefData { - &self.defs[idx] - } -} - -impl Index> for RawItems { - type Output = MacroData; - fn index(&self, idx: Idx) -> &MacroData { - &self.macros[idx] - } -} - -impl Index> for RawItems { - type Output = ImplData; - fn index(&self, idx: Idx) -> &ImplData { - &self.impls[idx] - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub(super) struct RawItem { - pub(super) attrs: Attrs, - pub(super) kind: RawItemKind, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(super) enum RawItemKind { - Module(Idx), - Import(Import), - Def(Idx), - Macro(Idx), - Impl(Idx), -} - -#[derive(Debug, PartialEq, Eq)] -pub(super) enum ModuleData { - Declaration { - name: Name, - visibility: RawVisibility, - ast_id: FileAstId, - }, - Definition { - name: Name, - visibility: RawVisibility, - ast_id: FileAstId, - items: Vec, - }, -} - -pub(crate) type Import = Idx; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ImportData { - pub(super) path: ModPath, - pub(super) alias: Option, - pub(super) is_glob: bool, - pub(super) is_prelude: bool, - pub(super) is_extern_crate: bool, - pub(super) is_macro_use: bool, - pub(super) visibility: RawVisibility, -} - -// type Def = Idx; - -#[derive(Debug, PartialEq, Eq)] -pub(super) struct DefData { - pub(super) name: Name, - pub(super) kind: DefKind, - pub(super) visibility: RawVisibility, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(super) enum StructDefKind { - Record, - Tuple, - Unit, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(super) enum DefKind { - Function(FileAstId), - Struct(FileAstId, StructDefKind), - Union(FileAstId), - Enum(FileAstId), - Const(FileAstId), - Static(FileAstId), - Trait(FileAstId), - TypeAlias(FileAstId), -} - -impl DefKind { - pub fn ast_id(self) -> FileAstId { - match self { - DefKind::Function(it) => it.upcast(), - DefKind::Struct(it, _) => it.upcast(), - DefKind::Union(it) => it.upcast(), - DefKind::Enum(it) => it.upcast(), - DefKind::Const(it) => it.upcast(), - DefKind::Static(it) => it.upcast(), - DefKind::Trait(it) => it.upcast(), - DefKind::TypeAlias(it) => it.upcast(), - } - } -} - -#[derive(Debug, PartialEq, Eq)] -pub(super) struct MacroData { - pub(super) ast_id: FileAstId, - pub(super) path: ModPath, - pub(super) name: Option, - pub(super) export: bool, - pub(super) local_inner: bool, - pub(super) builtin: bool, -} - -#[derive(Debug, PartialEq, Eq)] -pub(super) struct ImplData { - pub(super) ast_id: FileAstId, -} - -struct RawItemsCollector { - raw_items: RawItems, - source_ast_id_map: Arc, - file_id: HirFileId, - hygiene: Hygiene, -} - -impl RawItemsCollector { - fn process_module( - &mut self, - current_module: Option>, - body: impl ast::ModuleItemOwner, - ) { - for item in body.items() { - self.add_item(current_module, item) - } - } - - fn add_item(&mut self, current_module: Option>, item: ast::ModuleItem) { - let attrs = self.parse_attrs(&item); - let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); - let (kind, name) = match item { - ast::ModuleItem::Module(module) => { - self.add_module(current_module, module); - return; - } - ast::ModuleItem::UseItem(use_item) => { - self.add_use_item(current_module, use_item); - return; - } - ast::ModuleItem::ExternCrateItem(extern_crate) => { - self.add_extern_crate_item(current_module, extern_crate); - return; - } - ast::ModuleItem::ImplDef(it) => { - self.add_impl(current_module, it); - return; - } - ast::ModuleItem::StructDef(it) => { - let kind = match it.kind() { - ast::StructKind::Record(_) => StructDefKind::Record, - ast::StructKind::Tuple(_) => StructDefKind::Tuple, - ast::StructKind::Unit => StructDefKind::Unit, - }; - let id = self.source_ast_id_map.ast_id(&it); - let name = it.name(); - (DefKind::Struct(id, kind), name) - } - ast::ModuleItem::UnionDef(it) => { - let id = self.source_ast_id_map.ast_id(&it); - let name = it.name(); - (DefKind::Union(id), name) - } - ast::ModuleItem::EnumDef(it) => { - (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::FnDef(it) => { - (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::TraitDef(it) => { - (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::TypeAliasDef(it) => { - (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::ConstDef(it) => { - (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::StaticDef(it) => { - (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ModuleItem::MacroCall(it) => { - self.add_macro(current_module, it); - return; - } - ast::ModuleItem::ExternBlock(it) => { - self.add_extern_block(current_module, it); - return; - } - }; - if let Some(name) = name { - let name = name.as_name(); - let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); - self.push_item(current_module, attrs, RawItemKind::Def(def)); - } - } - - fn add_extern_block( - &mut self, - current_module: Option>, - block: ast::ExternBlock, - ) { - if let Some(items) = block.extern_item_list() { - for item in items.extern_items() { - let attrs = self.parse_attrs(&item); - let visibility = - RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene); - let (kind, name) = match item { - ast::ExternItem::FnDef(it) => { - (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) - } - ast::ExternItem::StaticDef(it) => { - (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) - } - }; - - if let Some(name) = name { - let name = name.as_name(); - let def = self.raw_items.defs.alloc(DefData { name, kind, visibility }); - self.push_item(current_module, attrs, RawItemKind::Def(def)); - } - } - } - } - - fn add_module(&mut self, current_module: Option>, module: ast::Module) { - let name = match module.name() { - Some(it) => it.as_name(), - None => return, - }; - let attrs = self.parse_attrs(&module); - let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); - - let ast_id = self.source_ast_id_map.ast_id(&module); - if module.semicolon_token().is_some() { - let item = - self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); - self.push_item(current_module, attrs, RawItemKind::Module(item)); - return; - } - - if let Some(item_list) = module.item_list() { - let item = self.raw_items.modules.alloc(ModuleData::Definition { - name, - visibility, - ast_id, - items: Vec::new(), - }); - self.process_module(Some(item), item_list); - self.push_item(current_module, attrs, RawItemKind::Module(item)); - return; - } - mark::hit!(name_res_works_for_broken_modules); - } - - fn add_use_item(&mut self, current_module: Option>, use_item: ast::UseItem) { - // FIXME: cfg_attr - let is_prelude = use_item.has_atom_attr("prelude_import"); - let attrs = self.parse_attrs(&use_item); - let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene); - - let mut buf = Vec::new(); - ModPath::expand_use_item( - InFile { value: use_item, file_id: self.file_id }, - &self.hygiene, - |path, _use_tree, is_glob, alias| { - let import_data = ImportData { - path, - alias, - is_glob, - is_prelude, - is_extern_crate: false, - is_macro_use: false, - visibility: visibility.clone(), - }; - buf.push(import_data); - }, - ); - for import_data in buf { - self.push_import(current_module, attrs.clone(), import_data); - } - } - - fn add_extern_crate_item( - &mut self, - current_module: Option>, - extern_crate: ast::ExternCrateItem, - ) { - if let Some(name_ref) = extern_crate.name_ref() { - let path = ModPath::from_name_ref(&name_ref); - let visibility = - RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene); - let alias = extern_crate.alias().map(|a| { - a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) - }); - let attrs = self.parse_attrs(&extern_crate); - // FIXME: cfg_attr - let is_macro_use = extern_crate.has_atom_attr("macro_use"); - let import_data = ImportData { - path, - alias, - is_glob: false, - is_prelude: false, - is_extern_crate: true, - is_macro_use, - visibility, - }; - self.push_import(current_module, attrs, import_data); - } - } - - fn add_macro(&mut self, current_module: Option>, m: ast::MacroCall) { - let attrs = self.parse_attrs(&m); - let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) { - Some(it) => it, - _ => return, - }; - - let name = m.name().map(|it| it.as_name()); - let ast_id = self.source_ast_id_map.ast_id(&m); - - // FIXME: cfg_attr - let export_attr = attrs.by_key("macro_export"); - - let export = export_attr.exists(); - let local_inner = if export { - export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - ident.text.contains("local_inner_macros") - } - _ => false, - }) - } else { - false - }; - - let builtin = attrs.by_key("rustc_builtin_macro").exists(); - - let m = self.raw_items.macros.alloc(MacroData { - ast_id, - path, - name, - export, - local_inner, - builtin, - }); - self.push_item(current_module, attrs, RawItemKind::Macro(m)); - } - - fn add_impl(&mut self, current_module: Option>, imp: ast::ImplDef) { - let attrs = self.parse_attrs(&imp); - let ast_id = self.source_ast_id_map.ast_id(&imp); - let imp = self.raw_items.impls.alloc(ImplData { ast_id }); - self.push_item(current_module, attrs, RawItemKind::Impl(imp)) - } - - fn push_import( - &mut self, - current_module: Option>, - attrs: Attrs, - data: ImportData, - ) { - let import = self.raw_items.imports.alloc(data); - self.push_item(current_module, attrs, RawItemKind::Import(import)) - } - - fn push_item( - &mut self, - current_module: Option>, - attrs: Attrs, - kind: RawItemKind, - ) { - match current_module { - Some(module) => match &mut self.raw_items.modules[module] { - ModuleData::Definition { items, .. } => items, - ModuleData::Declaration { .. } => unreachable!(), - }, - None => &mut self.raw_items.items, - } - .push(RawItem { attrs, kind }) - } - - fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { - Attrs::new(item, &self.hygiene) - } -} diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index a95f6c13c1..780c4feae6 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -199,7 +199,6 @@ impl RootDatabase { hir::db::InternEagerExpansionQuery // DefDatabase - hir::db::RawItemsQuery hir::db::CrateDefMapQueryQuery hir::db::StructDataQuery hir::db::UnionDataQuery From f9e5ba7d40680f8df96f33a8721ecc2eaab08ab6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Jun 2020 19:23:50 +0200 Subject: [PATCH 09/34] Remove now-broken incremental test The ItemTree tracks impl and trait items, so the CrateDefMap now needs recomputing when those change --- .../src/nameres/tests/incremental.rs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 87165ac33a..0c288a1085 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs @@ -57,44 +57,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() { ); } -#[test] -fn adding_inner_items_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - r" - //- /lib.rs - struct S { a: i32} - enum E { A } - trait T { - fn a() {} - } - mod foo;<|> - impl S { - fn a() {} - } - use crate::foo::bar::Baz; - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - pub struct Baz; - ", - r" - struct S { a: i32, b: () } - enum E { A, B } - trait T { - fn a() {} - fn b() {} - } - mod foo;<|> - impl S { - fn a() {} - fn b() {} - } - use crate::foo::bar::Baz; - ", - ); -} - #[test] fn typing_inside_a_macro_should_not_invalidate_def_map() { let (mut db, pos) = TestDB::with_position( From 278556f9fe8240f0c76daaaf8dcf7ee7f516e4af Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 16 Jun 2020 14:52:43 +0200 Subject: [PATCH 10/34] Move ItemTree lowering into its own module --- crates/ra_hir_def/src/item_tree.rs | 517 +---------------------- crates/ra_hir_def/src/item_tree/lower.rs | 501 ++++++++++++++++++++++ 2 files changed, 513 insertions(+), 505 deletions(-) create mode 100644 crates/ra_hir_def/src/item_tree/lower.rs diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 245ee5e629..a13a989dda 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -1,13 +1,23 @@ //! A simplified AST that only contains items. +mod lower; + +use std::{ + ops::{Index, Range}, + sync::Arc, +}; + +use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use either::Either; use hir_expand::{ - ast_id_map::{AstIdMap, FileAstId}, + ast_id_map::FileAstId, hygiene::Hygiene, name::{name, AsName, Name}, HirFileId, InFile, }; use ra_arena::{Arena, Idx, RawId}; use ra_syntax::{ast, match_ast}; +use rustc_hash::FxHashMap; use test_utils::mark; use crate::{ @@ -18,14 +28,6 @@ use crate::{ type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; -use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; -use either::Either; -use rustc_hash::FxHashMap; -use smallvec::SmallVec; -use std::{ - ops::{Index, Range}, - sync::Arc, -}; /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] @@ -80,7 +82,7 @@ impl ItemTree { }; let map = db.ast_id_map(file_id); - let mut ctx = Ctx { + let mut ctx = lower::Ctx { tree: ItemTree::default(), hygiene, file: file_id, @@ -366,498 +368,3 @@ pub struct Field { pub type_ref: TypeRef, pub visibility: RawVisibility, } - -struct ModItems(SmallVec<[ModItem; 1]>); - -impl From for ModItems -where - T: Into, -{ - fn from(t: T) -> Self { - ModItems(SmallVec::from_buf([t.into(); 1])) - } -} - -struct Ctx { - tree: ItemTree, - hygiene: Hygiene, - file: HirFileId, - source_ast_id_map: Arc, - body_ctx: crate::body::LowerCtx, -} - -impl Ctx { - fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { - self.tree.top_level = item_owner - .items() - .flat_map(|item| self.lower_mod_item(&item)) - .flat_map(|items| items.0) - .collect(); - self.tree - } - - fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option { - let attrs = Attrs::new(item, &self.hygiene); - let items = match item { - ast::ModuleItem::StructDef(ast) => { - self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) - } - ast::ModuleItem::UnionDef(ast) => { - self.lower_union(ast).map(|data| self.tree.unions.alloc(data).into()) - } - ast::ModuleItem::EnumDef(ast) => { - self.lower_enum(ast).map(|data| self.tree.enums.alloc(data).into()) - } - ast::ModuleItem::FnDef(ast) => { - self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) - } - ast::ModuleItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) - } - ast::ModuleItem::StaticDef(ast) => { - self.lower_static(ast).map(|data| self.tree.statics.alloc(data).into()) - } - ast::ModuleItem::ConstDef(ast) => { - let data = self.lower_const(ast); - Some(self.tree.consts.alloc(data).into()) - } - ast::ModuleItem::Module(ast) => { - self.lower_module(ast).map(|data| self.tree.mods.alloc(data).into()) - } - ast::ModuleItem::TraitDef(ast) => { - self.lower_trait(ast).map(|data| self.tree.traits.alloc(data).into()) - } - ast::ModuleItem::ImplDef(ast) => { - self.lower_impl(ast).map(|data| self.tree.impls.alloc(data).into()) - } - ast::ModuleItem::UseItem(ast) => Some(ModItems( - self.lower_use(ast) - .into_iter() - .map(|data| self.tree.imports.alloc(data).into()) - .collect::>(), - )), - ast::ModuleItem::ExternCrateItem(ast) => { - self.lower_extern_crate(ast).map(|data| self.tree.imports.alloc(data).into()) - } - ast::ModuleItem::MacroCall(ast) => { - self.lower_macro_call(ast).map(|data| self.tree.macro_calls.alloc(data).into()) - } - ast::ModuleItem::ExternBlock(ast) => Some(ModItems( - self.lower_extern_block(ast) - .into_iter() - .map(|item| match item { - Either::Left(func) => self.tree.functions.alloc(func).into(), - Either::Right(statik) => self.tree.statics.alloc(statik).into(), - }) - .collect::>(), - )), - }; - - if !attrs.is_empty() { - for item in items.iter().flat_map(|items| &items.0) { - self.tree.attrs.insert(*item, attrs.clone()); - } - } - - items - } - - fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { - match item { - ast::AssocItem::FnDef(ast) => { - self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) - } - ast::AssocItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) - } - ast::AssocItem::ConstDef(ast) => { - let data = self.lower_const(ast); - Some(self.tree.consts.alloc(data).into()) - } - } - } - - fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option { - let attrs = self.lower_attrs(strukt); - let visibility = self.lower_visibility(strukt); - let name = strukt.name()?.as_name(); - let generic_params = self.lower_generic_params(strukt); - let fields = self.lower_fields(&strukt.kind()); - let ast_id = self.source_ast_id_map.ast_id(strukt); - let kind = match strukt.kind() { - ast::StructKind::Record(_) => StructDefKind::Record, - ast::StructKind::Tuple(_) => StructDefKind::Tuple, - ast::StructKind::Unit => StructDefKind::Unit, - }; - let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; - Some(res) - } - - fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { - match strukt_kind { - ast::StructKind::Record(it) => { - let range = self.lower_record_fields(it); - Fields::Record(range) - } - ast::StructKind::Tuple(it) => { - let range = self.lower_tuple_fields(it); - Fields::Tuple(range) - } - ast::StructKind::Unit => Fields::Unit, - } - } - - fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range> { - let start = self.next_field_idx(); - for field in fields.fields() { - if let Some(data) = self.lower_record_field(&field) { - self.tree.fields.alloc(data); - } - } - let end = self.next_field_idx(); - start..end - } - - fn lower_record_field(&self, field: &ast::RecordFieldDef) -> Option { - let name = field.name()?.as_name(); - let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref(&field.ascribed_type()?); - let res = Field { name, type_ref, visibility }; - Some(res) - } - - fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range> { - let start = self.next_field_idx(); - for (i, field) in fields.fields().enumerate() { - if let Some(data) = self.lower_tuple_field(i, &field) { - self.tree.fields.alloc(data); - } - } - let end = self.next_field_idx(); - start..end - } - - fn lower_tuple_field(&self, idx: usize, field: &ast::TupleFieldDef) -> Option { - let name = Name::new_tuple_field(idx); - let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref(&field.type_ref()?); - let res = Field { name, type_ref, visibility }; - Some(res) - } - - fn lower_union(&mut self, union: &ast::UnionDef) -> Option { - let attrs = self.lower_attrs(union); - let visibility = self.lower_visibility(union); - let name = union.name()?.as_name(); - let generic_params = self.lower_generic_params(union); - let fields = match union.record_field_def_list() { - Some(record_field_def_list) => { - self.lower_fields(&StructKind::Record(record_field_def_list)) - } - None => Fields::Record(self.next_field_idx()..self.next_field_idx()), - }; - let ast_id = self.source_ast_id_map.ast_id(union); - let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; - Some(res) - } - - fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option { - let attrs = self.lower_attrs(enum_); - let visibility = self.lower_visibility(enum_); - let name = enum_.name()?.as_name(); - let generic_params = self.lower_generic_params(enum_); - let variants = match &enum_.variant_list() { - Some(variant_list) => self.lower_variants(variant_list), - None => self.next_variant_idx()..self.next_variant_idx(), - }; - let ast_id = self.source_ast_id_map.ast_id(enum_); - let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; - Some(res) - } - - fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { - let start = self.next_variant_idx(); - for variant in variants.variants() { - if let Some(data) = self.lower_variant(&variant) { - self.tree.variants.alloc(data); - } - } - let end = self.next_variant_idx(); - start..end - } - - fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option { - let name = variant.name()?.as_name(); - let fields = self.lower_fields(&variant.kind()); - let res = Variant { name, fields }; - Some(res) - } - - fn lower_function(&mut self, func: &ast::FnDef) -> Option { - let attrs = self.lower_attrs(func); - let visibility = self.lower_visibility(func); - let name = func.name()?.as_name(); - let generic_params = self.lower_generic_params(func); - - let mut params = Vec::new(); - let mut has_self_param = false; - if let Some(param_list) = func.param_list() { - if let Some(self_param) = param_list.self_param() { - let self_type = if let Some(type_ref) = self_param.ascribed_type() { - TypeRef::from_ast(&self.body_ctx, type_ref) - } else { - let self_type = TypeRef::Path(name![Self].into()); - match self_param.kind() { - ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => { - TypeRef::Reference(Box::new(self_type), Mutability::Shared) - } - ast::SelfParamKind::MutRef => { - TypeRef::Reference(Box::new(self_type), Mutability::Mut) - } - } - }; - params.push(self_type); - has_self_param = true; - } - for param in param_list.params() { - let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); - params.push(type_ref); - } - } - let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { - Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), - _ => TypeRef::unit(), - }; - - let ret_type = if func.async_token().is_some() { - let future_impl = desugar_future_path(ret_type); - let ty_bound = TypeBound::Path(future_impl); - TypeRef::ImplTrait(vec![ty_bound]) - } else { - ret_type - }; - - let ast_id = self.source_ast_id_map.ast_id(func); - let res = Function { - name, - attrs, - visibility, - generic_params, - has_self_param, - params, - ret_type, - ast_id, - }; - Some(res) - } - - fn lower_type_alias(&mut self, type_alias: &ast::TypeAliasDef) -> Option { - let name = type_alias.name()?.as_name(); - let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); - let visibility = self.lower_visibility(type_alias); - let generic_params = self.lower_generic_params(type_alias); - let ast_id = self.source_ast_id_map.ast_id(type_alias); - let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; - Some(res) - } - - fn lower_static(&mut self, static_: &ast::StaticDef) -> Option { - let name = static_.name()?.as_name(); - let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); - let visibility = self.lower_visibility(static_); - let ast_id = self.source_ast_id_map.ast_id(static_); - let res = Static { name, visibility, type_ref, ast_id }; - Some(res) - } - - fn lower_const(&mut self, konst: &ast::ConstDef) -> Const { - let name = konst.name().map(|it| it.as_name()); - let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); - let visibility = self.lower_visibility(konst); - let ast_id = self.source_ast_id_map.ast_id(konst); - Const { name, visibility, type_ref, ast_id } - } - - fn lower_module(&mut self, module: &ast::Module) -> Option { - let name = module.name()?.as_name(); - let visibility = self.lower_visibility(module); - let kind = if module.semicolon_token().is_some() { - ModKind::Outline {} - } else { - ModKind::Inline { - items: module - .item_list() - .map(|list| { - list.items() - .flat_map(|item| self.lower_mod_item(&item)) - .flat_map(|items| items.0) - .collect() - }) - .unwrap_or_else(|| { - mark::hit!(name_res_works_for_broken_modules); - Vec::new() - }), - } - }; - let ast_id = self.source_ast_id_map.ast_id(module); - Some(Mod { name, visibility, kind, ast_id }) - } - - fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { - let name = trait_def.name()?.as_name(); - let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(trait_def); - let auto = trait_def.auto_token().is_some(); - let items = trait_def.item_list().map(|list| { - // FIXME: Does not handle macros - list.assoc_items().flat_map(|item| self.lower_assoc_item(&item)).collect() - }); - let ast_id = self.source_ast_id_map.ast_id(trait_def); - Some(Trait { - name, - visibility, - generic_params, - auto, - items: items.unwrap_or_default(), - ast_id, - }) - } - - fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { - let generic_params = self.lower_generic_params(impl_def); - let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); - let target_type = self.lower_type_ref(&impl_def.target_type()?); - let is_negative = impl_def.excl_token().is_some(); - let items = impl_def - .item_list()? - .assoc_items() - .filter_map(|item| self.lower_assoc_item(&item)) - .collect(); - let ast_id = self.source_ast_id_map.ast_id(impl_def); - Some(Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }) - } - - fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec { - // FIXME: cfg_attr - let is_prelude = use_item.has_atom_attr("prelude_import"); - let visibility = self.lower_visibility(use_item); - - // Every use item can expand to many `Import`s. - let mut imports = Vec::new(); - ModPath::expand_use_item( - InFile::new(self.file, use_item.clone()), - &self.hygiene, - |path, _tree, is_glob, alias| { - imports.push(Import { - path, - alias, - visibility: visibility.clone(), - is_glob, - is_prelude, - is_extern_crate: false, - is_macro_use: false, - }); - }, - ); - - imports - } - - fn lower_extern_crate(&mut self, extern_crate: &ast::ExternCrateItem) -> Option { - let path = ModPath::from_name_ref(&extern_crate.name_ref()?); - let alias = extern_crate.alias().map(|a| { - a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) - }); - let visibility = self.lower_visibility(extern_crate); - // FIXME: cfg_attr - let is_macro_use = extern_crate.has_atom_attr("macro_use"); - - Some(Import { - path, - alias, - visibility, - is_glob: false, - is_prelude: false, - is_extern_crate: true, - is_macro_use, - }) - } - - fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option { - let name = m.name().map(|it| it.as_name()); - let attrs = Attrs::new(m, &self.hygiene); - let path = ModPath::from_src(m.path()?, &self.hygiene)?; - - let ast_id = self.source_ast_id_map.ast_id(m); - - // FIXME: cfg_attr - let export_attr = attrs.by_key("macro_export"); - - let is_export = export_attr.exists(); - let is_local_inner = if is_export { - export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - ident.text.contains("local_inner_macros") - } - _ => false, - }) - } else { - false - }; - - let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); - Some(MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }) - } - - fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec> { - block.extern_item_list().map_or(Vec::new(), |list| { - list.extern_items() - .filter_map(|item| match item { - ast::ExternItem::FnDef(ast) => self.lower_function(&ast).map(Either::Left), - ast::ExternItem::StaticDef(ast) => self.lower_static(&ast).map(Either::Right), - }) - .collect() - }) - } - - fn lower_generic_params( - &mut self, - _item: &impl ast::TypeParamsOwner, - ) -> generics::GenericParams { - // TODO - generics::GenericParams { types: Arena::new(), where_predicates: Vec::new() } - } - - fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { - Attrs::new(item, &self.hygiene) - } - fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { - RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) - } - fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { - TypeRef::from_ast(&self.body_ctx, type_ref.clone()) - } - fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { - TypeRef::from_ast_opt(&self.body_ctx, type_ref) - } - - fn next_field_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) - } - fn next_variant_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) - } -} - -fn desugar_future_path(orig: TypeRef) -> Path { - let path = path![core::future::Future]; - let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); - let mut last = GenericArgs::empty(); - let binding = - AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; - last.bindings.push(binding); - generic_args.push(Some(Arc::new(last))); - - Path::from_known_path(path, generic_args) -} diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs new file mode 100644 index 0000000000..d123a73106 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -0,0 +1,501 @@ +use super::*; +use crate::attr::Attrs; +use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; +use ra_syntax::ast::{self, ModuleItemOwner}; +use smallvec::SmallVec; +use std::sync::Arc; + +struct ModItems(SmallVec<[ModItem; 1]>); + +impl From for ModItems +where + T: Into, +{ + fn from(t: T) -> Self { + ModItems(SmallVec::from_buf([t.into(); 1])) + } +} + +pub(super) struct Ctx { + pub tree: ItemTree, + pub hygiene: Hygiene, + pub file: HirFileId, + pub source_ast_id_map: Arc, + pub body_ctx: crate::body::LowerCtx, +} + +impl Ctx { + pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { + self.tree.top_level = item_owner + .items() + .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|items| items.0) + .collect(); + self.tree + } + + fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option { + let attrs = Attrs::new(item, &self.hygiene); + let items = match item { + ast::ModuleItem::StructDef(ast) => { + self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) + } + ast::ModuleItem::UnionDef(ast) => { + self.lower_union(ast).map(|data| self.tree.unions.alloc(data).into()) + } + ast::ModuleItem::EnumDef(ast) => { + self.lower_enum(ast).map(|data| self.tree.enums.alloc(data).into()) + } + ast::ModuleItem::FnDef(ast) => { + self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) + } + ast::ModuleItem::TypeAliasDef(ast) => { + self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) + } + ast::ModuleItem::StaticDef(ast) => { + self.lower_static(ast).map(|data| self.tree.statics.alloc(data).into()) + } + ast::ModuleItem::ConstDef(ast) => { + let data = self.lower_const(ast); + Some(self.tree.consts.alloc(data).into()) + } + ast::ModuleItem::Module(ast) => { + self.lower_module(ast).map(|data| self.tree.mods.alloc(data).into()) + } + ast::ModuleItem::TraitDef(ast) => { + self.lower_trait(ast).map(|data| self.tree.traits.alloc(data).into()) + } + ast::ModuleItem::ImplDef(ast) => { + self.lower_impl(ast).map(|data| self.tree.impls.alloc(data).into()) + } + ast::ModuleItem::UseItem(ast) => Some(ModItems( + self.lower_use(ast) + .into_iter() + .map(|data| self.tree.imports.alloc(data).into()) + .collect::>(), + )), + ast::ModuleItem::ExternCrateItem(ast) => { + self.lower_extern_crate(ast).map(|data| self.tree.imports.alloc(data).into()) + } + ast::ModuleItem::MacroCall(ast) => { + self.lower_macro_call(ast).map(|data| self.tree.macro_calls.alloc(data).into()) + } + ast::ModuleItem::ExternBlock(ast) => Some(ModItems( + self.lower_extern_block(ast) + .into_iter() + .map(|item| match item { + Either::Left(func) => self.tree.functions.alloc(func).into(), + Either::Right(statik) => self.tree.statics.alloc(statik).into(), + }) + .collect::>(), + )), + }; + + if !attrs.is_empty() { + for item in items.iter().flat_map(|items| &items.0) { + self.tree.attrs.insert(*item, attrs.clone()); + } + } + + items + } + + fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { + match item { + ast::AssocItem::FnDef(ast) => { + self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) + } + ast::AssocItem::TypeAliasDef(ast) => { + self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) + } + ast::AssocItem::ConstDef(ast) => { + let data = self.lower_const(ast); + Some(self.tree.consts.alloc(data).into()) + } + } + } + + fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option { + let attrs = self.lower_attrs(strukt); + let visibility = self.lower_visibility(strukt); + let name = strukt.name()?.as_name(); + let generic_params = self.lower_generic_params(strukt); + let fields = self.lower_fields(&strukt.kind()); + let ast_id = self.source_ast_id_map.ast_id(strukt); + let kind = match strukt.kind() { + ast::StructKind::Record(_) => StructDefKind::Record, + ast::StructKind::Tuple(_) => StructDefKind::Tuple, + ast::StructKind::Unit => StructDefKind::Unit, + }; + let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; + Some(res) + } + + fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { + match strukt_kind { + ast::StructKind::Record(it) => { + let range = self.lower_record_fields(it); + Fields::Record(range) + } + ast::StructKind::Tuple(it) => { + let range = self.lower_tuple_fields(it); + Fields::Tuple(range) + } + ast::StructKind::Unit => Fields::Unit, + } + } + + fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range> { + let start = self.next_field_idx(); + for field in fields.fields() { + if let Some(data) = self.lower_record_field(&field) { + self.tree.fields.alloc(data); + } + } + let end = self.next_field_idx(); + start..end + } + + fn lower_record_field(&self, field: &ast::RecordFieldDef) -> Option { + let name = field.name()?.as_name(); + let visibility = self.lower_visibility(field); + let type_ref = self.lower_type_ref(&field.ascribed_type()?); + let res = Field { name, type_ref, visibility }; + Some(res) + } + + fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range> { + let start = self.next_field_idx(); + for (i, field) in fields.fields().enumerate() { + if let Some(data) = self.lower_tuple_field(i, &field) { + self.tree.fields.alloc(data); + } + } + let end = self.next_field_idx(); + start..end + } + + fn lower_tuple_field(&self, idx: usize, field: &ast::TupleFieldDef) -> Option { + let name = Name::new_tuple_field(idx); + let visibility = self.lower_visibility(field); + let type_ref = self.lower_type_ref(&field.type_ref()?); + let res = Field { name, type_ref, visibility }; + Some(res) + } + + fn lower_union(&mut self, union: &ast::UnionDef) -> Option { + let attrs = self.lower_attrs(union); + let visibility = self.lower_visibility(union); + let name = union.name()?.as_name(); + let generic_params = self.lower_generic_params(union); + let fields = match union.record_field_def_list() { + Some(record_field_def_list) => { + self.lower_fields(&StructKind::Record(record_field_def_list)) + } + None => Fields::Record(self.next_field_idx()..self.next_field_idx()), + }; + let ast_id = self.source_ast_id_map.ast_id(union); + let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; + Some(res) + } + + fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option { + let attrs = self.lower_attrs(enum_); + let visibility = self.lower_visibility(enum_); + let name = enum_.name()?.as_name(); + let generic_params = self.lower_generic_params(enum_); + let variants = match &enum_.variant_list() { + Some(variant_list) => self.lower_variants(variant_list), + None => self.next_variant_idx()..self.next_variant_idx(), + }; + let ast_id = self.source_ast_id_map.ast_id(enum_); + let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; + Some(res) + } + + fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { + let start = self.next_variant_idx(); + for variant in variants.variants() { + if let Some(data) = self.lower_variant(&variant) { + self.tree.variants.alloc(data); + } + } + let end = self.next_variant_idx(); + start..end + } + + fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option { + let name = variant.name()?.as_name(); + let fields = self.lower_fields(&variant.kind()); + let res = Variant { name, fields }; + Some(res) + } + + fn lower_function(&mut self, func: &ast::FnDef) -> Option { + let attrs = self.lower_attrs(func); + let visibility = self.lower_visibility(func); + let name = func.name()?.as_name(); + let generic_params = self.lower_generic_params(func); + + let mut params = Vec::new(); + let mut has_self_param = false; + if let Some(param_list) = func.param_list() { + if let Some(self_param) = param_list.self_param() { + let self_type = if let Some(type_ref) = self_param.ascribed_type() { + TypeRef::from_ast(&self.body_ctx, type_ref) + } else { + let self_type = TypeRef::Path(name![Self].into()); + match self_param.kind() { + ast::SelfParamKind::Owned => self_type, + ast::SelfParamKind::Ref => { + TypeRef::Reference(Box::new(self_type), Mutability::Shared) + } + ast::SelfParamKind::MutRef => { + TypeRef::Reference(Box::new(self_type), Mutability::Mut) + } + } + }; + params.push(self_type); + has_self_param = true; + } + for param in param_list.params() { + let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); + params.push(type_ref); + } + } + let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { + Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), + _ => TypeRef::unit(), + }; + + let ret_type = if func.async_token().is_some() { + let future_impl = desugar_future_path(ret_type); + let ty_bound = TypeBound::Path(future_impl); + TypeRef::ImplTrait(vec![ty_bound]) + } else { + ret_type + }; + + let ast_id = self.source_ast_id_map.ast_id(func); + let res = Function { + name, + attrs, + visibility, + generic_params, + has_self_param, + params, + ret_type, + ast_id, + }; + Some(res) + } + + fn lower_type_alias(&mut self, type_alias: &ast::TypeAliasDef) -> Option { + let name = type_alias.name()?.as_name(); + let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); + let visibility = self.lower_visibility(type_alias); + let generic_params = self.lower_generic_params(type_alias); + let ast_id = self.source_ast_id_map.ast_id(type_alias); + let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; + Some(res) + } + + fn lower_static(&mut self, static_: &ast::StaticDef) -> Option { + let name = static_.name()?.as_name(); + let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); + let visibility = self.lower_visibility(static_); + let ast_id = self.source_ast_id_map.ast_id(static_); + let res = Static { name, visibility, type_ref, ast_id }; + Some(res) + } + + fn lower_const(&mut self, konst: &ast::ConstDef) -> Const { + let name = konst.name().map(|it| it.as_name()); + let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); + let visibility = self.lower_visibility(konst); + let ast_id = self.source_ast_id_map.ast_id(konst); + Const { name, visibility, type_ref, ast_id } + } + + fn lower_module(&mut self, module: &ast::Module) -> Option { + let name = module.name()?.as_name(); + let visibility = self.lower_visibility(module); + let kind = if module.semicolon_token().is_some() { + ModKind::Outline {} + } else { + ModKind::Inline { + items: module + .item_list() + .map(|list| { + list.items() + .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|items| items.0) + .collect() + }) + .unwrap_or_else(|| { + mark::hit!(name_res_works_for_broken_modules); + Vec::new() + }), + } + }; + let ast_id = self.source_ast_id_map.ast_id(module); + Some(Mod { name, visibility, kind, ast_id }) + } + + fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { + let name = trait_def.name()?.as_name(); + let visibility = self.lower_visibility(trait_def); + let generic_params = self.lower_generic_params(trait_def); + let auto = trait_def.auto_token().is_some(); + let items = trait_def.item_list().map(|list| { + // FIXME: Does not handle macros + list.assoc_items().flat_map(|item| self.lower_assoc_item(&item)).collect() + }); + let ast_id = self.source_ast_id_map.ast_id(trait_def); + Some(Trait { + name, + visibility, + generic_params, + auto, + items: items.unwrap_or_default(), + ast_id, + }) + } + + fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { + let generic_params = self.lower_generic_params(impl_def); + let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); + let target_type = self.lower_type_ref(&impl_def.target_type()?); + let is_negative = impl_def.excl_token().is_some(); + let items = impl_def + .item_list()? + .assoc_items() + .filter_map(|item| self.lower_assoc_item(&item)) + .collect(); + let ast_id = self.source_ast_id_map.ast_id(impl_def); + Some(Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }) + } + + fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec { + // FIXME: cfg_attr + let is_prelude = use_item.has_atom_attr("prelude_import"); + let visibility = self.lower_visibility(use_item); + + // Every use item can expand to many `Import`s. + let mut imports = Vec::new(); + ModPath::expand_use_item( + InFile::new(self.file, use_item.clone()), + &self.hygiene, + |path, _tree, is_glob, alias| { + imports.push(Import { + path, + alias, + visibility: visibility.clone(), + is_glob, + is_prelude, + is_extern_crate: false, + is_macro_use: false, + }); + }, + ); + + imports + } + + fn lower_extern_crate(&mut self, extern_crate: &ast::ExternCrateItem) -> Option { + let path = ModPath::from_name_ref(&extern_crate.name_ref()?); + let alias = extern_crate.alias().map(|a| { + a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) + }); + let visibility = self.lower_visibility(extern_crate); + // FIXME: cfg_attr + let is_macro_use = extern_crate.has_atom_attr("macro_use"); + + Some(Import { + path, + alias, + visibility, + is_glob: false, + is_prelude: false, + is_extern_crate: true, + is_macro_use, + }) + } + + fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option { + let name = m.name().map(|it| it.as_name()); + let attrs = Attrs::new(m, &self.hygiene); + let path = ModPath::from_src(m.path()?, &self.hygiene)?; + + let ast_id = self.source_ast_id_map.ast_id(m); + + // FIXME: cfg_attr + let export_attr = attrs.by_key("macro_export"); + + let is_export = export_attr.exists(); + let is_local_inner = if is_export { + export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { + tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { + ident.text.contains("local_inner_macros") + } + _ => false, + }) + } else { + false + }; + + let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); + Some(MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }) + } + + fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec> { + block.extern_item_list().map_or(Vec::new(), |list| { + list.extern_items() + .filter_map(|item| match item { + ast::ExternItem::FnDef(ast) => self.lower_function(&ast).map(Either::Left), + ast::ExternItem::StaticDef(ast) => self.lower_static(&ast).map(Either::Right), + }) + .collect() + }) + } + + fn lower_generic_params( + &mut self, + _item: &impl ast::TypeParamsOwner, + ) -> generics::GenericParams { + // TODO + generics::GenericParams { types: Arena::new(), where_predicates: Vec::new() } + } + + fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { + Attrs::new(item, &self.hygiene) + } + fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { + RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) + } + fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { + TypeRef::from_ast(&self.body_ctx, type_ref.clone()) + } + fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { + TypeRef::from_ast_opt(&self.body_ctx, type_ref) + } + + fn next_field_idx(&self) -> Idx { + Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) + } + fn next_variant_idx(&self) -> Idx { + Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) + } +} + +fn desugar_future_path(orig: TypeRef) -> Path { + let path = path![core::future::Future]; + let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); + let mut last = GenericArgs::empty(); + let binding = + AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; + last.bindings.push(binding); + generic_args.push(Some(Arc::new(last))); + + Path::from_known_path(path, generic_args) +} From 864b650f92388f4e82d130713b2de9afe637102f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 16 Jun 2020 19:20:29 +0200 Subject: [PATCH 11/34] ItemTree: use a newtyped ID --- crates/ra_hir_def/src/item_tree.rs | 136 ++++++++++++++++----- crates/ra_hir_def/src/item_tree/lower.rs | 40 +++--- crates/ra_hir_def/src/nameres/collector.rs | 7 +- 3 files changed, 130 insertions(+), 53 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index a13a989dda..9656f845e9 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -3,6 +3,9 @@ mod lower; use std::{ + fmt::{self, Debug}, + hash::{Hash, Hasher}, + marker::PhantomData, ops::{Index, Range}, sync::Arc, }; @@ -109,6 +112,68 @@ impl ItemTree { } } +pub trait ItemTreeNode: Sized { + fn lookup(tree: &ItemTree, index: Idx) -> &Self; +} + +pub struct FileItemTreeId { + index: Idx, + _p: PhantomData, +} + +impl Clone for FileItemTreeId { + fn clone(&self) -> Self { + Self { index: self.index, _p: PhantomData } + } +} +impl Copy for FileItemTreeId {} + +impl PartialEq for FileItemTreeId { + fn eq(&self, other: &FileItemTreeId) -> bool { + self.index == other.index + } +} +impl Eq for FileItemTreeId {} + +impl Hash for FileItemTreeId { + fn hash(&self, state: &mut H) { + self.index.hash(state) + } +} + +impl fmt::Debug for FileItemTreeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.index.fmt(f) + } +} + +pub type ItemTreeId = InFile>; + +macro_rules! nodes { + ( $($node:ident in $fld:ident),+ $(,)? ) => { $( + impl ItemTreeNode for $node { + fn lookup(tree: &ItemTree, index: Idx) -> &Self { + &tree.$fld[index] + } + } + )+ }; +} + +nodes!( + Import in imports, + Function in functions, + Struct in structs, + Union in unions, + Enum in enums, + Const in consts, + Static in statics, + Trait in traits, + Impl in impls, + TypeAlias in type_aliases, + Mod in mods, + MacroCall in macro_calls, +); + macro_rules! impl_index { ( $($fld:ident: $t:ty),+ $(,)? ) => { $( @@ -141,6 +206,13 @@ impl_index!( exprs: Expr, ); +impl Index> for ItemTree { + type Output = N; + fn index(&self, id: FileItemTreeId) -> &N { + N::lookup(self, id.index) + } +} + /// A desugared `extern crate` or `use` import. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Import { @@ -304,48 +376,48 @@ macro_rules! impl_froms { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ModItem { - Import(Idx), - Function(Idx), - Struct(Idx), - Union(Idx), - Enum(Idx), - Const(Idx), - Static(Idx), - Trait(Idx), - Impl(Idx), - TypeAlias(Idx), - Mod(Idx), - MacroCall(Idx), + Import(FileItemTreeId), + Function(FileItemTreeId), + Struct(FileItemTreeId), + Union(FileItemTreeId), + Enum(FileItemTreeId), + Const(FileItemTreeId), + Static(FileItemTreeId), + Trait(FileItemTreeId), + Impl(FileItemTreeId), + TypeAlias(FileItemTreeId), + Mod(FileItemTreeId), + MacroCall(FileItemTreeId), } impl_froms!(ModItem { - Import(Idx), - Function(Idx), - Struct(Idx), - Union(Idx), - Enum(Idx), - Const(Idx), - Static(Idx), - Trait(Idx), - Impl(Idx), - TypeAlias(Idx), - Mod(Idx), - MacroCall(Idx), + Import(FileItemTreeId), + Function(FileItemTreeId), + Struct(FileItemTreeId), + Union(FileItemTreeId), + Enum(FileItemTreeId), + Const(FileItemTreeId), + Static(FileItemTreeId), + Trait(FileItemTreeId), + Impl(FileItemTreeId), + TypeAlias(FileItemTreeId), + Mod(FileItemTreeId), + MacroCall(FileItemTreeId), }); #[derive(Debug, Eq, PartialEq)] pub enum AssocItem { - Function(Idx), - TypeAlias(Idx), - Const(Idx), - MacroCall(Idx), + Function(FileItemTreeId), + TypeAlias(FileItemTreeId), + Const(FileItemTreeId), + MacroCall(FileItemTreeId), } impl_froms!(AssocItem { - Function(Idx), - TypeAlias(Idx), - Const(Idx), - MacroCall(Idx), + Function(FileItemTreeId), + TypeAlias(FileItemTreeId), + Const(FileItemTreeId), + MacroCall(FileItemTreeId), }); #[derive(Debug, Eq, PartialEq)] diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index d123a73106..0c9454848c 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -5,6 +5,10 @@ use ra_syntax::ast::{self, ModuleItemOwner}; use smallvec::SmallVec; use std::sync::Arc; +fn id(index: Idx) -> FileItemTreeId { + FileItemTreeId { index, _p: PhantomData } +} + struct ModItems(SmallVec<[ModItem; 1]>); impl From for ModItems @@ -38,54 +42,54 @@ impl Ctx { let attrs = Attrs::new(item, &self.hygiene); let items = match item { ast::ModuleItem::StructDef(ast) => { - self.lower_struct(ast).map(|data| self.tree.structs.alloc(data).into()) + self.lower_struct(ast).map(|data| id(self.tree.structs.alloc(data)).into()) } ast::ModuleItem::UnionDef(ast) => { - self.lower_union(ast).map(|data| self.tree.unions.alloc(data).into()) + self.lower_union(ast).map(|data| id(self.tree.unions.alloc(data)).into()) } ast::ModuleItem::EnumDef(ast) => { - self.lower_enum(ast).map(|data| self.tree.enums.alloc(data).into()) + self.lower_enum(ast).map(|data| id(self.tree.enums.alloc(data)).into()) } ast::ModuleItem::FnDef(ast) => { - self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) + self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) } ast::ModuleItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) + self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) } ast::ModuleItem::StaticDef(ast) => { - self.lower_static(ast).map(|data| self.tree.statics.alloc(data).into()) + self.lower_static(ast).map(|data| id(self.tree.statics.alloc(data)).into()) } ast::ModuleItem::ConstDef(ast) => { let data = self.lower_const(ast); - Some(self.tree.consts.alloc(data).into()) + Some(id(self.tree.consts.alloc(data)).into()) } ast::ModuleItem::Module(ast) => { - self.lower_module(ast).map(|data| self.tree.mods.alloc(data).into()) + self.lower_module(ast).map(|data| id(self.tree.mods.alloc(data)).into()) } ast::ModuleItem::TraitDef(ast) => { - self.lower_trait(ast).map(|data| self.tree.traits.alloc(data).into()) + self.lower_trait(ast).map(|data| id(self.tree.traits.alloc(data)).into()) } ast::ModuleItem::ImplDef(ast) => { - self.lower_impl(ast).map(|data| self.tree.impls.alloc(data).into()) + self.lower_impl(ast).map(|data| id(self.tree.impls.alloc(data)).into()) } ast::ModuleItem::UseItem(ast) => Some(ModItems( self.lower_use(ast) .into_iter() - .map(|data| self.tree.imports.alloc(data).into()) + .map(|data| id(self.tree.imports.alloc(data)).into()) .collect::>(), )), ast::ModuleItem::ExternCrateItem(ast) => { - self.lower_extern_crate(ast).map(|data| self.tree.imports.alloc(data).into()) + self.lower_extern_crate(ast).map(|data| id(self.tree.imports.alloc(data)).into()) } ast::ModuleItem::MacroCall(ast) => { - self.lower_macro_call(ast).map(|data| self.tree.macro_calls.alloc(data).into()) + self.lower_macro_call(ast).map(|data| id(self.tree.macro_calls.alloc(data)).into()) } ast::ModuleItem::ExternBlock(ast) => Some(ModItems( self.lower_extern_block(ast) .into_iter() .map(|item| match item { - Either::Left(func) => self.tree.functions.alloc(func).into(), - Either::Right(statik) => self.tree.statics.alloc(statik).into(), + Either::Left(func) => id(self.tree.functions.alloc(func)).into(), + Either::Right(statik) => id(self.tree.statics.alloc(statik)).into(), }) .collect::>(), )), @@ -103,14 +107,14 @@ impl Ctx { fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { match item { ast::AssocItem::FnDef(ast) => { - self.lower_function(ast).map(|data| self.tree.functions.alloc(data).into()) + self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) } ast::AssocItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| self.tree.type_aliases.alloc(data).into()) + self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) } ast::AssocItem::ConstDef(ast) => { let data = self.lower_const(ast); - Some(self.tree.consts.alloc(data).into()) + Some(id(self.tree.consts.alloc(data)).into()) } } } diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index b899a5fb35..c227b6da19 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -20,7 +20,9 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, - item_tree::{Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind}, + item_tree::{ + FileItemTreeId, Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind, + }, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, @@ -32,7 +34,6 @@ use crate::{ FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, }; -use ra_arena::Idx; pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { let crate_graph = db.crate_graph(); @@ -107,7 +108,7 @@ impl PartialResolvedImport { #[derive(Clone, Debug, Eq, PartialEq)] struct ImportDirective { module_id: LocalModuleId, - import_id: Idx, + import_id: FileItemTreeId, import: Import, status: PartialResolvedImport, } From c12f7b610be49901190cde994dfe4f594150dbf9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 17 Jun 2020 12:24:05 +0200 Subject: [PATCH 12/34] Lower generics --- crates/ra_hir_def/src/generics.rs | 13 ++-- crates/ra_hir_def/src/item_tree.rs | 16 ++--- crates/ra_hir_def/src/item_tree/lower.rs | 80 +++++++++++++++++++----- 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 09a5241f78..ed4f60c663 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -42,7 +42,7 @@ pub enum TypeParamProvenance { } /// Data about the generic parameters of a function, struct, impl, etc. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct GenericParams { pub types: Arena, // lifetimes: Arena, @@ -156,7 +156,12 @@ impl GenericParams { (generics, InFile::new(file_id, sm)) } - fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { + pub(crate) fn fill( + &mut self, + lower_ctx: &LowerCtx, + sm: &mut SourceMap, + node: &dyn TypeParamsOwner, + ) { if let Some(params) = node.type_param_list() { self.fill_params(lower_ctx, sm, params) } @@ -165,7 +170,7 @@ impl GenericParams { } } - fn fill_bounds( + pub(crate) fn fill_bounds( &mut self, lower_ctx: &LowerCtx, node: &dyn ast::TypeBoundsOwner, @@ -229,7 +234,7 @@ impl GenericParams { .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); } - fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { + pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { type_ref.walk(&mut |type_ref| { if let TypeRef::ImplTrait(bounds) = type_ref { let param = TypeParamData { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 9656f845e9..c3990c2ebb 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -26,7 +26,7 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, - generics, + generics::GenericParams, path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path}, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, @@ -230,7 +230,7 @@ pub struct Function { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub has_self_param: bool, pub params: Vec, pub ret_type: TypeRef, @@ -243,7 +243,7 @@ pub struct Struct { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub fields: Fields, pub ast_id: FileAstId, pub kind: StructDefKind, @@ -264,7 +264,7 @@ pub struct Union { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub fields: Fields, pub ast_id: FileAstId, } @@ -274,7 +274,7 @@ pub struct Enum { pub name: Name, pub attrs: Attrs, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub variants: Range>, pub ast_id: FileAstId, } @@ -300,7 +300,7 @@ pub struct Static { pub struct Trait { pub name: Name, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub auto: bool, pub items: Vec, pub ast_id: FileAstId, @@ -308,7 +308,7 @@ pub struct Trait { #[derive(Debug, Eq, PartialEq)] pub struct Impl { - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub target_trait: Option, pub target_type: TypeRef, pub is_negative: bool, @@ -320,7 +320,7 @@ pub struct Impl { pub struct TypeAlias { pub name: Name, pub visibility: RawVisibility, - pub generic_params: generics::GenericParams, + pub generic_params: GenericParams, pub type_ref: Option, pub ast_id: FileAstId, } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 0c9454848c..737a69c308 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -1,6 +1,12 @@ +//! AST -> `ItemTree` lowering code. + use super::*; -use crate::attr::Attrs; +use crate::{ + attr::Attrs, + generics::{GenericParams, TypeParamData, TypeParamProvenance}, +}; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; +use ra_arena::map::ArenaMap; use ra_syntax::ast::{self, ModuleItemOwner}; use smallvec::SmallVec; use std::sync::Arc; @@ -123,7 +129,7 @@ impl Ctx { let attrs = self.lower_attrs(strukt); let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); - let generic_params = self.lower_generic_params(strukt); + let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); let fields = self.lower_fields(&strukt.kind()); let ast_id = self.source_ast_id_map.ast_id(strukt); let kind = match strukt.kind() { @@ -191,7 +197,7 @@ impl Ctx { let attrs = self.lower_attrs(union); let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); - let generic_params = self.lower_generic_params(union); + let generic_params = self.lower_generic_params(GenericsOwner::Union, union); let fields = match union.record_field_def_list() { Some(record_field_def_list) => { self.lower_fields(&StructKind::Record(record_field_def_list)) @@ -207,7 +213,7 @@ impl Ctx { let attrs = self.lower_attrs(enum_); let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); - let generic_params = self.lower_generic_params(enum_); + let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), None => self.next_variant_idx()..self.next_variant_idx(), @@ -239,7 +245,6 @@ impl Ctx { let attrs = self.lower_attrs(func); let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); - let generic_params = self.lower_generic_params(func); let mut params = Vec::new(); let mut has_self_param = false; @@ -281,16 +286,17 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(func); - let res = Function { + let mut res = Function { name, attrs, visibility, - generic_params, + generic_params: GenericParams::default(), has_self_param, params, ret_type, ast_id, }; + res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); Some(res) } @@ -298,7 +304,7 @@ impl Ctx { let name = type_alias.name()?.as_name(); let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); - let generic_params = self.lower_generic_params(type_alias); + let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; Some(res) @@ -349,7 +355,7 @@ impl Ctx { fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(trait_def); + let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { // FIXME: Does not handle macros @@ -367,7 +373,7 @@ impl Ctx { } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { - let generic_params = self.lower_generic_params(impl_def); + let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); let target_type = self.lower_type_ref(&impl_def.target_type()?); let is_negative = impl_def.excl_token().is_some(); @@ -465,10 +471,43 @@ impl Ctx { fn lower_generic_params( &mut self, - _item: &impl ast::TypeParamsOwner, - ) -> generics::GenericParams { - // TODO - generics::GenericParams { types: Arena::new(), where_predicates: Vec::new() } + owner: GenericsOwner<'_>, + node: &impl ast::TypeParamsOwner, + ) -> GenericParams { + let mut sm = &mut ArenaMap::default(); + let mut generics = GenericParams::default(); + match owner { + GenericsOwner::Function(func) => { + generics.fill(&self.body_ctx, sm, node); + // lower `impl Trait` in arguments + for param in &func.params { + generics.fill_implicit_impl_trait_args(param); + } + } + GenericsOwner::Struct + | GenericsOwner::Enum + | GenericsOwner::Union + | GenericsOwner::TypeAlias => { + generics.fill(&self.body_ctx, sm, node); + } + GenericsOwner::Trait(trait_def) => { + // traits get the Self type as an implicit first type parameter + let self_param_id = generics.types.alloc(TypeParamData { + name: Some(name![Self]), + default: None, + provenance: TypeParamProvenance::TraitSelf, + }); + sm.insert(self_param_id, Either::Left(trait_def.clone())); + // add super traits as bounds on Self + // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar + let self_param = TypeRef::Path(name![Self].into()); + generics.fill_bounds(&self.body_ctx, trait_def, self_param); + + generics.fill(&self.body_ctx, &mut sm, node); + } + GenericsOwner::Impl => {} + } + generics } fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { @@ -503,3 +542,16 @@ fn desugar_future_path(orig: TypeRef) -> Path { Path::from_known_path(path, generic_args) } + +enum GenericsOwner<'a> { + /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument + /// position. + Function(&'a Function), + Struct, + Enum, + Union, + /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. + Trait(&'a ast::TraitDef), + TypeAlias, + Impl, +} From b94caeb88b4aab7219d4b2f5c8c6c668199247fb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 17 Jun 2020 18:43:41 +0200 Subject: [PATCH 13/34] ItemTree: Make clonable and add AST access --- crates/ra_hir_def/src/item_tree.rs | 84 ++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index c3990c2ebb..aca2503a0e 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -112,10 +112,19 @@ impl ItemTree { } } -pub trait ItemTreeNode: Sized { +/// Trait implemented by all nodes in the item tree. +pub trait ItemTreeNode: Clone { + /// Looks up an instance of `Self` in an item tree. fn lookup(tree: &ItemTree, index: Idx) -> &Self; } +/// Trait for item tree nodes that allow accessing the original AST node. +pub trait ItemTreeSource: ItemTreeNode { + type Source: AstNode; + + fn ast_id(&self) -> FileAstId; +} + pub struct FileItemTreeId { index: Idx, _p: PhantomData, @@ -174,6 +183,32 @@ nodes!( MacroCall in macro_calls, ); +macro_rules! source { + ( $($node:ident -> $ast:path),+ $(,)? ) => { $( + impl ItemTreeSource for $node { + type Source = $ast; + + fn ast_id(&self) -> FileAstId { + self.ast_id + } + } + )+ }; +} + +source! { + Function -> ast::FnDef, + Struct -> ast::StructDef, + Union -> ast::UnionDef, + Enum -> ast::EnumDef, + Const -> ast::ConstDef, + Static -> ast::StaticDef, + Trait -> ast::TraitDef, + Impl -> ast::ImplDef, + TypeAlias -> ast::TypeAliasDef, + Mod -> ast::Module, + MacroCall -> ast::MacroCall, +} + macro_rules! impl_index { ( $($fld:ident: $t:ty),+ $(,)? ) => { $( @@ -225,7 +260,7 @@ pub struct Import { pub is_macro_use: bool, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Function { pub name: Name, pub attrs: Attrs, @@ -238,7 +273,7 @@ pub struct Function { // FIXME inner items } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Struct { pub name: Name, pub attrs: Attrs, @@ -249,7 +284,7 @@ pub struct Struct { pub kind: StructDefKind, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub enum StructDefKind { /// `struct S { ... }` - type namespace only. Record, @@ -259,7 +294,7 @@ pub enum StructDefKind { Unit, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, pub attrs: Attrs, @@ -269,7 +304,7 @@ pub struct Union { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, pub attrs: Attrs, @@ -279,7 +314,7 @@ pub struct Enum { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Const { /// const _: () = (); pub name: Option, @@ -288,7 +323,7 @@ pub struct Const { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Static { pub name: Name, pub visibility: RawVisibility, @@ -296,7 +331,7 @@ pub struct Static { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Trait { pub name: Name, pub visibility: RawVisibility, @@ -306,7 +341,7 @@ pub struct Trait { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { pub generic_params: GenericParams, pub target_trait: Option, @@ -325,7 +360,7 @@ pub struct TypeAlias { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Mod { pub name: Name, pub visibility: RawVisibility, @@ -333,7 +368,7 @@ pub struct Mod { pub ast_id: FileAstId, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub enum ModKind { /// `mod m { ... }` Inline { items: Vec }, @@ -342,7 +377,7 @@ pub enum ModKind { Outline {}, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct MacroCall { /// For `macro_rules!` declarations, this is the name of the declared macro. pub name: Option, @@ -359,7 +394,7 @@ pub struct MacroCall { // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array // lengths, but we don't do much with them yet. -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Expr; macro_rules! impl_froms { @@ -390,6 +425,25 @@ pub enum ModItem { MacroCall(FileItemTreeId), } +impl ModItem { + pub fn as_assoc_item(&self) -> Option { + match self { + ModItem::Import(_) + | ModItem::Struct(_) + | ModItem::Union(_) + | ModItem::Enum(_) + | ModItem::Static(_) + | ModItem::Trait(_) + | ModItem::Impl(_) + | ModItem::Mod(_) => None, + ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), + ModItem::Const(konst) => Some(AssocItem::Const(*konst)), + ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), + ModItem::Function(func) => Some(AssocItem::Function(*func)), + } + } +} + impl_froms!(ModItem { Import(FileItemTreeId), Function(FileItemTreeId), @@ -405,7 +459,7 @@ impl_froms!(ModItem { MacroCall(FileItemTreeId), }); -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum AssocItem { Function(FileItemTreeId), TypeAlias(FileItemTreeId), From 4b03b39d5b4b00daffb120a4d2d9ea4a55a9a7ac Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 22 Jun 2020 15:07:06 +0200 Subject: [PATCH 14/34] draw the rest of the owl --- crates/ra_hir/src/code_model.rs | 10 +- crates/ra_hir_def/src/body.rs | 5 +- crates/ra_hir_def/src/body/lower.rs | 173 +++++++---- crates/ra_hir_def/src/data.rs | 218 ++++++-------- crates/ra_hir_def/src/item_tree.rs | 133 +++++++-- crates/ra_hir_def/src/item_tree/lower.rs | 271 ++++++++++-------- crates/ra_hir_def/src/item_tree/tests.rs | 254 ++++++++++++++++ crates/ra_hir_def/src/lib.rs | 97 +++++-- crates/ra_hir_def/src/nameres/collector.rs | 148 ++++++---- .../src/nameres/tests/mod_resolution.rs | 5 +- crates/ra_hir_def/src/src.rs | 31 +- crates/ra_hir_expand/src/ast_id_map.rs | 13 +- crates/ra_hir_ty/src/tests.rs | 16 +- 13 files changed, 959 insertions(+), 415 deletions(-) create mode 100644 crates/ra_hir_def/src/item_tree/tests.rs diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index ffd5278ecb..a379b9f49b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -31,10 +31,7 @@ use hir_ty::{ }; use ra_db::{CrateId, CrateName, Edition, FileId}; use ra_prof::profile; -use ra_syntax::{ - ast::{self, AttrsOwner, NameOwner}, - AstNode, -}; +use ra_syntax::ast::{self, AttrsOwner, NameOwner}; use rustc_hash::FxHashSet; use crate::{ @@ -205,7 +202,8 @@ impl ModuleDef { } pub use hir_def::{ - attr::Attrs, item_scope::ItemInNs, visibility::Visibility, AssocItemId, AssocItemLoc, + attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility, + AssocItemId, AssocItemLoc, }; impl Module { @@ -872,7 +870,7 @@ where ID: Lookup>, DEF: From, CTOR: FnOnce(DEF) -> AssocItem, - AST: AstNode, + AST: ItemTreeNode, { match id.lookup(db.upcast()).container { AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 4f2350915d..9c5272c2d9 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -243,7 +243,7 @@ impl Body { } }; let expander = Expander::new(db, file_id, module); - let (body, source_map) = Body::new(db, def, expander, params, body); + let (body, source_map) = Body::new(db, file_id, def, expander, params, body); (Arc::new(body), Arc::new(source_map)) } @@ -253,12 +253,13 @@ impl Body { fn new( db: &dyn DefDatabase, + file_id: HirFileId, def: DefWithBodyId, expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { - lower::lower(db, def, expander, params, body) + lower::lower(db, file_id, def, expander, params, body) } } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f159f80af0..e7cf80676b 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -5,7 +5,7 @@ use either::Either; use hir_expand::{ hygiene::Hygiene, name::{name, AsName, Name}, - HirFileId, MacroDefId, MacroDefKind, + AstId, HirFileId, MacroDefId, MacroDefKind, }; use ra_arena::Arena; use ra_syntax::{ @@ -27,6 +27,7 @@ use crate::{ LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, + item_tree::{FileItemTreeId, ItemTree, ItemTreeSource}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, @@ -35,6 +36,7 @@ use crate::{ use super::{ExprSource, PatSource}; use ast::AstChildren; +use std::sync::Arc; pub(crate) struct LowerCtx { hygiene: Hygiene, @@ -55,11 +57,13 @@ impl LowerCtx { pub(super) fn lower( db: &dyn DefDatabase, + file_id: HirFileId, def: DefWithBodyId, expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { + let item_tree = db.item_tree(file_id); ExprCollector { db, def, @@ -72,6 +76,7 @@ pub(super) fn lower( body_expr: dummy_expr_id(), item_scope: Default::default(), }, + item_trees: vec![(file_id, item_tree)], } .collect(params, body) } @@ -82,6 +87,8 @@ struct ExprCollector<'a> { expander: Expander, body: Body, source_map: BodySourceMap, + + item_trees: Vec<(HirFileId, Arc)>, } impl ExprCollector<'_> { @@ -533,6 +540,9 @@ impl ExprCollector<'_> { self.source_map .expansions .insert(macro_call, self.expander.current_file_id); + + let item_tree = self.db.item_tree(self.expander.current_file_id); + self.item_trees.push((self.expander.current_file_id, item_tree)); let id = self.collect_expr(expansion); self.expander.exit(self.db, mark); id @@ -547,6 +557,21 @@ impl ExprCollector<'_> { } } + fn find_inner_item(&self, id: AstId) -> FileItemTreeId { + let index = + self.item_trees.iter().position(|(file, _)| *file == id.file_id).unwrap_or_else(|| { + panic!("couldn't find item tree for file {:?}", id.file_id); + }); + let tree = &self.item_trees[index].1; + + // Root file (non-macro). + tree.all_inner_items() + .chain(tree.top_level_items().iter().copied()) + .filter_map(|mod_item| mod_item.downcast::()) + .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) + .unwrap() + } + fn collect_expr_opt(&mut self, expr: Option) -> ExprId { if let Some(expr) = expr { self.collect_expr(expr) @@ -578,56 +603,102 @@ impl ExprCollector<'_> { fn collect_block_items(&mut self, block: &ast::BlockExpr) { let container = ContainerId::DefWithBodyId(self.def); - for item in block.items() { - let (def, name): (ModuleDefId, Option) = match item { - ast::ModuleItem::FnDef(def) => { - let ast_id = self.expander.ast_id(&def); - ( - FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), - def.name(), - ) - } - ast::ModuleItem::TypeAliasDef(def) => { - let ast_id = self.expander.ast_id(&def); - ( - TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), - def.name(), - ) - } - ast::ModuleItem::ConstDef(def) => { - let ast_id = self.expander.ast_id(&def); - ( - ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), - def.name(), - ) - } - ast::ModuleItem::StaticDef(def) => { - let ast_id = self.expander.ast_id(&def); - (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) - } - ast::ModuleItem::StructDef(def) => { - let ast_id = self.expander.ast_id(&def); - (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) - } - ast::ModuleItem::EnumDef(def) => { - let ast_id = self.expander.ast_id(&def); - (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) - } - ast::ModuleItem::UnionDef(def) => { - let ast_id = self.expander.ast_id(&def); - (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) - } - ast::ModuleItem::TraitDef(def) => { - let ast_id = self.expander.ast_id(&def); - (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) - } - ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks - ast::ModuleItem::ImplDef(_) - | ast::ModuleItem::UseItem(_) - | ast::ModuleItem::ExternCrateItem(_) - | ast::ModuleItem::Module(_) - | ast::ModuleItem::MacroCall(_) => continue, - }; + + let items = block + .items() + .filter_map(|item| { + let (def, name): (ModuleDefId, Option) = match item { + ast::ModuleItem::FnDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + FunctionLoc { container: container.into(), id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::TypeAliasDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + TypeAliasLoc { container: container.into(), id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::ConstDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + ConstLoc { container: container.into(), id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::StaticDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + StaticLoc { container, id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::StructDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + StructLoc { container, id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::EnumDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + EnumLoc { container, id: ast_id.with_value(id) }.intern(self.db).into(), + def.name(), + ) + } + ast::ModuleItem::UnionDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + UnionLoc { container, id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::TraitDef(def) => { + let ast_id = self.expander.ast_id(&def); + let id = self.find_inner_item(ast_id.map(|id| id.upcast())); + ( + TraitLoc { container, id: ast_id.with_value(id) } + .intern(self.db) + .into(), + def.name(), + ) + } + ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks + ast::ModuleItem::ImplDef(_) + | ast::ModuleItem::UseItem(_) + | ast::ModuleItem::ExternCrateItem(_) + | ast::ModuleItem::Module(_) + | ast::ModuleItem::MacroCall(_) => return None, + }; + + Some((def, name)) + }) + .collect::>(); + + for (def, name) in items { self.body.item_scope.define_def(def); if let Some(name) = name { let vis = crate::visibility::Visibility::Public; // FIXME determine correctly diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 53599e74a2..697fde3d21 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -5,24 +5,23 @@ use std::sync::Arc; use hir_expand::{ hygiene::Hygiene, name::{name, AsName, Name}, - AstId, InFile, + InFile, }; use ra_prof::profile; -use ra_syntax::ast::{ - self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, - VisibilityOwner, -}; +use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, VisibilityOwner}; use crate::{ attr::Attrs, + body::Expander, body::LowerCtx, db::DefDatabase, + item_tree::{AssocItem, ItemTreeId, ModItem}, path::{path, AssociatedTypeBinding, GenericArgs, Path}, src::HasSource, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, - AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, - ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, + AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, + Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -155,30 +154,24 @@ pub struct TraitData { impl TraitData { pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc { let tr_loc = tr.lookup(db); - let src = tr_loc.source(db); - let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); - let auto = src.value.auto_token().is_some(); + let item_tree = db.item_tree(tr_loc.id.file_id); + let tr_def = &item_tree[tr_loc.id.value]; + let name = tr_def.name.clone(); + let auto = tr_def.auto; let module_id = tr_loc.container.module(db); - let container = AssocContainerId::TraitId(tr); - let mut items = Vec::new(); + let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); + + let items = collect_items( + db, + module_id, + &mut expander, + tr_def.items.iter().copied(), + tr_loc.id.file_id, + container, + 100, + ); - if let Some(item_list) = src.value.item_list() { - let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); - items.extend(collect_items( - db, - &mut expander, - item_list.assoc_items(), - src.file_id, - container, - )); - items.extend(collect_items_in_macros( - db, - &mut expander, - &src.with_value(item_list), - container, - )); - } Arc::new(TraitData { name, items, auto }) } @@ -209,33 +202,28 @@ impl ImplData { pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc { let _p = profile("impl_data_query"); let impl_loc = id.lookup(db); - let src = impl_loc.source(db); - let lower_ctx = LowerCtx::new(db, src.file_id); - let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); - let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); - let is_negative = src.value.excl_token().is_some(); + 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 is_negative = impl_def.is_negative; let module_id = impl_loc.container.module(db); let container = AssocContainerId::ImplId(id); + let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); - let mut items: Vec = Vec::new(); + let items = collect_items( + db, + module_id, + &mut expander, + impl_def.items.iter().copied(), + impl_loc.id.file_id, + container, + 100, + ); + let items = items.into_iter().map(|(_, item)| item).collect(); - if let Some(item_list) = src.value.item_list() { - let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); - items.extend( - collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) - .into_iter() - .map(|(_, item)| item), - ); - items.extend( - collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) - .into_iter() - .map(|(_, item)| item), - ); - } - - let res = ImplData { target_trait, target_type, items, is_negative }; - Arc::new(res) + Arc::new(ImplData { target_trait, target_type, items, is_negative }) } } @@ -295,28 +283,12 @@ impl StaticData { } } -fn collect_items_in_macros( +fn collect_items( db: &dyn DefDatabase, + module: ModuleId, expander: &mut Expander, - impl_def: &InFile, - container: AssocContainerId, -) -> Vec<(Name, AssocItemId)> { - let mut res = Vec::new(); - - // We set a limit to protect against infinite recursion - let limit = 100; - - for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { - res.extend(collect_items_in_macro(db, expander, m, container, limit)) - } - - res -} - -fn collect_items_in_macro( - db: &dyn DefDatabase, - expander: &mut Expander, - m: ast::MacroCall, + assoc_items: impl Iterator, + file_id: crate::HirFileId, container: AssocContainerId, limit: usize, ) -> Vec<(Name, AssocItemId)> { @@ -324,62 +296,62 @@ fn collect_items_in_macro( return Vec::new(); } - if let Some((mark, items)) = expander.enter_expand(db, None, m) { - let items: InFile = expander.to_source(items); - let mut res = collect_items( - db, - expander, - items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), - items.file_id, - container, - ); + let item_tree = db.item_tree(file_id); + let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); - // Recursive collect macros - // Note that ast::ModuleItem do not include ast::MacroCall - // We cannot use ModuleItemOwner::items here - for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { - res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) - } - expander.exit(db, mark); - res - } else { - Vec::new() - } -} - -fn collect_items( - db: &dyn DefDatabase, - expander: &mut Expander, - assoc_items: impl Iterator, - file_id: crate::HirFileId, - container: AssocContainerId, -) -> Vec<(Name, AssocItemId)> { - let items = db.ast_id_map(file_id); - - assoc_items - .filter_map(|item_node| match item_node { - ast::AssocItem::FnDef(it) => { - let name = it.name().map_or_else(Name::missing, |it| it.as_name()); - if !expander.is_cfg_enabled(&it) { - return None; + let mut items = Vec::new(); + for item in assoc_items { + match item { + AssocItem::Function(id) => { + let item = &item_tree[id]; + if !item.attrs.is_cfg_enabled(&cfg_options) { + continue; } - let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } - .intern(db); - Some((name, def.into())) + let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); + items.push((item.name.clone(), def.into())); } - ast::AssocItem::ConstDef(it) => { - let name = it.name().map_or_else(Name::missing, |it| it.as_name()); - let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } - .intern(db); - Some((name, def.into())) + // FIXME: cfg? + AssocItem::Const(id) => { + let item = &item_tree[id]; + let name = if let Some(name) = item.name.clone() { + name + } else { + continue; + }; + let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); + items.push((name, def.into())); } - ast::AssocItem::TypeAliasDef(it) => { - let name = it.name().map_or_else(Name::missing, |it| it.as_name()); - let def = - TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } - .intern(db); - Some((name, def.into())) + AssocItem::TypeAlias(id) => { + let item = &item_tree[id]; + let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); + items.push((item.name.clone(), def.into())); } - }) - .collect() + AssocItem::MacroCall(call) => { + let call = &item_tree[call]; + let ast_id_map = db.ast_id_map(file_id); + let root = db.parse_or_expand(file_id).unwrap(); + let call = ast_id_map.get(call.ast_id).to_node(&root); + + if let Some((mark, mac)) = expander.enter_expand(db, None, call) { + let src: InFile = expander.to_source(mac); + let item_tree = db.item_tree(src.file_id); + let iter = + item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); + items.extend(collect_items( + db, + module, + expander, + iter, + src.file_id, + container, + limit - 1, + )); + + expander.exit(db, mark); + } + } + } + } + + items } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index aca2503a0e..9a5dd701eb 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -1,6 +1,8 @@ //! A simplified AST that only contains items. mod lower; +#[cfg(test)] +mod tests; use std::{ fmt::{self, Debug}, @@ -31,16 +33,20 @@ use crate::{ type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; +use smallvec::SmallVec; /// The item tree of a source file. -#[derive(Debug, Default, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct ItemTree { + file_id: HirFileId, top_level: Vec, top_attrs: Attrs, attrs: FxHashMap, empty_attrs: Attrs, + inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, imports: Arena, + extern_crates: Arena, functions: Arena, structs: Arena, fields: Arena, @@ -63,7 +69,7 @@ impl ItemTree { let syntax = if let Some(node) = db.parse_or_expand(file_id) { node } else { - return Default::default(); + return Arc::new(Self::empty(file_id)); }; let hygiene = Hygiene::new(db.upcast(), file_id); @@ -80,20 +86,41 @@ impl ItemTree { file_storage = file; &file_storage }, - _ => return Default::default(), + _ => return Arc::new(Self::empty(file_id)), } }; - let map = db.ast_id_map(file_id); - let mut ctx = lower::Ctx { - tree: ItemTree::default(), - hygiene, - file: file_id, - source_ast_id_map: map, - body_ctx: crate::body::LowerCtx::new(db, file_id), - }; - ctx.tree.top_attrs = top_attrs.unwrap_or_default(); - Arc::new(ctx.lower(item_owner)) + let ctx = lower::Ctx::new(db, hygiene, file_id); + let mut item_tree = ctx.lower(item_owner); + item_tree.top_attrs = top_attrs.unwrap_or_default(); + Arc::new(item_tree) + } + + fn empty(file_id: HirFileId) -> Self { + Self { + file_id, + top_level: Default::default(), + top_attrs: Default::default(), + attrs: Default::default(), + empty_attrs: Default::default(), + inner_items: Default::default(), + imports: Default::default(), + extern_crates: Default::default(), + functions: Default::default(), + structs: Default::default(), + fields: Default::default(), + unions: Default::default(), + enums: Default::default(), + variants: Default::default(), + consts: Default::default(), + statics: Default::default(), + traits: Default::default(), + impls: Default::default(), + type_aliases: Default::default(), + mods: Default::default(), + macro_calls: Default::default(), + exprs: Default::default(), + } } /// Returns an iterator over all items located at the top level of the `HirFileId` this @@ -110,17 +137,49 @@ impl ItemTree { pub fn attrs(&self, of: ModItem) -> &Attrs { self.attrs.get(&of).unwrap_or(&self.empty_attrs) } + + /// Returns the lowered inner items that `ast` corresponds to. + /// + /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered + /// to multiple items in the `ItemTree`. + pub fn inner_items(&self, ast: FileAstId) -> &[ModItem] { + &self.inner_items[&ast] + } + + pub fn all_inner_items(&self) -> impl Iterator + '_ { + self.inner_items.values().flatten().copied() + } + + pub fn source( + &self, + db: &dyn DefDatabase, + of: FileItemTreeId, + ) -> S::Source { + // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty + // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). + let root = db + .parse_or_expand(self.file_id) + .expect("parse_or_expand failed on constructed ItemTree"); + + let id = self[of].ast_id(); + let map = db.ast_id_map(self.file_id); + let ptr = map.get(id); + ptr.to_node(&root) + } } /// Trait implemented by all nodes in the item tree. pub trait ItemTreeNode: Clone { /// Looks up an instance of `Self` in an item tree. fn lookup(tree: &ItemTree, index: Idx) -> &Self; + + /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. + fn id_from_mod_item(mod_item: ModItem) -> Option>; } /// Trait for item tree nodes that allow accessing the original AST node. pub trait ItemTreeSource: ItemTreeNode { - type Source: AstNode; + type Source: AstNode + Into; fn ast_id(&self) -> FileAstId; } @@ -164,12 +223,22 @@ macro_rules! nodes { fn lookup(tree: &ItemTree, index: Idx) -> &Self { &tree.$fld[index] } + + + fn id_from_mod_item(mod_item: ModItem) -> Option> { + if let ModItem::$node(id) = mod_item { + Some(id) + } else { + None + } + } } )+ }; } nodes!( Import in imports, + ExternCrate in extern_crates, Function in functions, Struct in structs, Union in unions, @@ -196,6 +265,8 @@ macro_rules! source { } source! { + Import -> ast::UseItem, + ExternCrate -> ast::ExternCrateItem, Function -> ast::FnDef, Struct -> ast::StructDef, Union -> ast::UnionDef, @@ -248,7 +319,7 @@ impl Index> for ItemTree { } } -/// A desugared `extern crate` or `use` import. +/// A desugared `use` import. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Import { pub path: ModPath, @@ -256,8 +327,19 @@ pub struct Import { pub visibility: RawVisibility, pub is_glob: bool, pub is_prelude: bool, - pub is_extern_crate: bool, + /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many + /// `Import`s can map to the same `use` item. + pub ast_id: FileAstId, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternCrate { + pub path: ModPath, + pub alias: Option, + pub visibility: RawVisibility, + /// Whether this is a `#[macro_use] extern crate ...`. pub is_macro_use: bool, + pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -270,7 +352,6 @@ pub struct Function { pub params: Vec, pub ret_type: TypeRef, pub ast_id: FileAstId, - // FIXME inner items } #[derive(Debug, Clone, Eq, PartialEq)] @@ -412,6 +493,7 @@ macro_rules! impl_froms { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ModItem { Import(FileItemTreeId), + ExternCrate(FileItemTreeId), Function(FileItemTreeId), Struct(FileItemTreeId), Union(FileItemTreeId), @@ -429,6 +511,7 @@ impl ModItem { pub fn as_assoc_item(&self) -> Option { match self { ModItem::Import(_) + | ModItem::ExternCrate(_) | ModItem::Struct(_) | ModItem::Union(_) | ModItem::Enum(_) @@ -442,10 +525,15 @@ impl ModItem { ModItem::Function(func) => Some(AssocItem::Function(*func)), } } + + pub fn downcast(self) -> Option> { + N::id_from_mod_item(self) + } } impl_froms!(ModItem { Import(FileItemTreeId), + ExternCrate(FileItemTreeId), Function(FileItemTreeId), Struct(FileItemTreeId), Union(FileItemTreeId), @@ -474,6 +562,17 @@ impl_froms!(AssocItem { MacroCall(FileItemTreeId), }); +impl From for ModItem { + fn from(item: AssocItem) -> Self { + match item { + AssocItem::Function(it) => it.into(), + AssocItem::TypeAlias(it) => it.into(), + AssocItem::Const(it) => it.into(), + AssocItem::MacroCall(it) => it.into(), + } + } +} + #[derive(Debug, Eq, PartialEq)] pub struct Variant { pub name: Name, diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 737a69c308..f2b8a94182 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -7,9 +7,12 @@ use crate::{ }; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; use ra_arena::map::ArenaMap; -use ra_syntax::ast::{self, ModuleItemOwner}; +use ra_syntax::{ + ast::{self, ModuleItemOwner}, + SyntaxNode, +}; use smallvec::SmallVec; -use std::sync::Arc; +use std::{mem, sync::Arc}; fn id(index: Idx) -> FileItemTreeId { FileItemTreeId { index, _p: PhantomData } @@ -27,78 +30,81 @@ where } pub(super) struct Ctx { - pub tree: ItemTree, - pub hygiene: Hygiene, - pub file: HirFileId, - pub source_ast_id_map: Arc, - pub body_ctx: crate::body::LowerCtx, + tree: ItemTree, + hygiene: Hygiene, + file: HirFileId, + source_ast_id_map: Arc, + body_ctx: crate::body::LowerCtx, + inner_items: Vec, } impl Ctx { + pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { + Self { + tree: ItemTree::empty(file), + hygiene, + file, + source_ast_id_map: db.ast_id_map(file), + body_ctx: crate::body::LowerCtx::new(db, file), + inner_items: Vec::new(), + } + } + pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { self.tree.top_level = item_owner .items() - .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|item| self.lower_mod_item(&item, false)) .flat_map(|items| items.0) .collect(); self.tree } - fn lower_mod_item(&mut self, item: &ast::ModuleItem) -> Option { + fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { + assert!(inner || self.inner_items.is_empty()); + + // Collect inner items for 1-to-1-lowered items. + match item { + ast::ModuleItem::StructDef(_) + | ast::ModuleItem::UnionDef(_) + | ast::ModuleItem::EnumDef(_) + | ast::ModuleItem::FnDef(_) + | ast::ModuleItem::TypeAliasDef(_) + | ast::ModuleItem::ConstDef(_) + | ast::ModuleItem::StaticDef(_) + | ast::ModuleItem::MacroCall(_) => self.collect_inner_items(item.syntax()), + + // These are handled in their respective `lower_X` method (since we can't just blindly + // walk them). + ast::ModuleItem::TraitDef(_) + | ast::ModuleItem::ImplDef(_) + | ast::ModuleItem::ExternBlock(_) => {} + + // These don't have inner items. + ast::ModuleItem::Module(_) + | ast::ModuleItem::ExternCrateItem(_) + | ast::ModuleItem::UseItem(_) => {} + }; + let attrs = Attrs::new(item, &self.hygiene); let items = match item { - ast::ModuleItem::StructDef(ast) => { - self.lower_struct(ast).map(|data| id(self.tree.structs.alloc(data)).into()) - } - ast::ModuleItem::UnionDef(ast) => { - self.lower_union(ast).map(|data| id(self.tree.unions.alloc(data)).into()) - } - ast::ModuleItem::EnumDef(ast) => { - self.lower_enum(ast).map(|data| id(self.tree.enums.alloc(data)).into()) - } - ast::ModuleItem::FnDef(ast) => { - self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) - } - ast::ModuleItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) - } - ast::ModuleItem::StaticDef(ast) => { - self.lower_static(ast).map(|data| id(self.tree.statics.alloc(data)).into()) - } - ast::ModuleItem::ConstDef(ast) => { - let data = self.lower_const(ast); - Some(id(self.tree.consts.alloc(data)).into()) - } - ast::ModuleItem::Module(ast) => { - self.lower_module(ast).map(|data| id(self.tree.mods.alloc(data)).into()) - } - ast::ModuleItem::TraitDef(ast) => { - self.lower_trait(ast).map(|data| id(self.tree.traits.alloc(data)).into()) - } - ast::ModuleItem::ImplDef(ast) => { - self.lower_impl(ast).map(|data| id(self.tree.impls.alloc(data)).into()) - } + ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), + ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), + ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), + ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), + ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), + ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), + ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), + ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), + ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), + ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), ast::ModuleItem::UseItem(ast) => Some(ModItems( - self.lower_use(ast) - .into_iter() - .map(|data| id(self.tree.imports.alloc(data)).into()) - .collect::>(), + self.lower_use(ast).into_iter().map(Into::into).collect::>(), )), - ast::ModuleItem::ExternCrateItem(ast) => { - self.lower_extern_crate(ast).map(|data| id(self.tree.imports.alloc(data)).into()) + ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), + ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), + ast::ModuleItem::ExternBlock(ast) => { + Some(ModItems(self.lower_extern_block(ast).into_iter().collect::>())) } - ast::ModuleItem::MacroCall(ast) => { - self.lower_macro_call(ast).map(|data| id(self.tree.macro_calls.alloc(data)).into()) - } - ast::ModuleItem::ExternBlock(ast) => Some(ModItems( - self.lower_extern_block(ast) - .into_iter() - .map(|item| match item { - Either::Left(func) => id(self.tree.functions.alloc(func)).into(), - Either::Right(statik) => id(self.tree.statics.alloc(statik)).into(), - }) - .collect::>(), - )), }; if !attrs.is_empty() { @@ -110,22 +116,28 @@ impl Ctx { items } - fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option { + fn collect_inner_items(&mut self, container: &SyntaxNode) { + let mut inner_items = mem::replace(&mut self.tree.inner_items, FxHashMap::default()); + inner_items.extend( + container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { + let ast_id = self.source_ast_id_map.ast_id(&item); + Some((ast_id, self.lower_mod_item(&item, true)?.0)) + }), + ); + self.tree.inner_items = inner_items; + } + + fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option { match item { - ast::AssocItem::FnDef(ast) => { - self.lower_function(ast).map(|data| id(self.tree.functions.alloc(data)).into()) - } - ast::AssocItem::TypeAliasDef(ast) => { - self.lower_type_alias(ast).map(|data| id(self.tree.type_aliases.alloc(data)).into()) - } - ast::AssocItem::ConstDef(ast) => { - let data = self.lower_const(ast); - Some(id(self.tree.consts.alloc(data)).into()) - } + ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), + ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), + ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), + ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), + _ => None, } } - fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option { + fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option> { let attrs = self.lower_attrs(strukt); let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); @@ -138,7 +150,7 @@ impl Ctx { ast::StructKind::Unit => StructDefKind::Unit, }; let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; - Some(res) + Some(id(self.tree.structs.alloc(res))) } fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { @@ -193,7 +205,7 @@ impl Ctx { Some(res) } - fn lower_union(&mut self, union: &ast::UnionDef) -> Option { + fn lower_union(&mut self, union: &ast::UnionDef) -> Option> { let attrs = self.lower_attrs(union); let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); @@ -206,10 +218,10 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(union); let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; - Some(res) + Some(id(self.tree.unions.alloc(res))) } - fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option { + fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option> { let attrs = self.lower_attrs(enum_); let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); @@ -220,7 +232,7 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; - Some(res) + Some(id(self.tree.enums.alloc(res))) } fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { @@ -241,7 +253,7 @@ impl Ctx { Some(res) } - fn lower_function(&mut self, func: &ast::FnDef) -> Option { + fn lower_function(&mut self, func: &ast::FnDef) -> Option> { let attrs = self.lower_attrs(func); let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -297,37 +309,42 @@ impl Ctx { ast_id, }; res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); - Some(res) + + Some(id(self.tree.functions.alloc(res))) } - fn lower_type_alias(&mut self, type_alias: &ast::TypeAliasDef) -> Option { + fn lower_type_alias( + &mut self, + type_alias: &ast::TypeAliasDef, + ) -> Option> { let name = type_alias.name()?.as_name(); let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; - Some(res) + Some(id(self.tree.type_aliases.alloc(res))) } - fn lower_static(&mut self, static_: &ast::StaticDef) -> Option { + fn lower_static(&mut self, static_: &ast::StaticDef) -> Option> { let name = static_.name()?.as_name(); let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); let visibility = self.lower_visibility(static_); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, type_ref, ast_id }; - Some(res) + Some(id(self.tree.statics.alloc(res))) } - fn lower_const(&mut self, konst: &ast::ConstDef) -> Const { + fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId { let name = konst.name().map(|it| it.as_name()); let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); - Const { name, visibility, type_ref, ast_id } + let res = Const { name, visibility, type_ref, ast_id }; + id(self.tree.consts.alloc(res)) } - fn lower_module(&mut self, module: &ast::Module) -> Option { + fn lower_module(&mut self, module: &ast::Module) -> Option> { let name = module.name()?.as_name(); let visibility = self.lower_visibility(module); let kind = if module.semicolon_token().is_some() { @@ -338,7 +355,7 @@ impl Ctx { .item_list() .map(|list| { list.items() - .flat_map(|item| self.lower_mod_item(&item)) + .flat_map(|item| self.lower_mod_item(&item, false)) .flat_map(|items| items.0) .collect() }) @@ -349,90 +366,101 @@ impl Ctx { } }; let ast_id = self.source_ast_id_map.ast_id(module); - Some(Mod { name, visibility, kind, ast_id }) + let res = Mod { name, visibility, kind, ast_id }; + Some(id(self.tree.mods.alloc(res))) } - fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option { + fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { - // FIXME: Does not handle macros - list.assoc_items().flat_map(|item| self.lower_assoc_item(&item)).collect() + list.items() + .flat_map(|item| { + self.collect_inner_items(item.syntax()); + self.lower_assoc_item(&item) + }) + .collect() }); let ast_id = self.source_ast_id_map.ast_id(trait_def); - Some(Trait { + let res = Trait { name, visibility, generic_params, auto, items: items.unwrap_or_default(), ast_id, - }) + }; + Some(id(self.tree.traits.alloc(res))) } - fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option { + fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); let target_type = self.lower_type_ref(&impl_def.target_type()?); let is_negative = impl_def.excl_token().is_some(); + + // We cannot use `assoc_items()` here as that does not include macro calls. let items = impl_def .item_list()? - .assoc_items() - .filter_map(|item| self.lower_assoc_item(&item)) + .items() + .filter_map(|item| { + self.collect_inner_items(item.syntax()); + let assoc = self.lower_assoc_item(&item)?; + Some(assoc) + }) .collect(); let ast_id = self.source_ast_id_map.ast_id(impl_def); - Some(Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }) + let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; + Some(id(self.tree.impls.alloc(res))) } - fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec { + fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec> { // FIXME: cfg_attr let is_prelude = use_item.has_atom_attr("prelude_import"); let visibility = self.lower_visibility(use_item); + let ast_id = self.source_ast_id_map.ast_id(use_item); // Every use item can expand to many `Import`s. let mut imports = Vec::new(); + let tree = &mut self.tree; ModPath::expand_use_item( InFile::new(self.file, use_item.clone()), &self.hygiene, |path, _tree, is_glob, alias| { - imports.push(Import { + imports.push(id(tree.imports.alloc(Import { path, alias, visibility: visibility.clone(), is_glob, is_prelude, - is_extern_crate: false, - is_macro_use: false, - }); + ast_id, + }))); }, ); imports } - fn lower_extern_crate(&mut self, extern_crate: &ast::ExternCrateItem) -> Option { + fn lower_extern_crate( + &mut self, + extern_crate: &ast::ExternCrateItem, + ) -> Option> { let path = ModPath::from_name_ref(&extern_crate.name_ref()?); let alias = extern_crate.alias().map(|a| { a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) }); let visibility = self.lower_visibility(extern_crate); + let ast_id = self.source_ast_id_map.ast_id(extern_crate); // FIXME: cfg_attr let is_macro_use = extern_crate.has_atom_attr("macro_use"); - Some(Import { - path, - alias, - visibility, - is_glob: false, - is_prelude: false, - is_extern_crate: true, - is_macro_use, - }) + let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; + Some(id(self.tree.extern_crates.alloc(res))) } - fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option { + fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { let name = m.name().map(|it| it.as_name()); let attrs = Attrs::new(m, &self.hygiene); let path = ModPath::from_src(m.path()?, &self.hygiene)?; @@ -455,15 +483,26 @@ impl Ctx { }; let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); - Some(MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }) + let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; + Some(id(self.tree.macro_calls.alloc(res))) } - fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec> { + fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec { block.extern_item_list().map_or(Vec::new(), |list| { list.extern_items() - .filter_map(|item| match item { - ast::ExternItem::FnDef(ast) => self.lower_function(&ast).map(Either::Left), - ast::ExternItem::StaticDef(ast) => self.lower_static(&ast).map(Either::Right), + .filter_map(|item| { + self.collect_inner_items(item.syntax()); + let id = match item { + ast::ExternItem::FnDef(ast) => { + let func = self.lower_function(&ast)?; + func.into() + } + ast::ExternItem::StaticDef(ast) => { + let statik = self.lower_static(&ast)?; + statik.into() + } + }; + Some(id) }) .collect() }) diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs new file mode 100644 index 0000000000..b60e6cbb0c --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -0,0 +1,254 @@ +use super::{ItemTree, ModItem, ModKind}; +use crate::{db::DefDatabase, test_db::TestDB}; +use hir_expand::db::AstDatabase; +use insta::assert_snapshot; +use ra_db::fixture::WithFixture; +use ra_syntax::{ast, AstNode}; +use rustc_hash::FxHashSet; +use std::sync::Arc; +use stdx::format_to; + +fn test_inner_items(ra_fixture: &str) { + let (db, file_id) = TestDB::with_single_file(ra_fixture); + let tree = db.item_tree(file_id.into()); + let root = db.parse_or_expand(file_id.into()).unwrap(); + let ast_id_map = db.ast_id_map(file_id.into()); + + // Traverse the item tree and collect all module/impl/trait-level items as AST nodes. + let mut outer_items = FxHashSet::default(); + let mut worklist = tree.top_level_items().to_vec(); + while let Some(item) = worklist.pop() { + let node: ast::ModuleItem = match item { + ModItem::Import(it) => tree.source(&db, it).into(), + ModItem::ExternCrate(it) => tree.source(&db, it).into(), + ModItem::Function(it) => tree.source(&db, it).into(), + ModItem::Struct(it) => tree.source(&db, it).into(), + ModItem::Union(it) => tree.source(&db, it).into(), + ModItem::Enum(it) => tree.source(&db, it).into(), + ModItem::Const(it) => tree.source(&db, it).into(), + ModItem::Static(it) => tree.source(&db, it).into(), + ModItem::TypeAlias(it) => tree.source(&db, it).into(), + ModItem::Mod(it) => { + if let ModKind::Inline { items } = &tree[it].kind { + worklist.extend(items); + } + tree.source(&db, it).into() + } + ModItem::Trait(it) => { + worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); + tree.source(&db, it).into() + } + ModItem::Impl(it) => { + worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); + tree.source(&db, it).into() + } + ModItem::MacroCall(_) => continue, + }; + + outer_items.insert(node); + } + + // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or + // registered as inner items. + for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { + if outer_items.contains(&item) { + continue; + } + + let ast_id = ast_id_map.ast_id(&item); + assert!(!tree.inner_items(ast_id).is_empty()); + } +} + +fn item_tree(ra_fixture: &str) -> Arc { + let (db, file_id) = TestDB::with_single_file(ra_fixture); + db.item_tree(file_id.into()) +} + +fn print_item_tree(ra_fixture: &str) -> String { + let tree = item_tree(ra_fixture); + let mut out = String::new(); + + format_to!(out, "inner attrs: {:?}\n\n", tree.top_level_attrs()); + format_to!(out, "top-level items:\n"); + for item in tree.top_level_items() { + fmt_mod_item(&mut out, &tree, *item); + format_to!(out, "\n"); + } + + if !tree.inner_items.is_empty() { + format_to!(out, "\ninner items:\n"); + for (ast_id, items) in &tree.inner_items { + format_to!(out, "{:?}:\n", ast_id); + for inner in items { + format_to!(out, "- "); + fmt_mod_item(&mut out, &tree, *inner); + format_to!(out, "\n"); + } + } + } + + out +} + +fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { + match item { + ModItem::ExternCrate(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Import(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Function(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Struct(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Union(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Enum(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Const(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Static(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Trait(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Impl(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::TypeAlias(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::Mod(it) => { + format_to!(out, "{:?}", tree[it]); + } + ModItem::MacroCall(it) => { + format_to!(out, "{:?}", tree[it]); + } + } +} + +#[test] +fn smoke() { + assert_snapshot!(print_item_tree(r" + #![attr] + + use {a, b::*}; + extern crate krate; + + trait Tr { + type AssocTy: Tr<()>; + const CONST: u8; + fn method(&self); + fn dfl_method(&mut self) {} + } + + struct Struct0; + struct Struct1(u8); + struct Struct2 { + fld: (T, ), + } + + enum En { + Variant { + field: u8, + }, + } + + union Un { + fld: u16, + } + "), @r###" +inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } + +top-level items: +Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } +Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } +ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_macro_use: false, ast_id: FileAstId::(1) } +Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } +Struct { name: Name(Text("Struct0")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } +Struct { name: Name(Text("Struct1")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } +Struct { name: Name(Text("Struct2")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } +Enum { name: Name(Text("En")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } +Union { name: Name(Text("Un")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } + "###); +} + +#[test] +fn simple_inner_items() { + let tree = print_item_tree( + r" + impl D for Response { + fn foo() { + end(); + fn end() { + let _x: T = loop {}; + } + } + } + ", + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } + +inner items: +FileAstId::(2): +- Function { name: Name(Text("end")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } + "###); +} + +#[test] +fn cursed_inner_items() { + test_inner_items( + r" + struct S(T); + + enum En { + Var1 { + t: [(); { trait Inner {} 0 }], + }, + + Var2([u16; { enum Inner {} 0 }]), + } + + type Ty = [En; { struct Inner; 0 }]; + + impl En { + fn assoc() { + trait InnerTrait {} + struct InnerStruct {} + impl InnerTrait for InnerStruct {} + } + } + ", + ); +} + +#[test] +fn assoc_item_macros() { + let tree = print_item_tree( + r" + impl S { + items!(); + } + ", + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } + "###); +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index b5500f3707..564434cccf 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -50,7 +50,7 @@ pub mod import_map; #[cfg(test)] mod test_db; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; use hir_expand::{ ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, @@ -58,10 +58,13 @@ use hir_expand::{ }; use ra_arena::Idx; use ra_db::{impl_intern_key, salsa, CrateId}; -use ra_syntax::{ast, AstNode}; +use ra_syntax::ast; -use crate::body::Expander; use crate::builtin_type::BuiltinType; +use item_tree::{ + Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, + TypeAlias, Union, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ModuleId { @@ -72,16 +75,62 @@ pub struct ModuleId { /// An ID of a module, **local** to a specific crate pub type LocalModuleId = Idx; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ItemLoc { +#[derive(Debug)] +pub struct ItemLoc { pub container: ContainerId, - pub ast_id: AstId, + pub id: ItemTreeId, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct AssocItemLoc { +impl Clone for ItemLoc { + fn clone(&self) -> Self { + Self { container: self.container, id: self.id } + } +} + +impl Copy for ItemLoc {} + +impl PartialEq for ItemLoc { + fn eq(&self, other: &Self) -> bool { + self.container == other.container && self.id == other.id + } +} + +impl Eq for ItemLoc {} + +impl Hash for ItemLoc { + fn hash(&self, state: &mut H) { + self.container.hash(state); + self.id.hash(state); + } +} + +#[derive(Debug)] +pub struct AssocItemLoc { pub container: AssocContainerId, - pub ast_id: AstId, + pub id: ItemTreeId, +} + +impl Clone for AssocItemLoc { + fn clone(&self) -> Self { + Self { container: self.container, id: self.id } + } +} + +impl Copy for AssocItemLoc {} + +impl PartialEq for AssocItemLoc { + fn eq(&self, other: &Self) -> bool { + self.container == other.container && self.id == other.id + } +} + +impl Eq for AssocItemLoc {} + +impl Hash for AssocItemLoc { + fn hash(&self, state: &mut H) { + self.container.hash(state); + self.id.hash(state); + } } macro_rules! impl_intern { @@ -106,22 +155,22 @@ macro_rules! impl_intern { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FunctionId(salsa::InternId); -type FunctionLoc = AssocItemLoc; +type FunctionLoc = AssocItemLoc; impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct StructId(salsa::InternId); -type StructLoc = ItemLoc; +type StructLoc = ItemLoc; impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UnionId(salsa::InternId); -pub type UnionLoc = ItemLoc; +pub type UnionLoc = ItemLoc; impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumId(salsa::InternId); -pub type EnumLoc = ItemLoc; +pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); // FIXME: rename to `VariantId`, only enums can ave variants @@ -143,27 +192,27 @@ pub type LocalFieldId = Idx; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); -type ConstLoc = AssocItemLoc; +type ConstLoc = AssocItemLoc; impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct StaticId(salsa::InternId); -pub type StaticLoc = ItemLoc; +pub type StaticLoc = ItemLoc; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TraitId(salsa::InternId); -pub type TraitLoc = ItemLoc; +pub type TraitLoc = ItemLoc; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TypeAliasId(salsa::InternId); -type TypeAliasLoc = AssocItemLoc; +type TypeAliasLoc = AssocItemLoc; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ImplId(salsa::InternId); -type ImplLoc = ItemLoc; +type ImplLoc = ItemLoc; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -367,7 +416,7 @@ impl HasModule for AssocContainerId { } } -impl HasModule for AssocItemLoc { +impl HasModule for AssocItemLoc { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { self.container.module(db) } @@ -394,6 +443,16 @@ impl HasModule for DefWithBodyId { } } +impl DefWithBodyId { + pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { + match self { + DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), + DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), + DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), + } + } +} + impl HasModule for GenericDefId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index c227b6da19..40aff830f0 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -20,9 +20,7 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, - item_tree::{ - FileItemTreeId, Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind, - }, + item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind}, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, @@ -105,10 +103,48 @@ impl PartialResolvedImport { } } +#[derive(Clone, Debug, Eq, PartialEq)] +struct Import { + pub path: ModPath, + pub alias: Option, + pub visibility: RawVisibility, + pub is_glob: bool, + pub is_prelude: bool, + pub is_extern_crate: bool, + pub is_macro_use: bool, +} + +impl From for Import { + fn from(it: item_tree::Import) -> Self { + Self { + path: it.path, + alias: it.alias, + visibility: it.visibility, + is_glob: it.is_glob, + is_prelude: it.is_prelude, + is_extern_crate: false, + is_macro_use: false, + } + } +} + +impl From for Import { + fn from(it: item_tree::ExternCrate) -> Self { + Self { + path: it.path, + alias: it.alias, + visibility: it.visibility, + is_glob: false, + is_prelude: false, + is_extern_crate: true, + is_macro_use: it.is_macro_use, + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] struct ImportDirective { module_id: LocalModuleId, - import_id: FileItemTreeId, import: Import, status: PartialResolvedImport, } @@ -297,7 +333,7 @@ impl DefCollector<'_> { fn import_macros_from_extern_crate( &mut self, current_module_id: LocalModuleId, - import: &Import, + import: &item_tree::ExternCrate, ) { log::debug!( "importing macros from extern crate: {:?} ({:?})", @@ -703,9 +739,9 @@ impl ModCollector<'_, '_> { // any other items. for item in items { if self.is_cfg_enabled(self.item_tree.attrs(*item)) { - if let ModItem::Import(import_id) = item { - let import = self.item_tree[*import_id].clone(); - if import.is_extern_crate && import.is_macro_use { + if let ModItem::ExternCrate(id) = item { + let import = self.item_tree[*id].clone(); + if import.is_macro_use { self.def_collector.import_macros_from_extern_crate(self.module_id, &import); } } @@ -725,8 +761,14 @@ impl ModCollector<'_, '_> { ModItem::Import(import_id) => { self.def_collector.unresolved_imports.push(ImportDirective { module_id: self.module_id, - import_id, - import: self.item_tree[import_id].clone(), + import: self.item_tree[import_id].clone().into(), + status: PartialResolvedImport::Unresolved, + }) + } + ModItem::ExternCrate(import_id) => { + self.def_collector.unresolved_imports.push(ImportDirective { + module_id: self.module_id, + import: self.item_tree[import_id].clone().into(), status: PartialResolvedImport::Unresolved, }) } @@ -737,30 +779,28 @@ impl ModCollector<'_, '_> { local_id: self.module_id, }; let container = ContainerId::ModuleId(module); - let ast_id = self.item_tree[imp].ast_id; - let impl_id = - ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } - .intern(self.def_collector.db); + let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } + .intern(self.def_collector.db); self.def_collector.def_map.modules[self.module_id] .scope .define_impl(impl_id) } - ModItem::Function(it) => { - let it = &self.item_tree[it]; + ModItem::Function(id) => { + let func = &self.item_tree[id]; def = Some(DefData { id: FunctionLoc { container: container.into(), - ast_id: AstId::new(self.file_id, it.ast_id), + id: ItemTreeId::new(self.file_id, id), } .intern(self.def_collector.db) .into(), - name: &it.name, - visibility: &it.visibility, + name: &func.name, + visibility: &func.visibility, has_constructor: false, }); } - ModItem::Struct(it) => { - let it = &self.item_tree[it]; + ModItem::Struct(id) => { + let it = &self.item_tree[id]; // FIXME: check attrs to see if this is an attribute macro invocation; // in which case we don't add the invocation, just a single attribute @@ -768,19 +808,16 @@ impl ModCollector<'_, '_> { self.collect_derives(attrs, it.ast_id.upcast()); def = Some(DefData { - id: StructLoc { - container, - ast_id: AstId::new(self.file_id, it.ast_id), - } - .intern(self.def_collector.db) - .into(), + id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } + .intern(self.def_collector.db) + .into(), name: &it.name, visibility: &it.visibility, has_constructor: it.kind != StructDefKind::Record, }); } - ModItem::Union(it) => { - let it = &self.item_tree[it]; + ModItem::Union(id) => { + let it = &self.item_tree[id]; // FIXME: check attrs to see if this is an attribute macro invocation; // in which case we don't add the invocation, just a single attribute @@ -788,7 +825,7 @@ impl ModCollector<'_, '_> { self.collect_derives(attrs, it.ast_id.upcast()); def = Some(DefData { - id: UnionLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } .intern(self.def_collector.db) .into(), name: &it.name, @@ -796,8 +833,8 @@ impl ModCollector<'_, '_> { has_constructor: false, }); } - ModItem::Enum(it) => { - let it = &self.item_tree[it]; + ModItem::Enum(id) => { + let it = &self.item_tree[id]; // FIXME: check attrs to see if this is an attribute macro invocation; // in which case we don't add the invocation, just a single attribute @@ -805,7 +842,7 @@ impl ModCollector<'_, '_> { self.collect_derives(attrs, it.ast_id.upcast()); def = Some(DefData { - id: EnumLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } .intern(self.def_collector.db) .into(), name: &it.name, @@ -813,14 +850,14 @@ impl ModCollector<'_, '_> { has_constructor: false, }); } - ModItem::Const(it) => { - let it = &self.item_tree[it]; + ModItem::Const(id) => { + let it = &self.item_tree[id]; if let Some(name) = &it.name { def = Some(DefData { id: ConstLoc { container: container.into(), - ast_id: AstId::new(self.file_id, it.ast_id), + id: ItemTreeId::new(self.file_id, id), } .intern(self.def_collector.db) .into(), @@ -830,26 +867,11 @@ impl ModCollector<'_, '_> { }); } } - ModItem::Static(it) => { - let it = &self.item_tree[it]; + ModItem::Static(id) => { + let it = &self.item_tree[id]; def = Some(DefData { - id: StaticLoc { - container, - ast_id: AstId::new(self.file_id, it.ast_id), - } - .intern(self.def_collector.db) - .into(), - name: &it.name, - visibility: &it.visibility, - has_constructor: false, - }); - } - ModItem::Trait(it) => { - let it = &self.item_tree[it]; - - def = Some(DefData { - id: TraitLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) } + id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) } .intern(self.def_collector.db) .into(), name: &it.name, @@ -857,13 +879,25 @@ impl ModCollector<'_, '_> { has_constructor: false, }); } - ModItem::TypeAlias(it) => { - let it = &self.item_tree[it]; + ModItem::Trait(id) => { + let it = &self.item_tree[id]; + + def = Some(DefData { + id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) } + .intern(self.def_collector.db) + .into(), + name: &it.name, + visibility: &it.visibility, + has_constructor: false, + }); + } + ModItem::TypeAlias(id) => { + let it = &self.item_tree[id]; def = Some(DefData { id: TypeAliasLoc { container: container.into(), - ast_id: AstId::new(self.file_id, it.ast_id), + id: ItemTreeId::new(self.file_id, id), } .intern(self.def_collector.db) .into(), diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index d42933eed7..e9a5e4cba1 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs @@ -722,10 +722,7 @@ fn unresolved_module_diagnostics() { ), ), ), - value: FileAstId { - raw: Idx::(1), - _ty: PhantomData, - }, + value: FileAstId::(1), }, candidate: "bar.rs", }, diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs index 46e90da700..10e21d48e6 100644 --- a/crates/ra_hir_def/src/src.rs +++ b/crates/ra_hir_def/src/src.rs @@ -2,30 +2,37 @@ use hir_expand::InFile; use ra_arena::map::ArenaMap; -use ra_syntax::AstNode; -use crate::{db::DefDatabase, AssocItemLoc, ItemLoc}; +use crate::{db::DefDatabase, item_tree::ItemTreeSource, AssocItemLoc, ItemLoc}; pub trait HasSource { type Value; fn source(&self, db: &dyn DefDatabase) -> InFile; } -impl HasSource for AssocItemLoc { - type Value = N; +impl HasSource for AssocItemLoc { + type Value = N::Source; - fn source(&self, db: &dyn DefDatabase) -> InFile { - let node = self.ast_id.to_node(db.upcast()); - InFile::new(self.ast_id.file_id, node) + fn source(&self, db: &dyn DefDatabase) -> InFile { + let tree = db.item_tree(self.id.file_id); + let ast_id_map = db.ast_id_map(self.id.file_id); + let root = db.parse_or_expand(self.id.file_id).unwrap(); + let node = &tree[self.id.value]; + + InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) } } -impl HasSource for ItemLoc { - type Value = N; +impl HasSource for ItemLoc { + type Value = N::Source; - fn source(&self, db: &dyn DefDatabase) -> InFile { - let node = self.ast_id.to_node(db.upcast()); - InFile::new(self.ast_id.file_id, node) + fn source(&self, db: &dyn DefDatabase) -> InFile { + let tree = db.item_tree(self.id.file_id); + let ast_id_map = db.ast_id_map(self.id.file_id); + let root = db.parse_or_expand(self.id.file_id).unwrap(); + let node = &tree[self.id.value]; + + InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root)) } } diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index d19569245e..f4d31526a6 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs @@ -6,6 +6,8 @@ //! changes. use std::{ + any::type_name, + fmt, hash::{Hash, Hasher}, marker::PhantomData, }; @@ -14,7 +16,6 @@ use ra_arena::{Arena, Idx}; use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. -#[derive(Debug)] pub struct FileAstId { raw: ErasedFileAstId, _ty: PhantomData N>, @@ -39,11 +40,17 @@ impl Hash for FileAstId { } } +impl fmt::Debug for FileAstId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FileAstId::<{}>({})", type_name::(), self.raw.into_raw()) + } +} + impl FileAstId { // Can't make this a From implementation because of coherence pub fn upcast(self) -> FileAstId where - M: From, + N: Into, { FileAstId { raw: self.raw, _ty: PhantomData } } @@ -89,7 +96,7 @@ impl AstIdMap { } } - pub(crate) fn get(&self, id: FileAstId) -> AstPtr { + pub fn get(&self, id: FileAstId) -> AstPtr { self.arena[id.raw].clone().cast::().unwrap() } diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 1fe05c70c9..e82f2c11e2 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -67,8 +67,8 @@ fn type_at_pos_displayed( panic!("Can't find expression") } -fn type_at(content: &str) -> String { - let (db, file_pos) = TestDB::with_position(content); +fn type_at(ra_fixture: &str) -> String { + let (db, file_pos) = TestDB::with_position(ra_fixture); type_at_pos(&db, file_pos) } @@ -164,13 +164,19 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); defs.sort_by_key(|def| match def { DefWithBodyId::FunctionId(it) => { - it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() + let loc = it.lookup(&db); + let tree = db.item_tree(loc.id.file_id); + tree.source(&db, loc.id.value).syntax().text_range().start() } DefWithBodyId::ConstId(it) => { - it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() + let loc = it.lookup(&db); + let tree = db.item_tree(loc.id.file_id); + tree.source(&db, loc.id.value).syntax().text_range().start() } DefWithBodyId::StaticId(it) => { - it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() + let loc = it.lookup(&db); + let tree = db.item_tree(loc.id.file_id); + tree.source(&db, loc.id.value).syntax().text_range().start() } }); for def in defs { From 1fbe21a545104e85aa5f9d0d8a45ec1040396cb9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 22 Jun 2020 16:41:10 +0200 Subject: [PATCH 15/34] Make remaining item data queries use item tree --- crates/ra_hir_def/src/data.rs | 160 ++++++----------------- crates/ra_hir_def/src/item_tree.rs | 4 + crates/ra_hir_def/src/item_tree/lower.rs | 51 ++++++-- crates/ra_hir_def/src/item_tree/tests.rs | 2 +- crates/ra_hir_def/src/visibility.rs | 21 +-- 5 files changed, 88 insertions(+), 150 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 697fde3d21..921253c42d 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -2,23 +2,16 @@ use std::sync::Arc; -use hir_expand::{ - hygiene::Hygiene, - name::{name, AsName, Name}, - InFile, -}; +use hir_expand::{name::Name, InFile}; use ra_prof::profile; -use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, VisibilityOwner}; +use ra_syntax::ast; use crate::{ attr::Attrs, body::Expander, - body::LowerCtx, db::DefDatabase, item_tree::{AssocItem, ItemTreeId, ModItem}, - path::{path, AssociatedTypeBinding, GenericArgs, Path}, - src::HasSource, - type_ref::{Mutability, TypeBound, TypeRef}, + type_ref::{TypeBound, TypeRef}, visibility::RawVisibility, AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, @@ -40,82 +33,27 @@ pub struct FunctionData { impl FunctionData { pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc { let loc = func.lookup(db); - let src = loc.source(db); - let ctx = LowerCtx::new(db, src.file_id); - let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); - let mut params = Vec::new(); - let mut has_self_param = false; - if let Some(param_list) = src.value.param_list() { - if let Some(self_param) = param_list.self_param() { - let self_type = if let Some(type_ref) = self_param.ascribed_type() { - TypeRef::from_ast(&ctx, type_ref) - } else { - let self_type = TypeRef::Path(name![Self].into()); - match self_param.kind() { - ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => { - TypeRef::Reference(Box::new(self_type), Mutability::Shared) - } - ast::SelfParamKind::MutRef => { - TypeRef::Reference(Box::new(self_type), Mutability::Mut) - } - } - }; - params.push(self_type); - has_self_param = true; - } - for param in param_list.params() { - let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); - params.push(type_ref); - } - } - let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); + let item_tree = db.item_tree(loc.id.file_id); + let func = &item_tree[loc.id.value]; - let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { - TypeRef::from_ast(&ctx, type_ref) - } else { - TypeRef::unit() - }; - - let ret_type = if src.value.async_token().is_some() { - let future_impl = desugar_future_path(ret_type); - let ty_bound = TypeBound::Path(future_impl); - TypeRef::ImplTrait(vec![ty_bound]) - } else { - ret_type - }; - - let is_unsafe = src.value.unsafe_token().is_some(); - - let vis_default = RawVisibility::default_for_container(loc.container); - let visibility = - RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); - - let sig = - FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; - Arc::new(sig) + Arc::new(FunctionData { + name: func.name.clone(), + params: func.params.clone(), + ret_type: func.ret_type.clone(), + attrs: func.attrs.clone(), + has_self_param: func.has_self_param, + is_unsafe: func.is_unsafe, + visibility: func.visibility.clone(), + }) } } -fn desugar_future_path(orig: TypeRef) -> Path { - let path = path![core::future::Future]; - let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); - let mut last = GenericArgs::empty(); - last.bindings.push(AssociatedTypeBinding { - name: name![Output], - type_ref: Some(orig), - bounds: Vec::new(), - }); - generic_args.push(Some(Arc::new(last))); - - Path::from_known_path(path, generic_args) -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAliasData { pub name: Name, pub type_ref: Option, pub visibility: RawVisibility, + /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). pub bounds: Vec, } @@ -125,22 +63,15 @@ impl TypeAliasData { typ: TypeAliasId, ) -> Arc { let loc = typ.lookup(db); - let node = loc.source(db); - let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); - let lower_ctx = LowerCtx::new(db, node.file_id); - let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); - let vis_default = RawVisibility::default_for_container(loc.container); - let visibility = RawVisibility::from_ast_with_default( - db, - vis_default, - node.as_ref().map(|n| n.visibility()), - ); - let bounds = if let Some(bound_list) = node.value.type_bound_list() { - bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() - } else { - Vec::new() - }; - Arc::new(TypeAliasData { name, type_ref, visibility, bounds }) + let item_tree = db.item_tree(loc.id.file_id); + let typ = &item_tree[loc.id.value]; + + Arc::new(TypeAliasData { + name: typ.name.clone(), + type_ref: typ.type_ref.clone(), + visibility: typ.visibility.clone(), + bounds: typ.bounds.clone(), + }) } } @@ -238,22 +169,14 @@ pub struct ConstData { impl ConstData { pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc { let loc = konst.lookup(db); - let node = loc.source(db); - let vis_default = RawVisibility::default_for_container(loc.container); - Arc::new(ConstData::new(db, vis_default, node)) - } + let item_tree = db.item_tree(loc.id.file_id); + let konst = &item_tree[loc.id.value]; - fn new( - db: &dyn DefDatabase, - vis_default: RawVisibility, - node: InFile, - ) -> ConstData { - let ctx = LowerCtx::new(db, node.file_id); - let name = node.value.name().map(|n| n.as_name()); - let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); - let visibility = - RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); - ConstData { name, type_ref, visibility } + Arc::new(ConstData { + name: konst.name.clone(), + type_ref: konst.type_ref.clone(), + visibility: konst.visibility.clone(), + }) } } @@ -267,19 +190,16 @@ pub struct StaticData { impl StaticData { pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc { - let node = konst.lookup(db).source(db); - let ctx = LowerCtx::new(db, node.file_id); + let node = konst.lookup(db); + let item_tree = db.item_tree(node.id.file_id); + let statik = &item_tree[node.id.value]; - let name = node.value.name().map(|n| n.as_name()); - let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); - let mutable = node.value.mut_token().is_some(); - let visibility = RawVisibility::from_ast_with_default( - db, - RawVisibility::private(), - node.map(|n| n.visibility()), - ); - - Arc::new(StaticData { name, type_ref, visibility, mutable }) + Arc::new(StaticData { + name: Some(statik.name.clone()), + type_ref: statik.type_ref.clone(), + visibility: statik.visibility.clone(), + mutable: statik.mutable, + }) } } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 9a5dd701eb..c35d632952 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -349,6 +349,7 @@ pub struct Function { pub visibility: RawVisibility, pub generic_params: GenericParams, pub has_self_param: bool, + pub is_unsafe: bool, pub params: Vec, pub ret_type: TypeRef, pub ast_id: FileAstId, @@ -408,6 +409,7 @@ pub struct Const { pub struct Static { pub name: Name, pub visibility: RawVisibility, + pub mutable: bool, pub type_ref: TypeRef, pub ast_id: FileAstId, } @@ -436,6 +438,8 @@ pub struct Impl { pub struct TypeAlias { pub name: Name, pub visibility: RawVisibility, + /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. + pub bounds: Vec, pub generic_params: GenericParams, pub type_ref: Option, pub ast_id: FileAstId, diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index f2b8a94182..42af8bb5e5 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -36,6 +36,7 @@ pub(super) struct Ctx { source_ast_id_map: Arc, body_ctx: crate::body::LowerCtx, inner_items: Vec, + forced_visibility: Option, } impl Ctx { @@ -47,6 +48,7 @@ impl Ctx { source_ast_id_map: db.ast_id_map(file), body_ctx: crate::body::LowerCtx::new(db, file), inner_items: Vec::new(), + forced_visibility: None, } } @@ -117,6 +119,7 @@ impl Ctx { } fn collect_inner_items(&mut self, container: &SyntaxNode) { + let forced_vis = self.forced_visibility.take(); let mut inner_items = mem::replace(&mut self.tree.inner_items, FxHashMap::default()); inner_items.extend( container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { @@ -125,6 +128,7 @@ impl Ctx { }), ); self.tree.inner_items = inner_items; + self.forced_visibility = forced_vis; } fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option { @@ -304,6 +308,7 @@ impl Ctx { visibility, generic_params: GenericParams::default(), has_self_param, + is_unsafe: func.unsafe_token().is_some(), params, ret_type, ast_id, @@ -320,9 +325,10 @@ impl Ctx { let name = type_alias.name()?.as_name(); let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); + let bounds = self.lower_type_bounds(type_alias); let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); - let res = TypeAlias { name, visibility, generic_params, type_ref, ast_id }; + let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; Some(id(self.tree.type_aliases.alloc(res))) } @@ -330,8 +336,9 @@ impl Ctx { let name = static_.name()?.as_name(); let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); let visibility = self.lower_visibility(static_); + let mutable = static_.mut_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); - let res = Static { name, visibility, type_ref, ast_id }; + let res = Static { name, visibility, mutable, type_ref, ast_id }; Some(id(self.tree.statics.alloc(res))) } @@ -376,12 +383,14 @@ impl Ctx { let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { - list.items() - .flat_map(|item| { - self.collect_inner_items(item.syntax()); - self.lower_assoc_item(&item) - }) - .collect() + self.with_inherited_visibility(visibility.clone(), |this| { + list.items() + .flat_map(|item| { + this.collect_inner_items(item.syntax()); + this.lower_assoc_item(&item) + }) + .collect() + }) }); let ast_id = self.source_ast_id_map.ast_id(trait_def); let res = Trait { @@ -549,11 +558,23 @@ impl Ctx { generics } + fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec { + if let Some(bound_list) = node.type_bound_list() { + bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() + } else { + Vec::new() + } + } + fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { Attrs::new(item, &self.hygiene) } fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { - RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) + if let Some(vis) = self.forced_visibility.as_ref() { + vis.clone() + } else { + RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) + } } fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { TypeRef::from_ast(&self.body_ctx, type_ref.clone()) @@ -562,6 +583,18 @@ impl Ctx { TypeRef::from_ast_opt(&self.body_ctx, type_ref) } + /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. + fn with_inherited_visibility( + &mut self, + vis: RawVisibility, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + let old = mem::replace(&mut self.forced_visibility, Some(vis)); + let res = f(self); + self.forced_visibility = old; + res + } + fn next_field_idx(&self) -> Idx { Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) } diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index b60e6cbb0c..1db1ce7a9a 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -204,7 +204,7 @@ Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_ inner items: FileAstId::(2): -- Function { name: Name(Text("end")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +- Function { name: Name(Text("end")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 1482d3be04..8136cb50cc 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs @@ -6,7 +6,7 @@ use ra_syntax::ast; use crate::{ db::DefDatabase, path::{ModPath, PathKind}, - AssocContainerId, ModuleId, + ModuleId, }; /// Visibility of an item, not yet resolved. @@ -25,25 +25,6 @@ impl RawVisibility { RawVisibility::Module(path) } - pub(crate) fn default_for_container(container_id: AssocContainerId) -> Self { - match container_id { - AssocContainerId::TraitId(_) => RawVisibility::Public, - _ => RawVisibility::private(), - } - } - - pub(crate) fn from_ast_with_default( - db: &dyn DefDatabase, - default: RawVisibility, - node: InFile>, - ) -> RawVisibility { - Self::from_ast_with_hygiene_and_default( - node.value, - default, - &Hygiene::new(db.upcast(), node.file_id), - ) - } - pub(crate) fn from_ast( db: &dyn DefDatabase, node: InFile>, From 19586bc5c62541db5253986c84ce3ba5c6392656 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 22 Jun 2020 16:59:15 +0200 Subject: [PATCH 16/34] Record HirFileId's in profiler --- crates/ra_db/src/lib.rs | 2 +- crates/ra_hir_def/src/item_tree.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 875290259b..4a3ba57dab 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -114,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { } fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse { - let _p = profile("parse_query"); + let _p = profile("parse_query").detail(|| format!("{:?}", file_id)); let text = db.file_text(file_id); SourceFile::parse(&*text) } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index c35d632952..59a4a411ae 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -65,7 +65,7 @@ pub struct ItemTree { impl ItemTree { pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = ra_prof::profile("item_tree_query"); + let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); let syntax = if let Some(node) = db.parse_or_expand(file_id) { node } else { From ffa0435050ae57c5171c19224ca6e9f8a4e3435d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 22 Jun 2020 19:15:54 +0200 Subject: [PATCH 17/34] Make generics and attr queries use ItemTree Now it's fast --- crates/ra_hir_def/src/attr.rs | 35 +++++++++-------- crates/ra_hir_def/src/generics.rs | 49 +++++++++++++++++++++++- crates/ra_hir_def/src/item_tree.rs | 7 ++++ crates/ra_hir_def/src/item_tree/lower.rs | 7 +++- crates/ra_hir_def/src/item_tree/tests.rs | 2 +- 5 files changed, 79 insertions(+), 21 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 2eeba05729..deea83a6d7 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -13,7 +13,11 @@ use ra_syntax::{ use tt::Subtree; use crate::{ - db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, + db::DefDatabase, + item_tree::{ItemTreeId, ItemTreeNode}, + nameres::ModuleSource, + path::ModPath, + src::HasChildSource, AdtId, AttrDefId, Lookup, }; @@ -65,19 +69,19 @@ impl Attrs { Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) } AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), - AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), - AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), + AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), }, - AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), + AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), AttrDefId::MacroDefId(it) => { it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) } - AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), - AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), - AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), - AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), - AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), + AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), } } @@ -187,11 +191,8 @@ where Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) } -fn attrs_from_loc(node: T, db: &dyn DefDatabase) -> Attrs -where - T: HasSource, - T::Value: ast::AttrsOwner, -{ - let src = node.source(db); - Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) +fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase) -> Attrs { + let tree = db.item_tree(id.file_id); + let mod_item = N::id_to_mod_item(id.value); + tree.attrs(mod_item).clone() } diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index ed4f60c663..c4b9f626f4 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -74,8 +74,53 @@ impl GenericParams { def: GenericDefId, ) -> Arc { let _p = profile("generic_params_query"); - let (params, _source_map) = GenericParams::new(db, def); - Arc::new(params) + + let generics = match def { + GenericDefId::FunctionId(id) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::AdtId(AdtId::StructId(id)) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::AdtId(AdtId::EnumId(id)) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::AdtId(AdtId::UnionId(id)) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::TraitId(id) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::TypeAliasId(id) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::ImplId(id) => { + let id = id.lookup(db).id; + let tree = db.item_tree(id.file_id); + let item = &tree[id.value]; + item.generic_params.clone() + } + GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), + }; + Arc::new(generics) } fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile) { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 59a4a411ae..efcb5dc604 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -175,6 +175,9 @@ pub trait ItemTreeNode: Clone { /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. fn id_from_mod_item(mod_item: ModItem) -> Option>; + + /// Upcasts a `FileItemTreeId` to a generic `ModItem`. + fn id_to_mod_item(id: FileItemTreeId) -> ModItem; } /// Trait for item tree nodes that allow accessing the original AST node. @@ -232,6 +235,10 @@ macro_rules! nodes { None } } + + fn id_to_mod_item(id: FileItemTreeId) -> ModItem { + ModItem::$node(id) + } } )+ }; } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 42af8bb5e5..841c7a852c 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -553,7 +553,12 @@ impl Ctx { generics.fill(&self.body_ctx, &mut sm, node); } - GenericsOwner::Impl => {} + GenericsOwner::Impl => { + // Note that we don't add `Self` here: in `impl`s, `Self` is not a + // type-parameter, but rather is a type-alias for impl's target + // type, so this is handled by the resolver. + generics.fill(&self.body_ctx, &mut sm, node); + } } generics } diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index 1db1ce7a9a..7b8523b9f0 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -200,7 +200,7 @@ fn simple_inner_items() { inner attrs: Attrs { entries: None } top-level items: -Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } +Impl { generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("A"))] }, generic_args: [None] }) }] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } inner items: FileAstId::(2): From 5a81427304114d2c6ada9e9258ffe31e715c25bc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 11:57:23 +0200 Subject: [PATCH 18/34] Measure ItemTree query memory usage --- crates/ra_hir/src/db.rs | 4 ++-- crates/ra_ide_db/src/change.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 309402a5aa..bb67952de2 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -6,8 +6,8 @@ pub use hir_def::db::{ ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, - InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery, StructDataQuery, - TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, + InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery, + StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 780c4feae6..b507000f22 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -199,6 +199,7 @@ impl RootDatabase { hir::db::InternEagerExpansionQuery // DefDatabase + hir::db::ItemTreeQuery hir::db::CrateDefMapQueryQuery hir::db::StructDataQuery hir::db::UnionDataQuery From 689e147c9dc416027fd36e94673431533df545f9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 13:46:38 +0200 Subject: [PATCH 19/34] Collect inner items in expression macros --- crates/ra_hir_def/src/body/lower.rs | 4 +++- crates/ra_hir_def/src/body/scope.rs | 20 ++++++++++++++++++ crates/ra_hir_def/src/item_tree.rs | 27 +++++++++++++----------- crates/ra_hir_def/src/item_tree/lower.rs | 7 +++++- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index e7cf80676b..bbde0b8024 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -564,12 +564,14 @@ impl ExprCollector<'_> { }); let tree = &self.item_trees[index].1; + // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes + // Root file (non-macro). tree.all_inner_items() .chain(tree.top_level_items().iter().copied()) .filter_map(|mod_item| mod_item.downcast::()) .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) - .unwrap() + .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id)) } fn collect_expr_opt(&mut self, expr: Option) -> ExprId { diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 0b74199d9f..81397b0631 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs @@ -317,6 +317,26 @@ fn foo() { ); } + #[test] + fn macro_inner_item() { + do_check( + r" + macro_rules! mac { + () => {{ + fn inner() {} + inner(); + }}; + } + + fn foo() { + mac!(); + <|> + } + ", + &[], + ); + } + fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { let (db, position) = TestDB::with_position(ra_fixture); let file_id = position.file_id; diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index efcb5dc604..a1a78fc5c5 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -12,7 +12,7 @@ use std::{ sync::Arc, }; -use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; use either::Either; use hir_expand::{ ast_id_map::FileAstId, @@ -73,25 +73,28 @@ impl ItemTree { }; let hygiene = Hygiene::new(db.upcast(), file_id); + let ctx = lower::Ctx::new(db, hygiene.clone(), file_id); let mut top_attrs = None; - let (macro_storage, file_storage); - let item_owner = match_ast! { + let mut item_tree = match_ast! { match syntax { - ast::MacroItems(items) => { - macro_storage = items; - ¯o_storage as &dyn ModuleItemOwner - }, ast::SourceFile(file) => { top_attrs = Some(Attrs::new(&file, &hygiene)); - file_storage = file; - &file_storage + ctx.lower_module_items(&file) + }, + ast::MacroItems(items) => { + ctx.lower_module_items(&items) + }, + // Macros can expand to expressions. We return an empty item tree in this case, but + // still need to collect inner items. + ast::Expr(e) => { + ctx.lower_inner_items(e.syntax()) + }, + _ => { + panic!("cannot create item tree from {:?}", syntax); }, - _ => return Arc::new(Self::empty(file_id)), } }; - let ctx = lower::Ctx::new(db, hygiene, file_id); - let mut item_tree = ctx.lower(item_owner); item_tree.top_attrs = top_attrs.unwrap_or_default(); Arc::new(item_tree) } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 841c7a852c..3bb437e810 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -52,7 +52,7 @@ impl Ctx { } } - pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { + pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { self.tree.top_level = item_owner .items() .flat_map(|item| self.lower_mod_item(&item, false)) @@ -61,6 +61,11 @@ impl Ctx { self.tree } + pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { + self.collect_inner_items(within); + self.tree + } + fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { assert!(inner || self.inner_items.is_empty()); From ae7a296c85bba6ab279dd17b193f86db22ec3437 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 18:20:51 +0200 Subject: [PATCH 20/34] Unify and test attribute handling --- crates/ra_hir_def/src/attr.rs | 12 ++ crates/ra_hir_def/src/data.rs | 5 +- crates/ra_hir_def/src/item_tree.rs | 4 - crates/ra_hir_def/src/item_tree/lower.rs | 41 +++-- crates/ra_hir_def/src/item_tree/tests.rs | 198 +++++++++++++++++++++-- 5 files changed, 227 insertions(+), 33 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index deea83a6d7..e0f468bf39 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -107,6 +107,18 @@ impl Attrs { Attrs { entries } } + pub fn merge(&self, other: Attrs) -> Attrs { + match (&self.entries, &other.entries) { + (None, None) => Attrs { entries: None }, + (Some(entries), None) | (None, Some(entries)) => { + Attrs { entries: Some(entries.clone()) } + } + (Some(a), Some(b)) => { + Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } + } + } + } + pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { AttrQuery { attrs: self, key } } diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 921253c42d..51c97c5847 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -40,7 +40,7 @@ impl FunctionData { name: func.name.clone(), params: func.params.clone(), ret_type: func.ret_type.clone(), - attrs: func.attrs.clone(), + attrs: item_tree.attrs(loc.id.value.into()).clone(), has_self_param: func.has_self_param, is_unsafe: func.is_unsafe, visibility: func.visibility.clone(), @@ -224,7 +224,8 @@ fn collect_items( match item { AssocItem::Function(id) => { let item = &item_tree[id]; - if !item.attrs.is_cfg_enabled(&cfg_options) { + let attrs = item_tree.attrs(id.into()); + if !attrs.is_cfg_enabled(&cfg_options) { continue; } let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index a1a78fc5c5..6eb0c1b912 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -355,7 +355,6 @@ pub struct ExternCrate { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Function { pub name: Name, - pub attrs: Attrs, pub visibility: RawVisibility, pub generic_params: GenericParams, pub has_self_param: bool, @@ -368,7 +367,6 @@ pub struct Function { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Struct { pub name: Name, - pub attrs: Attrs, pub visibility: RawVisibility, pub generic_params: GenericParams, pub fields: Fields, @@ -389,7 +387,6 @@ pub enum StructDefKind { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, - pub attrs: Attrs, pub visibility: RawVisibility, pub generic_params: GenericParams, pub fields: Fields, @@ -399,7 +396,6 @@ pub struct Union { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, - pub attrs: Attrs, pub visibility: RawVisibility, pub generic_params: GenericParams, pub variants: Range>, diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 3bb437e810..88530af74b 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -12,7 +12,7 @@ use ra_syntax::{ SyntaxNode, }; use smallvec::SmallVec; -use std::{mem, sync::Arc}; +use std::{collections::hash_map::Entry, mem, sync::Arc}; fn id(index: Idx) -> FileItemTreeId { FileItemTreeId { index, _p: PhantomData } @@ -116,13 +116,24 @@ impl Ctx { if !attrs.is_empty() { for item in items.iter().flat_map(|items| &items.0) { - self.tree.attrs.insert(*item, attrs.clone()); + self.add_attrs(*item, attrs.clone()); } } items } + fn add_attrs(&mut self, item: ModItem, attrs: Attrs) { + match self.tree.attrs.entry(item) { + Entry::Occupied(mut entry) => { + *entry.get_mut() = entry.get().merge(attrs); + } + Entry::Vacant(entry) => { + entry.insert(attrs); + } + } + } + fn collect_inner_items(&mut self, container: &SyntaxNode) { let forced_vis = self.forced_visibility.take(); let mut inner_items = mem::replace(&mut self.tree.inner_items, FxHashMap::default()); @@ -147,7 +158,6 @@ impl Ctx { } fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option> { - let attrs = self.lower_attrs(strukt); let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); @@ -158,7 +168,7 @@ impl Ctx { ast::StructKind::Tuple(_) => StructDefKind::Tuple, ast::StructKind::Unit => StructDefKind::Unit, }; - let res = Struct { name, attrs, visibility, generic_params, fields, ast_id, kind }; + let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; Some(id(self.tree.structs.alloc(res))) } @@ -215,7 +225,6 @@ impl Ctx { } fn lower_union(&mut self, union: &ast::UnionDef) -> Option> { - let attrs = self.lower_attrs(union); let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Union, union); @@ -226,12 +235,11 @@ impl Ctx { None => Fields::Record(self.next_field_idx()..self.next_field_idx()), }; let ast_id = self.source_ast_id_map.ast_id(union); - let res = Union { name, attrs, visibility, generic_params, fields, ast_id }; + let res = Union { name, visibility, generic_params, fields, ast_id }; Some(id(self.tree.unions.alloc(res))) } fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option> { - let attrs = self.lower_attrs(enum_); let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); @@ -240,7 +248,7 @@ impl Ctx { None => self.next_variant_idx()..self.next_variant_idx(), }; let ast_id = self.source_ast_id_map.ast_id(enum_); - let res = Enum { name, attrs, visibility, generic_params, variants, ast_id }; + let res = Enum { name, visibility, generic_params, variants, ast_id }; Some(id(self.tree.enums.alloc(res))) } @@ -263,7 +271,6 @@ impl Ctx { } fn lower_function(&mut self, func: &ast::FnDef) -> Option> { - let attrs = self.lower_attrs(func); let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -309,7 +316,6 @@ impl Ctx { let ast_id = self.source_ast_id_map.ast_id(func); let mut res = Function { name, - attrs, visibility, generic_params: GenericParams::default(), has_self_param, @@ -390,9 +396,13 @@ impl Ctx { let items = trait_def.item_list().map(|list| { self.with_inherited_visibility(visibility.clone(), |this| { list.items() - .flat_map(|item| { + .filter_map(|item| { + let attrs = Attrs::new(&item, &this.hygiene); this.collect_inner_items(item.syntax()); - this.lower_assoc_item(&item) + this.lower_assoc_item(&item).map(|item| { + this.add_attrs(item.into(), attrs); + item + }) }) .collect() }) @@ -422,6 +432,8 @@ impl Ctx { .filter_map(|item| { self.collect_inner_items(item.syntax()); let assoc = self.lower_assoc_item(&item)?; + let attrs = Attrs::new(&item, &self.hygiene); + self.add_attrs(assoc.into(), attrs); Some(assoc) }) .collect(); @@ -506,6 +518,7 @@ impl Ctx { list.extern_items() .filter_map(|item| { self.collect_inner_items(item.syntax()); + let attrs = Attrs::new(&item, &self.hygiene); let id = match item { ast::ExternItem::FnDef(ast) => { let func = self.lower_function(&ast)?; @@ -516,6 +529,7 @@ impl Ctx { statik.into() } }; + self.add_attrs(id, attrs); Some(id) }) .collect() @@ -576,9 +590,6 @@ impl Ctx { } } - fn lower_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { - Attrs::new(item, &self.hygiene) - } fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { if let Some(vis) = self.forced_visibility.as_ref() { vis.clone() diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index 7b8523b9f0..2df1b3e0cb 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -77,13 +77,12 @@ fn print_item_tree(ra_fixture: &str) -> String { } if !tree.inner_items.is_empty() { - format_to!(out, "\ninner items:\n"); + format_to!(out, "\ninner items:\n\n"); for (ast_id, items) in &tree.inner_items { - format_to!(out, "{:?}:\n", ast_id); + format_to!(out, "for AST {:?}:\n", ast_id); for inner in items { - format_to!(out, "- "); fmt_mod_item(&mut out, &tree, *inner); - format_to!(out, "\n"); + format_to!(out, "\n\n"); } } } @@ -92,6 +91,12 @@ fn print_item_tree(ra_fixture: &str) -> String { } fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { + let attrs = tree.attrs(item); + if !attrs.is_empty() { + format_to!(out, "#[{:?}]\n", attrs); + } + + let mut children = String::new(); match item { ModItem::ExternCrate(it) => { format_to!(out, "{:?}", tree[it]); @@ -119,20 +124,41 @@ fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { } ModItem::Trait(it) => { format_to!(out, "{:?}", tree[it]); + for item in &tree[it].items { + fmt_mod_item(&mut children, tree, ModItem::from(*item)); + format_to!(children, "\n"); + } } ModItem::Impl(it) => { format_to!(out, "{:?}", tree[it]); + for item in &tree[it].items { + fmt_mod_item(&mut children, tree, ModItem::from(*item)); + format_to!(children, "\n"); + } } ModItem::TypeAlias(it) => { format_to!(out, "{:?}", tree[it]); } ModItem::Mod(it) => { format_to!(out, "{:?}", tree[it]); + match &tree[it].kind { + ModKind::Inline { items } => { + for item in items { + fmt_mod_item(&mut children, tree, *item); + format_to!(children, "\n"); + } + } + ModKind::Outline {} => {} + } } ModItem::MacroCall(it) => { format_to!(out, "{:?}", tree[it]); } } + + for line in children.lines() { + format_to!(out, "\n> {}", line); + } } #[test] @@ -140,44 +166,83 @@ fn smoke() { assert_snapshot!(print_item_tree(r" #![attr] + #[attr_on_use] use {a, b::*}; + + #[ext_crate] extern crate krate; + #[on_trait] trait Tr { + #[assoc_ty] type AssocTy: Tr<()>; + + #[assoc_const] const CONST: u8; + + #[assoc_method] fn method(&self); + + #[assoc_dfl_method] fn dfl_method(&mut self) {} } + #[struct0] struct Struct0; - struct Struct1(u8); + + #[struct1] + struct Struct1(#[struct1fld] u8); + + #[struct2] struct Struct2 { + #[struct2fld] fld: (T, ), } + #[en] enum En { + #[enum_variant] Variant { + #[enum_field] field: u8, }, } + #[un] union Un { + #[union_fld] fld: u16, } "), @r###" inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } top-level items: +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_macro_use: false, ast_id: FileAstId::(1) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } -Struct { name: Name(Text("Struct0")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } -Struct { name: Name(Text("Struct1")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } -Struct { name: Name(Text("Struct2")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } -Enum { name: Name(Text("En")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } -Union { name: Name(Text("Un")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] +> TypeAlias { name: Name(Text("AssocTy")), visibility: Module(ModPath { kind: Super(0), segments: [] }), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::(8) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] +> Const { name: Some(Name(Text("CONST"))), visibility: Module(ModPath { kind: Super(0), segments: [] }), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] +> Function { name: Name(Text("method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::(10) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] +> Function { name: Name(Text("dfl_method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::(11) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] +Struct { name: Name(Text("Struct0")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] +Struct { name: Name(Text("Struct1")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] +Struct { name: Name(Text("Struct2")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] +Enum { name: Name(Text("En")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] +Union { name: Name(Text("Un")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } "###); } @@ -201,10 +266,92 @@ inner attrs: Attrs { entries: None } top-level items: Impl { generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("A"))] }, generic_args: [None] }) }] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } +> Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } inner items: -FileAstId::(2): -- Function { name: Name(Text("end")), attrs: Attrs { entries: None }, visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } + +for AST FileAstId::(2): +Function { name: Name(Text("end")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } + + "###); +} + +#[test] +fn extern_attrs() { + let tree = print_item_tree( + r#" + #[block_attr] + extern "C" { + #[attr_a] + fn a() {} + #[attr_b] + fn b() {} + } + "#, + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] +Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] +Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } + "###); +} + +#[test] +fn trait_attrs() { + let tree = print_item_tree( + r#" + #[trait_attr] + trait Tr { + #[attr_a] + fn a() {} + #[attr_b] + fn b() {} + } + "#, + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] +Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] +> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] +> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } + "###); +} + +#[test] +fn impl_attrs() { + let tree = print_item_tree( + r#" + #[impl_attr] + impl Ty { + #[attr_a] + fn a() {} + #[attr_b] + fn b() {} + } + "#, + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] +Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] +> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] +> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -235,6 +382,32 @@ fn cursed_inner_items() { ); } +#[test] +fn inner_item_attrs() { + let tree = print_item_tree( + r" + fn foo() { + #[on_inner] + fn inner() {} + } + ", + ); + + assert_snapshot!(tree, @r###" +inner attrs: Attrs { entries: None } + +top-level items: +Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(0) } + +inner items: + +for AST FileAstId::(1): +#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] +Function { name: Name(Text("inner")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } + + "###); +} + #[test] fn assoc_item_macros() { let tree = print_item_tree( @@ -250,5 +423,6 @@ inner attrs: Attrs { entries: None } top-level items: Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } +> MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::(1) } "###); } From a0ad457575bdde24d65c3fbcd4b2819459ad0291 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 18:28:47 +0200 Subject: [PATCH 21/34] if let else -> match --- crates/ra_hir_def/src/item_tree/lower.rs | 40 +++++++++++++----------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 88530af74b..b97927f27d 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -278,17 +278,18 @@ impl Ctx { let mut has_self_param = false; if let Some(param_list) = func.param_list() { if let Some(self_param) = param_list.self_param() { - let self_type = if let Some(type_ref) = self_param.ascribed_type() { - TypeRef::from_ast(&self.body_ctx, type_ref) - } else { - let self_type = TypeRef::Path(name![Self].into()); - match self_param.kind() { - ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => { - TypeRef::Reference(Box::new(self_type), Mutability::Shared) - } - ast::SelfParamKind::MutRef => { - TypeRef::Reference(Box::new(self_type), Mutability::Mut) + let self_type = match self_param.ascribed_type() { + Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), + None => { + let self_type = TypeRef::Path(name![Self].into()); + match self_param.kind() { + ast::SelfParamKind::Owned => self_type, + ast::SelfParamKind::Ref => { + TypeRef::Reference(Box::new(self_type), Mutability::Shared) + } + ast::SelfParamKind::MutRef => { + TypeRef::Reference(Box::new(self_type), Mutability::Mut) + } } } }; @@ -583,20 +584,21 @@ impl Ctx { } fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec { - if let Some(bound_list) = node.type_bound_list() { - bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() - } else { - Vec::new() + match node.type_bound_list() { + Some(bound_list) => { + bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() + } + None => Vec::new(), } } fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { - if let Some(vis) = self.forced_visibility.as_ref() { - vis.clone() - } else { - RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene) + match &self.forced_visibility { + Some(vis) => vis.clone(), + None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), } } + fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { TypeRef::from_ast(&self.body_ctx, type_ref.clone()) } From 20ff1cdcfbef92429962569f7e98a169c6a10e50 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 18:31:14 +0200 Subject: [PATCH 22/34] Address more comments --- crates/ra_hir_def/src/data.rs | 7 +++---- crates/ra_hir_def/src/item_tree/lower.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 51c97c5847..5f8eb72a05 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -234,10 +234,9 @@ fn collect_items( // FIXME: cfg? AssocItem::Const(id) => { let item = &item_tree[id]; - let name = if let Some(name) = item.name.clone() { - name - } else { - continue; + let name = match item.name.clone() { + Some(name) => name, + None => continue, }; let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); items.push((name, def.into())); diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index b97927f27d..733fcac7ac 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -136,7 +136,7 @@ impl Ctx { fn collect_inner_items(&mut self, container: &SyntaxNode) { let forced_vis = self.forced_visibility.take(); - let mut inner_items = mem::replace(&mut self.tree.inner_items, FxHashMap::default()); + let mut inner_items = mem::take(&mut self.tree.inner_items); inner_items.extend( container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { let ast_id = self.source_ast_id_map.ast_id(&item); From b5fd02d93cdfafeba23f50ca9c414053aaa548ae Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 18:41:32 +0200 Subject: [PATCH 23/34] Generate ModItem via macro --- crates/ra_hir_def/src/item_tree.rs | 167 +++++++++++------------------ 1 file changed, 61 insertions(+), 106 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 6eb0c1b912..5beb11df7b 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -223,71 +223,75 @@ impl fmt::Debug for FileItemTreeId { pub type ItemTreeId = InFile>; -macro_rules! nodes { - ( $($node:ident in $fld:ident),+ $(,)? ) => { $( - impl ItemTreeNode for $node { - fn lookup(tree: &ItemTree, index: Idx) -> &Self { - &tree.$fld[index] +macro_rules! mod_items { + ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] + pub enum ModItem { + $( + $typ(FileItemTreeId<$typ>), + )+ + } + + $( + impl From> for ModItem { + fn from(id: FileItemTreeId<$typ>) -> ModItem { + ModItem::$typ(id) + } } + )+ + $( + impl ItemTreeNode for $typ { + fn lookup(tree: &ItemTree, index: Idx) -> &Self { + &tree.$fld[index] + } - fn id_from_mod_item(mod_item: ModItem) -> Option> { - if let ModItem::$node(id) = mod_item { - Some(id) - } else { - None + fn id_from_mod_item(mod_item: ModItem) -> Option> { + if let ModItem::$typ(id) = mod_item { + Some(id) + } else { + None + } + } + + fn id_to_mod_item(id: FileItemTreeId) -> ModItem { + ModItem::$typ(id) } } - fn id_to_mod_item(id: FileItemTreeId) -> ModItem { - ModItem::$node(id) + impl ItemTreeSource for $typ { + type Source = $ast; + + fn ast_id(&self) -> FileAstId { + self.ast_id + } } - } - )+ }; + + impl Index> for ItemTree { + type Output = $typ; + + fn index(&self, index: Idx<$typ>) -> &Self::Output { + &self.$fld[index] + } + } + )+ + }; } -nodes!( - Import in imports, - ExternCrate in extern_crates, - Function in functions, - Struct in structs, - Union in unions, - Enum in enums, - Const in consts, - Static in statics, - Trait in traits, - Impl in impls, - TypeAlias in type_aliases, - Mod in mods, - MacroCall in macro_calls, -); - -macro_rules! source { - ( $($node:ident -> $ast:path),+ $(,)? ) => { $( - impl ItemTreeSource for $node { - type Source = $ast; - - fn ast_id(&self) -> FileAstId { - self.ast_id - } - } - )+ }; -} - -source! { - Import -> ast::UseItem, - ExternCrate -> ast::ExternCrateItem, - Function -> ast::FnDef, - Struct -> ast::StructDef, - Union -> ast::UnionDef, - Enum -> ast::EnumDef, - Const -> ast::ConstDef, - Static -> ast::StaticDef, - Trait -> ast::TraitDef, - Impl -> ast::ImplDef, - TypeAlias -> ast::TypeAliasDef, - Mod -> ast::Module, - MacroCall -> ast::MacroCall, +mod_items! { + Import in imports -> ast::UseItem, + ExternCrate in extern_crates -> ast::ExternCrateItem, + Function in functions -> ast::FnDef, + Struct in structs -> ast::StructDef, + Union in unions -> ast::UnionDef, + Enum in enums -> ast::EnumDef, + Const in consts -> ast::ConstDef, + Static in statics -> ast::StaticDef, + Trait in traits -> ast::TraitDef, + Impl in impls -> ast::ImplDef, + TypeAlias in type_aliases -> ast::TypeAliasDef, + Mod in mods -> ast::Module, + MacroCall in macro_calls -> ast::MacroCall, } macro_rules! impl_index { @@ -304,23 +308,7 @@ macro_rules! impl_index { }; } -impl_index!( - imports: Import, - functions: Function, - structs: Struct, - fields: Field, - unions: Union, - enums: Enum, - variants: Variant, - consts: Const, - statics: Static, - traits: Trait, - impls: Impl, - type_aliases: TypeAlias, - mods: Mod, - macro_calls: MacroCall, - exprs: Expr, -); +impl_index!(fields: Field, variants: Variant, exprs: Expr); impl Index> for ItemTree { type Output = N; @@ -500,23 +488,6 @@ macro_rules! impl_froms { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum ModItem { - Import(FileItemTreeId), - ExternCrate(FileItemTreeId), - Function(FileItemTreeId), - Struct(FileItemTreeId), - Union(FileItemTreeId), - Enum(FileItemTreeId), - Const(FileItemTreeId), - Static(FileItemTreeId), - Trait(FileItemTreeId), - Impl(FileItemTreeId), - TypeAlias(FileItemTreeId), - Mod(FileItemTreeId), - MacroCall(FileItemTreeId), -} - impl ModItem { pub fn as_assoc_item(&self) -> Option { match self { @@ -541,22 +512,6 @@ impl ModItem { } } -impl_froms!(ModItem { - Import(FileItemTreeId), - ExternCrate(FileItemTreeId), - Function(FileItemTreeId), - Struct(FileItemTreeId), - Union(FileItemTreeId), - Enum(FileItemTreeId), - Const(FileItemTreeId), - Static(FileItemTreeId), - Trait(FileItemTreeId), - Impl(FileItemTreeId), - TypeAlias(FileItemTreeId), - Mod(FileItemTreeId), - MacroCall(FileItemTreeId), -}); - #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum AssocItem { Function(FileItemTreeId), From f9a1a9cd3c7757ca3f8ba59287b5d36645008b9b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 18:46:08 +0200 Subject: [PATCH 24/34] Merge item tree traits The Source trait isn't needed anymore since we no longer merge extern crate items with use items. --- crates/ra_hir_def/src/body/lower.rs | 4 ++-- crates/ra_hir_def/src/item_tree.rs | 27 +++++++++++---------------- crates/ra_hir_def/src/src.rs | 6 +++--- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index bbde0b8024..a74136b8e6 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -27,7 +27,7 @@ use crate::{ LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, - item_tree::{FileItemTreeId, ItemTree, ItemTreeSource}, + item_tree::{FileItemTreeId, ItemTree, ItemTreeNode}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, @@ -557,7 +557,7 @@ impl ExprCollector<'_> { } } - fn find_inner_item(&self, id: AstId) -> FileItemTreeId { + fn find_inner_item(&self, id: AstId) -> FileItemTreeId { let index = self.item_trees.iter().position(|(file, _)| *file == id.file_id).unwrap_or_else(|| { panic!("couldn't find item tree for file {:?}", id.file_id); diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 5beb11df7b..a752717038 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -153,7 +153,7 @@ impl ItemTree { self.inner_items.values().flatten().copied() } - pub fn source( + pub fn source( &self, db: &dyn DefDatabase, of: FileItemTreeId, @@ -173,6 +173,10 @@ impl ItemTree { /// Trait implemented by all nodes in the item tree. pub trait ItemTreeNode: Clone { + type Source: AstNode + Into; + + fn ast_id(&self) -> FileAstId; + /// Looks up an instance of `Self` in an item tree. fn lookup(tree: &ItemTree, index: Idx) -> &Self; @@ -183,13 +187,6 @@ pub trait ItemTreeNode: Clone { fn id_to_mod_item(id: FileItemTreeId) -> ModItem; } -/// Trait for item tree nodes that allow accessing the original AST node. -pub trait ItemTreeSource: ItemTreeNode { - type Source: AstNode + Into; - - fn ast_id(&self) -> FileAstId; -} - pub struct FileItemTreeId { index: Idx, _p: PhantomData, @@ -242,6 +239,12 @@ macro_rules! mod_items { $( impl ItemTreeNode for $typ { + type Source = $ast; + + fn ast_id(&self) -> FileAstId { + self.ast_id + } + fn lookup(tree: &ItemTree, index: Idx) -> &Self { &tree.$fld[index] } @@ -259,14 +262,6 @@ macro_rules! mod_items { } } - impl ItemTreeSource for $typ { - type Source = $ast; - - fn ast_id(&self) -> FileAstId { - self.ast_id - } - } - impl Index> for ItemTree { type Output = $typ; diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs index 10e21d48e6..043b93fad5 100644 --- a/crates/ra_hir_def/src/src.rs +++ b/crates/ra_hir_def/src/src.rs @@ -3,14 +3,14 @@ use hir_expand::InFile; use ra_arena::map::ArenaMap; -use crate::{db::DefDatabase, item_tree::ItemTreeSource, AssocItemLoc, ItemLoc}; +use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; pub trait HasSource { type Value; fn source(&self, db: &dyn DefDatabase) -> InFile; } -impl HasSource for AssocItemLoc { +impl HasSource for AssocItemLoc { type Value = N::Source; fn source(&self, db: &dyn DefDatabase) -> InFile { @@ -23,7 +23,7 @@ impl HasSource for AssocItemLoc { } } -impl HasSource for ItemLoc { +impl HasSource for ItemLoc { type Value = N::Source; fn source(&self, db: &dyn DefDatabase) -> InFile { From c019002d17185f4e8be54a978ab5d67bc632f518 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 19:42:19 +0200 Subject: [PATCH 25/34] Slightly reduce ItemTree memory footprint --- crates/ra_hir_def/src/attr.rs | 2 + crates/ra_hir_def/src/item_tree.rs | 73 +++++++++++++----------- crates/ra_hir_def/src/item_tree/lower.rs | 46 +++++++++------ 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index e0f468bf39..197737ffce 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -38,6 +38,8 @@ impl ops::Deref for Attrs { } impl Attrs { + pub const EMPTY: Attrs = Attrs { entries: None }; + pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { match def { AttrDefId::ModuleId(module) => { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index a752717038..d55b3f7772 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -35,16 +35,8 @@ use crate::{ }; use smallvec::SmallVec; -/// The item tree of a source file. -#[derive(Debug, Eq, PartialEq)] -pub struct ItemTree { - file_id: HirFileId, - top_level: Vec, - top_attrs: Attrs, - attrs: FxHashMap, - empty_attrs: Attrs, - inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, - +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemTreeData { imports: Arena, extern_crates: Arena, functions: Arena, @@ -63,6 +55,26 @@ pub struct ItemTree { exprs: Arena, } +#[derive(Debug, Eq, PartialEq, Hash)] +enum AttrOwner { + /// Attributes on an item. + ModItem(ModItem), + /// Inner attributes of the source file. + TopLevel, + // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. +} + +/// The item tree of a source file. +#[derive(Debug, Eq, PartialEq)] +pub struct ItemTree { + file_id: HirFileId, + top_level: SmallVec<[ModItem; 1]>, + attrs: FxHashMap, + inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, + + data: Option>, +} + impl ItemTree { pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); @@ -95,7 +107,9 @@ impl ItemTree { } }; - item_tree.top_attrs = top_attrs.unwrap_or_default(); + if let Some(attrs) = top_attrs { + item_tree.attrs.insert(AttrOwner::TopLevel, attrs); + } Arc::new(item_tree) } @@ -103,26 +117,9 @@ impl ItemTree { Self { file_id, top_level: Default::default(), - top_attrs: Default::default(), attrs: Default::default(), - empty_attrs: Default::default(), inner_items: Default::default(), - imports: Default::default(), - extern_crates: Default::default(), - functions: Default::default(), - structs: Default::default(), - fields: Default::default(), - unions: Default::default(), - enums: Default::default(), - variants: Default::default(), - consts: Default::default(), - statics: Default::default(), - traits: Default::default(), - impls: Default::default(), - type_aliases: Default::default(), - mods: Default::default(), - macro_calls: Default::default(), - exprs: Default::default(), + data: Default::default(), } } @@ -134,11 +131,11 @@ impl ItemTree { /// Returns the inner attributes of the source file. pub fn top_level_attrs(&self) -> &Attrs { - &self.top_attrs + self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) } pub fn attrs(&self, of: ModItem) -> &Attrs { - self.attrs.get(&of).unwrap_or(&self.empty_attrs) + self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY) } /// Returns the lowered inner items that `ast` corresponds to. @@ -169,6 +166,14 @@ impl ItemTree { let ptr = map.get(id); ptr.to_node(&root) } + + fn data(&self) -> &ItemTreeData { + self.data.as_ref().expect("attempted to access data of empty ItemTree") + } + + fn data_mut(&mut self) -> &mut ItemTreeData { + self.data.get_or_insert_with(Box::default) + } } /// Trait implemented by all nodes in the item tree. @@ -246,7 +251,7 @@ macro_rules! mod_items { } fn lookup(tree: &ItemTree, index: Idx) -> &Self { - &tree.$fld[index] + &tree.data().$fld[index] } fn id_from_mod_item(mod_item: ModItem) -> Option> { @@ -266,7 +271,7 @@ macro_rules! mod_items { type Output = $typ; fn index(&self, index: Idx<$typ>) -> &Self::Output { - &self.$fld[index] + &self.data().$fld[index] } } )+ @@ -296,7 +301,7 @@ macro_rules! impl_index { type Output = $t; fn index(&self, index: Idx<$t>) -> &Self::Output { - &self.$fld[index] + &self.data().$fld[index] } } )+ diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 733fcac7ac..7d28fe7c65 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -66,6 +66,10 @@ impl Ctx { self.tree } + fn data(&mut self) -> &mut ItemTreeData { + self.tree.data_mut() + } + fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { assert!(inner || self.inner_items.is_empty()); @@ -124,7 +128,7 @@ impl Ctx { } fn add_attrs(&mut self, item: ModItem, attrs: Attrs) { - match self.tree.attrs.entry(item) { + match self.tree.attrs.entry(AttrOwner::ModItem(item)) { Entry::Occupied(mut entry) => { *entry.get_mut() = entry.get().merge(attrs); } @@ -169,7 +173,7 @@ impl Ctx { ast::StructKind::Unit => StructDefKind::Unit, }; let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; - Some(id(self.tree.structs.alloc(res))) + Some(id(self.data().structs.alloc(res))) } fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { @@ -190,7 +194,7 @@ impl Ctx { let start = self.next_field_idx(); for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { - self.tree.fields.alloc(data); + self.data().fields.alloc(data); } } let end = self.next_field_idx(); @@ -209,7 +213,7 @@ impl Ctx { let start = self.next_field_idx(); for (i, field) in fields.fields().enumerate() { if let Some(data) = self.lower_tuple_field(i, &field) { - self.tree.fields.alloc(data); + self.data().fields.alloc(data); } } let end = self.next_field_idx(); @@ -236,7 +240,7 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(union); let res = Union { name, visibility, generic_params, fields, ast_id }; - Some(id(self.tree.unions.alloc(res))) + Some(id(self.data().unions.alloc(res))) } fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option> { @@ -249,14 +253,14 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, visibility, generic_params, variants, ast_id }; - Some(id(self.tree.enums.alloc(res))) + Some(id(self.data().enums.alloc(res))) } fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { let start = self.next_variant_idx(); for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { - self.tree.variants.alloc(data); + self.data().variants.alloc(data); } } let end = self.next_variant_idx(); @@ -327,7 +331,7 @@ impl Ctx { }; res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); - Some(id(self.tree.functions.alloc(res))) + Some(id(self.data().functions.alloc(res))) } fn lower_type_alias( @@ -341,7 +345,7 @@ impl Ctx { let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; - Some(id(self.tree.type_aliases.alloc(res))) + Some(id(self.data().type_aliases.alloc(res))) } fn lower_static(&mut self, static_: &ast::StaticDef) -> Option> { @@ -351,7 +355,7 @@ impl Ctx { let mutable = static_.mut_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, mutable, type_ref, ast_id }; - Some(id(self.tree.statics.alloc(res))) + Some(id(self.data().statics.alloc(res))) } fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId { @@ -360,7 +364,7 @@ impl Ctx { 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 }; - id(self.tree.consts.alloc(res)) + id(self.data().consts.alloc(res)) } fn lower_module(&mut self, module: &ast::Module) -> Option> { @@ -386,7 +390,7 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(module); let res = Mod { name, visibility, kind, ast_id }; - Some(id(self.tree.mods.alloc(res))) + Some(id(self.data().mods.alloc(res))) } fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { @@ -417,7 +421,7 @@ impl Ctx { items: items.unwrap_or_default(), ast_id, }; - Some(id(self.tree.traits.alloc(res))) + Some(id(self.data().traits.alloc(res))) } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { @@ -440,7 +444,7 @@ impl Ctx { .collect(); let ast_id = self.source_ast_id_map.ast_id(impl_def); let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; - Some(id(self.tree.impls.alloc(res))) + Some(id(self.data().impls.alloc(res))) } fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec> { @@ -451,7 +455,7 @@ impl Ctx { // Every use item can expand to many `Import`s. let mut imports = Vec::new(); - let tree = &mut self.tree; + let tree = self.tree.data_mut(); ModPath::expand_use_item( InFile::new(self.file, use_item.clone()), &self.hygiene, @@ -484,7 +488,7 @@ impl Ctx { let is_macro_use = extern_crate.has_atom_attr("macro_use"); let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; - Some(id(self.tree.extern_crates.alloc(res))) + Some(id(self.data().extern_crates.alloc(res))) } fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { @@ -511,7 +515,7 @@ impl Ctx { let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; - Some(id(self.tree.macro_calls.alloc(res))) + Some(id(self.data().macro_calls.alloc(res))) } fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec { @@ -619,10 +623,14 @@ impl Ctx { } fn next_field_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) + Idx::from_raw(RawId::from( + self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), + )) } fn next_variant_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) + Idx::from_raw(RawId::from( + self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), + )) } } From 16fd4dabb754b017237127e70ef1e2b409c4f9b6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 20:20:30 +0200 Subject: [PATCH 26/34] Remove file id from item tree It's not needed, and `source` is only used by tests anyways --- crates/ra_hir_def/src/item_tree.rs | 21 +++++---------- crates/ra_hir_def/src/item_tree/lower.rs | 2 +- crates/ra_hir_def/src/item_tree/tests.rs | 33 ++++++++++++------------ crates/ra_hir_ty/src/tests.rs | 6 ++--- 4 files changed, 28 insertions(+), 34 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index d55b3f7772..40bb78b57a 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -67,7 +67,6 @@ enum AttrOwner { /// The item tree of a source file. #[derive(Debug, Eq, PartialEq)] pub struct ItemTree { - file_id: HirFileId, top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, @@ -81,7 +80,7 @@ impl ItemTree { let syntax = if let Some(node) = db.parse_or_expand(file_id) { node } else { - return Arc::new(Self::empty(file_id)); + return Arc::new(Self::empty()); }; let hygiene = Hygiene::new(db.upcast(), file_id); @@ -113,9 +112,8 @@ impl ItemTree { Arc::new(item_tree) } - fn empty(file_id: HirFileId) -> Self { + fn empty() -> Self { Self { - file_id, top_level: Default::default(), attrs: Default::default(), inner_items: Default::default(), @@ -150,19 +148,14 @@ impl ItemTree { self.inner_items.values().flatten().copied() } - pub fn source( - &self, - db: &dyn DefDatabase, - of: FileItemTreeId, - ) -> S::Source { + pub fn source(&self, db: &dyn DefDatabase, of: ItemTreeId) -> S::Source { // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). - let root = db - .parse_or_expand(self.file_id) - .expect("parse_or_expand failed on constructed ItemTree"); + let root = + db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree"); - let id = self[of].ast_id(); - let map = db.ast_id_map(self.file_id); + let id = self[of.value].ast_id(); + let map = db.ast_id_map(of.file_id); let ptr = map.get(id); ptr.to_node(&root) } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 7d28fe7c65..3af22149d8 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -42,7 +42,7 @@ pub(super) struct Ctx { impl Ctx { pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { Self { - tree: ItemTree::empty(file), + tree: ItemTree::empty(), hygiene, file, source_ast_id_map: db.ast_id_map(file), diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index 2df1b3e0cb..179baee788 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -1,6 +1,6 @@ use super::{ItemTree, ModItem, ModKind}; use crate::{db::DefDatabase, test_db::TestDB}; -use hir_expand::db::AstDatabase; +use hir_expand::{db::AstDatabase, HirFileId, InFile}; use insta::assert_snapshot; use ra_db::fixture::WithFixture; use ra_syntax::{ast, AstNode}; @@ -10,37 +10,38 @@ use stdx::format_to; fn test_inner_items(ra_fixture: &str) { let (db, file_id) = TestDB::with_single_file(ra_fixture); - let tree = db.item_tree(file_id.into()); - let root = db.parse_or_expand(file_id.into()).unwrap(); - let ast_id_map = db.ast_id_map(file_id.into()); + let file_id = HirFileId::from(file_id); + let tree = db.item_tree(file_id); + let root = db.parse_or_expand(file_id).unwrap(); + let ast_id_map = db.ast_id_map(file_id); // Traverse the item tree and collect all module/impl/trait-level items as AST nodes. let mut outer_items = FxHashSet::default(); let mut worklist = tree.top_level_items().to_vec(); while let Some(item) = worklist.pop() { let node: ast::ModuleItem = match item { - ModItem::Import(it) => tree.source(&db, it).into(), - ModItem::ExternCrate(it) => tree.source(&db, it).into(), - ModItem::Function(it) => tree.source(&db, it).into(), - ModItem::Struct(it) => tree.source(&db, it).into(), - ModItem::Union(it) => tree.source(&db, it).into(), - ModItem::Enum(it) => tree.source(&db, it).into(), - ModItem::Const(it) => tree.source(&db, it).into(), - ModItem::Static(it) => tree.source(&db, it).into(), - ModItem::TypeAlias(it) => tree.source(&db, it).into(), + ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Struct(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Union(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Enum(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Const(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::Static(it) => tree.source(&db, InFile::new(file_id, it)).into(), + ModItem::TypeAlias(it) => tree.source(&db, InFile::new(file_id, it)).into(), ModItem::Mod(it) => { if let ModKind::Inline { items } = &tree[it].kind { worklist.extend(items); } - tree.source(&db, it).into() + tree.source(&db, InFile::new(file_id, it)).into() } ModItem::Trait(it) => { worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); - tree.source(&db, it).into() + tree.source(&db, InFile::new(file_id, it)).into() } ModItem::Impl(it) => { worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); - tree.source(&db, it).into() + tree.source(&db, InFile::new(file_id, it)).into() } ModItem::MacroCall(_) => continue, }; diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index e82f2c11e2..85ff26a368 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -166,17 +166,17 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { DefWithBodyId::FunctionId(it) => { let loc = it.lookup(&db); let tree = db.item_tree(loc.id.file_id); - tree.source(&db, loc.id.value).syntax().text_range().start() + tree.source(&db, loc.id).syntax().text_range().start() } DefWithBodyId::ConstId(it) => { let loc = it.lookup(&db); let tree = db.item_tree(loc.id.file_id); - tree.source(&db, loc.id.value).syntax().text_range().start() + tree.source(&db, loc.id).syntax().text_range().start() } DefWithBodyId::StaticId(it) => { let loc = it.lookup(&db); let tree = db.item_tree(loc.id.file_id); - tree.source(&db, loc.id.value).syntax().text_range().start() + tree.source(&db, loc.id).syntax().text_range().start() } }); for def in defs { From 43cad21623bc5de59598a565097be9c7d8642818 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 15:36:18 +0200 Subject: [PATCH 27/34] Don't allocate common visibilities --- crates/ra_hir_def/src/data.rs | 8 +- crates/ra_hir_def/src/item_tree.rs | 87 ++++++++++++++++++---- crates/ra_hir_def/src/item_tree/lower.rs | 22 +++--- crates/ra_hir_def/src/item_tree/tests.rs | 48 ++++++------ crates/ra_hir_def/src/nameres/collector.rs | 52 +++++++------ 5 files changed, 142 insertions(+), 75 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 5f8eb72a05..5ca331380e 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -43,7 +43,7 @@ impl FunctionData { attrs: item_tree.attrs(loc.id.value.into()).clone(), has_self_param: func.has_self_param, is_unsafe: func.is_unsafe, - visibility: func.visibility.clone(), + visibility: item_tree[func.visibility].clone(), }) } } @@ -69,7 +69,7 @@ impl TypeAliasData { Arc::new(TypeAliasData { name: typ.name.clone(), type_ref: typ.type_ref.clone(), - visibility: typ.visibility.clone(), + visibility: item_tree[typ.visibility].clone(), bounds: typ.bounds.clone(), }) } @@ -175,7 +175,7 @@ impl ConstData { Arc::new(ConstData { name: konst.name.clone(), type_ref: konst.type_ref.clone(), - visibility: konst.visibility.clone(), + visibility: item_tree[konst.visibility].clone(), }) } } @@ -197,7 +197,7 @@ impl StaticData { Arc::new(StaticData { name: Some(statik.name.clone()), type_ref: statik.type_ref.clone(), - visibility: statik.visibility.clone(), + visibility: item_tree[statik.visibility].clone(), mutable: statik.mutable, }) } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 40bb78b57a..bbaa7c1f6f 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -29,12 +29,59 @@ use crate::{ attr::Attrs, db::DefDatabase, generics::GenericParams, - path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path}, + path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; use smallvec::SmallVec; +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemVisibilities { + arena: Arena, +} + +impl ItemVisibilities { + fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { + match &vis { + RawVisibility::Public => RawVisibilityId::PUB, + RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { + PathKind::Super(0) => RawVisibilityId::PRIV, + PathKind::Crate => RawVisibilityId::PUB_CRATE, + _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), + }, + _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct RawVisibilityId(u32); + +impl RawVisibilityId { + pub const PUB: Self = RawVisibilityId(u32::max_value()); + pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); + pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); +} + +impl fmt::Debug for RawVisibilityId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f.debug_tuple("RawVisibilityId"); + match *self { + Self::PUB => f.field(&"pub"), + Self::PRIV => f.field(&"pub(self)"), + Self::PUB_CRATE => f.field(&"pub(crate)"), + _ => f.field(&self.0), + }; + f.finish() + } +} + +static VIS_PUB: RawVisibility = RawVisibility::Public; +static VIS_PRIV: RawVisibility = + RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); +static VIS_PUB_CRATE: RawVisibility = + RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); + #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { imports: Arena, @@ -53,6 +100,8 @@ struct ItemTreeData { mods: Arena, macro_calls: Arena, exprs: Arena, + + vis: ItemVisibilities, } #[derive(Debug, Eq, PartialEq, Hash)] @@ -303,6 +352,18 @@ macro_rules! impl_index { impl_index!(fields: Field, variants: Variant, exprs: Expr); +impl Index for ItemTree { + type Output = RawVisibility; + fn index(&self, index: RawVisibilityId) -> &Self::Output { + match index { + RawVisibilityId::PRIV => &VIS_PRIV, + RawVisibilityId::PUB => &VIS_PUB, + RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, + _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], + } + } +} + impl Index> for ItemTree { type Output = N; fn index(&self, id: FileItemTreeId) -> &N { @@ -315,7 +376,7 @@ impl Index> for ItemTree { pub struct Import { pub path: ModPath, pub alias: Option, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub is_glob: bool, pub is_prelude: bool, /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many @@ -327,7 +388,7 @@ pub struct Import { pub struct ExternCrate { pub path: ModPath, pub alias: Option, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, /// Whether this is a `#[macro_use] extern crate ...`. pub is_macro_use: bool, pub ast_id: FileAstId, @@ -336,7 +397,7 @@ pub struct ExternCrate { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Function { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub generic_params: GenericParams, pub has_self_param: bool, pub is_unsafe: bool, @@ -348,7 +409,7 @@ pub struct Function { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Struct { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub generic_params: GenericParams, pub fields: Fields, pub ast_id: FileAstId, @@ -368,7 +429,7 @@ pub enum StructDefKind { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub generic_params: GenericParams, pub fields: Fields, pub ast_id: FileAstId, @@ -377,7 +438,7 @@ pub struct Union { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub generic_params: GenericParams, pub variants: Range>, pub ast_id: FileAstId, @@ -387,7 +448,7 @@ pub struct Enum { pub struct Const { /// const _: () = (); pub name: Option, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub type_ref: TypeRef, pub ast_id: FileAstId, } @@ -395,7 +456,7 @@ pub struct Const { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Static { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub mutable: bool, pub type_ref: TypeRef, pub ast_id: FileAstId, @@ -404,7 +465,7 @@ pub struct Static { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Trait { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub generic_params: GenericParams, pub auto: bool, pub items: Vec, @@ -424,7 +485,7 @@ pub struct Impl { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAlias { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. pub bounds: Vec, pub generic_params: GenericParams, @@ -435,7 +496,7 @@ pub struct TypeAlias { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Mod { pub name: Name, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, pub kind: ModKind, pub ast_id: FileAstId, } @@ -549,5 +610,5 @@ pub enum Fields { pub struct Field { pub name: Name, pub type_ref: TypeRef, - pub visibility: RawVisibility, + pub visibility: RawVisibilityId, } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 3af22149d8..73c21b9ec1 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -36,7 +36,7 @@ pub(super) struct Ctx { source_ast_id_map: Arc, body_ctx: crate::body::LowerCtx, inner_items: Vec, - forced_visibility: Option, + forced_visibility: Option, } impl Ctx { @@ -201,7 +201,7 @@ impl Ctx { start..end } - fn lower_record_field(&self, field: &ast::RecordFieldDef) -> Option { + fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option { let name = field.name()?.as_name(); let visibility = self.lower_visibility(field); let type_ref = self.lower_type_ref(&field.ascribed_type()?); @@ -220,7 +220,7 @@ impl Ctx { start..end } - fn lower_tuple_field(&self, idx: usize, field: &ast::TupleFieldDef) -> Option { + fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option { let name = Name::new_tuple_field(idx); let visibility = self.lower_visibility(field); let type_ref = self.lower_type_ref(&field.type_ref()?); @@ -399,7 +399,7 @@ impl Ctx { let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { - self.with_inherited_visibility(visibility.clone(), |this| { + self.with_inherited_visibility(visibility, |this| { list.items() .filter_map(|item| { let attrs = Attrs::new(&item, &this.hygiene); @@ -463,7 +463,7 @@ impl Ctx { imports.push(id(tree.imports.alloc(Import { path, alias, - visibility: visibility.clone(), + visibility, is_glob, is_prelude, ast_id, @@ -596,11 +596,13 @@ impl Ctx { } } - fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility { - match &self.forced_visibility { - Some(vis) => vis.clone(), + fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { + let vis = match self.forced_visibility { + Some(vis) => return vis, None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), - } + }; + + self.data().vis.alloc(vis) } fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { @@ -613,7 +615,7 @@ impl Ctx { /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. fn with_inherited_visibility( &mut self, - vis: RawVisibility, + vis: RawVisibilityId, f: impl FnOnce(&mut Self) -> R, ) -> R { let old = mem::replace(&mut self.forced_visibility, Some(vis)); diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index 179baee788..42394a9607 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -219,31 +219,31 @@ inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] -Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } +Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::(0) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] -Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } +Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::(0) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] -ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_macro_use: false, ast_id: FileAstId::(1) } +ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] -Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } +Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] -> TypeAlias { name: Name(Text("AssocTy")), visibility: Module(ModPath { kind: Super(0), segments: [] }), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::(8) } +> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::(8) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] -> Const { name: Some(Name(Text("CONST"))), visibility: Module(ModPath { kind: Super(0), segments: [] }), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } +> Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] -> Function { name: Name(Text("method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::(10) } +> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::(10) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] -> Function { name: Name(Text("dfl_method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::(11) } +> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::(11) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] -Struct { name: Name(Text("Struct0")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } +Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] -Struct { name: Name(Text("Struct1")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } +Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] -Struct { name: Name(Text("Struct2")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } +Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] -Enum { name: Name(Text("En")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } +Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] -Union { name: Name(Text("Un")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } +Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } "###); } @@ -267,12 +267,12 @@ inner attrs: Attrs { entries: None } top-level items: Impl { generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("A"))] }, generic_args: [None] }) }] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } -> Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } inner items: for AST FileAstId::(2): -Function { name: Name(Text("end")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -296,9 +296,9 @@ inner attrs: Attrs { entries: None } top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] -Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] -Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -321,11 +321,11 @@ inner attrs: Attrs { entries: None } top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] -Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } +Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] -> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] -> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -350,9 +350,9 @@ top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] -> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] -> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -398,13 +398,13 @@ fn inner_item_attrs() { inner attrs: Attrs { entries: None } top-level items: -Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(0) } +Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(0) } inner items: for AST FileAstId::(1): #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] -Function { name: Name(Text("inner")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } "###); } diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 40aff830f0..94da700ad3 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -20,7 +20,9 @@ use test_utils::mark; use crate::{ attr::Attrs, db::DefDatabase, - item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind}, + item_tree::{ + self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, + }, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, @@ -114,26 +116,28 @@ struct Import { pub is_macro_use: bool, } -impl From for Import { - fn from(it: item_tree::Import) -> Self { +impl Import { + fn from_use(tree: &ItemTree, id: FileItemTreeId) -> Self { + let it = &tree[id]; + let visibility = &tree[it.visibility]; Self { - path: it.path, - alias: it.alias, - visibility: it.visibility, + path: it.path.clone(), + alias: it.alias.clone(), + visibility: visibility.clone(), is_glob: it.is_glob, is_prelude: it.is_prelude, is_extern_crate: false, is_macro_use: false, } } -} -impl From for Import { - fn from(it: item_tree::ExternCrate) -> Self { + fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId) -> Self { + let it = &tree[id]; + let visibility = &tree[it.visibility]; Self { - path: it.path, - alias: it.alias, - visibility: it.visibility, + path: it.path.clone(), + alias: it.alias.clone(), + visibility: visibility.clone(), is_glob: false, is_prelude: false, is_extern_crate: true, @@ -761,14 +765,14 @@ impl ModCollector<'_, '_> { ModItem::Import(import_id) => { self.def_collector.unresolved_imports.push(ImportDirective { module_id: self.module_id, - import: self.item_tree[import_id].clone().into(), + import: Import::from_use(&self.item_tree, import_id), status: PartialResolvedImport::Unresolved, }) } ModItem::ExternCrate(import_id) => { self.def_collector.unresolved_imports.push(ImportDirective { module_id: self.module_id, - import: self.item_tree[import_id].clone().into(), + import: Import::from_extern_crate(&self.item_tree, import_id), status: PartialResolvedImport::Unresolved, }) } @@ -795,7 +799,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &func.name, - visibility: &func.visibility, + visibility: &self.item_tree[func.visibility], has_constructor: false, }); } @@ -812,7 +816,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: it.kind != StructDefKind::Record, }); } @@ -829,7 +833,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -846,7 +850,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -862,7 +866,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -875,7 +879,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -887,7 +891,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -902,7 +906,7 @@ impl ModCollector<'_, '_> { .intern(self.def_collector.db) .into(), name: &it.name, - visibility: &it.visibility, + visibility: &self.item_tree[it.visibility], has_constructor: false, }); } @@ -935,7 +939,7 @@ impl ModCollector<'_, '_> { module.name.clone(), AstId::new(self.file_id, module.ast_id), None, - &module.visibility, + &self.item_tree[module.visibility], ); ModCollector { @@ -965,7 +969,7 @@ impl ModCollector<'_, '_> { module.name.clone(), ast_id, Some((file_id, is_mod_rs)), - &module.visibility, + &self.item_tree[module.visibility], ); let item_tree = self.def_collector.db.item_tree(file_id.into()); ModCollector { From abdba92334f800d236c65e543377f75327f7307a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 15:54:35 +0200 Subject: [PATCH 28/34] Don't allocate empty generics --- crates/ra_hir_def/src/generics.rs | 14 +++---- crates/ra_hir_def/src/item_tree.rs | 51 ++++++++++++++++++++---- crates/ra_hir_def/src/item_tree/lower.rs | 7 ++-- crates/ra_hir_def/src/item_tree/tests.rs | 46 ++++++++++----------- 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index c4b9f626f4..6a0f493a79 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -80,43 +80,43 @@ impl GenericParams { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::AdtId(AdtId::StructId(id)) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::AdtId(AdtId::EnumId(id)) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::AdtId(AdtId::UnionId(id)) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::TraitId(id) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::TypeAliasId(id) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::ImplId(id) => { let id = id.lookup(db).id; let tree = db.item_tree(id.file_id); let item = &tree[id.value]; - item.generic_params.clone() + tree[item.generic_params].clone() } GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), }; diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index bbaa7c1f6f..9e1fd904fa 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -76,12 +76,37 @@ impl fmt::Debug for RawVisibilityId { } } +#[derive(Default, Debug, Eq, PartialEq)] +struct GenericParamsStorage { + arena: Arena, +} + +impl GenericParamsStorage { + fn alloc(&mut self, params: GenericParams) -> GenericParamsId { + if params.types.is_empty() && params.where_predicates.is_empty() { + return GenericParamsId::EMPTY; + } + + GenericParamsId(self.arena.alloc(params).into_raw().into()) + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct GenericParamsId(u32); + +impl GenericParamsId { + pub const EMPTY: Self = GenericParamsId(u32::max_value()); +} + static VIS_PUB: RawVisibility = RawVisibility::Public; static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); +static EMPTY_GENERICS: GenericParams = + GenericParams { types: Arena::new(), where_predicates: Vec::new() }; + #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { imports: Arena, @@ -102,6 +127,7 @@ struct ItemTreeData { exprs: Arena, vis: ItemVisibilities, + generics: GenericParamsStorage, } #[derive(Debug, Eq, PartialEq, Hash)] @@ -364,6 +390,17 @@ impl Index for ItemTree { } } +impl Index for ItemTree { + type Output = GenericParams; + + fn index(&self, index: GenericParamsId) -> &Self::Output { + match index { + GenericParamsId::EMPTY => &EMPTY_GENERICS, + _ => &self.data().generics.arena[Idx::from_raw(index.0.into())], + } + } +} + impl Index> for ItemTree { type Output = N; fn index(&self, id: FileItemTreeId) -> &N { @@ -398,7 +435,7 @@ pub struct ExternCrate { pub struct Function { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub has_self_param: bool, pub is_unsafe: bool, pub params: Vec, @@ -410,7 +447,7 @@ pub struct Function { pub struct Struct { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub fields: Fields, pub ast_id: FileAstId, pub kind: StructDefKind, @@ -430,7 +467,7 @@ pub enum StructDefKind { pub struct Union { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub fields: Fields, pub ast_id: FileAstId, } @@ -439,7 +476,7 @@ pub struct Union { pub struct Enum { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub variants: Range>, pub ast_id: FileAstId, } @@ -466,7 +503,7 @@ pub struct Static { pub struct Trait { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub auto: bool, pub items: Vec, pub ast_id: FileAstId, @@ -474,7 +511,7 @@ pub struct Trait { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub target_trait: Option, pub target_type: TypeRef, pub is_negative: bool, @@ -488,7 +525,7 @@ pub struct TypeAlias { pub visibility: RawVisibilityId, /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. pub bounds: Vec, - pub generic_params: GenericParams, + pub generic_params: GenericParamsId, pub type_ref: Option, pub ast_id: FileAstId, } diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 73c21b9ec1..b1847a6cb5 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -322,7 +322,7 @@ impl Ctx { let mut res = Function { name, visibility, - generic_params: GenericParams::default(), + generic_params: GenericParamsId::EMPTY, has_self_param, is_unsafe: func.unsafe_token().is_some(), params, @@ -545,7 +545,7 @@ impl Ctx { &mut self, owner: GenericsOwner<'_>, node: &impl ast::TypeParamsOwner, - ) -> GenericParams { + ) -> GenericParamsId { let mut sm = &mut ArenaMap::default(); let mut generics = GenericParams::default(); match owner { @@ -584,7 +584,8 @@ impl Ctx { generics.fill(&self.body_ctx, &mut sm, node); } } - generics + + self.data().generics.alloc(generics) } fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec { diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index 42394a9607..b72f0f47bb 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -225,25 +225,25 @@ Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] -Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } +Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::(0)), Const(Idx::(0)), Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(2) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] -> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::(8) } +> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::(8) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::(9) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] -> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::(10) } +> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::(10) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] -> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::(11) } +> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::(11) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] -Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::(3), kind: Unit } +Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::(3), kind: Unit } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] -Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } +Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(Idx::(0)..Idx::(1)), ast_id: FileAstId::(4), kind: Tuple } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] -Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } +Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(Idx::(1)..Idx::(2)), ast_id: FileAstId::(5), kind: Record } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] -Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } +Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: Idx::(0)..Idx::(1), ast_id: FileAstId::(6) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] -Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } +Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(Idx::(3)..Idx::(4)), ast_id: FileAstId::(7) } "###); } @@ -266,13 +266,13 @@ fn simple_inner_items() { inner attrs: Attrs { entries: None } top-level items: -Impl { generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("A"))] }, generic_args: [None] }) }] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } -> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::(1))], ast_id: FileAstId::(0) } +> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } inner items: for AST FileAstId::(2): -Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -296,9 +296,9 @@ inner attrs: Attrs { entries: None } top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] -Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] -Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -321,11 +321,11 @@ inner attrs: Attrs { entries: None } top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] -Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } +Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] -> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] -> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -348,11 +348,11 @@ inner attrs: Attrs { entries: None } top-level items: #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] -Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } +Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::(0)), Function(Idx::(1))], ast_id: FileAstId::(0) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] -> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] -> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } +> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(2) } "###); } @@ -398,13 +398,13 @@ fn inner_item_attrs() { inner attrs: Attrs { entries: None } top-level items: -Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(0) } +Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(0) } inner items: for AST FileAstId::(1): #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] -Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } +Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::(1) } "###); } @@ -423,7 +423,7 @@ fn assoc_item_macros() { inner attrs: Attrs { entries: None } top-level items: -Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } +Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::(0))], ast_id: FileAstId::(0) } > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::(1) } "###); } From 94169ee504bf1a5e59530c1ab1f5f5550ae45914 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:07:02 +0200 Subject: [PATCH 29/34] ItemTree: Use more boxed slices --- crates/ra_hir_def/src/data.rs | 4 ++-- crates/ra_hir_def/src/item_tree.rs | 10 +++++----- crates/ra_hir_def/src/item_tree/lower.rs | 15 +++++++++++---- crates/ra_hir_def/src/item_tree/tests.rs | 8 ++++---- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 5ca331380e..f9e5701db2 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -38,7 +38,7 @@ impl FunctionData { Arc::new(FunctionData { name: func.name.clone(), - params: func.params.clone(), + params: func.params.to_vec(), ret_type: func.ret_type.clone(), attrs: item_tree.attrs(loc.id.value.into()).clone(), has_self_param: func.has_self_param, @@ -70,7 +70,7 @@ impl TypeAliasData { name: typ.name.clone(), type_ref: typ.type_ref.clone(), visibility: item_tree[typ.visibility].clone(), - bounds: typ.bounds.clone(), + bounds: typ.bounds.to_vec(), }) } } diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 9e1fd904fa..5155b61111 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -438,7 +438,7 @@ pub struct Function { pub generic_params: GenericParamsId, pub has_self_param: bool, pub is_unsafe: bool, - pub params: Vec, + pub params: Box<[TypeRef]>, pub ret_type: TypeRef, pub ast_id: FileAstId, } @@ -505,7 +505,7 @@ pub struct Trait { pub visibility: RawVisibilityId, pub generic_params: GenericParamsId, pub auto: bool, - pub items: Vec, + pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } @@ -515,7 +515,7 @@ pub struct Impl { pub target_trait: Option, pub target_type: TypeRef, pub is_negative: bool, - pub items: Vec, + pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } @@ -524,7 +524,7 @@ 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: Vec, + pub bounds: Box<[TypeBound]>, pub generic_params: GenericParamsId, pub type_ref: Option, pub ast_id: FileAstId, @@ -541,7 +541,7 @@ pub struct Mod { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ModKind { /// `mod m { ... }` - Inline { items: Vec }, + Inline { items: Box<[ModItem]> }, /// `mod m;` Outline {}, diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index b1847a6cb5..6e31266a2c 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -325,7 +325,7 @@ impl Ctx { generic_params: GenericParamsId::EMPTY, has_self_param, is_unsafe: func.unsafe_token().is_some(), - params, + params: params.into_boxed_slice(), ret_type, ast_id, }; @@ -344,7 +344,14 @@ impl Ctx { let bounds = self.lower_type_bounds(type_alias); let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); - let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; + let res = TypeAlias { + name, + visibility, + bounds: bounds.into_boxed_slice(), + generic_params, + type_ref, + ast_id, + }; Some(id(self.data().type_aliases.alloc(res))) } @@ -384,7 +391,7 @@ impl Ctx { }) .unwrap_or_else(|| { mark::hit!(name_res_works_for_broken_modules); - Vec::new() + Box::new([]) as Box<[_]> }), } }; @@ -552,7 +559,7 @@ impl Ctx { GenericsOwner::Function(func) => { generics.fill(&self.body_ctx, sm, node); // lower `impl Trait` in arguments - for param in &func.params { + for param in &*func.params { generics.fill_implicit_impl_trait_args(param); } } diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index b72f0f47bb..cd4c8a1996 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -31,7 +31,7 @@ fn test_inner_items(ra_fixture: &str) { ModItem::TypeAlias(it) => tree.source(&db, InFile::new(file_id, it)).into(), ModItem::Mod(it) => { if let ModKind::Inline { items } = &tree[it].kind { - worklist.extend(items); + worklist.extend(&**items); } tree.source(&db, InFile::new(file_id, it)).into() } @@ -125,14 +125,14 @@ fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { } ModItem::Trait(it) => { format_to!(out, "{:?}", tree[it]); - for item in &tree[it].items { + for item in &*tree[it].items { fmt_mod_item(&mut children, tree, ModItem::from(*item)); format_to!(children, "\n"); } } ModItem::Impl(it) => { format_to!(out, "{:?}", tree[it]); - for item in &tree[it].items { + for item in &*tree[it].items { fmt_mod_item(&mut children, tree, ModItem::from(*item)); format_to!(children, "\n"); } @@ -144,7 +144,7 @@ fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { format_to!(out, "{:?}", tree[it]); match &tree[it].kind { ModKind::Inline { items } => { - for item in items { + for item in &**items { fmt_mod_item(&mut children, tree, *item); format_to!(children, "\n"); } From d4ddec2bdfc0766782a662b87e1456a9041e8182 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:14:58 +0200 Subject: [PATCH 30/34] Shrink arenas after building ItemTree --- crates/ra_arena/src/lib.rs | 3 ++ crates/ra_hir_def/src/item_tree.rs | 46 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs index 441fbb3cbe..3169aa5b8c 100644 --- a/crates/ra_arena/src/lib.rs +++ b/crates/ra_arena/src/lib.rs @@ -116,6 +116,9 @@ impl Arena { ) -> impl Iterator, &T)> + ExactSizeIterator + DoubleEndedIterator { self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) } + pub fn shrink_to_fit(&mut self) { + self.data.shrink_to_fit(); + } } impl Default for Arena { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 5155b61111..31f3c4bd83 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -184,6 +184,7 @@ impl ItemTree { if let Some(attrs) = top_attrs { item_tree.attrs.insert(AttrOwner::TopLevel, attrs); } + item_tree.shrink_to_fit(); Arc::new(item_tree) } @@ -196,6 +197,51 @@ impl ItemTree { } } + fn shrink_to_fit(&mut self) { + if let Some(data) = &mut self.data { + let ItemTreeData { + imports, + extern_crates, + functions, + structs, + fields, + unions, + enums, + variants, + consts, + statics, + traits, + impls, + type_aliases, + mods, + macro_calls, + exprs, + vis, + generics, + } = &mut **data; + + imports.shrink_to_fit(); + extern_crates.shrink_to_fit(); + functions.shrink_to_fit(); + structs.shrink_to_fit(); + fields.shrink_to_fit(); + unions.shrink_to_fit(); + enums.shrink_to_fit(); + variants.shrink_to_fit(); + consts.shrink_to_fit(); + statics.shrink_to_fit(); + traits.shrink_to_fit(); + impls.shrink_to_fit(); + type_aliases.shrink_to_fit(); + mods.shrink_to_fit(); + macro_calls.shrink_to_fit(); + exprs.shrink_to_fit(); + + vis.arena.shrink_to_fit(); + generics.arena.shrink_to_fit(); + } + } + /// Returns an iterator over all items located at the top level of the `HirFileId` this /// `ItemTree` was created from. pub fn top_level_items(&self) -> &[ModItem] { From 59d4640b644fa12ecc8f5075d92e5c53124e5dd7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:21:00 +0200 Subject: [PATCH 31/34] Remove unneeded HirFileId argument --- crates/ra_hir_def/src/body.rs | 5 ++--- crates/ra_hir_def/src/body/lower.rs | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 9c5272c2d9..4f2350915d 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -243,7 +243,7 @@ impl Body { } }; let expander = Expander::new(db, file_id, module); - let (body, source_map) = Body::new(db, file_id, def, expander, params, body); + let (body, source_map) = Body::new(db, def, expander, params, body); (Arc::new(body), Arc::new(source_map)) } @@ -253,13 +253,12 @@ impl Body { fn new( db: &dyn DefDatabase, - file_id: HirFileId, def: DefWithBodyId, expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { - lower::lower(db, file_id, def, expander, params, body) + lower::lower(db, def, expander, params, body) } } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index a74136b8e6..852d5cda77 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -57,17 +57,15 @@ impl LowerCtx { pub(super) fn lower( db: &dyn DefDatabase, - file_id: HirFileId, def: DefWithBodyId, expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { - let item_tree = db.item_tree(file_id); + let item_tree = db.item_tree(expander.current_file_id); ExprCollector { db, def, - expander, source_map: BodySourceMap::default(), body: Body { exprs: Arena::default(), @@ -76,7 +74,8 @@ pub(super) fn lower( body_expr: dummy_expr_id(), item_scope: Default::default(), }, - item_trees: vec![(file_id, item_tree)], + item_trees: vec![(expander.current_file_id, item_tree)], + expander, } .collect(params, body) } From 3b50b0b2b658006c23d21749627e413af5c2aa44 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:26:26 +0200 Subject: [PATCH 32/34] Use a HashMap instead of Vec This is no longer enforcing stack discipline, so a Vec isn't necessary or helpful --- crates/ra_hir_def/src/body/lower.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 852d5cda77..3ced648e56 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -36,6 +36,7 @@ use crate::{ use super::{ExprSource, PatSource}; use ast::AstChildren; +use rustc_hash::FxHashMap; use std::sync::Arc; pub(crate) struct LowerCtx { @@ -74,7 +75,11 @@ pub(super) fn lower( body_expr: dummy_expr_id(), item_scope: Default::default(), }, - item_trees: vec![(expander.current_file_id, item_tree)], + item_trees: { + let mut map = FxHashMap::default(); + map.insert(expander.current_file_id, item_tree); + map + }, expander, } .collect(params, body) @@ -87,7 +92,7 @@ struct ExprCollector<'a> { body: Body, source_map: BodySourceMap, - item_trees: Vec<(HirFileId, Arc)>, + item_trees: FxHashMap>, } impl ExprCollector<'_> { @@ -541,7 +546,7 @@ impl ExprCollector<'_> { .insert(macro_call, self.expander.current_file_id); let item_tree = self.db.item_tree(self.expander.current_file_id); - self.item_trees.push((self.expander.current_file_id, item_tree)); + self.item_trees.insert(self.expander.current_file_id, item_tree); let id = self.collect_expr(expansion); self.expander.exit(self.db, mark); id @@ -557,11 +562,7 @@ impl ExprCollector<'_> { } fn find_inner_item(&self, id: AstId) -> FileItemTreeId { - let index = - self.item_trees.iter().position(|(file, _)| *file == id.file_id).unwrap_or_else(|| { - panic!("couldn't find item tree for file {:?}", id.file_id); - }); - let tree = &self.item_trees[index].1; + let tree = &self.item_trees[&id.file_id]; // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes From d6fd7809b016787e8a23f443b1b626840c4ea5c7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:46:44 +0200 Subject: [PATCH 33/34] Clean up and fix inner item collection a bit --- crates/ra_hir_def/src/item_tree/lower.rs | 33 +++++++++++++++++++++--- crates/ra_hir_def/src/item_tree/tests.rs | 12 ++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 6e31266a2c..f10ad25f70 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -82,7 +82,13 @@ impl Ctx { | ast::ModuleItem::TypeAliasDef(_) | ast::ModuleItem::ConstDef(_) | ast::ModuleItem::StaticDef(_) - | ast::ModuleItem::MacroCall(_) => self.collect_inner_items(item.syntax()), + | ast::ModuleItem::MacroCall(_) => { + // Skip this if we're already collecting inner items. We'll descend into all nodes + // already. + if !inner { + self.collect_inner_items(item.syntax()); + } + } // These are handled in their respective `lower_X` method (since we can't just blindly // walk them). @@ -403,7 +409,8 @@ impl Ctx { fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); + let generic_params = + self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { self.with_inherited_visibility(visibility, |this| { @@ -432,7 +439,8 @@ impl Ctx { } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { - let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); + let generic_params = + self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); let target_type = self.lower_type_ref(&impl_def.target_type()?); let is_negative = impl_def.excl_token().is_some(); @@ -548,6 +556,23 @@ impl Ctx { }) } + /// Lowers generics defined on `node` and collects inner items defined within. + fn lower_generic_params_and_inner_items( + &mut self, + owner: GenericsOwner<'_>, + node: &impl ast::TypeParamsOwner, + ) -> GenericParamsId { + // Generics are part of item headers and may contain inner items we need to collect. + if let Some(params) = node.type_param_list() { + self.collect_inner_items(params.syntax()); + } + if let Some(clause) = node.where_clause() { + self.collect_inner_items(clause.syntax()); + } + + self.lower_generic_params(owner, node) + } + fn lower_generic_params( &mut self, owner: GenericsOwner<'_>, @@ -617,7 +642,7 @@ impl Ctx { TypeRef::from_ast(&self.body_ctx, type_ref.clone()) } fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { - TypeRef::from_ast_opt(&self.body_ctx, type_ref) + type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) } /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index cd4c8a1996..dc035d809e 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -374,11 +374,17 @@ fn cursed_inner_items() { impl En { fn assoc() { - trait InnerTrait {} - struct InnerStruct {} - impl InnerTrait for InnerStruct {} + trait InnerTrait {} + struct InnerStruct {} + impl InnerTrait for InnerStruct {} } } + + trait Tr { + type AssocTy = [u8; { fn f() {} }]; + + const AssocConst: [u8; { fn f() {} }]; + } ", ); } From 2928600374a8356c2c2bffee080c47cb0f463fb9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 24 Jun 2020 16:50:23 +0200 Subject: [PATCH 34/34] Reorder items --- crates/ra_hir_def/src/item_tree.rs | 152 ++++++++++++++--------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index 31f3c4bd83..d7bc64e6ca 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -23,6 +23,7 @@ use hir_expand::{ use ra_arena::{Arena, Idx, RawId}; use ra_syntax::{ast, match_ast}; use rustc_hash::FxHashMap; +use smallvec::SmallVec; use test_utils::mark; use crate::{ @@ -33,26 +34,6 @@ use crate::{ type_ref::{Mutability, TypeBound, TypeRef}, visibility::RawVisibility, }; -use smallvec::SmallVec; - -#[derive(Default, Debug, Eq, PartialEq)] -struct ItemVisibilities { - arena: Arena, -} - -impl ItemVisibilities { - fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { - match &vis { - RawVisibility::Public => RawVisibilityId::PUB, - RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { - PathKind::Super(0) => RawVisibilityId::PRIV, - PathKind::Crate => RawVisibilityId::PUB_CRATE, - _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), - }, - _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), - } - } -} #[derive(Copy, Clone, Eq, PartialEq)] pub struct RawVisibilityId(u32); @@ -76,21 +57,6 @@ impl fmt::Debug for RawVisibilityId { } } -#[derive(Default, Debug, Eq, PartialEq)] -struct GenericParamsStorage { - arena: Arena, -} - -impl GenericParamsStorage { - fn alloc(&mut self, params: GenericParams) -> GenericParamsId { - if params.types.is_empty() && params.where_predicates.is_empty() { - return GenericParamsId::EMPTY; - } - - GenericParamsId(self.arena.alloc(params).into_raw().into()) - } -} - #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct GenericParamsId(u32); @@ -98,47 +64,6 @@ impl GenericParamsId { pub const EMPTY: Self = GenericParamsId(u32::max_value()); } -static VIS_PUB: RawVisibility = RawVisibility::Public; -static VIS_PRIV: RawVisibility = - RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); -static VIS_PUB_CRATE: RawVisibility = - RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); - -static EMPTY_GENERICS: GenericParams = - GenericParams { types: Arena::new(), where_predicates: Vec::new() }; - -#[derive(Default, Debug, Eq, PartialEq)] -struct ItemTreeData { - imports: Arena, - extern_crates: Arena, - functions: Arena, - structs: Arena, - fields: Arena, - unions: Arena, - enums: Arena, - variants: Arena, - consts: Arena, - statics: Arena, - traits: Arena, - impls: Arena, - type_aliases: Arena, - mods: Arena, - macro_calls: Arena, - exprs: Arena, - - vis: ItemVisibilities, - generics: GenericParamsStorage, -} - -#[derive(Debug, Eq, PartialEq, Hash)] -enum AttrOwner { - /// Attributes on an item. - ModItem(ModItem), - /// Inner attributes of the source file. - TopLevel, - // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. -} - /// The item tree of a source file. #[derive(Debug, Eq, PartialEq)] pub struct ItemTree { @@ -290,6 +215,81 @@ impl ItemTree { } } +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemVisibilities { + arena: Arena, +} + +impl ItemVisibilities { + fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { + match &vis { + RawVisibility::Public => RawVisibilityId::PUB, + RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { + PathKind::Super(0) => RawVisibilityId::PRIV, + PathKind::Crate => RawVisibilityId::PUB_CRATE, + _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), + }, + _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), + } + } +} + +static VIS_PUB: RawVisibility = RawVisibility::Public; +static VIS_PRIV: RawVisibility = + RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); +static VIS_PUB_CRATE: RawVisibility = + RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); + +#[derive(Default, Debug, Eq, PartialEq)] +struct GenericParamsStorage { + arena: Arena, +} + +impl GenericParamsStorage { + fn alloc(&mut self, params: GenericParams) -> GenericParamsId { + if params.types.is_empty() && params.where_predicates.is_empty() { + return GenericParamsId::EMPTY; + } + + GenericParamsId(self.arena.alloc(params).into_raw().into()) + } +} + +static EMPTY_GENERICS: GenericParams = + GenericParams { types: Arena::new(), where_predicates: Vec::new() }; + +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemTreeData { + imports: Arena, + extern_crates: Arena, + functions: Arena, + structs: Arena, + fields: Arena, + unions: Arena, + enums: Arena, + variants: Arena, + consts: Arena, + statics: Arena, + traits: Arena, + impls: Arena, + type_aliases: Arena, + mods: Arena, + macro_calls: Arena, + exprs: Arena, + + vis: ItemVisibilities, + generics: GenericParamsStorage, +} + +#[derive(Debug, Eq, PartialEq, Hash)] +enum AttrOwner { + /// Attributes on an item. + ModItem(ModItem), + /// Inner attributes of the source file. + TopLevel, + // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. +} + /// Trait implemented by all nodes in the item tree. pub trait ItemTreeNode: Clone { type Source: AstNode + Into;