From 1a90ad58023b065b7eecddf7f24417889a311850 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 12 Nov 2019 18:46:57 +0300 Subject: Move expression lowering to hir_def --- crates/ra_hir_def/src/body.rs | 142 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) (limited to 'crates/ra_hir_def/src/body.rs') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7447904ea..ac8f8261b 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -1,2 +1,144 @@ //! FIXME: write short doc here mod lower; + +use std::{ops::Index, sync::Arc}; + +use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; +use ra_arena::{map::ArenaMap, Arena}; +use ra_syntax::{ast, AstPtr}; +use rustc_hash::FxHashMap; + +use crate::{ + db::DefDatabase2, + expr::{Expr, ExprId, Pat, PatId}, + nameres::CrateDefMap, + path::Path, + ModuleId, +}; + +pub struct MacroResolver { + crate_def_map: Arc, + module: ModuleId, +} + +impl MacroResolver { + pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { + MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } + } + + pub(crate) fn resolve_path_as_macro( + &self, + db: &impl DefDatabase2, + path: &Path, + ) -> Option { + self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() + } +} + +/// The body of an item (function, const etc.). +#[derive(Debug, Eq, PartialEq)] +pub struct Body { + exprs: Arena, + pats: Arena, + /// The patterns for the function's parameters. While the parameter types are + /// part of the function signature, the patterns are not (they don't change + /// the external type of the function). + /// + /// If this `Body` is for the body of a constant, this will just be + /// empty. + params: Vec, + /// The `ExprId` of the actual body expression. + body_expr: ExprId, +} + +pub type ExprPtr = Either, AstPtr>; +pub type ExprSource = Source; + +pub type PatPtr = Either, AstPtr>; +pub type PatSource = Source; + +/// An item body together with the mapping from syntax nodes to HIR expression +/// IDs. This is needed to go from e.g. a position in a file to the HIR +/// expression containing it; but for type inference etc., we want to operate on +/// a structure that is agnostic to the actual positions of expressions in the +/// file, so that we don't recompute types whenever some whitespace is typed. +/// +/// One complication here is that, due to macro expansion, a single `Body` might +/// be spread across several files. So, for each ExprId and PatId, we record +/// both the HirFileId and the position inside the file. However, we only store +/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle +/// this properly for macros. +#[derive(Default, Debug, Eq, PartialEq)] +pub struct BodySourceMap { + expr_map: FxHashMap, + expr_map_back: ArenaMap, + pat_map: FxHashMap, + pat_map_back: ArenaMap, + field_map: FxHashMap<(ExprId, usize), AstPtr>, +} + +impl Body { + pub fn new( + db: &impl DefDatabase2, + resolver: MacroResolver, + file_id: HirFileId, + params: Option, + body: Option, + ) -> (Body, BodySourceMap) { + lower::lower(db, resolver, file_id, params, body) + } + + pub fn params(&self) -> &[PatId] { + &self.params + } + + pub fn body_expr(&self) -> ExprId { + self.body_expr + } + + pub fn exprs(&self) -> impl Iterator { + self.exprs.iter() + } + + pub fn pats(&self) -> impl Iterator { + self.pats.iter() + } +} + +impl Index for Body { + type Output = Expr; + + fn index(&self, expr: ExprId) -> &Expr { + &self.exprs[expr] + } +} + +impl Index for Body { + type Output = Pat; + + fn index(&self, pat: PatId) -> &Pat { + &self.pats[pat] + } +} + +impl BodySourceMap { + pub fn expr_syntax(&self, expr: ExprId) -> Option { + self.expr_map_back.get(expr).copied() + } + + pub fn node_expr(&self, node: &ast::Expr) -> Option { + self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() + } + + pub fn pat_syntax(&self, pat: PatId) -> Option { + self.pat_map_back.get(pat).copied() + } + + pub fn node_pat(&self, node: &ast::Pat) -> Option { + self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() + } + + pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr { + self.field_map[&(expr, field)] + } +} -- cgit v1.2.3