move enum variant to the new API

This commit is contained in:
Aleksey Kladov 2019-01-24 23:32:41 +03:00
parent 11dda8a0fb
commit 4c514a3e02
6 changed files with 97 additions and 142 deletions

View file

@ -4,14 +4,12 @@
use std::sync::Arc; use std::sync::Arc;
use ra_syntax::{ use ra_syntax::{
SyntaxNode, ast::{self, NameOwner, StructFlavor}
ast::{self, NameOwner, StructFlavor, AstNode}
}; };
use crate::{ use crate::{
DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant, Module, HirFileId, Name, AsName, Struct, Enum, EnumVariant, Module, HirFileId,
HirDatabase, DefKind, HirDatabase,
SourceItemId,
type_ref::TypeRef, type_ref::TypeRef,
ids::ItemLoc, ids::ItemLoc,
}; };
@ -66,26 +64,17 @@ impl StructData {
} }
} }
fn get_def_id( impl EnumVariant {
pub(crate) fn from_ast(
db: &impl HirDatabase, db: &impl HirDatabase,
module: Module, module: Module,
file_id: HirFileId, file_id: HirFileId,
node: &SyntaxNode, ast: &ast::EnumVariant,
expected_kind: DefKind, ) -> EnumVariant {
) -> DefId { let loc = ItemLoc::from_ast(db, module, file_id, ast);
let file_items = db.file_items(file_id); let id = db.as_ref().enum_variants.loc2id(&loc);
EnumVariant { id }
let item_id = file_items.id_of(file_id, node); }
let source_item_id = SourceItemId {
file_id,
item_id: Some(item_id),
};
let loc = DefLoc {
module,
kind: expected_kind,
source_item_id,
};
loc.id(db)
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -107,17 +96,7 @@ impl EnumData {
vl.variants() vl.variants()
.filter_map(|variant_def| { .filter_map(|variant_def| {
let name = variant_def.name().map(|n| n.as_name()); let name = variant_def.name().map(|n| n.as_name());
name.map(|n| (n, EnumVariant::from_ast(db, module, file_id, variant_def)))
name.map(|n| {
let def_id = get_def_id(
db,
module,
file_id,
variant_def.syntax(),
DefKind::EnumVariant,
);
(n, EnumVariant::new(def_id))
})
}) })
.collect() .collect()
} else { } else {
@ -148,17 +127,12 @@ impl EnumVariantData {
pub(crate) fn enum_variant_data_query( pub(crate) fn enum_variant_data_query(
db: &impl HirDatabase, db: &impl HirDatabase,
def_id: DefId, var: EnumVariant,
) -> Arc<EnumVariantData> { ) -> Arc<EnumVariantData> {
let def_loc = def_id.loc(db); let (file_id, variant_def) = var.source(db);
assert!(def_loc.kind == DefKind::EnumVariant);
let syntax = db.file_item(def_loc.source_item_id);
let variant_def = ast::EnumVariant::cast(&syntax)
.expect("enum variant def should point to EnumVariant node");
let enum_def = variant_def.parent_enum(); let enum_def = variant_def.parent_enum();
let e = Enum::from_ast(db, def_loc.module, def_loc.source_item_id.file_id, enum_def); let e = Enum::from_ast(db, var.module(db), file_id, enum_def);
Arc::new(EnumVariantData::new(&*variant_def, e))
Arc::new(EnumVariantData::new(variant_def, e))
} }
} }

View file

@ -16,7 +16,7 @@ use crate::{
code_model_impl::def_id_to_ast, code_model_impl::def_id_to_ast,
docs::{Documentation, Docs, docs_from_ast}, docs::{Documentation, Docs, docs_from_ast},
module_tree::ModuleId, module_tree::ModuleId,
ids::{FunctionId, StructId, EnumId}, ids::{FunctionId, StructId, EnumId, EnumVariantId},
}; };
/// hir::Crate describes a single crate. It's the main interface with which /// hir::Crate describes a single crate. It's the main interface with which
@ -68,9 +68,11 @@ pub enum ModuleDef {
Function(Function), Function(Function),
Struct(Struct), Struct(Struct),
Enum(Enum), Enum(Enum),
// Can't be directly declared, but can be imported.
EnumVariant(EnumVariant),
Def(DefId), Def(DefId),
} }
impl_froms!(ModuleDef: Module, Function, Struct, Enum); impl_froms!(ModuleDef: Module, Function, Struct, Enum, EnumVariant);
impl From<DefId> for ModuleDef { impl From<DefId> for ModuleDef {
fn from(it: DefId) -> ModuleDef { fn from(it: DefId) -> ModuleDef {
@ -264,30 +266,25 @@ impl Docs for Enum {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumVariant { pub struct EnumVariant {
pub(crate) def_id: DefId, pub(crate) id: EnumVariantId,
} }
impl EnumVariant { impl EnumVariant {
pub(crate) fn new(def_id: DefId) -> Self { pub fn module(&self, db: &impl HirDatabase) -> Module {
EnumVariant { def_id } self.id.loc(db).module
} }
pub fn def_id(&self) -> DefId {
self.def_id
}
pub fn parent_enum(&self, db: &impl HirDatabase) -> Enum { pub fn parent_enum(&self, db: &impl HirDatabase) -> Enum {
db.enum_variant_data(self.def_id).parent_enum.clone() db.enum_variant_data(*self).parent_enum.clone()
} }
pub fn name(&self, db: &impl HirDatabase) -> Option<Name> { pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
db.enum_variant_data(self.def_id).name.clone() db.enum_variant_data(*self).name.clone()
} }
pub fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> { pub fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
db.enum_variant_data(self.def_id).variant_data.clone() db.enum_variant_data(*self).variant_data.clone()
} }
pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> { pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
@ -295,14 +292,14 @@ impl EnumVariant {
.fields() .fields()
.iter() .iter()
.map(|it| StructField { .map(|it| StructField {
parent: self.def_id.into(), parent: (*self).into(),
name: it.name.clone(), name: it.name.clone(),
}) })
.collect() .collect()
} }
pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::EnumVariant>) { pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::EnumVariant>) {
def_id_to_ast(db, self.def_id) self.id.loc(db).source(db)
} }
} }

View file

@ -143,11 +143,11 @@ impl Module {
.find(|(n, _variant)| n == &segment.name); .find(|(n, _variant)| n == &segment.name);
match matching_variant { match matching_variant {
Some((_n, variant)) => PerNs::both(variant.def_id().into(), (*e).into()), Some((_n, variant)) => PerNs::both(variant.into(), (*e).into()),
None => PerNs::none(), None => PerNs::none(),
} }
} }
ModuleDef::Function(_) | ModuleDef::Struct(_) => { ModuleDef::Function(_) | ModuleDef::Struct(_) | ModuleDef::EnumVariant(_) => {
// could be an inherent method call in UFCS form // could be an inherent method call in UFCS form
// (`Struct::method`), or some other kind of associated // (`Struct::method`), or some other kind of associated
// item... Which we currently don't handle (TODO) // item... Which we currently don't handle (TODO)

View file

@ -4,11 +4,11 @@ use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
use ra_db::{SyntaxDatabase, CrateId, salsa}; use ra_db::{SyntaxDatabase, CrateId, salsa};
use crate::{ use crate::{
DefId, MacroCallId, Name, HirFileId, MacroCallId, Name, HirFileId,
SourceFileItems, SourceItemId, Crate, Module, HirInterner, SourceFileItems, SourceItemId, Crate, Module, HirInterner,
query_definitions, query_definitions,
Function, FnSignature, FnScopes, Function, FnSignature, FnScopes,
Struct, Enum, Struct, Enum, EnumVariant,
macros::MacroExpansion, macros::MacroExpansion,
module_tree::ModuleTree, module_tree::ModuleTree,
nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
@ -36,7 +36,7 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
fn enum_data(&self, e: Enum) -> Arc<EnumData>; fn enum_data(&self, e: Enum) -> Arc<EnumData>;
#[salsa::invoke(crate::adt::EnumVariantData::enum_variant_data_query)] #[salsa::invoke(crate::adt::EnumVariantData::enum_variant_data_query)]
fn enum_variant_data(&self, def_id: DefId) -> Arc<EnumVariantData>; fn enum_variant_data(&self, var: EnumVariant) -> Arc<EnumVariantData>;
#[salsa::invoke(crate::ty::infer)] #[salsa::invoke(crate::ty::infer)]
fn infer(&self, func: Function) -> Arc<InferenceResult>; fn infer(&self, func: Function) -> Arc<InferenceResult>;

View file

@ -5,7 +5,7 @@ use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast};
use ra_arena::{Arena, RawId, impl_arena_id}; use ra_arena::{Arena, RawId, impl_arena_id};
use crate::{ use crate::{
HirDatabase, Def, EnumVariant, Crate, HirDatabase, Def, Crate,
Module, Trait, Type, Static, Const, Module, Trait, Type, Static, Const,
}; };
@ -16,6 +16,7 @@ pub struct HirInterner {
pub(crate) fns: LocationIntener<ItemLoc<ast::FnDef>, FunctionId>, pub(crate) fns: LocationIntener<ItemLoc<ast::FnDef>, FunctionId>,
pub(crate) structs: LocationIntener<ItemLoc<ast::StructDef>, StructId>, pub(crate) structs: LocationIntener<ItemLoc<ast::StructDef>, StructId>,
pub(crate) enums: LocationIntener<ItemLoc<ast::EnumDef>, EnumId>, pub(crate) enums: LocationIntener<ItemLoc<ast::EnumDef>, EnumId>,
pub(crate) enum_variants: LocationIntener<ItemLoc<ast::EnumVariant>, EnumVariantId>,
} }
impl HirInterner { impl HirInterner {
@ -208,6 +209,16 @@ impl EnumId {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumVariantId(RawId);
impl_arena_id!(EnumVariantId);
impl EnumVariantId {
pub(crate) fn loc(self, db: &impl AsRef<HirInterner>) -> ItemLoc<ast::EnumVariant> {
db.as_ref().enum_variants.id2loc(self)
}
}
/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc) /// Def's are a core concept of hir. A `Def` is an Item (function, module, etc)
/// in a specific module. /// in a specific module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -223,7 +234,6 @@ pub struct DefLoc {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) enum DefKind { pub(crate) enum DefKind {
EnumVariant,
Const, Const,
Static, Static,
Trait, Trait,
@ -249,7 +259,6 @@ impl DefId {
pub fn resolve(self, db: &impl HirDatabase) -> Def { pub fn resolve(self, db: &impl HirDatabase) -> Def {
let loc = self.loc(db); let loc = self.loc(db);
match loc.kind { match loc.kind {
DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)),
DefKind::Const => { DefKind::Const => {
let def = Const::new(self); let def = Const::new(self);
Def::Const(def) Def::Const(def)

View file

@ -431,25 +431,24 @@ impl Ty {
TypableDef::Function(func) => (func.generic_params(db), last), TypableDef::Function(func) => (func.generic_params(db), last),
TypableDef::Struct(s) => (s.generic_params(db), last), TypableDef::Struct(s) => (s.generic_params(db), last),
TypableDef::Enum(e) => (e.generic_params(db), last), TypableDef::Enum(e) => (e.generic_params(db), last),
TypableDef::Def(def_id) => match def_id.resolve(db) { TypableDef::EnumVariant(var) => {
Def::Trait(t) => (t.generic_params(db), last),
Def::EnumVariant(ev) => {
// the generic args for an enum variant may be either specified // the generic args for an enum variant may be either specified
// on the segment referring to the enum, or on the segment // on the segment referring to the enum, or on the segment
// referring to the variant. So `Option::<T>::None` and // referring to the variant. So `Option::<T>::None` and
// `Option::None::<T>` are both allowed (though the former is // `Option::None::<T>` are both allowed (though the former is
// preferred). See also `def_ids_for_path_segments` in rustc. // preferred). See also `def_ids_for_path_segments` in rustc.
let len = path.segments.len(); let len = path.segments.len();
let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
{
// Option::<T>::None // Option::<T>::None
&path.segments[len - 2] &path.segments[len - 2]
} else { } else {
// Option::None::<T> // Option::None::<T>
last last
}; };
(ev.parent_enum(db).generic_params(db), segment) (var.parent_enum(db).generic_params(db), segment)
} }
TypableDef::Def(def_id) => match def_id.resolve(db) {
Def::Trait(t) => (t.generic_params(db), last),
_ => return Substs::empty(), _ => return Substs::empty(),
}, },
}; };
@ -688,9 +687,10 @@ pub enum TypableDef {
Function(Function), Function(Function),
Struct(Struct), Struct(Struct),
Enum(Enum), Enum(Enum),
EnumVariant(EnumVariant),
Def(DefId), Def(DefId),
} }
impl_froms!(TypableDef: Function, Struct, Enum); impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant);
impl From<DefId> for TypableDef { impl From<DefId> for TypableDef {
fn from(func: DefId) -> TypableDef { fn from(func: DefId) -> TypableDef {
@ -705,6 +705,7 @@ impl From<ModuleDef> for Option<TypableDef> {
ModuleDef::Function(f) => f.into(), ModuleDef::Function(f) => f.into(),
ModuleDef::Struct(s) => s.into(), ModuleDef::Struct(s) => s.into(),
ModuleDef::Enum(e) => e.into(), ModuleDef::Enum(e) => e.into(),
ModuleDef::EnumVariant(v) => v.into(),
ModuleDef::Module(_) => return None, ModuleDef::Module(_) => return None,
}; };
Some(res) Some(res)
@ -716,9 +717,8 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
TypableDef::Function(f) => type_for_fn(db, f), TypableDef::Function(f) => type_for_fn(db, f),
TypableDef::Struct(s) => type_for_struct(db, s), TypableDef::Struct(s) => type_for_struct(db, s),
TypableDef::Enum(e) => type_for_enum(db, e), TypableDef::Enum(e) => type_for_enum(db, e),
TypableDef::Def(def_id) => match def_id.resolve(db) { TypableDef::EnumVariant(v) => type_for_enum_variant(db, v),
Def::EnumVariant(ev) => type_for_enum_variant(db, ev), TypableDef::Def(def_id) => {
_ => {
log::debug!( log::debug!(
"trying to get type for item of unknown type {:?} {:?}", "trying to get type for item of unknown type {:?} {:?}",
def_id, def_id,
@ -726,38 +726,24 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
); );
Ty::Unknown Ty::Unknown
} }
},
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum VariantDef { pub enum VariantDef {
Struct(Struct), Struct(Struct),
Def(DefId), // EnumVariant EnumVariant(EnumVariant),
}
impl_froms!(VariantDef: Struct);
impl From<DefId> for VariantDef {
fn from(def_id: DefId) -> VariantDef {
VariantDef::Def(def_id)
}
} }
impl_froms!(VariantDef: Struct, EnumVariant);
pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> { pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> {
let (variant_data, generics, module) = match def { let (variant_data, generics, module) = match def {
VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)), VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)),
VariantDef::Def(def_id) => match def_id.resolve(db) { VariantDef::EnumVariant(var) => (
Def::EnumVariant(ev) => ( var.variant_data(db),
ev.variant_data(db), var.parent_enum(db).generic_params(db),
ev.parent_enum(db).generic_params(db), var.module(db),
def_id.module(db),
), ),
// TODO: unions
_ => panic!(
"trying to get type for field {:?} in non-struct/variant {:?}",
field, def_id
),
},
}; };
// We can't have an impl block ere, right? // We can't have an impl block ere, right?
// let impl_block = def_id.impl_block(db); // let impl_block = def_id.impl_block(db);
@ -1156,21 +1142,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
def, def,
); );
match def { match def {
TypableDef::Def(def_id) => match def_id.resolve(self.db) {
Def::EnumVariant(ev) => {
let ty = type_for_enum_variant(self.db, ev);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(def_id.into()))
}
_ => (Ty::Unknown, None),
},
TypableDef::Function(_) => (Ty::Unknown, None),
TypableDef::Struct(s) => { TypableDef::Struct(s) => {
let ty = type_for_struct(self.db, s); let ty = type_for_struct(self.db, s);
let ty = self.insert_type_vars(ty.apply_substs(substs)); let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(s.into())) (ty, Some(s.into()))
} }
TypableDef::Enum(_) => (Ty::Unknown, None), TypableDef::EnumVariant(var) => {
let ty = type_for_enum_variant(self.db, var);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(var.into()))
}
TypableDef::Def(_) | TypableDef::Enum(_) | TypableDef::Function(_) => {
(Ty::Unknown, None)
}
} }
} }
@ -1181,13 +1165,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let fields = s.fields(self.db); let fields = s.fields(self.db);
Some((ty, fields)) Some((ty, fields))
} }
VariantDef::Def(def_id) => match def_id.resolve(self.db) { VariantDef::EnumVariant(var) => {
Def::EnumVariant(ev) => { let fields = var.fields(self.db);
let fields = ev.fields(self.db);
Some((ty, fields)) Some((ty, fields))
} }
_ => None,
},
} }
} }
@ -1285,13 +1266,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.module .module
.resolve_path(self.db, &path) .resolve_path(self.db, &path)
.take_values() .take_values()
.and_then(|module_def| match module_def { .and_then(|module_def| module_def.into())
ModuleDef::Def(it) => Some(it.into()),
ModuleDef::Function(func) => Some(func.into()),
ModuleDef::Struct(s) => Some(s.into()),
ModuleDef::Enum(e) => Some(e.into()),
ModuleDef::Module(_) => None,
})
.map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)), .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)),
Pat::Bind { Pat::Bind {
mode, mode,