Skip to content

Commit 248b656

Browse files
bors[bot]lnicola
andauthored
Merge #5162
5162: Try to reduce Semantics monomorphisations r=matklad a=lnicola Co-authored-by: Laurențiu Nicola <[email protected]>
2 parents f372b13 + d89827f commit 248b656

File tree

2 files changed

+204
-57
lines changed

2 files changed

+204
-57
lines changed

crates/ra_hir/src/semantics.rs

Lines changed: 197 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ impl PathResolution {
8383
/// Primary API to get semantic information, like types, from syntax trees.
8484
pub struct Semantics<'db, DB> {
8585
pub db: &'db DB,
86+
imp: SemanticsImpl<'db>,
87+
}
88+
89+
pub struct SemanticsImpl<'db> {
90+
pub db: &'db dyn HirDatabase,
8691
s2d_cache: RefCell<SourceToDefCache>,
8792
cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
8893
}
@@ -95,20 +100,180 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
95100

96101
impl<'db, DB: HirDatabase> Semantics<'db, DB> {
97102
pub fn new(db: &DB) -> Semantics<DB> {
98-
Semantics { db, s2d_cache: Default::default(), cache: Default::default() }
103+
let impl_ = SemanticsImpl::new(db);
104+
Semantics { db, imp: impl_ }
99105
}
100106

101107
pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
102-
let tree = self.db.parse(file_id).tree();
103-
self.cache(tree.syntax().clone(), file_id.into());
104-
tree
108+
self.imp.parse(file_id)
105109
}
106110

107111
pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
108112
let file_id = d.source().file_id;
109113
let root = self.db.parse_or_expand(file_id).unwrap();
110-
self.cache(root, file_id);
111-
d.ast(self.db)
114+
self.imp.cache(root, file_id);
115+
d.ast(self.db.upcast())
116+
}
117+
118+
pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
119+
self.imp.expand(macro_call)
120+
}
121+
122+
pub fn expand_hypothetical(
123+
&self,
124+
actual_macro_call: &ast::MacroCall,
125+
hypothetical_args: &ast::TokenTree,
126+
token_to_map: SyntaxToken,
127+
) -> Option<(SyntaxNode, SyntaxToken)> {
128+
self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map)
129+
}
130+
131+
pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
132+
self.imp.descend_into_macros(token)
133+
}
134+
135+
pub fn descend_node_at_offset<N: ast::AstNode>(
136+
&self,
137+
node: &SyntaxNode,
138+
offset: TextSize,
139+
) -> Option<N> {
140+
self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
141+
}
142+
143+
pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
144+
self.imp.original_range(node)
145+
}
146+
147+
pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
148+
self.imp.diagnostics_range(diagnostics)
149+
}
150+
151+
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
152+
self.imp.ancestors_with_macros(node)
153+
}
154+
155+
pub fn ancestors_at_offset_with_macros(
156+
&self,
157+
node: &SyntaxNode,
158+
offset: TextSize,
159+
) -> impl Iterator<Item = SyntaxNode> + '_ {
160+
self.imp.ancestors_at_offset_with_macros(node, offset)
161+
}
162+
163+
/// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
164+
/// search up until it is of the target AstNode type
165+
pub fn find_node_at_offset_with_macros<N: AstNode>(
166+
&self,
167+
node: &SyntaxNode,
168+
offset: TextSize,
169+
) -> Option<N> {
170+
self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
171+
}
172+
173+
/// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
174+
/// descend it and find again
175+
pub fn find_node_at_offset_with_descend<N: AstNode>(
176+
&self,
177+
node: &SyntaxNode,
178+
offset: TextSize,
179+
) -> Option<N> {
180+
if let Some(it) = find_node_at_offset(&node, offset) {
181+
return Some(it);
182+
}
183+
184+
self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
185+
}
186+
187+
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
188+
self.imp.type_of_expr(expr)
189+
}
190+
191+
pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
192+
self.imp.type_of_pat(pat)
193+
}
194+
195+
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
196+
self.imp.resolve_method_call(call)
197+
}
198+
199+
pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
200+
self.imp.resolve_field(field)
201+
}
202+
203+
pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> {
204+
self.imp.resolve_record_field(field)
205+
}
206+
207+
pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
208+
self.imp.resolve_record_field_pat(field)
209+
}
210+
211+
pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
212+
self.imp.resolve_macro_call(macro_call)
213+
}
214+
215+
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
216+
self.imp.resolve_path(path)
217+
}
218+
219+
pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> {
220+
self.imp.resolve_variant(record_lit)
221+
}
222+
223+
pub fn lower_path(&self, path: &ast::Path) -> Option<Path> {
224+
self.imp.lower_path(path)
225+
}
226+
227+
pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
228+
self.imp.resolve_bind_pat_to_const(pat)
229+
}
230+
231+
// FIXME: use this instead?
232+
// pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
233+
234+
pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> {
235+
self.imp.record_literal_missing_fields(literal)
236+
}
237+
238+
pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
239+
self.imp.record_pattern_missing_fields(pattern)
240+
}
241+
242+
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
243+
let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned();
244+
T::to_def(&self.imp, src)
245+
}
246+
247+
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
248+
self.imp.to_module_def(file)
249+
}
250+
251+
pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
252+
self.imp.scope(node)
253+
}
254+
255+
pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
256+
self.imp.scope_at_offset(node, offset)
257+
}
258+
259+
pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
260+
self.imp.scope_for_def(def)
261+
}
262+
263+
pub fn assert_contains_node(&self, node: &SyntaxNode) {
264+
self.imp.assert_contains_node(node)
265+
}
266+
}
267+
268+
impl<'db> SemanticsImpl<'db> {
269+
pub fn new(db: &'db dyn HirDatabase) -> Self {
270+
Self { db, s2d_cache: Default::default(), cache: Default::default() }
271+
}
272+
273+
pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
274+
let tree = self.db.parse(file_id).tree();
275+
self.cache(tree.syntax().clone(), file_id.into());
276+
tree
112277
}
113278

