From c3f84960aa99529a3afc8f28c16e657fb071db5f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 14:53:09 +0300 Subject: Flatten expr module --- crates/ra_hir/src/code_model.rs | 2 +- crates/ra_hir/src/expr.rs | 132 ++++++++++++++++++++++++++++++++- crates/ra_hir/src/expr/validation.rs | 137 ----------------------------------- 3 files changed, 130 insertions(+), 141 deletions(-) delete mode 100644 crates/ra_hir/src/expr/validation.rs (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index dd43271f4..078bd8609 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -23,7 +23,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, - expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, + expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, generics::{GenericDef, HasGenericParams}, ids::{ AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index e4598eec0..e3733779e 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -1,12 +1,19 @@ //! FIXME: write short doc here -pub(crate) mod validation; - use std::sync::Arc; +use hir_def::path::known; +use hir_expand::diagnostics::DiagnosticSink; +use ra_syntax::ast; use ra_syntax::AstPtr; +use rustc_hash::FxHashSet; -use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; +use crate::{ + db::HirDatabase, + diagnostics::{MissingFields, MissingOkInTailExpr}, + ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, + Adt, DefWithBody, Function, HasBody, Name, Path, Resolver, +}; pub use hir_def::{ body::{ @@ -42,3 +49,122 @@ pub(crate) fn resolver_for_scope( } r } + +pub(crate) struct ExprValidator<'a, 'b: 'a> { + func: Function, + infer: Arc, + sink: &'a mut DiagnosticSink<'b>, +} + +impl<'a, 'b> ExprValidator<'a, 'b> { + pub(crate) fn new( + func: Function, + infer: Arc, + sink: &'a mut DiagnosticSink<'b>, + ) -> ExprValidator<'a, 'b> { + ExprValidator { func, infer, sink } + } + + pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { + let body = self.func.body(db); + + for e in body.exprs() { + if let (id, Expr::RecordLit { path, fields, spread }) = e { + self.validate_record_literal(id, path, fields, *spread, db); + } + } + + let body_expr = &body[body.body_expr()]; + if let Expr::Block { statements: _, tail: Some(t) } = body_expr { + self.validate_results_in_tail_expr(body.body_expr(), *t, db); + } + } + + fn validate_record_literal( + &mut self, + id: ExprId, + _path: &Option, + fields: &[RecordLitField], + spread: Option, + db: &impl HirDatabase, + ) { + if spread.is_some() { + return; + } + + let struct_def = match self.infer[id].as_adt() { + Some((Adt::Struct(s), _)) => s, + _ => return, + }; + + let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); + let missed_fields: Vec = struct_def + .fields(db) + .iter() + .filter_map(|f| { + let name = f.name(db); + if lit_fields.contains(&name) { + None + } else { + Some(name) + } + }) + .collect(); + if missed_fields.is_empty() { + return; + } + let source_map = self.func.body_source_map(db); + + if let Some(source_ptr) = source_map.expr_syntax(id) { + if let Some(expr) = source_ptr.ast.a() { + let root = source_ptr.file_syntax(db); + if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { + if let Some(field_list) = record_lit.record_field_list() { + self.sink.push(MissingFields { + file: source_ptr.file_id, + field_list: AstPtr::new(&field_list), + missed_fields, + }) + } + } + } + } + } + + fn validate_results_in_tail_expr( + &mut self, + body_id: ExprId, + id: ExprId, + db: &impl HirDatabase, + ) { + // the mismatch will be on the whole block currently + let mismatch = match self.infer.type_mismatch_for_expr(body_id) { + Some(m) => m, + None => return, + }; + + let std_result_path = known::std_result_result(); + + let resolver = self.func.resolver(db); + let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { + Some(it) => it, + _ => return, + }; + + let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); + let params = match &mismatch.expected { + Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, + _ => return, + }; + + if params.len() == 2 && ¶ms[0] == &mismatch.actual { + let source_map = self.func.body_source_map(db); + + if let Some(source_ptr) = source_map.expr_syntax(id) { + if let Some(expr) = source_ptr.ast.a() { + self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); + } + } + } + } +} diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs deleted file mode 100644 index 3054f1dce..000000000 --- a/crates/ra_hir/src/expr/validation.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! FIXME: write short doc here - -use std::sync::Arc; - -use hir_def::path::known; -use hir_expand::diagnostics::DiagnosticSink; -use ra_syntax::ast; -use rustc_hash::FxHashSet; - -use crate::{ - db::HirDatabase, - diagnostics::{MissingFields, MissingOkInTailExpr}, - expr::AstPtr, - ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, - Adt, Function, Name, Path, -}; - -use super::{Expr, ExprId, RecordLitField}; - -pub(crate) struct ExprValidator<'a, 'b: 'a> { - func: Function, - infer: Arc, - sink: &'a mut DiagnosticSink<'b>, -} - -impl<'a, 'b> ExprValidator<'a, 'b> { - pub(crate) fn new( - func: Function, - infer: Arc, - sink: &'a mut DiagnosticSink<'b>, - ) -> ExprValidator<'a, 'b> { - ExprValidator { func, infer, sink } - } - - pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { - let body = self.func.body(db); - - for e in body.exprs() { - if let (id, Expr::RecordLit { path, fields, spread }) = e { - self.validate_record_literal(id, path, fields, *spread, db); - } - } - - let body_expr = &body[body.body_expr()]; - if let Expr::Block { statements: _, tail: Some(t) } = body_expr { - self.validate_results_in_tail_expr(body.body_expr(), *t, db); - } - } - - fn validate_record_literal( - &mut self, - id: ExprId, - _path: &Option, - fields: &[RecordLitField], - spread: Option, - db: &impl HirDatabase, - ) { - if spread.is_some() { - return; - } - - let struct_def = match self.infer[id].as_adt() { - Some((Adt::Struct(s), _)) => s, - _ => return, - }; - - let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); - let missed_fields: Vec = struct_def - .fields(db) - .iter() - .filter_map(|f| { - let name = f.name(db); - if lit_fields.contains(&name) { - None - } else { - Some(name) - } - }) - .collect(); - if missed_fields.is_empty() { - return; - } - let source_map = self.func.body_source_map(db); - - if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.ast.a() { - let root = source_ptr.file_syntax(db); - if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { - if let Some(field_list) = record_lit.record_field_list() { - self.sink.push(MissingFields { - file: source_ptr.file_id, - field_list: AstPtr::new(&field_list), - missed_fields, - }) - } - } - } - } - } - - fn validate_results_in_tail_expr( - &mut self, - body_id: ExprId, - id: ExprId, - db: &impl HirDatabase, - ) { - // the mismatch will be on the whole block currently - let mismatch = match self.infer.type_mismatch_for_expr(body_id) { - Some(m) => m, - None => return, - }; - - let std_result_path = known::std_result_result(); - - let resolver = self.func.resolver(db); - let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { - Some(it) => it, - _ => return, - }; - - let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); - let params = match &mismatch.expected { - Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, - _ => return, - }; - - if params.len() == 2 && ¶ms[0] == &mismatch.actual { - let source_map = self.func.body_source_map(db); - - if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.ast.a() { - self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); - } - } - } - } -} -- cgit v1.2.3