From 4c29214bba65d23e18875bd060325c489be5a8e4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 7 Apr 2020 17:09:02 +0200 Subject: Move computation of missing fields into hir --- crates/ra_hir/src/code_model.rs | 31 ++++--------- crates/ra_hir/src/semantics.rs | 28 +++++++---- crates/ra_hir/src/source_analyzer.rs | 90 ++++++++++++++++++++++++++++-------- 3 files changed, 98 insertions(+), 51 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index c6f3bdb8e..9baebf643 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -1027,8 +1027,16 @@ impl Type { ty: Ty, ) -> Option { let krate = resolver.krate()?; + Some(Type::new_with_resolver_inner(db, krate, resolver, ty)) + } + pub(crate) fn new_with_resolver_inner( + db: &dyn HirDatabase, + krate: CrateId, + resolver: &Resolver, + ty: Ty, + ) -> Type { let environment = TraitEnvironment::lower(db, &resolver); - Some(Type { krate, ty: InEnvironment { value: ty, environment } }) + Type { krate, ty: InEnvironment { value: ty, environment } } } fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { @@ -1152,27 +1160,6 @@ impl Type { res } - pub fn variant_fields( - &self, - db: &dyn HirDatabase, - def: VariantDef, - ) -> Vec<(StructField, Type)> { - // FIXME: check that ty and def match - match &self.ty.value { - Ty::Apply(a_ty) => { - let field_types = db.field_types(def.into()); - def.fields(db) - .into_iter() - .map(|it| { - let ty = field_types[it.id].clone().subst(&a_ty.parameters); - (it, self.derived(ty)) - }) - .collect() - } - _ => Vec::new(), - } - } - pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { // There should be no inference vars in types passed here // FIXME check that? diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 2ad231d36..2707e422d 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -23,7 +23,7 @@ use crate::{ semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, - Origin, Path, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef, + Origin, Path, ScopeDef, StructField, Trait, Type, TypeParam, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -187,14 +187,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.analyze(field.syntax()).resolve_record_field(self.db, field) } - pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option { - self.analyze(record_lit.syntax()).resolve_record_literal(self.db, record_lit) - } - - pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option { - self.analyze(record_pat.syntax()).resolve_record_pattern(record_pat) - } - pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option { let sa = self.analyze(macro_call.syntax()); let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); @@ -212,6 +204,24 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { // FIXME: use this instead? // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option; + pub fn record_literal_missing_fields( + &self, + literal: &ast::RecordLit, + ) -> Vec<(StructField, Type)> { + self.analyze(literal.syntax()) + .record_literal_missing_fields(self.db, literal) + .unwrap_or_default() + } + + pub fn record_pattern_missing_fields( + &self, + pattern: &ast::RecordPat, + ) -> Vec<(StructField, Type)> { + self.analyze(pattern.syntax()) + .record_pattern_missing_fields(self.db, pattern) + .unwrap_or_default() + } + pub fn to_def(&self, src: &T) -> Option { let src = self.find_file(src.syntax().clone()).with_value(src).cloned(); T::to_def(self, src) diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 815ca158c..45631f8fd 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -14,10 +14,13 @@ use hir_def::{ }, expr::{ExprId, Pat, PatId}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, - AsMacroCall, DefWithBodyId, + AsMacroCall, DefWithBodyId, LocalStructFieldId, StructFieldId, VariantId, }; use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; -use hir_ty::InferenceResult; +use hir_ty::{ + expr::{record_literal_missing_fields, record_pattern_missing_fields}, + InferenceResult, Substs, Ty, +}; use ra_syntax::{ ast::{self, AstNode}, SyntaxNode, SyntaxNodePtr, TextUnit, @@ -25,8 +28,10 @@ use ra_syntax::{ use crate::{ db::HirDatabase, semantics::PathResolution, Adt, Const, EnumVariant, Function, Local, MacroDef, - ModPath, ModuleDef, Path, PathKind, Static, Struct, Trait, Type, TypeAlias, TypeParam, + ModPath, ModuleDef, Path, PathKind, Static, Struct, StructField, Trait, Type, TypeAlias, + TypeParam, }; +use ra_db::CrateId; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of /// original source files. It should not be used inside the HIR itself. @@ -164,23 +169,6 @@ impl SourceAnalyzer { Some((struct_field.into(), local)) } - pub(crate) fn resolve_record_literal( - &self, - db: &dyn HirDatabase, - record_lit: &ast::RecordLit, - ) -> Option { - let expr_id = self.expr_id(db, &record_lit.clone().into())?; - self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) - } - - pub(crate) fn resolve_record_pattern( - &self, - record_pat: &ast::RecordPat, - ) -> Option { - let pat_id = self.pat_id(&record_pat.clone().into())?; - self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into()) - } - pub(crate) fn resolve_macro_call( &self, db: &dyn HirDatabase, @@ -231,6 +219,68 @@ impl SourceAnalyzer { resolve_hir_path(db, &self.resolver, &hir_path) } + pub(crate) fn record_literal_missing_fields( + &self, + db: &dyn HirDatabase, + literal: &ast::RecordLit, + ) -> Option> { + let krate = self.resolver.krate()?; + let body = self.body.as_ref()?; + let infer = self.infer.as_ref()?; + + let expr_id = self.expr_id(db, &literal.clone().into())?; + let substs = match &infer.type_of_expr[expr_id] { + Ty::Apply(a_ty) => &a_ty.parameters, + _ => return None, + }; + + let (variant, missing_fields, _exhaustive) = + record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; + let res = self.missing_fields(db, krate, substs, variant, missing_fields); + Some(res) + } + + pub(crate) fn record_pattern_missing_fields( + &self, + db: &dyn HirDatabase, + pattern: &ast::RecordPat, + ) -> Option> { + let krate = self.resolver.krate()?; + let body = self.body.as_ref()?; + let infer = self.infer.as_ref()?; + + let pat_id = self.pat_id(&pattern.clone().into())?; + let substs = match &infer.type_of_pat[pat_id] { + Ty::Apply(a_ty) => &a_ty.parameters, + _ => return None, + }; + + let (variant, missing_fields) = + record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; + let res = self.missing_fields(db, krate, substs, variant, missing_fields); + Some(res) + } + + fn missing_fields( + &self, + db: &dyn HirDatabase, + krate: CrateId, + substs: &Substs, + variant: VariantId, + missing_fields: Vec, + ) -> Vec<(StructField, Type)> { + let field_types = db.field_types(variant); + + missing_fields + .into_iter() + .map(|local_id| { + let field = StructFieldId { parent: variant, local_id }; + let ty = field_types[local_id].clone().subst(substs); + (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty)) + }) + .collect() + } + pub(crate) fn expand( &self, db: &dyn HirDatabase, -- cgit v1.2.3