From e8505f14d4bb8d393ca77ec234dd1c99826a2d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 1 Jul 2020 12:43:36 +0300 Subject: Try to reduce Semantics monomorphisations --- crates/ra_hir/src/semantics.rs | 209 ++++++++++++++++++++++++++++++++++++----- crates/ra_ide_db/src/lib.rs | 8 +- 2 files changed, 193 insertions(+), 24 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 810c49d6f..fbea9ad57 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -83,6 +83,11 @@ impl PathResolution { /// Primary API to get semantic information, like types, from syntax trees. pub struct Semantics<'db, DB> { pub db: &'db DB, + impl_: SemanticsImpl<'db>, +} + +pub struct SemanticsImpl<'db> { + pub db: &'db dyn HirDatabase, s2d_cache: RefCell, cache: RefCell>, } @@ -95,7 +100,166 @@ impl fmt::Debug for Semantics<'_, DB> { impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn new(db: &DB) -> Semantics { - Semantics { db, s2d_cache: Default::default(), cache: Default::default() } + let impl_ = SemanticsImpl::new(db); + Semantics { db, impl_ } + } + + pub fn parse(&self, file_id: FileId) -> ast::SourceFile { + self.impl_.parse(file_id) + } + + pub fn ast(&self, d: &T) -> ::AST { + self.impl_.ast(d) + } + + pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { + self.impl_.expand(macro_call) + } + + pub fn expand_hypothetical( + &self, + actual_macro_call: &ast::MacroCall, + hypothetical_args: &ast::TokenTree, + token_to_map: SyntaxToken, + ) -> Option<(SyntaxNode, SyntaxToken)> { + self.impl_.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) + } + + pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { + self.impl_.descend_into_macros(token) + } + + pub fn descend_node_at_offset( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> Option { + self.impl_.descend_node_at_offset(node, offset) + } + + pub fn original_range(&self, node: &SyntaxNode) -> FileRange { + self.impl_.original_range(node) + } + + pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { + self.impl_.diagnostics_range(diagnostics) + } + + pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { + self.impl_.ancestors_with_macros(node) + } + + pub fn ancestors_at_offset_with_macros( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> impl Iterator + '_ { + self.impl_.ancestors_at_offset_with_macros(node, offset) + } + + /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, + /// search up until it is of the target AstNode type + pub fn find_node_at_offset_with_macros( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> Option { + self.impl_.find_node_at_offset_with_macros(node, offset) + } + + /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, + /// descend it and find again + pub fn find_node_at_offset_with_descend( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> Option { + self.impl_.find_node_at_offset_with_descend(node, offset) + } + + pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { + self.impl_.type_of_expr(expr) + } + + pub fn type_of_pat(&self, pat: &ast::Pat) -> Option { + self.impl_.type_of_pat(pat) + } + + pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { + self.impl_.resolve_method_call(call) + } + + pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { + self.impl_.resolve_field(field) + } + + pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option)> { + self.impl_.resolve_record_field(field) + } + + pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option { + self.impl_.resolve_record_field_pat(field) + } + + pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option { + self.impl_.resolve_macro_call(macro_call) + } + + pub fn resolve_path(&self, path: &ast::Path) -> Option { + self.impl_.resolve_path(path) + } + + pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option { + self.impl_.resolve_variant(record_lit) + } + + pub fn lower_path(&self, path: &ast::Path) -> Option { + self.impl_.lower_path(path) + } + + pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option { + self.impl_.resolve_bind_pat_to_const(pat) + } + + // 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<(Field, Type)> { + self.impl_.record_literal_missing_fields(literal) + } + + pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { + self.impl_.record_pattern_missing_fields(pattern) + } + + pub fn to_def(&self, src: &T) -> Option { + self.impl_.to_def(src) + } + + pub fn to_module_def(&self, file: FileId) -> Option { + self.impl_.to_module_def(file) + } + + pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { + self.impl_.scope(node) + } + + pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { + self.impl_.scope_at_offset(node, offset) + } + + pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { + self.impl_.scope_for_def(def) + } + + pub fn assert_contains_node(&self, node: &SyntaxNode) { + self.impl_.assert_contains_node(node) + } +} + +impl<'db> SemanticsImpl<'db> { + pub fn new(db: &'db dyn HirDatabase) -> Self { + Self { db, s2d_cache: Default::default(), cache: Default::default() } } pub fn parse(&self, file_id: FileId) -> ast::SourceFile { @@ -108,7 +272,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { let file_id = d.source().file_id; let root = self.db.parse_or_expand(file_id).unwrap(); self.cache(root, file_id); - d.ast(self.db) + d.ast(self.db.upcast()) } pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { @@ -130,9 +294,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); let krate = sa.resolver.krate()?; - let macro_call_id = macro_call - .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; - hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) + let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { + sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) + })?; + hir_expand::db::expand_hypothetical( + self.db.upcast(), + macro_call_id, + hypothetical_args, + token_to_map, + ) } pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { @@ -147,7 +317,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { return None; } let file_id = sa.expand(self.db, token.with_value(¯o_call))?; - let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?; + let token = file_id.expansion_info(self.db.upcast())?.map_token_down(token.as_ref())?; self.cache(find_root(&token.value.parent()), token.file_id); @@ -184,7 +354,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { let node = self.find_file(node); - node.ancestors_with_macros(self.db).map(|it| it.value) + node.ancestors_with_macros(self.db.upcast()).map(|it| it.value) } pub fn ancestors_at_offset_with_macros( @@ -197,8 +367,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) } - /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, - /// search up until it is of the target AstNode type pub fn find_node_at_offset_with_macros( &self, node: &SyntaxNode, @@ -207,8 +375,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) } - /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, - /// descend it and find again pub fn find_node_at_offset_with_descend( &self, node: &SyntaxNode, @@ -267,9 +433,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) } - // 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<(Field, Type)> { self.analyze(literal.syntax()) .record_literal_missing_fields(self.db, literal) @@ -310,7 +473,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { } pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - let resolver = def.id.resolver(self.db); + let resolver = def.id.resolver(self.db.upcast()); SemanticsScope { db: self.db, resolver } } @@ -331,12 +494,12 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { ChildContainer::DefWithBodyId(def) => { return SourceAnalyzer::new_for_body(self.db, def, src, offset) } - ChildContainer::TraitId(it) => it.resolver(self.db), - ChildContainer::ImplId(it) => it.resolver(self.db), - ChildContainer::ModuleId(it) => it.resolver(self.db), - ChildContainer::EnumId(it) => it.resolver(self.db), - ChildContainer::VariantId(it) => it.resolver(self.db), - ChildContainer::GenericDefId(it) => it.resolver(self.db), + ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), + ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), + ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()), + ChildContainer::EnumId(it) => it.resolver(self.db.upcast()), + ChildContainer::VariantId(it) => it.resolver(self.db.upcast()), + ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()), }; SourceAnalyzer::new_for_resolver(resolver, src) } @@ -382,14 +545,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub trait ToDef: AstNode + Clone { type Def; - fn to_def(sema: &Semantics, src: InFile) -> Option; + fn to_def(sema: &SemanticsImpl, src: InFile) -> Option; } macro_rules! to_def_impls { ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( impl ToDef for $ast { type Def = $def; - fn to_def(sema: &Semantics, src: InFile) -> Option { + fn to_def(sema: &SemanticsImpl, src: InFile) -> Option { sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) } } diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index a808de4f1..c78071ad6 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -13,7 +13,7 @@ mod wasm_shims; use std::sync::Arc; -use hir::db::{AstDatabase, DefDatabase}; +use hir::db::{AstDatabase, DefDatabase, HirDatabase}; use ra_db::{ salsa::{self, Database, Durability}, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, @@ -52,6 +52,12 @@ impl Upcast for RootDatabase { } } +impl Upcast for RootDatabase { + fn upcast(&self) -> &(dyn HirDatabase + 'static) { + &*self + } +} + impl FileLoader for RootDatabase { fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) -- cgit v1.2.3 From d89827f9e01d855e9116a0d5276ffe1dad34ed3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 1 Jul 2020 14:32:18 +0300 Subject: Make less code generic --- crates/ra_hir/src/semantics.rs | 116 +++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 69 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index fbea9ad57..3d78f71c1 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -83,7 +83,7 @@ impl PathResolution { /// Primary API to get semantic information, like types, from syntax trees. pub struct Semantics<'db, DB> { pub db: &'db DB, - impl_: SemanticsImpl<'db>, + imp: SemanticsImpl<'db>, } pub struct SemanticsImpl<'db> { @@ -101,19 +101,22 @@ impl fmt::Debug for Semantics<'_, DB> { impl<'db, DB: HirDatabase> Semantics<'db, DB> { pub fn new(db: &DB) -> Semantics { let impl_ = SemanticsImpl::new(db); - Semantics { db, impl_ } + Semantics { db, imp: impl_ } } pub fn parse(&self, file_id: FileId) -> ast::SourceFile { - self.impl_.parse(file_id) + self.imp.parse(file_id) } pub fn ast(&self, d: &T) -> ::AST { - self.impl_.ast(d) + let file_id = d.source().file_id; + let root = self.db.parse_or_expand(file_id).unwrap(); + self.imp.cache(root, file_id); + d.ast(self.db.upcast()) } pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { - self.impl_.expand(macro_call) + self.imp.expand(macro_call) } pub fn expand_hypothetical( @@ -122,11 +125,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { hypothetical_args: &ast::TokenTree, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { - self.impl_.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) + self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) } pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { - self.impl_.descend_into_macros(token) + self.imp.descend_into_macros(token) } pub fn descend_node_at_offset( @@ -134,19 +137,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { node: &SyntaxNode, offset: TextSize, ) -> Option { - self.impl_.descend_node_at_offset(node, offset) + self.imp.descend_node_at_offset(node, offset).find_map(N::cast) } pub fn original_range(&self, node: &SyntaxNode) -> FileRange { - self.impl_.original_range(node) + self.imp.original_range(node) } pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { - self.impl_.diagnostics_range(diagnostics) + self.imp.diagnostics_range(diagnostics) } pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { - self.impl_.ancestors_with_macros(node) + self.imp.ancestors_with_macros(node) } pub fn ancestors_at_offset_with_macros( @@ -154,7 +157,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { node: &SyntaxNode, offset: TextSize, ) -> impl Iterator + '_ { - self.impl_.ancestors_at_offset_with_macros(node, offset) + self.imp.ancestors_at_offset_with_macros(node, offset) } /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, @@ -164,7 +167,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { node: &SyntaxNode, offset: TextSize, ) -> Option { - self.impl_.find_node_at_offset_with_macros(node, offset) + self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) } /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, @@ -174,86 +177,91 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { node: &SyntaxNode, offset: TextSize, ) -> Option { - self.impl_.find_node_at_offset_with_descend(node, offset) + if let Some(it) = find_node_at_offset(&node, offset) { + return Some(it); + } + + self.imp.descend_node_at_offset(node, offset).find_map(N::cast) } pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { - self.impl_.type_of_expr(expr) + self.imp.type_of_expr(expr) } pub fn type_of_pat(&self, pat: &ast::Pat) -> Option { - self.impl_.type_of_pat(pat) + self.imp.type_of_pat(pat) } pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { - self.impl_.resolve_method_call(call) + self.imp.resolve_method_call(call) } pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { - self.impl_.resolve_field(field) + self.imp.resolve_field(field) } pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option)> { - self.impl_.resolve_record_field(field) + self.imp.resolve_record_field(field) } pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option { - self.impl_.resolve_record_field_pat(field) + self.imp.resolve_record_field_pat(field) } pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option { - self.impl_.resolve_macro_call(macro_call) + self.imp.resolve_macro_call(macro_call) } pub fn resolve_path(&self, path: &ast::Path) -> Option { - self.impl_.resolve_path(path) + self.imp.resolve_path(path) } pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option { - self.impl_.resolve_variant(record_lit) + self.imp.resolve_variant(record_lit) } pub fn lower_path(&self, path: &ast::Path) -> Option { - self.impl_.lower_path(path) + self.imp.lower_path(path) } pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option { - self.impl_.resolve_bind_pat_to_const(pat) + self.imp.resolve_bind_pat_to_const(pat) } // 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<(Field, Type)> { - self.impl_.record_literal_missing_fields(literal) + self.imp.record_literal_missing_fields(literal) } pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { - self.impl_.record_pattern_missing_fields(pattern) + self.imp.record_pattern_missing_fields(pattern) } pub fn to_def(&self, src: &T) -> Option { - self.impl_.to_def(src) + let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned(); + T::to_def(&self.imp, src) } pub fn to_module_def(&self, file: FileId) -> Option { - self.impl_.to_module_def(file) + self.imp.to_module_def(file) } pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { - self.impl_.scope(node) + self.imp.scope(node) } pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { - self.impl_.scope_at_offset(node, offset) + self.imp.scope_at_offset(node, offset) } pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - self.impl_.scope_for_def(def) + self.imp.scope_for_def(def) } pub fn assert_contains_node(&self, node: &SyntaxNode) { - self.impl_.assert_contains_node(node) + self.imp.assert_contains_node(node) } } @@ -268,13 +276,6 @@ impl<'db> SemanticsImpl<'db> { tree } - pub fn ast(&self, d: &T) -> ::AST { - let file_id = d.source().file_id; - let root = self.db.parse_or_expand(file_id).unwrap(); - self.cache(root, file_id); - d.ast(self.db.upcast()) - } - pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); @@ -329,15 +330,16 @@ impl<'db> SemanticsImpl<'db> { token.value } - pub fn descend_node_at_offset( + pub fn descend_node_at_offset( &self, node: &SyntaxNode, offset: TextSize, - ) -> Option { + ) -> impl Iterator + '_ { // Handle macro token cases node.token_at_offset(offset) .map(|token| self.descend_into_macros(token)) - .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) + .map(|it| self.ancestors_with_macros(it.parent())) + .flatten() } pub fn original_range(&self, node: &SyntaxNode) -> FileRange { @@ -367,25 +369,6 @@ impl<'db> SemanticsImpl<'db> { .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) } - pub fn find_node_at_offset_with_macros( - &self, - node: &SyntaxNode, - offset: TextSize, - ) -> Option { - self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) - } - - pub fn find_node_at_offset_with_descend( - &self, - node: &SyntaxNode, - offset: TextSize, - ) -> Option { - if let Some(it) = find_node_at_offset(&node, offset) { - return Some(it); - } - self.descend_node_at_offset(&node, offset) - } - pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { self.analyze(expr.syntax()).type_of(self.db, &expr) } @@ -445,11 +428,6 @@ impl<'db> SemanticsImpl<'db> { .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) - } - fn with_ctx T, T>(&self, f: F) -> T { let mut cache = self.s2d_cache.borrow_mut(); let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; @@ -504,7 +482,7 @@ impl<'db> SemanticsImpl<'db> { SourceAnalyzer::new_for_resolver(resolver, src) } - fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { + pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { assert!(root_node.parent().is_none()); let mut cache = self.cache.borrow_mut(); let prev = cache.insert(root_node, file_id); @@ -520,7 +498,7 @@ impl<'db> SemanticsImpl<'db> { cache.get(root_node).copied() } - fn find_file(&self, node: SyntaxNode) -> InFile { + pub fn find_file(&self, node: SyntaxNode) -> InFile { let root_node = find_root(&node); let file_id = self.lookup(&root_node).unwrap_or_else(|| { panic!( -- cgit v1.2.3