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;