use std::sync::Arc;
use ra_syntax::{
- SyntaxNode,
- ast::{self, NameOwner, StructFlavor, AstNode}
+ ast::{self, NameOwner, StructFlavor}
};
use crate::{
- DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant, Module, HirFileId,
- HirDatabase, DefKind,
- SourceItemId,
+ Name, AsName, Struct, Enum, EnumVariant, Module, HirFileId,
+ HirDatabase,
type_ref::TypeRef,
ids::ItemLoc,
};
}
}
-fn get_def_id(
- db: &impl HirDatabase,
- module: Module,
- file_id: HirFileId,
- node: &SyntaxNode,
- expected_kind: DefKind,
-) -> DefId {
- let file_items = db.file_items(file_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)
+impl EnumVariant {
+ pub(crate) fn from_ast(
+ db: &impl HirDatabase,
+ module: Module,
+ file_id: HirFileId,
+ ast: &ast::EnumVariant,
+ ) -> EnumVariant {
+ let loc = ItemLoc::from_ast(db, module, file_id, ast);
+ let id = db.as_ref().enum_variants.loc2id(&loc);
+ EnumVariant { id }
+ }
}
#[derive(Debug, Clone, PartialEq, Eq)]
vl.variants()
.filter_map(|variant_def| {
let name = variant_def.name().map(|n| n.as_name());
-
- name.map(|n| {
- let def_id = get_def_id(
- db,
- module,
- file_id,
- variant_def.syntax(),
- DefKind::EnumVariant,
- );
- (n, EnumVariant::new(def_id))
- })
+ name.map(|n| (n, EnumVariant::from_ast(db, module, file_id, variant_def)))
})
.collect()
} else {
pub(crate) fn enum_variant_data_query(
db: &impl HirDatabase,
- def_id: DefId,
+ var: EnumVariant,
) -> Arc<EnumVariantData> {
- let def_loc = def_id.loc(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 (file_id, variant_def) = var.source(db);
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);
-
- Arc::new(EnumVariantData::new(variant_def, e))
+ let e = Enum::from_ast(db, var.module(db), file_id, enum_def);
+ Arc::new(EnumVariantData::new(&*variant_def, e))
}
}
code_model_impl::def_id_to_ast,
docs::{Documentation, Docs, docs_from_ast},
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
Function(Function),
Struct(Struct),
Enum(Enum),
+ // Can't be directly declared, but can be imported.
+ EnumVariant(EnumVariant),
Def(DefId),
}
-impl_froms!(ModuleDef: Module, Function, Struct, Enum);
+impl_froms!(ModuleDef: Module, Function, Struct, Enum, EnumVariant);
impl From<DefId> for ModuleDef {
fn from(it: DefId) -> ModuleDef {
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumVariant {
- pub(crate) def_id: DefId,
+ pub(crate) id: EnumVariantId,
}
impl EnumVariant {
- pub(crate) fn new(def_id: DefId) -> Self {
- EnumVariant { def_id }
- }
-
- pub fn def_id(&self) -> DefId {
- self.def_id
+ pub fn module(&self, db: &impl HirDatabase) -> Module {
+ self.id.loc(db).module
}
-
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> {
- 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> {
- 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> {
.fields()
.iter()
.map(|it| StructField {
- parent: self.def_id.into(),
+ parent: (*self).into(),
name: it.name.clone(),
})
.collect()
}
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)
}
}
.find(|(n, _variant)| n == &segment.name);
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(),
}
}
- ModuleDef::Function(_) | ModuleDef::Struct(_) => {
+ ModuleDef::Function(_) | ModuleDef::Struct(_) | ModuleDef::EnumVariant(_) => {
// could be an inherent method call in UFCS form
// (`Struct::method`), or some other kind of associated
// item... Which we currently don't handle (TODO)
use ra_db::{SyntaxDatabase, CrateId, salsa};
use crate::{
- DefId, MacroCallId, Name, HirFileId,
+ MacroCallId, Name, HirFileId,
SourceFileItems, SourceItemId, Crate, Module, HirInterner,
query_definitions,
Function, FnSignature, FnScopes,
- Struct, Enum,
+ Struct, Enum, EnumVariant,
macros::MacroExpansion,
module_tree::ModuleTree,
nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
fn enum_data(&self, e: Enum) -> Arc<EnumData>;
#[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)]
fn infer(&self, func: Function) -> Arc<InferenceResult>;
use ra_arena::{Arena, RawId, impl_arena_id};
use crate::{
- HirDatabase, Def, EnumVariant, Crate,
+ HirDatabase, Def, Crate,
Module, Trait, Type, Static, Const,
};
pub(crate) fns: LocationIntener<ItemLoc<ast::FnDef>, FunctionId>,
pub(crate) structs: LocationIntener<ItemLoc<ast::StructDef>, StructId>,
pub(crate) enums: LocationIntener<ItemLoc<ast::EnumDef>, EnumId>,
+ pub(crate) enum_variants: LocationIntener<ItemLoc<ast::EnumVariant>, EnumVariantId>,
}
impl HirInterner {
}
}
+#[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)
/// in a specific module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) enum DefKind {
- EnumVariant,
Const,
Static,
Trait,
pub fn resolve(self, db: &impl HirDatabase) -> Def {
let loc = self.loc(db);
match loc.kind {
- DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)),
DefKind::Const => {
let def = Const::new(self);
Def::Const(def)
TypableDef::Function(func) => (func.generic_params(db), last),
TypableDef::Struct(s) => (s.generic_params(db), last),
TypableDef::Enum(e) => (e.generic_params(db), last),
+ TypableDef::EnumVariant(var) => {
+ // the generic args for an enum variant may be either specified
+ // on the segment referring to the enum, or on the segment
+ // referring to the variant. So `Option::<T>::None` and
+ // `Option::None::<T>` are both allowed (though the former is
+ // preferred). See also `def_ids_for_path_segments` in rustc.
+ let len = path.segments.len();
+ let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
+ // Option::<T>::None
+ &path.segments[len - 2]
+ } else {
+ // Option::None::<T>
+ last
+ };
+ (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),
- Def::EnumVariant(ev) => {
- // the generic args for an enum variant may be either specified
- // on the segment referring to the enum, or on the segment
- // referring to the variant. So `Option::<T>::None` and
- // `Option::None::<T>` are both allowed (though the former is
- // preferred). See also `def_ids_for_path_segments` in rustc.
- let len = path.segments.len();
- let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some()
- {
- // Option::<T>::None
- &path.segments[len - 2]
- } else {
- // Option::None::<T>
- last
- };
- (ev.parent_enum(db).generic_params(db), segment)
- }
_ => return Substs::empty(),
},
};
Function(Function),
Struct(Struct),
Enum(Enum),
+ EnumVariant(EnumVariant),
Def(DefId),
}
-impl_froms!(TypableDef: Function, Struct, Enum);
+impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant);
impl From<DefId> for TypableDef {
fn from(func: DefId) -> TypableDef {
ModuleDef::Function(f) => f.into(),
ModuleDef::Struct(s) => s.into(),
ModuleDef::Enum(e) => e.into(),
+ ModuleDef::EnumVariant(v) => v.into(),
ModuleDef::Module(_) => return None,
};
Some(res)
TypableDef::Function(f) => type_for_fn(db, f),
TypableDef::Struct(s) => type_for_struct(db, s),
TypableDef::Enum(e) => type_for_enum(db, e),
- TypableDef::Def(def_id) => match def_id.resolve(db) {
- Def::EnumVariant(ev) => type_for_enum_variant(db, ev),
- _ => {
- log::debug!(
- "trying to get type for item of unknown type {:?} {:?}",
- def_id,
- def
- );
- Ty::Unknown
- }
- },
+ TypableDef::EnumVariant(v) => type_for_enum_variant(db, v),
+ TypableDef::Def(def_id) => {
+ log::debug!(
+ "trying to get type for item of unknown type {:?} {:?}",
+ def_id,
+ def
+ );
+ Ty::Unknown
+ }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum VariantDef {
Struct(Struct),
- Def(DefId), // EnumVariant
-}
-impl_froms!(VariantDef: Struct);
-
-impl From<DefId> for VariantDef {
- fn from(def_id: DefId) -> VariantDef {
- VariantDef::Def(def_id)
- }
+ EnumVariant(EnumVariant),
}
+impl_froms!(VariantDef: Struct, EnumVariant);
pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> {
let (variant_data, generics, module) = match def {
VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)),
- VariantDef::Def(def_id) => match def_id.resolve(db) {
- Def::EnumVariant(ev) => (
- ev.variant_data(db),
- ev.parent_enum(db).generic_params(db),
- def_id.module(db),
- ),
- // TODO: unions
- _ => panic!(
- "trying to get type for field {:?} in non-struct/variant {:?}",
- field, def_id
- ),
- },
+ VariantDef::EnumVariant(var) => (
+ var.variant_data(db),
+ var.parent_enum(db).generic_params(db),
+ var.module(db),
+ ),
};
// We can't have an impl block ere, right?
// let impl_block = def_id.impl_block(db);
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) => {
let ty = type_for_struct(self.db, s);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(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)
+ }
}
}
let fields = s.fields(self.db);
Some((ty, fields))
}
- VariantDef::Def(def_id) => match def_id.resolve(self.db) {
- Def::EnumVariant(ev) => {
- let fields = ev.fields(self.db);
- Some((ty, fields))
- }
- _ => None,
- },
+ VariantDef::EnumVariant(var) => {
+ let fields = var.fields(self.db);
+ Some((ty, fields))
+ }
}
}
.module
.resolve_path(self.db, &path)
.take_values()
- .and_then(|module_def| match module_def {
- 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,
- })
+ .and_then(|module_def| module_def.into())
.map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)),
Pat::Bind {
mode,