use positional ids for fields

This commit is contained in:
Aleksey Kladov 2019-01-25 14:21:14 +03:00
parent 47e5536678
commit 87ac5f5b36
6 changed files with 144 additions and 131 deletions

View file

@ -4,6 +4,7 @@ use std::{
fmt, fmt,
marker::PhantomData, marker::PhantomData,
ops::{Index, IndexMut}, ops::{Index, IndexMut},
iter::FromIterator,
}; };
pub mod map; pub mod map;
@ -109,3 +110,15 @@ impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
&mut self.data[idx] &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,
}
}
}

View file

@ -79,12 +79,13 @@ impl EnumVariant {
.to_owned(); .to_owned();
(file_id, var) (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)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData { pub struct EnumData {
pub(crate) name: Option<Name>, pub(crate) name: Option<Name>,
@ -94,28 +95,31 @@ pub struct EnumData {
impl EnumData { impl EnumData {
pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> { pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> {
let (_file_id, enum_def) = e.source(db); let (_file_id, enum_def) = e.source(db);
let mut res = EnumData { let name = enum_def.name().map(|n| n.as_name());
name: enum_def.name().map(|n| n.as_name()), let variants = variants(&*enum_def)
variants: Arena::default(), .map(|var| EnumVariantData {
};
for var in variants(&*enum_def) {
let data = EnumVariantData {
name: var.name().map(|it| it.as_name()), name: var.name().map(|it| it.as_name()),
variant_data: Arc::new(VariantData::new(var.flavor())), variant_data: Arc::new(VariantData::new(var.flavor())),
}; })
res.variants.alloc(data); .collect();
} Arc::new(EnumData { name, variants })
Arc::new(res)
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct EnumVariantId(RawId);
impl_arena_id!(EnumVariantId);
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariantData { pub struct EnumVariantData {
pub(crate) name: Option<Name>, pub(crate) name: Option<Name>,
pub(crate) variant_data: Arc<VariantData>, 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 /// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldData { pub struct StructFieldData {
@ -125,45 +129,27 @@ pub struct StructFieldData {
/// Fields of an enum variant or struct /// Fields of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData { pub struct VariantData(VariantDataInner);
Struct(Vec<StructFieldData>),
Tuple(Vec<StructFieldData>), #[derive(Debug, Clone, PartialEq, Eq)]
enum VariantDataInner {
Struct(Arena<StructFieldId, StructFieldData>),
Tuple(Arena<StructFieldId, StructFieldData>),
Unit, Unit,
} }
impl VariantData { impl VariantData {
pub fn fields(&self) -> &[StructFieldData] { pub(crate) fn fields(&self) -> Option<&Arena<StructFieldId, StructFieldData>> {
match self { match &self.0 {
VariantData::Struct(fields) | VariantData::Tuple(fields) => fields, VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
_ => &[], _ => None,
}
}
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,
} }
} }
} }
impl VariantData { impl VariantData {
fn new(flavor: StructFlavor) -> Self { fn new(flavor: StructFlavor) -> Self {
match flavor { let inner = match flavor {
StructFlavor::Tuple(fl) => { StructFlavor::Tuple(fl) => {
let fields = fl let fields = fl
.fields() .fields()
@ -173,7 +159,7 @@ impl VariantData {
type_ref: TypeRef::from_ast_opt(fd.type_ref()), type_ref: TypeRef::from_ast_opt(fd.type_ref()),
}) })
.collect(); .collect();
VariantData::Tuple(fields) VariantDataInner::Tuple(fields)
} }
StructFlavor::Named(fl) => { StructFlavor::Named(fl) => {
let fields = fl let fields = fl
@ -183,16 +169,17 @@ impl VariantData {
type_ref: TypeRef::from_ast_opt(fd.type_ref()), type_ref: TypeRef::from_ast_opt(fd.type_ref()),
}) })
.collect(); .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> { // pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
self.fields() // self.fields()
.iter() // .iter()
.find(|f| f.name == *field_name) // .find(|f| f.name == *field_name)
.map(|f| &f.type_ref) // .map(|f| &f.type_ref)
} // }
} }

View file

@ -11,7 +11,7 @@ use crate::{
db::HirDatabase, db::HirDatabase,
expr::BodySyntaxMapping, expr::BodySyntaxMapping,
ty::{InferenceResult, VariantDef}, ty::{InferenceResult, VariantDef},
adt::{VariantData, EnumVariantId}, adt::{EnumVariantId, StructFieldId},
generics::GenericParams, generics::GenericParams,
docs::{Documentation, Docs, docs_from_ast}, docs::{Documentation, Docs, docs_from_ast},
module_tree::ModuleId, module_tree::ModuleId,
@ -177,19 +177,25 @@ impl Module {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructField { pub struct StructField {
parent: VariantDef, parent: VariantDef,
name: Name, pub(crate) id: StructFieldId,
} }
impl StructField { impl StructField {
pub fn name(&self) -> &Name { pub fn name(&self, db: &impl HirDatabase) -> Name {
&self.name self.parent.variant_data(db).fields().unwrap()[self.id]
.name
.clone()
} }
pub fn ty(&self, db: &impl HirDatabase) -> Option<Ty> { pub fn ty(&self, db: &impl HirDatabase) -> Ty {
db.type_for_field(self.parent, self.name.clone()) db.type_for_field(*self)
}
pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
self.parent
} }
} }
@ -215,14 +221,28 @@ impl Struct {
db.struct_data(*self) db.struct_data(*self)
.variant_data .variant_data
.fields() .fields()
.iter() .into_iter()
.map(|it| StructField { .flat_map(|it| it.iter())
.map(|(id, _)| StructField {
parent: (*self).into(), parent: (*self).into(),
name: it.name.clone(), id,
}) })
.collect() .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> { pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into()) db.generic_params((*self).into())
} }
@ -300,22 +320,29 @@ impl EnumVariant {
db.enum_data(self.parent).variants[self.id].name.clone() 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> { pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
self.variant_data(db) self.variant_data(db)
.fields() .fields()
.iter() .into_iter()
.map(|it| StructField { .flat_map(|it| it.iter())
.map(|(id, _)| StructField {
parent: (*self).into(), parent: (*self).into(),
name: it.name.clone(), id,
}) })
.collect() .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 { impl Docs for EnumVariant {

View file

@ -4,15 +4,15 @@ use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
use ra_db::{SyntaxDatabase, CrateId, salsa}; use ra_db::{SyntaxDatabase, CrateId, salsa};
use crate::{ use crate::{
MacroCallId, Name, HirFileId, MacroCallId, 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, StructField,
macros::MacroExpansion, macros::MacroExpansion,
module_tree::ModuleTree, module_tree::ModuleTree,
nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, VariantDef}, ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
adt::{StructData, EnumData}, adt::{StructData, EnumData},
impl_block::ModuleImplBlocks, impl_block::ModuleImplBlocks,
generics::{GenericParams, GenericDef}, generics::{GenericParams, GenericDef},
@ -42,7 +42,7 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
fn type_for_def(&self, def: TypableDef) -> Ty; fn type_for_def(&self, def: TypableDef) -> Ty;
#[salsa::invoke(crate::ty::type_for_field)] #[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)] #[salsa::invoke(query_definitions::file_items)]
fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;

View file

@ -38,6 +38,7 @@ use crate::{
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
generics::GenericParams, generics::GenericParams,
path::GenericArg, path::GenericArg,
adt::VariantData,
}; };
/// The ID of a type variable. /// The ID of a type variable.
@ -702,19 +703,30 @@ pub enum VariantDef {
} }
impl_froms!(VariantDef: Struct, EnumVariant); impl_froms!(VariantDef: Struct, EnumVariant);
pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> { impl VariantDef {
let (variant_data, generics, module) = match def { pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)), match self {
VariantDef::EnumVariant(var) => ( VariantDef::Struct(it) => it.field(db, name),
var.variant_data(db), VariantDef::EnumVariant(it) => it.field(db, name),
var.parent_enum(db).generic_params(db), }
var.module(db), }
), 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 var_data = parent_def.variant_data(db);
// let impl_block = def_id.impl_block(db); let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
let type_ref = variant_data.get_field_type_ref(&field)?; Ty::from_hir(db, &module, None, &generics, type_ref)
Some(Ty::from_hir(db, &module, None, &generics, &type_ref))
} }
/// The result of type inference: A mapping from expressions and patterns to types. /// The result of type inference: A mapping from expressions and patterns to types.
@ -1122,39 +1134,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} }
} }
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( fn infer_tuple_struct_pat(
&mut self, &mut self,
path: Option<&Path>, path: Option<&Path>,
subpats: &[PatId], subpats: &[PatId],
expected: &Ty, expected: &Ty,
) -> Ty { ) -> Ty {
let (ty, fields) = self let (ty, def) = self.resolve_variant(path);
.resolve_fields(path)
.unwrap_or((Ty::Unknown, Vec::new()));
self.unify(&ty, expected); self.unify(&ty, expected);
let substs = ty.substs().unwrap_or_else(Substs::empty); let substs = ty.substs().unwrap_or_else(Substs::empty);
for (i, &subpat) in subpats.iter().enumerate() { for (i, &subpat) in subpats.iter().enumerate() {
let expected_ty = fields let expected_ty = def
.get(i) .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
.and_then(|field| field.ty(self.db)) .map_or(Ty::Unknown, |field| field.ty(self.db))
.unwrap_or(Ty::Unknown)
.subst(&substs); .subst(&substs);
self.infer_pat(subpat, &expected_ty); self.infer_pat(subpat, &expected_ty);
} }
@ -1163,19 +1158,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} }
fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty {
let (ty, fields) = self let (ty, def) = self.resolve_variant(path);
.resolve_fields(path)
.unwrap_or((Ty::Unknown, Vec::new()));
self.unify(&ty, expected); self.unify(&ty, expected);
let substs = ty.substs().unwrap_or_else(Substs::empty); let substs = ty.substs().unwrap_or_else(Substs::empty);
for subpat in subpats { 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 let expected_ty = matching_field
.and_then(|field| field.ty(self.db)) .map_or(Ty::Unknown, |field| field.ty(self.db))
.unwrap_or(Ty::Unknown)
.subst(&substs); .subst(&substs);
self.infer_pat(subpat.pat, &expected_ty); self.infer_pat(subpat.pat, &expected_ty);
} }
@ -1420,14 +1412,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let (ty, def_id) = self.resolve_variant(path.as_ref()); let (ty, def_id) = self.resolve_variant(path.as_ref());
let substs = ty.substs().unwrap_or_else(Substs::empty); let substs = ty.substs().unwrap_or_else(Substs::empty);
for field in fields { for field in fields {
let field_ty = if let Some(def_id) = def_id { let field_ty = def_id
self.db .and_then(|it| it.field(self.db, &field.name))
.type_for_field(def_id.into(), field.name.clone()) .map_or(Ty::Unknown, |field| field.ty(self.db))
.unwrap_or(Ty::Unknown) .subst(&substs);
.subst(&substs)
} else {
Ty::Unknown
};
self.infer_expr(field.expr, &Expectation::has_type(field_ty)); self.infer_expr(field.expr, &Expectation::has_type(field_ty));
} }
if let Some(expr) = spread { if let Some(expr) = spread {
@ -1440,7 +1428,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = receiver_ty let ty = receiver_ty
.autoderef(self.db) .autoderef(self.db)
.find_map(|derefed_ty| match derefed_ty { .find_map(|derefed_ty| match derefed_ty {
// this is more complicated than necessary because type_for_field is cancelable
Ty::Tuple(fields) => { Ty::Tuple(fields) => {
let i = name.to_string().parse::<usize>().ok(); let i = name.to_string().parse::<usize>().ok();
i.and_then(|i| fields.get(i).cloned()) i.and_then(|i| fields.get(i).cloned())
@ -1449,10 +1436,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
def_id: AdtDef::Struct(s), def_id: AdtDef::Struct(s),
ref substs, ref substs,
.. ..
} => self } => s
.db .field(self.db, name)
.type_for_field(s.into(), name.clone()) .map(|field| field.ty(self.db).subst(substs)),
.map(|ty| ty.subst(substs)),
_ => None, _ => None,
}) })
.unwrap_or(Ty::Unknown); .unwrap_or(Ty::Unknown);

View file

@ -34,10 +34,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
CompletionItem::new( CompletionItem::new(
CompletionKind::Reference, CompletionKind::Reference,
ctx.source_range(), ctx.source_range(),
field.name().to_string(), field.name(ctx.db).to_string(),
) )
.kind(CompletionItemKind::Field) .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); .add_to(acc);
} }
} }