mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
use positional ids for fields
This commit is contained in:
parent
47e5536678
commit
87ac5f5b36
6 changed files with 144 additions and 131 deletions
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue