fmt,
marker::PhantomData,
ops::{Index, IndexMut},
+ iter::FromIterator,
};
pub mod map;
&mut self.data[idx]
}
}
+
+impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ Arena {
+ data: Vec::from_iter(iter),
+ _ty: PhantomData,
+ }
+ }
+}
.to_owned();
(file_id, var)
}
+ pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
+ db.enum_data(self.parent).variants[self.id]
+ .variant_data
+ .clone()
+ }
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) struct EnumVariantId(RawId);
-impl_arena_id!(EnumVariantId);
-
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
pub(crate) name: Option<Name>,
impl EnumData {
pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> {
let (_file_id, enum_def) = e.source(db);
- let mut res = EnumData {
- name: enum_def.name().map(|n| n.as_name()),
- variants: Arena::default(),
- };
- for var in variants(&*enum_def) {
- let data = EnumVariantData {
+ let name = enum_def.name().map(|n| n.as_name());
+ let variants = variants(&*enum_def)
+ .map(|var| EnumVariantData {
name: var.name().map(|it| it.as_name()),
variant_data: Arc::new(VariantData::new(var.flavor())),
- };
- res.variants.alloc(data);
- }
-
- Arc::new(res)
+ })
+ .collect();
+ Arc::new(EnumData { name, variants })
}
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct EnumVariantId(RawId);
+impl_arena_id!(EnumVariantId);
+
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariantData {
pub(crate) name: Option<Name>,
pub(crate) variant_data: Arc<VariantData>,
}
+#[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 {
/// Fields of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum VariantData {
- Struct(Vec<StructFieldData>),
- Tuple(Vec<StructFieldData>),
+pub struct VariantData(VariantDataInner);
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum VariantDataInner {
+ Struct(Arena<StructFieldId, StructFieldData>),
+ Tuple(Arena<StructFieldId, StructFieldData>),
Unit,
}
impl VariantData {
- pub fn fields(&self) -> &[StructFieldData] {
- match self {
- VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
- _ => &[],
- }
- }
-
- pub fn is_struct(&self) -> bool {
- match self {
- VariantData::Struct(..) => true,
- _ => false,
- }
- }
-
- pub fn is_tuple(&self) -> bool {
- match self {
- VariantData::Tuple(..) => true,
- _ => false,
- }
- }
-
- pub fn is_unit(&self) -> bool {
- match self {
- VariantData::Unit => true,
- _ => false,
+ pub(crate) fn fields(&self) -> Option<&Arena<StructFieldId, StructFieldData>> {
+ match &self.0 {
+ VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
+ _ => None,
}
}
}
impl VariantData {
fn new(flavor: StructFlavor) -> Self {
- match flavor {
+ let inner = match flavor {
StructFlavor::Tuple(fl) => {
let fields = fl
.fields()
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
})
.collect();
- VariantData::Tuple(fields)
+ VariantDataInner::Tuple(fields)
}
StructFlavor::Named(fl) => {
let fields = fl
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
})
.collect();
- VariantData::Struct(fields)
+ VariantDataInner::Struct(fields)
}
- StructFlavor::Unit => VariantData::Unit,
- }
+ StructFlavor::Unit => VariantDataInner::Unit,
+ };
+ VariantData(inner)
}
- pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
- self.fields()
- .iter()
- .find(|f| f.name == *field_name)
- .map(|f| &f.type_ref)
- }
+ // pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
+ // self.fields()
+ // .iter()
+ // .find(|f| f.name == *field_name)
+ // .map(|f| &f.type_ref)
+ // }
}
db::HirDatabase,
expr::BodySyntaxMapping,
ty::{InferenceResult, VariantDef},
- adt::{VariantData, EnumVariantId},
+ adt::{EnumVariantId, StructFieldId},
generics::GenericParams,
docs::{Documentation, Docs, docs_from_ast},
module_tree::ModuleId,
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructField {
parent: VariantDef,
- name: Name,
+ pub(crate) id: StructFieldId,
}
impl StructField {
- pub fn name(&self) -> &Name {
- &self.name
+ pub fn name(&self, db: &impl HirDatabase) -> Name {
+ self.parent.variant_data(db).fields().unwrap()[self.id]
+ .name
+ .clone()
}
- pub fn ty(&self, db: &impl HirDatabase) -> Option<Ty> {
- db.type_for_field(self.parent, self.name.clone())
+ pub fn ty(&self, db: &impl HirDatabase) -> Ty {
+ db.type_for_field(*self)
+ }
+
+ pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
+ self.parent
}
}
db.struct_data(*self)
.variant_data
.fields()
- .iter()
- .map(|it| StructField {
+ .into_iter()
+ .flat_map(|it| it.iter())
+ .map(|(id, _)| StructField {
parent: (*self).into(),
- name: it.name.clone(),
+ id,
})
.collect()
}
+ pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+ db.struct_data(*self)
+ .variant_data
+ .fields()
+ .into_iter()
+ .flat_map(|it| it.iter())
+ .find(|(_id, data)| data.name == *name)
+ .map(|(id, _)| StructField {
+ parent: (*self).into(),
+ id,
+ })
+ }
+
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into())
}
db.enum_data(self.parent).variants[self.id].name.clone()
}
- pub fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
- db.enum_data(self.parent).variants[self.id]
- .variant_data
- .clone()
- }
-
pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
self.variant_data(db)
.fields()
- .iter()
- .map(|it| StructField {
+ .into_iter()
+ .flat_map(|it| it.iter())
+ .map(|(id, _)| StructField {
parent: (*self).into(),
- name: it.name.clone(),
+ id,
})
.collect()
}
+
+ pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+ self.variant_data(db)
+ .fields()
+ .into_iter()
+ .flat_map(|it| it.iter())
+ .find(|(_id, data)| data.name == *name)
+ .map(|(id, _)| StructField {
+ parent: (*self).into(),
+ id,
+ })
+ }
}
impl Docs for EnumVariant {
use ra_db::{SyntaxDatabase, CrateId, salsa};
use crate::{
- MacroCallId, Name, HirFileId,
+ MacroCallId, HirFileId,
SourceFileItems, SourceItemId, Crate, Module, HirInterner,
query_definitions,
Function, FnSignature, FnScopes,
- Struct, Enum,
+ Struct, Enum, StructField,
macros::MacroExpansion,
module_tree::ModuleTree,
nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
- ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, VariantDef},
+ ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
adt::{StructData, EnumData},
impl_block::ModuleImplBlocks,
generics::{GenericParams, GenericDef},
fn type_for_def(&self, def: TypableDef) -> Ty;
#[salsa::invoke(crate::ty::type_for_field)]
- fn type_for_field(&self, def: VariantDef, field: Name) -> Option<Ty>;
+ fn type_for_field(&self, field: StructField) -> Ty;
#[salsa::invoke(query_definitions::file_items)]
fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
generics::GenericParams,
path::GenericArg,
+ adt::VariantData,
};
/// The ID of a type variable.
}
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::EnumVariant(var) => (
- var.variant_data(db),
- var.parent_enum(db).generic_params(db),
- var.module(db),
- ),
+impl VariantDef {
+ pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+ match self {
+ VariantDef::Struct(it) => it.field(db, name),
+ VariantDef::EnumVariant(it) => it.field(db, name),
+ }
+ }
+ pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc<VariantData> {
+ match self {
+ VariantDef::Struct(it) => it.variant_data(db),
+ VariantDef::EnumVariant(it) => it.variant_data(db),
+ }
+ }
+}
+
+pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
+ let parent_def = field.parent_def(db);
+ let (generics, module) = match parent_def {
+ VariantDef::Struct(it) => (it.generic_params(db), it.module(db)),
+ VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)),
};
- // We can't have an impl block ere, right?
- // let impl_block = def_id.impl_block(db);
- let type_ref = variant_data.get_field_type_ref(&field)?;
- Some(Ty::from_hir(db, &module, None, &generics, &type_ref))
+ let var_data = parent_def.variant_data(db);
+ let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
+ Ty::from_hir(db, &module, None, &generics, type_ref)
}
/// The result of type inference: A mapping from expressions and patterns to types.
}
}
- fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> {
- let (ty, def) = self.resolve_variant(path);
- match def? {
- VariantDef::Struct(s) => {
- let fields = s.fields(self.db);
- Some((ty, fields))
- }
- VariantDef::EnumVariant(var) => {
- let fields = var.fields(self.db);
- Some((ty, fields))
- }
- }
- }
-
fn infer_tuple_struct_pat(
&mut self,
path: Option<&Path>,
subpats: &[PatId],
expected: &Ty,
) -> Ty {
- let (ty, fields) = self
- .resolve_fields(path)
- .unwrap_or((Ty::Unknown, Vec::new()));
+ let (ty, def) = self.resolve_variant(path);
self.unify(&ty, expected);
let substs = ty.substs().unwrap_or_else(Substs::empty);
for (i, &subpat) in subpats.iter().enumerate() {
- let expected_ty = fields
- .get(i)
- .and_then(|field| field.ty(self.db))
- .unwrap_or(Ty::Unknown)
+ let expected_ty = def
+ .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
+ .map_or(Ty::Unknown, |field| field.ty(self.db))
.subst(&substs);
self.infer_pat(subpat, &expected_ty);
}
}
fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty {
- let (ty, fields) = self
- .resolve_fields(path)
- .unwrap_or((Ty::Unknown, Vec::new()));
+ let (ty, def) = self.resolve_variant(path);
self.unify(&ty, expected);
let substs = ty.substs().unwrap_or_else(Substs::empty);
for subpat in subpats {
- let matching_field = fields.iter().find(|field| field.name() == &subpat.name);
+ let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
let expected_ty = matching_field
- .and_then(|field| field.ty(self.db))
- .unwrap_or(Ty::Unknown)
+ .map_or(Ty::Unknown, |field| field.ty(self.db))
.subst(&substs);
self.infer_pat(subpat.pat, &expected_ty);
}
let (ty, def_id) = self.resolve_variant(path.as_ref());
let substs = ty.substs().unwrap_or_else(Substs::empty);
for field in fields {
- let field_ty = if let Some(def_id) = def_id {
- self.db
- .type_for_field(def_id.into(), field.name.clone())
- .unwrap_or(Ty::Unknown)
- .subst(&substs)
- } else {
- Ty::Unknown
- };
+ let field_ty = def_id
+ .and_then(|it| it.field(self.db, &field.name))
+ .map_or(Ty::Unknown, |field| field.ty(self.db))
+ .subst(&substs);
self.infer_expr(field.expr, &Expectation::has_type(field_ty));
}
if let Some(expr) = spread {
let ty = receiver_ty
.autoderef(self.db)
.find_map(|derefed_ty| match derefed_ty {
- // this is more complicated than necessary because type_for_field is cancelable
Ty::Tuple(fields) => {
let i = name.to_string().parse::<usize>().ok();
i.and_then(|i| fields.get(i).cloned())
def_id: AdtDef::Struct(s),
ref substs,
..
- } => self
- .db
- .type_for_field(s.into(), name.clone())
- .map(|ty| ty.subst(substs)),
+ } => s
+ .field(self.db, name)
+ .map(|field| field.ty(self.db).subst(substs)),
_ => None,
})
.unwrap_or(Ty::Unknown);
CompletionItem::new(
CompletionKind::Reference,
ctx.source_range(),
- field.name().to_string(),
+ field.name(ctx.db).to_string(),
)
.kind(CompletionItemKind::Field)
- .set_detail(field.ty(ctx.db).map(|ty| ty.subst(substs).to_string()))
+ .detail(field.ty(ctx.db).subst(substs).to_string())
.add_to(acc);
}
}