diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 4fa2062bdb..0436d20b79 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,152 +3,16 @@ use std::sync::Arc; -use hir_def::{type_ref::TypeRef, LocalEnumVariantId}; -use hir_expand::name::AsName; -use ra_arena::{impl_arena_id, Arena, RawId}; -use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; +use hir_def::adt::VariantData; use crate::{ - db::{AstDatabase, DefDatabase, HirDatabase}, - Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField, + db::{DefDatabase, HirDatabase}, + EnumVariant, Module, Name, Struct, StructField, }; impl Struct { pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc { - db.struct_data(self).variant_data.clone() - } -} - -/// Note that we use `StructData` for unions as well! -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructData { - pub(crate) name: Option, - pub(crate) variant_data: Arc, -} - -impl StructData { - fn new(struct_def: &ast::StructDef) -> StructData { - let name = struct_def.name().map(|n| n.as_name()); - let variant_data = VariantData::new(struct_def.kind()); - let variant_data = Arc::new(variant_data); - StructData { name, variant_data } - } - - pub(crate) fn struct_data_query( - db: &(impl DefDatabase + AstDatabase), - struct_: Struct, - ) -> Arc { - let src = struct_.source(db); - Arc::new(StructData::new(&src.ast)) - } -} - -fn variants(enum_def: &ast::EnumDef) -> impl Iterator { - enum_def.variant_list().into_iter().flat_map(|it| it.variants()) -} - -impl EnumVariant { - pub(crate) fn source_impl( - self, - db: &(impl DefDatabase + AstDatabase), - ) -> Source { - let src = self.parent.source(db); - let ast = variants(&src.ast) - .zip(db.enum_data(self.parent).variants.iter()) - .find(|(_syntax, (id, _))| *id == self.id) - .unwrap() - .0; - Source { file_id: src.file_id, ast } - } - pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc { - db.enum_data(self.parent).variants[self.id].variant_data.clone() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumData { - pub(crate) name: Option, - pub(crate) variants: Arena, -} - -impl EnumData { - pub(crate) fn enum_data_query(db: &(impl DefDatabase + AstDatabase), e: Enum) -> Arc { - let src = e.source(db); - let name = src.ast.name().map(|n| n.as_name()); - let variants = variants(&src.ast) - .map(|var| EnumVariantData { - name: var.name().map(|it| it.as_name()), - variant_data: Arc::new(VariantData::new(var.kind())), - }) - .collect(); - Arc::new(EnumData { name, variants }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct EnumVariantData { - pub(crate) name: Option, - variant_data: Arc, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct StructFieldId(RawId); -impl_arena_id!(StructFieldId); - -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructFieldData { - pub(crate) name: Name, - pub(crate) type_ref: TypeRef, -} - -/// Fields of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct VariantData(VariantDataInner); - -#[derive(Debug, Clone, PartialEq, Eq)] -enum VariantDataInner { - Struct(Arena), - Tuple(Arena), - Unit, -} - -impl VariantData { - pub(crate) fn fields(&self) -> Option<&Arena> { - match &self.0 { - VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields), - _ => None, - } - } -} - -impl VariantData { - fn new(flavor: StructKind) -> Self { - let inner = match flavor { - ast::StructKind::Tuple(fl) => { - let fields = fl - .fields() - .enumerate() - .map(|(i, fd)| StructFieldData { - name: Name::new_tuple_field(i), - type_ref: TypeRef::from_ast_opt(fd.type_ref()), - }) - .collect(); - VariantDataInner::Tuple(fields) - } - ast::StructKind::Named(fl) => { - let fields = fl - .fields() - .map(|fd| StructFieldData { - name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), - type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), - }) - .collect(); - VariantDataInner::Struct(fields) - } - ast::StructKind::Unit => VariantDataInner::Unit, - }; - VariantData(inner) + db.struct_data(self.id).variant_data.clone() } } @@ -188,35 +52,3 @@ impl VariantDef { } } } - -impl StructField { - pub(crate) fn source_impl(&self, db: &(impl DefDatabase + AstDatabase)) -> Source { - let var_data = self.parent.variant_data(db); - let fields = var_data.fields().unwrap(); - let ss; - let es; - let (file_id, struct_kind) = match self.parent { - VariantDef::Struct(s) => { - ss = s.source(db); - (ss.file_id, ss.ast.kind()) - } - VariantDef::EnumVariant(e) => { - es = e.source(db); - (es.file_id, es.ast.kind()) - } - }; - - let field_sources = match struct_kind { - ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(), - ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(), - ast::StructKind::Unit => Vec::new(), - }; - let ast = field_sources - .into_iter() - .zip(fields.iter()) - .find(|(_syntax, (id, _))| *id == self.id) - .unwrap() - .0; - Source { file_id, ast } - } -} diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index b32aa145ea..ae6ef76067 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -6,16 +6,17 @@ pub(crate) mod docs; use std::sync::Arc; use hir_def::{ + adt::VariantData, builtin_type::BuiltinType, type_ref::{Mutability, TypeRef}, - CrateModuleId, LocalEnumVariantId, ModuleId, + CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, }; use hir_expand::name::{self, AsName}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ - adt::{StructFieldId, VariantDef}, + adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, diagnostics::DiagnosticSink, expr::{validation::ExprValidator, Body, BodySourceMap}, @@ -250,7 +251,7 @@ impl Module { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct StructField { pub(crate) parent: VariantDef, - pub(crate) id: StructFieldId, + pub(crate) id: LocalStructFieldId, } #[derive(Debug, PartialEq, Eq)] @@ -288,11 +289,11 @@ impl Struct { } pub fn name(self, db: &impl DefDatabase) -> Option { - db.struct_data(self).name.clone() + db.struct_data(self.id).name.clone() } pub fn fields(self, db: &impl HirDatabase) -> Vec { - db.struct_data(self) + db.struct_data(self.id) .variant_data .fields() .into_iter() @@ -302,7 +303,7 @@ impl Struct { } pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option { - db.struct_data(self) + db.struct_data(self.id) .variant_data .fields() .into_iter() @@ -338,7 +339,7 @@ pub struct Union { impl Union { pub fn name(self, db: &impl DefDatabase) -> Option { - db.struct_data(Struct { id: self.id }).name.clone() + db.struct_data(self.id).name.clone() } pub fn module(self, db: &impl HirDatabase) -> Module { @@ -376,15 +377,19 @@ impl Enum { } pub fn name(self, db: &impl DefDatabase) -> Option { - db.enum_data(self).name.clone() + db.enum_data(self.id).name.clone() } pub fn variants(self, db: &impl DefDatabase) -> Vec { - db.enum_data(self).variants.iter().map(|(id, _)| EnumVariant { parent: self, id }).collect() + db.enum_data(self.id) + .variants + .iter() + .map(|(id, _)| EnumVariant { parent: self, id }) + .collect() } pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option { - db.enum_data(self) + db.enum_data(self.id) .variants .iter() .find(|(_id, data)| data.name.as_ref() == Some(name)) @@ -422,7 +427,7 @@ impl EnumVariant { } pub fn name(self, db: &impl DefDatabase) -> Option { - db.enum_data(self.parent).variants[self.id].name.clone() + db.enum_data(self.parent.id).variants[self.id].name.clone() } pub fn fields(self, db: &impl HirDatabase) -> Vec { @@ -442,6 +447,10 @@ impl EnumVariant { .find(|(_id, data)| data.name == *name) .map(|(id, _)| StructField { parent: self.into(), id }) } + + pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc { + db.enum_data(self.parent.id).variants[self.id].variant_data.clone() + } } /// A Data Type diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 5c7f61eefb..0f4c78df76 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -3,6 +3,7 @@ use ra_syntax::ast::{self, AstNode}; use crate::{ + adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, ids::AstItemDef, Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module, @@ -45,7 +46,33 @@ impl Module { impl HasSource for StructField { type Ast = FieldSource; fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - self.source_impl(db) + let var_data = self.parent.variant_data(db); + let fields = var_data.fields().unwrap(); + let ss; + let es; + let (file_id, struct_kind) = match self.parent { + VariantDef::Struct(s) => { + ss = s.source(db); + (ss.file_id, ss.ast.kind()) + } + VariantDef::EnumVariant(e) => { + es = e.source(db); + (es.file_id, es.ast.kind()) + } + }; + + let field_sources = match struct_kind { + ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(), + ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(), + ast::StructKind::Unit => Vec::new(), + }; + let ast = field_sources + .into_iter() + .zip(fields.iter()) + .find(|(_syntax, (id, _))| *id == self.id) + .unwrap() + .0; + Source { file_id, ast } } } impl HasSource for Struct { @@ -69,7 +96,18 @@ impl HasSource for Enum { impl HasSource for EnumVariant { type Ast = ast::EnumVariant; fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - self.source_impl(db) + let enum_data = db.enum_data(self.parent.id); + let src = self.parent.id.source(db); + let ast = src + .ast + .variant_list() + .into_iter() + .flat_map(|it| it.variants()) + .zip(enum_data.variants.iter()) + .find(|(_syntax, (id, _))| *id == self.id) + .unwrap() + .0; + Source { file_id: src.file_id, ast } } } impl HasSource for Function { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index ebfd970ebc..89ca4e39f0 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -6,7 +6,6 @@ use ra_db::salsa; use ra_syntax::SmolStr; use crate::{ - adt::{EnumData, StructData}, debug::HirDebugDatabase, generics::{GenericDef, GenericParams}, ids, @@ -19,13 +18,13 @@ use crate::{ InferenceResult, Substs, Ty, TypableDef, TypeCtor, }, type_alias::TypeAliasData, - Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, Module, Static, - Struct, StructField, Trait, TypeAlias, + Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, + StructField, Trait, TypeAlias, }; pub use hir_def::db::{ - DefDatabase2, DefDatabase2Storage, InternDatabase, InternDatabaseStorage, RawItemsQuery, - RawItemsWithSourceMapQuery, + DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage, + RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, @@ -36,12 +35,6 @@ pub use hir_expand::db::{ #[salsa::query_group(DefDatabaseStorage)] #[salsa::requires(AstDatabase)] pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { - #[salsa::invoke(crate::adt::StructData::struct_data_query)] - fn struct_data(&self, s: Struct) -> Arc; - - #[salsa::invoke(crate::adt::EnumData::enum_data_query)] - fn enum_data(&self, e: Enum) -> Arc; - #[salsa::invoke(crate::traits::TraitData::trait_data_query)] fn trait_data(&self, t: Trait) -> Arc; diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index dd7cd979ff..8e28343071 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -655,8 +655,8 @@ fn type_for_builtin(def: BuiltinType) -> Ty { } fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { - let var_data = def.variant_data(db); - let fields = match var_data.fields() { + let struct_data = db.struct_data(def.id); + let fields = match struct_data.variant_data.fields() { Some(fields) => fields, None => panic!("fn_sig_for_struct_constructor called on unit struct"), }; @@ -671,8 +671,8 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { /// Build the type of a tuple struct constructor. fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { - let var_data = def.variant_data(db); - if var_data.fields().is_none() { + let struct_data = db.struct_data(def.id); + if struct_data.variant_data.fields().is_none() { return type_for_adt(db, def); // Unit struct } let generics = def.generic_params(db); diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs new file mode 100644 index 0000000000..22bd469f0a --- /dev/null +++ b/crates/ra_hir_def/src/adt.rs @@ -0,0 +1,114 @@ +//! Defines hir-level representation of structs, enums and unions + +use std::sync::Arc; + +use hir_expand::name::{AsName, Name}; +use ra_arena::Arena; +use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; + +use crate::{ + db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, + LocalStructFieldId, StructId, +}; + +/// Note that we use `StructData` for unions as well! +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructData { + pub name: Option, + pub variant_data: Arc, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumData { + pub name: Option, + pub variants: Arena, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumVariantData { + pub name: Option, + pub variant_data: Arc, +} + +/// Fields of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VariantData(VariantDataInner); + +#[derive(Debug, Clone, PartialEq, Eq)] +enum VariantDataInner { + Struct(Arena), + Tuple(Arena), + Unit, +} + +/// A single field of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructFieldData { + pub name: Name, + pub type_ref: TypeRef, +} + +impl StructData { + pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Arc { + let src = struct_.source(db); + let name = src.ast.name().map(|n| n.as_name()); + let variant_data = VariantData::new(src.ast.kind()); + let variant_data = Arc::new(variant_data); + Arc::new(StructData { name, variant_data }) + } +} + +impl EnumData { + pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc { + let src = e.source(db); + let name = src.ast.name().map(|n| n.as_name()); + let variants = src + .ast + .variant_list() + .into_iter() + .flat_map(|it| it.variants()) + .map(|var| EnumVariantData { + name: var.name().map(|it| it.as_name()), + variant_data: Arc::new(VariantData::new(var.kind())), + }) + .collect(); + Arc::new(EnumData { name, variants }) + } +} + +impl VariantData { + fn new(flavor: ast::StructKind) -> Self { + let inner = match flavor { + ast::StructKind::Tuple(fl) => { + let fields = fl + .fields() + .enumerate() + .map(|(i, fd)| StructFieldData { + name: Name::new_tuple_field(i), + type_ref: TypeRef::from_ast_opt(fd.type_ref()), + }) + .collect(); + VariantDataInner::Tuple(fields) + } + ast::StructKind::Named(fl) => { + let fields = fl + .fields() + .map(|fd| StructFieldData { + name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), + type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), + }) + .collect(); + VariantDataInner::Struct(fields) + } + ast::StructKind::Unit => VariantDataInner::Unit, + }; + VariantData(inner) + } + + pub fn fields(&self) -> Option<&Arena> { + match &self.0 { + VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields), + _ => None, + } + } +} diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index b271636b07..f6027013f2 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -5,7 +5,11 @@ use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::{salsa, SourceDatabase}; use ra_syntax::ast; -use crate::nameres::raw::{ImportSourceMap, RawItems}; +use crate::{ + adt::{EnumData, StructData}, + nameres::raw::{ImportSourceMap, RawItems}, + EnumId, StructId, +}; #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { @@ -37,4 +41,10 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { #[salsa::invoke(RawItems::raw_items_query)] fn raw_items(&self, file_id: HirFileId) -> Arc; + + #[salsa::invoke(StructData::struct_data_query)] + fn struct_data(&self, s: StructId) -> Arc; + + #[salsa::invoke(EnumData::enum_data_query)] + fn enum_data(&self, e: EnumId) -> Arc; } diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 93ad40005c..76d5f18522 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -12,6 +12,7 @@ pub mod attr; pub mod path; pub mod type_ref; pub mod builtin_type; +pub mod adt; // FIXME: this should be private pub mod nameres; @@ -259,6 +260,22 @@ pub struct EnumVariantId { pub struct LocalEnumVariantId(RawId); impl_arena_id!(LocalEnumVariantId); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum VariantId { + EnumVariantId(EnumVariantId), + StructId(StructId), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StructFieldId { + parent: VariantId, + local_id: LocalStructFieldId, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocalStructFieldId(RawId); +impl_arena_id!(LocalStructFieldId); + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); impl_intern_key!(ConstId);