Use Id for variats

This commit is contained in:
Aleksey Kladov 2019-11-27 16:25:01 +03:00
parent 17680f6060
commit 9fa46ff5c6
7 changed files with 60 additions and 52 deletions

View File

@ -534,14 +534,6 @@ impl VariantDef {
}
}
pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
match self {
VariantDef::Struct(it) => it.field(db, name),
VariantDef::Union(it) => it.field(db, name),
VariantDef::EnumVariant(it) => it.field(db, name),
}
}
pub fn module(self, db: &impl HirDatabase) -> Module {
match self {
VariantDef::Struct(it) => it.module(db),

View File

@ -229,12 +229,12 @@ impl SourceAnalyzer {
pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
let expr_id = self.expr_id(&record_lit.clone().into())?;
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into())
}
pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> {
let pat_id = self.pat_id(&record_pat.clone().into())?;
self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into())
}
pub fn resolve_macro_call(

View File

@ -28,7 +28,7 @@ use hir_def::{
path::{known, Path},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{Mutability, TypeRef},
AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId,
AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
};
use hir_expand::{diagnostics::DiagnosticSink, name};
use ra_arena::map::ArenaMap;
@ -41,7 +41,7 @@ use super::{
ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
TypeWalk, Uncertain,
};
use crate::{db::HirDatabase, ty::infer::diagnostics::InferenceDiagnostic, VariantDef};
use crate::{db::HirDatabase, ty::infer::diagnostics::InferenceDiagnostic};
macro_rules! ty_app {
($ctor:pat, $param:pat) => {
@ -124,7 +124,7 @@ pub struct InferenceResult {
/// For each field in record literal, records the field it resolves to.
record_field_resolutions: FxHashMap<ExprId, StructFieldId>,
/// For each struct literal, records the variant it resolves to.
variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
/// For each associated item record what it resolves to
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
diagnostics: Vec<InferenceDiagnostic>,
@ -143,10 +143,10 @@ impl InferenceResult {
pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> {
self.record_field_resolutions.get(&expr).copied()
}
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
self.variant_resolutions.get(&id.into()).copied()
}
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantDef> {
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
self.variant_resolutions.get(&id.into()).copied()
}
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
@ -248,7 +248,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.result.field_resolutions.insert(expr, field);
}
fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantDef) {
fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
self.result.variant_resolutions.insert(id, variant);
}
@ -511,7 +511,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
})
}
fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) {
let path = match path {
Some(path) => path,
None => return (Ty::Unknown, None),
@ -524,13 +524,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
let ty = self.db.ty(strukt.into());
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(VariantDef::Struct(strukt.into())))
(ty, Some(strukt.into()))
}
Some(TypeNs::EnumVariantId(var)) => {
let substs = Ty::substs_from_path(self.db, resolver, path, var.into());
let ty = self.db.ty(var.parent.into());
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(VariantDef::EnumVariant(var.into())))
(ty, Some(var.into()))
}
Some(_) | None => (Ty::Unknown, None),
}

View File

@ -16,9 +16,9 @@ use hir_expand::name::{self, Name};
use crate::{
db::HirDatabase,
ty::{
autoderef, method_resolution, op, traits::InEnvironment, CallableDef, InferTy, IntTy,
Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
TypeWalk, Uncertain,
autoderef, method_resolution, op, traits::InEnvironment, utils::variant_data, CallableDef,
InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs,
TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
},
};
@ -218,22 +218,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
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();
let variant_data = def_id.map(|it| variant_data(self.db, it));
for (field_idx, field) in fields.iter().enumerate() {
let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
Some(field) => Some(field),
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: tgt_expr,
field: field_idx,
});
None
}
});
let field_def =
variant_data.as_ref().and_then(|it| match it.field(&field.name) {
Some(local_id) => {
Some(StructFieldId { parent: def_id.unwrap(), local_id })
}
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: tgt_expr,
field: field_idx,
});
None
}
});
if let Some(field_def) = field_def {
self.result.record_field_resolutions.insert(field.expr, field_def.into());
self.result.record_field_resolutions.insert(field.expr, field_def);
}
let field_ty = field_def
.map_or(Ty::Unknown, |it| field_types[it.id].clone())
.map_or(Ty::Unknown, |it| field_types[it.local_id].clone())
.subst(&substs);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
}