114279
pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
@@ -130,9 +295,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
130295
self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
131296
let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
132297
let krate = sa.resolver.krate()?;
133-
let macro_call_id = macro_call
134-
.as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
135-
hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map)
298+
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
299+
sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
300+
})?;
301+
hir_expand::db::expand_hypothetical(
302+
self.db.upcast(),
303+
macro_call_id,
304+
hypothetical_args,
305+
token_to_map,
306+
)
136307
}
137308

138309
pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
@@ -147,7 +318,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
147318
return None;
148319
}
149320
let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
150-
let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?;
321+
let token = file_id.expansion_info(self.db.upcast())?.map_token_down(token.as_ref())?;
151322

152323
self.cache(find_root(&token.value.parent()), token.file_id);
153324

@@ -159,15 +330,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
159330
token.value
160331
}
161332

162-
pub fn descend_node_at_offset<N: ast::AstNode>(
333+
pub fn descend_node_at_offset(
163334
&self,
164335
node: &SyntaxNode,
165336
offset: TextSize,
166-
) -> Option<N> {
337+
) -> impl Iterator<Item = SyntaxNode> + '_ {
167338
// Handle macro token cases
168339
node.token_at_offset(offset)
169340
.map(|token| self.descend_into_macros(token))
170-
.find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast))
341+
.map(|it| self.ancestors_with_macros(it.parent()))
342+
.flatten()
171343
}
172344

173345
pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
@@ -184,7 +356,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
184356

185357
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
186358
let node = self.find_file(node);
187-
node.ancestors_with_macros(self.db).map(|it| it.value)
359+
node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
188360
}
189361

190362
pub fn ancestors_at_offset_with_macros(
@@ -197,29 +369,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
197369
.kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
198370
}
199371

