mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Switch to variant-granularity field type inference
This commit is contained in:
parent
f16cff3cad
commit
d06904e90c
10 changed files with 68 additions and 42 deletions
|
@ -85,7 +85,7 @@ impl<ID: ArenaId, T> Arena<ID, T> {
|
||||||
self.data.push(value);
|
self.data.push(value);
|
||||||
ID::from_raw(id)
|
ID::from_raw(id)
|
||||||
}
|
}
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> + ExactSizeIterator {
|
pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> + ExactSizeIterator + DoubleEndedIterator {
|
||||||
self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
|
self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ impl StructField {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
||||||
db.type_for_field(*self)
|
db.field_types(self.parent.into())[self.id].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
|
pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ra_arena::map::ArenaMap;
|
||||||
use ra_db::salsa;
|
use ra_db::salsa;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -11,15 +12,19 @@ use crate::{
|
||||||
CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
|
CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
|
||||||
TypeCtor,
|
TypeCtor,
|
||||||
},
|
},
|
||||||
Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
|
Crate, DefWithBody, GenericDef, ImplBlock, Trait,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use hir_def::db::{
|
pub use hir_def::{
|
||||||
BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
|
db::{
|
||||||
DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
|
BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
|
||||||
FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
|
DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
|
||||||
LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery,
|
FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase,
|
||||||
StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
|
InternDatabaseStorage, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery,
|
||||||
|
RawItemsWithSourceMapQuery, StaticDataQuery, StructDataQuery, TraitDataQuery,
|
||||||
|
TypeAliasDataQuery,
|
||||||
|
},
|
||||||
|
LocalStructFieldId, VariantId,
|
||||||
};
|
};
|
||||||
pub use hir_expand::db::{
|
pub use hir_expand::db::{
|
||||||
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
|
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
|
||||||
|
@ -35,8 +40,8 @@ pub trait HirDatabase: DefDatabase {
|
||||||
#[salsa::invoke(crate::ty::type_for_def)]
|
#[salsa::invoke(crate::ty::type_for_def)]
|
||||||
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
|
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
|
||||||
|
|
||||||
#[salsa::invoke(crate::ty::type_for_field)]
|
#[salsa::invoke(crate::ty::field_types_query)]
|
||||||
fn type_for_field(&self, field: StructField) -> Ty;
|
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::ty::callable_item_sig)]
|
#[salsa::invoke(crate::ty::callable_item_sig)]
|
||||||
fn callable_item_signature(&self, def: CallableDef) -> FnSig;
|
fn callable_item_signature(&self, def: CallableDef) -> FnSig;
|
||||||
|
|
|
@ -30,8 +30,9 @@ pub(crate) use autoderef::autoderef;
|
||||||
pub(crate) use infer::{infer_query, InferTy, InferenceResult};
|
pub(crate) use infer::{infer_query, InferTy, InferenceResult};
|
||||||
pub use lower::CallableDef;
|
pub use lower::CallableDef;
|
||||||
pub(crate) use lower::{
|
pub(crate) use lower::{
|
||||||
callable_item_sig, generic_defaults_query, generic_predicates_for_param_query,
|
callable_item_sig, field_types_query, generic_defaults_query,
|
||||||
generic_predicates_query, type_for_def, type_for_field, Namespace, TypableDef,
|
generic_predicates_for_param_query, generic_predicates_query, type_for_def, Namespace,
|
||||||
|
TypableDef,
|
||||||
};
|
};
|
||||||
pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
|
pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
|
||||||
|
|
||||||
|
|
|
@ -245,14 +245,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
|
ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
|
||||||
ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
|
ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
|
||||||
) if struct1 == struct2 => {
|
) if struct1 == struct2 => {
|
||||||
let fields = struct1.fields(self.db);
|
let field_tys = self.db.field_types(struct1.id.into());
|
||||||
let (last_field, prev_fields) = fields.split_last()?;
|
let struct_data = self.db.struct_data(struct1.id.0);
|
||||||
|
|
||||||
|
let mut fields = struct_data.variant_data.fields().iter();
|
||||||
|
let (last_field_id, _data) = fields.next_back()?;
|
||||||
|
|
||||||
// Get the generic parameter involved in the last field.
|
// Get the generic parameter involved in the last field.
|
||||||
let unsize_generic_index = {
|
let unsize_generic_index = {
|
||||||
let mut index = None;
|
let mut index = None;
|
||||||
let mut multiple_param = false;
|
let mut multiple_param = false;
|
||||||
last_field.ty(self.db).walk(&mut |ty| match ty {
|
field_tys[last_field_id].walk(&mut |ty| match ty {
|
||||||
&Ty::Param { idx, .. } => {
|
&Ty::Param { idx, .. } => {
|
||||||
if index.is_none() {
|
if index.is_none() {
|
||||||
index = Some(idx);
|
index = Some(idx);
|
||||||
|
@ -271,8 +274,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
// Check other fields do not involve it.
|
// Check other fields do not involve it.
|
||||||
let mut multiple_used = false;
|
let mut multiple_used = false;
|
||||||
prev_fields.iter().for_each(|field| {
|
fields.for_each(|(field_id, _data)| {
|
||||||
field.ty(self.db).walk(&mut |ty| match ty {
|
field_tys[field_id].walk(&mut |ty| match ty {
|
||||||
&Ty::Param { idx, .. } if idx == unsize_generic_index => {
|
&Ty::Param { idx, .. } if idx == unsize_generic_index => {
|
||||||
multiple_used = true
|
multiple_used = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
self.unify(&ty, &expected.ty);
|
self.unify(&ty, &expected.ty);
|
||||||
|
|
||||||
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
||||||
|
let field_types =
|
||||||
|
def_id.map(|it| self.db.field_types(it.into())).unwrap_or_default();
|
||||||
for (field_idx, field) in fields.iter().enumerate() {
|
for (field_idx, field) in fields.iter().enumerate() {
|
||||||
let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
|
let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
|
||||||
Some(field) => Some(field),
|
Some(field) => Some(field),
|
||||||
|
@ -228,8 +230,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
if let Some(field_def) = field_def {
|
if let Some(field_def) = field_def {
|
||||||
self.result.record_field_resolutions.insert(field.expr, field_def);
|
self.result.record_field_resolutions.insert(field.expr, field_def);
|
||||||
}
|
}
|
||||||
let field_ty =
|
let field_ty = field_def
|
||||||
field_def.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
|
.map_or(Ty::Unknown, |it| field_types[it.id].clone())
|
||||||
|
.subst(&substs);
|
||||||
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
|
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
|
||||||
}
|
}
|
||||||
if let Some(expr) = spread {
|
if let Some(expr) = spread {
|
||||||
|
@ -252,7 +255,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
.and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
|
.and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
|
||||||
TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
|
TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
|
||||||
self.write_field_resolution(tgt_expr, field);
|
self.write_field_resolution(tgt_expr, field);
|
||||||
field.ty(self.db).subst(&a_ty.parameters)
|
self.db.field_types(s.id.into())[field.id]
|
||||||
|
.clone()
|
||||||
|
.subst(&a_ty.parameters)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,10 +27,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
||||||
|
|
||||||
|
let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default();
|
||||||
for (i, &subpat) in subpats.iter().enumerate() {
|
for (i, &subpat) in subpats.iter().enumerate() {
|
||||||
let expected_ty = def
|
let expected_ty = def
|
||||||
.and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
|
.and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
|
||||||
.map_or(Ty::Unknown, |field| field.ty(self.db))
|
.map_or(Ty::Unknown, |field| field_tys[field.id].clone())
|
||||||
.subst(&substs);
|
.subst(&substs);
|
||||||
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
||||||
self.infer_pat(subpat, &expected_ty, default_bm);
|
self.infer_pat(subpat, &expected_ty, default_bm);
|
||||||
|
@ -56,10 +57,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
||||||
|
|
||||||
|
let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default();
|
||||||
for subpat in subpats {
|
for subpat in subpats {
|
||||||
let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
|
let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
|
||||||
let expected_ty =
|
let expected_ty = matching_field
|
||||||
matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
|
.map_or(Ty::Unknown, |field| field_tys[field.id].clone())
|
||||||
|
.subst(&substs);
|
||||||
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
||||||
self.infer_pat(subpat.pat, &expected_ty, default_bm);
|
self.infer_pat(subpat.pat, &expected_ty, default_bm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ use hir_def::{
|
||||||
path::{GenericArg, PathSegment},
|
path::{GenericArg, PathSegment},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
AdtId, GenericDefId,
|
AdtId, GenericDefId, LocalStructFieldId, VariantId,
|
||||||
};
|
};
|
||||||
|
use ra_arena::map::ArenaMap;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||||
|
@ -29,7 +30,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
util::make_mut_slice,
|
util::make_mut_slice,
|
||||||
Const, Enum, EnumVariant, Function, GenericDef, ImplBlock, ModuleDef, Path, Static, Struct,
|
Const, Enum, EnumVariant, Function, GenericDef, ImplBlock, ModuleDef, Path, Static, Struct,
|
||||||
StructField, Trait, TypeAlias, Union, VariantDef,
|
Trait, TypeAlias, Union,
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: this is only really used in `type_for_def`, which contains a bunch of
|
// FIXME: this is only really used in `type_for_def`, which contains a bunch of
|
||||||
|
@ -549,16 +550,23 @@ pub(crate) fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> FnSi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the type of a specific field of a struct or enum variant.
|
/// Build the type of all specific fields of a struct or enum variant.
|
||||||
pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
|
pub(crate) fn field_types_query(
|
||||||
let parent_def = field.parent_def(db);
|
db: &impl HirDatabase,
|
||||||
let resolver = match parent_def {
|
variant_id: VariantId,
|
||||||
VariantDef::Struct(it) => it.id.resolver(db),
|
) -> Arc<ArenaMap<LocalStructFieldId, Ty>> {
|
||||||
VariantDef::EnumVariant(it) => it.parent.id.resolver(db),
|
let (resolver, var_data) = match variant_id {
|
||||||
|
VariantId::StructId(it) => (it.resolver(db), db.struct_data(it.0).variant_data.clone()),
|
||||||
|
VariantId::EnumVariantId(it) => (
|
||||||
|
it.parent.resolver(db),
|
||||||
|
db.enum_data(it.parent).variants[it.local_id].variant_data.clone(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
let var_data = parent_def.variant_data(db);
|
let mut res = ArenaMap::default();
|
||||||
let type_ref = &var_data.fields()[field.id].type_ref;
|
for (field_id, field_data) in var_data.fields().iter() {
|
||||||
Ty::from_hir(db, &resolver, type_ref)
|
res.insert(field_id, Ty::from_hir(db, &resolver, &field_data.type_ref))
|
||||||
|
}
|
||||||
|
Arc::new(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This query exists only to be used when resolving short-hand associated types
|
/// This query exists only to be used when resolving short-hand associated types
|
||||||
|
|
|
@ -191,12 +191,6 @@ pub struct EnumVariantId {
|
||||||
pub struct LocalEnumVariantId(RawId);
|
pub struct LocalEnumVariantId(RawId);
|
||||||
impl_arena_id!(LocalEnumVariantId);
|
impl_arena_id!(LocalEnumVariantId);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub enum VariantId {
|
|
||||||
EnumVariantId(EnumVariantId),
|
|
||||||
StructId(StructId),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct StructFieldId {
|
pub struct StructFieldId {
|
||||||
pub parent: VariantId,
|
pub parent: VariantId,
|
||||||
|
@ -437,6 +431,13 @@ impl_froms!(
|
||||||
ImplId
|
ImplId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum VariantId {
|
||||||
|
EnumVariantId(EnumVariantId),
|
||||||
|
StructId(StructId),
|
||||||
|
}
|
||||||
|
impl_froms!(VariantId: EnumVariantId, StructId);
|
||||||
|
|
||||||
trait Intern {
|
trait Intern {
|
||||||
type ID;
|
type ID;
|
||||||
fn intern(self, db: &impl db::DefDatabase) -> Self::ID;
|
fn intern(self, db: &impl db::DefDatabase) -> Self::ID;
|
||||||
|
|
|
@ -324,7 +324,7 @@ impl RootDatabase {
|
||||||
hir::db::ExprScopesQuery
|
hir::db::ExprScopesQuery
|
||||||
hir::db::InferQuery
|
hir::db::InferQuery
|
||||||
hir::db::TypeForDefQuery
|
hir::db::TypeForDefQuery
|
||||||
hir::db::TypeForFieldQuery
|
hir::db::FieldTypesQuery
|
||||||
hir::db::CallableItemSignatureQuery
|
hir::db::CallableItemSignatureQuery
|
||||||
hir::db::GenericPredicatesQuery
|
hir::db::GenericPredicatesQuery
|
||||||
hir::db::GenericDefaultsQuery
|
hir::db::GenericDefaultsQuery
|
||||||
|
|
Loading…
Reference in a new issue