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 { pub fn module(self, db: &impl HirDatabase) -> Module {
match self { match self {
VariantDef::Struct(it) => it.module(db), 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> { pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
let expr_id = self.expr_id(&record_lit.clone().into())?; 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> { pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> {
let pat_id = self.pat_id(&record_pat.clone().into())?; 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( pub fn resolve_macro_call(

View file

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

View file

@ -16,9 +16,9 @@ use hir_expand::name::{self, Name};
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
ty::{ ty::{
autoderef, method_resolution, op, traits::InEnvironment, CallableDef, InferTy, IntTy, autoderef, method_resolution, op, traits::InEnvironment, utils::variant_data, CallableDef,
Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs,
TypeWalk, Uncertain, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
}, },
}; };
@ -218,9 +218,13 @@ 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_types = let field_types =
def_id.map(|it| self.db.field_types(it.into())).unwrap_or_default(); 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() { 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 =
Some(field) => Some(field), variant_data.as_ref().and_then(|it| match it.field(&field.name) {
Some(local_id) => {
Some(StructFieldId { parent: def_id.unwrap(), local_id })
}
None => { None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField { self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: tgt_expr, expr: tgt_expr,
@ -230,10 +234,10 @@ 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.into()); self.result.record_field_resolutions.insert(field.expr, field_def);
} }
let field_ty = 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); .subst(&substs);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 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 super::{BindingMode, InferenceContext};
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
ty::{Substs, Ty, TypeCtor, TypeWalk}, ty::{utils::variant_data, Substs, Ty, TypeCtor, TypeWalk},
}; };
impl<'a, D: HirDatabase> InferenceContext<'a, D> { impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@ -26,16 +26,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
default_bm: BindingMode, default_bm: BindingMode,
) -> Ty { ) -> Ty {
let (ty, def) = self.resolve_variant(path); let (ty, def) = self.resolve_variant(path);
let var_data = def.map(|it| variant_data(self.db, it));
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);
let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default(); 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 = var_data
.and_then(|d| d.field(self.db, &Name::new_tuple_field(i))) .as_ref()
.map_or(Ty::Unknown, |field| field_tys[field.id].clone()) .and_then(|d| d.field(&Name::new_tuple_field(i)))
.map_or(Ty::Unknown, |field| field_tys[field].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);
@ -53,6 +55,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
id: PatId, id: PatId,
) -> Ty { ) -> Ty {
let (ty, def) = self.resolve_variant(path); let (ty, def) = self.resolve_variant(path);
let var_data = def.map(|it| variant_data(self.db, it));
if let Some(variant) = def { if let Some(variant) = def {
self.write_variant_resolution(id.into(), variant); 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(); 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 = var_data.as_ref().and_then(|it| it.field(&subpat.name));
let expected_ty = matching_field let expected_ty =
.map_or(Ty::Unknown, |field| field_tys[field.id].clone()) matching_field.map_or(Ty::Unknown, |field| field_tys[field].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.pat, &expected_ty, default_bm); self.infer_pat(subpat.pat, &expected_ty, default_bm);
} }

View file

@ -28,7 +28,7 @@ use crate::{
db::HirDatabase, db::HirDatabase,
ty::{ ty::{
primitive::{FloatTy, IntTy}, 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, util::make_mut_slice,
Adt, Const, Enum, EnumVariant, Function, ImplBlock, ModuleDef, Path, Static, Struct, Trait, Adt, Const, Enum, EnumVariant, Function, ImplBlock, ModuleDef, Path, Static, Struct, Trait,
@ -514,13 +514,11 @@ pub(crate) fn field_types_query(
db: &impl HirDatabase, db: &impl HirDatabase,
variant_id: VariantId, variant_id: VariantId,
) -> Arc<ArenaMap<LocalStructFieldId, Ty>> { ) -> Arc<ArenaMap<LocalStructFieldId, Ty>> {
let (resolver, var_data) = match variant_id { let var_data = variant_data(db, variant_id);
VariantId::StructId(it) => (it.resolver(db), db.struct_data(it).variant_data.clone()), let resolver = match variant_id {
VariantId::UnionId(it) => (it.resolver(db), db.union_data(it).variant_data.clone()), VariantId::StructId(it) => it.resolver(db),
VariantId::EnumVariantId(it) => ( VariantId::UnionId(it) => it.resolver(db),
it.parent.resolver(db), VariantId::EnumVariantId(it) => it.parent.resolver(db),
db.enum_data(it.parent).variants[it.local_id].variant_data.clone(),
),
}; };
let mut res = ArenaMap::default(); let mut res = ArenaMap::default();
for (field_id, field_data) in var_data.fields().iter() { 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 //! 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`). //! query, but can't be computed directly from `*Data` (ie, which need a `db`).
use std::sync::Arc;
use hir_def::{ use hir_def::{
adt::VariantData,
db::DefDatabase, db::DefDatabase,
resolver::{HasResolver, TypeNs}, resolver::{HasResolver, TypeNs},
type_ref::TypeRef, type_ref::TypeRef,
TraitId, TypeAliasId, TraitId, TypeAliasId, VariantId,
}; };
use hir_expand::name::{self, Name}; use hir_expand::name::{self, Name};
@ -61,3 +63,13 @@ pub(super) fn associated_type_by_name_including_super_traits(
.into_iter() .into_iter()
.find_map(|t| db.trait_data(t).associated_type_by_name(name)) .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()
}
}
}