View File

@ -14,7 +14,7 @@ use test_utils::tested_by;
use super::{BindingMode, InferenceContext};
use crate::{
db::HirDatabase,
ty::{Substs, Ty, TypeCtor, TypeWalk},
ty::{utils::variant_data, Substs, Ty, TypeCtor, TypeWalk},
};
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@ -26,16 +26,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
default_bm: BindingMode,
) -> Ty {
let (ty, def) = self.resolve_variant(path);
let var_data = def.map(|it| variant_data(self.db, it));
self.unify(&ty, expected);
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() {
let expected_ty = def
.and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
.map_or(Ty::Unknown, |field| field_tys[field.id].clone())
let expected_ty = var_data
.as_ref()
.and_then(|d| d.field(&Name::new_tuple_field(i)))
.map_or(Ty::Unknown, |field| field_tys[field].clone())
.subst(&substs);
let expected_ty = self.normalize_associated_types_in(expected_ty);
self.infer_pat(subpat, &expected_ty, default_bm);
@ -53,6 +55,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
id: PatId,
) -> Ty {
let (ty, def) = self.resolve_variant(path);
let var_data = def.map(|it| variant_data(self.db, it));
if let Some(variant) = def {
self.write_variant_resolution(id.into(), variant);
}
@ -63,10 +66,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default();
for subpat in subpats {
let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
let expected_ty = matching_field
.map_or(Ty::Unknown, |field| field_tys[field.id].clone())
.subst(&substs);
let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
let expected_ty =
matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone()).subst(&substs);
let expected_ty = self.normalize_associated_types_in(expected_ty);
self.infer_pat(subpat.pat, &expected_ty, default_bm);
}

View File

@ -28,7 +28,7 @@ use crate::{
db::HirDatabase,
ty::{
primitive::{FloatTy, IntTy},
utils::{all_super_traits, associated_type_by_name_including_super_traits},
utils::{all_super_traits, associated_type_by_name_including_super_traits, variant_data},
},
util::make_mut_slice,
Adt, Const, Enum, EnumVariant, Function, ImplBlock, ModuleDef, Path, Static, Struct, Trait,
@ -514,13 +514,11 @@ pub(crate) fn field_types_query(
db: &impl HirDatabase,
variant_id: VariantId,
) -> Arc<ArenaMap<LocalStructFieldId, Ty>> {
let (resolver, var_data) = match variant_id {
VariantId::StructId(it) => (it.resolver(db), db.struct_data(it).variant_data.clone()),
VariantId::UnionId(it) => (it.resolver(db), db.union_data(it).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 = variant_data(db, variant_id);
let resolver = match variant_id {
VariantId::StructId(it) => it.resolver(db),
VariantId::UnionId(it) => it.resolver(db),
VariantId::EnumVariantId(it) => it.parent.resolver(db),
};
let mut res = ArenaMap::default();
for (field_id, field_data) in var_data.fields().iter() {

View File

@ -1,11 +1,13 @@
//! Helper functions for working with def, which don't need to be a separate
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
use std::sync::Arc;
use hir_def::{
adt::VariantData,
db::DefDatabase,
resolver::{HasResolver, TypeNs},
type_ref::TypeRef,
TraitId, TypeAliasId,
TraitId, TypeAliasId, VariantId,
};
use hir_expand::name::{self, Name};
@ -61,3 +63,13 @@ pub(super) fn associated_type_by_name_including_super_traits(
.into_iter()
.find_map(|t| db.trait_data(t).associated_type_by_name(name))
}
pub(super) fn variant_data(db: &impl DefDatabase, var: VariantId) -> Arc<VariantData> {
match var {
VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
VariantId::EnumVariantId(it) => {
db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
}
}
}