200-
/// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
201-
/// search up until it is of the target AstNode type
202-
pub fn find_node_at_offset_with_macros<N: AstNode>(
203-
&self,
204-
node: &SyntaxNode,
205-
offset: TextSize,
206-
) -> Option<N> {
207-
self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
208-
}
209-
210-
/// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
211-
/// descend it and find again
212-
pub fn find_node_at_offset_with_descend<N: AstNode>(
213-
&self,
214-
node: &SyntaxNode,
215-
offset: TextSize,
216-
) -> Option<N> {
217-
if let Some(it) = find_node_at_offset(&node, offset) {
218-
return Some(it);
219-
}
220-
self.descend_node_at_offset(&node, offset)
221-
}
222-
223372
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
224373
self.analyze(expr.syntax()).type_of(self.db, &expr)
225374
}
@@ -267,9 +416,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
267416
self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
268417
}
269418

270-
// FIXME: use this instead?
271-
// pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
272-
273419
pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> {
274420
self.analyze(literal.syntax())
275421
.record_literal_missing_fields(self.db, literal)
@@ -282,11 +428,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
282428
.unwrap_or_default()
283429
}
284430

285-
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
286-
let src = self.find_file(src.syntax().clone()).with_value(src).cloned();
287-
T::to_def(self, src)
288-
}
289-
290431
fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T {
291432
let mut cache = self.s2d_cache.borrow_mut();
292433
let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
@@ -310,7 +451,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
310451
}
311452

312453
pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
313-
let resolver = def.id.resolver(self.db);
454+
let resolver = def.id.resolver(self.db.upcast());
314455
SemanticsScope { db: self.db, resolver }
315456
}
316457

@@ -331,17 +472,17 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
331472
ChildContainer::DefWithBodyId(def) => {
332473
return SourceAnalyzer::new_for_body(self.db, def, src, offset)
333474
}
334-
ChildContainer::TraitId(it) => it.resolver(self.db),
335-
ChildContainer::ImplId(it) => it.resolver(self.db),
336-
ChildContainer::ModuleId(it) => it.resolver(self.db),
337-
ChildContainer::EnumId(it) => it.resolver(self.db),
338-
ChildContainer::VariantId(it) => it.resolver(self.db),
339-
ChildContainer::GenericDefId(it) => it.resolver(self.db),
475+
ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
476+
ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
477+
ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()),
478+
ChildContainer::EnumId(it) => it.resolver(self.db.upcast()),
479+
ChildContainer::VariantId(it) => it.resolver(self.db.upcast()),
480+
ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
340481
};
341482
SourceAnalyzer::new_for_resolver(resolver, src)
342483
}
343484

344-
fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
485+
pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
345486
assert!(root_node.parent().is_none());
346487
let mut cache = self.cache.borrow_mut();
347488
let prev = cache.insert(root_node, file_id);
@@ -357,7 +498,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
357498
cache.get(root_node).copied()
358499
}
359500

360-
fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
501+
pub fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
361502
let root_node = find_root(&node);
362503
let file_id = self.lookup(&root_node).unwrap_or_else(|| {
363504
panic!(
@@ -382,14 +523,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
382523
pub trait ToDef: AstNode + Clone {
383524
type Def;
384525

385-
fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def>;
526+
fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>;
386527
}
387528

388529
macro_rules! to_def_impls {
389530
($(($def:path, $ast:path, $meth:ident)),* ,) => {$(
390531
impl ToDef for $ast {
391532
type Def = $def;
392-
fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def> {
533+
fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> {
393534
sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
394535
}
395536
}

crates/ra_ide_db/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod wasm_shims;
1313

1414
use std::sync::Arc;
1515

16-
use hir::db::{AstDatabase, DefDatabase};
16+
use hir::db::{AstDatabase, DefDatabase, HirDatabase};
1717
use ra_db::{
1818
salsa::{self, Database, Durability},
1919
Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
@@ -52,6 +52,12 @@ impl Upcast<dyn DefDatabase> for RootDatabase {
5252
}
5353
}
5454

55+
impl Upcast<dyn HirDatabase> for RootDatabase {
56+
fn upcast(&self) -> &(dyn HirDatabase + 'static) {
57+
&*self
58+
}
59+
}
60+
5561
impl FileLoader for RootDatabase {
5662
fn file_text(&self, file_id: FileId) -> Arc<String> {
5763
FileLoaderDelegate(self).file_text(file_id)

0 commit comments

Comments
 (0)