diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
commit | f05d7b41a719d848844b054a16477b29d0f063c6 (patch) | |
tree | 0a8a0946e8aef2ce64d4c13d0035ba41cce2daf3 /crates/ra_hir/src/semantics.rs | |
parent | 73ff610e41959e3e7c78a2b4b25b086883132956 (diff) | |
parent | 6b7cb8b5ab539fc4333ce34bc29bf77c976f232a (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Hasn't fixed tests yet.
Diffstat (limited to 'crates/ra_hir/src/semantics.rs')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 381 |
1 files changed, 282 insertions, 99 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 6a49c424a..6f3b3dc9a 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors}; | |||
6 | 6 | ||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, VariantId, | 9 | AsMacroCall, FunctionId, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
@@ -24,8 +24,8 @@ use crate::{ | |||
24 | diagnostics::Diagnostic, | 24 | diagnostics::Diagnostic, |
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, |
27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, |
28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 28 | ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, |
29 | }; | 29 | }; |
30 | use resolver::TypeNs; | 30 | use resolver::TypeNs; |
31 | 31 | ||
@@ -83,7 +83,13 @@ impl PathResolution { | |||
83 | /// Primary API to get semantic information, like types, from syntax trees. | 83 | /// Primary API to get semantic information, like types, from syntax trees. |
84 | pub struct Semantics<'db, DB> { | 84 | pub struct Semantics<'db, DB> { |
85 | pub db: &'db DB, | 85 | pub db: &'db DB, |
86 | imp: SemanticsImpl<'db>, | ||
87 | } | ||
88 | |||
89 | pub struct SemanticsImpl<'db> { | ||
90 | pub db: &'db dyn HirDatabase, | ||
86 | s2d_cache: RefCell<SourceToDefCache>, | 91 | s2d_cache: RefCell<SourceToDefCache>, |
92 | expansion_info_cache: RefCell<FxHashMap<HirFileId, Option<ExpansionInfo>>>, | ||
87 | cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, | 93 | cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, |
88 | } | 94 | } |
89 | 95 | ||
@@ -95,23 +101,199 @@ impl<DB> fmt::Debug for Semantics<'_, DB> { | |||
95 | 101 | ||
96 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { | 102 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { |
97 | pub fn new(db: &DB) -> Semantics<DB> { | 103 | pub fn new(db: &DB) -> Semantics<DB> { |
98 | Semantics { db, s2d_cache: Default::default(), cache: Default::default() } | 104 | let impl_ = SemanticsImpl::new(db); |
105 | Semantics { db, imp: impl_ } | ||
99 | } | 106 | } |
100 | 107 | ||
101 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { | 108 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { |
102 | let tree = self.db.parse(file_id).tree(); | 109 | self.imp.parse(file_id) |
103 | self.cache(tree.syntax().clone(), file_id.into()); | ||
104 | tree | ||
105 | } | 110 | } |
106 | 111 | ||
107 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | 112 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { |
108 | let file_id = d.source().file_id; | 113 | let file_id = d.source().file_id; |
109 | let root = self.db.parse_or_expand(file_id).unwrap(); | 114 | let root = self.db.parse_or_expand(file_id).unwrap(); |
110 | self.cache(root, file_id); | 115 | self.imp.cache(root, file_id); |
111 | d.ast(self.db) | 116 | d.ast(self.db.upcast()) |
112 | } | 117 | } |
113 | 118 | ||
114 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 119 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
120 | self.imp.expand(macro_call) | ||
121 | } | ||
122 | |||
123 | pub fn expand_hypothetical( | ||
124 | &self, | ||
125 | actual_macro_call: &ast::MacroCall, | ||
126 | hypothetical_args: &ast::TokenTree, | ||
127 | token_to_map: SyntaxToken, | ||
128 | ) -> Option<(SyntaxNode, SyntaxToken)> { | ||
129 | self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) | ||
130 | } | ||
131 | |||
132 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | ||
133 | self.imp.descend_into_macros(token) | ||
134 | } | ||
135 | |||
136 | pub fn descend_node_at_offset<N: ast::AstNode>( | ||
137 | &self, | ||
138 | node: &SyntaxNode, | ||
139 | offset: TextSize, | ||
140 | ) -> Option<N> { | ||
141 | self.imp.descend_node_at_offset(node, offset).find_map(N::cast) | ||
142 | } | ||
143 | |||
144 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | ||
145 | self.imp.original_range(node) | ||
146 | } | ||
147 | |||
148 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
149 | self.imp.diagnostics_range(diagnostics) | ||
150 | } | ||
151 | |||
152 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | ||
153 | self.imp.ancestors_with_macros(node) | ||
154 | } | ||
155 | |||
156 | pub fn ancestors_at_offset_with_macros( | ||
157 | &self, | ||
158 | node: &SyntaxNode, | ||
159 | offset: TextSize, | ||
160 | ) -> impl Iterator<Item = SyntaxNode> + '_ { | ||
161 | self.imp.ancestors_at_offset_with_macros(node, offset) | ||
162 | } | ||
163 | |||
164 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | ||
165 | /// search up until it is of the target AstNode type | ||
166 | pub fn find_node_at_offset_with_macros<N: AstNode>( | ||
167 | &self, | ||
168 | node: &SyntaxNode, | ||
169 | offset: TextSize, | ||
170 | ) -> Option<N> { | ||
171 | self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | ||
172 | } | ||
173 | |||
174 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | ||
175 | /// descend it and find again | ||
176 | pub fn find_node_at_offset_with_descend<N: AstNode>( | ||
177 | &self, | ||
178 | node: &SyntaxNode, | ||
179 | offset: TextSize, | ||
180 | ) -> Option<N> { | ||
181 | if let Some(it) = find_node_at_offset(&node, offset) { | ||
182 | return Some(it); | ||
183 | } | ||
184 | |||
185 | self.imp.descend_node_at_offset(node, offset).find_map(N::cast) | ||
186 | } | ||
187 | |||
188 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | ||
189 | self.imp.type_of_expr(expr) | ||
190 | } | ||
191 | |||
192 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { | ||
193 | self.imp.type_of_pat(pat) | ||
194 | } | ||
195 | |||
196 | pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { | ||
197 | self.imp.type_of_self(param) | ||
198 | } | ||
199 | |||
200 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | ||
201 | self.imp.resolve_method_call(call).map(Function::from) | ||
202 | } | ||
203 | |||
204 | pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { | ||
205 | self.imp.resolve_method_call_as_callable(call) | ||
206 | } | ||
207 | |||
208 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | ||
209 | self.imp.resolve_field(field) | ||
210 | } | ||
211 | |||
212 | pub fn resolve_record_field( | ||
213 | &self, | ||
214 | field: &ast::RecordExprField, | ||
215 | ) -> Option<(Field, Option<Local>)> { | ||
216 | self.imp.resolve_record_field(field) | ||
217 | } | ||
218 | |||
219 | pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { | ||
220 | self.imp.resolve_record_field_pat(field) | ||
221 | } | ||
222 | |||
223 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | ||
224 | self.imp.resolve_macro_call(macro_call) | ||
225 | } | ||
226 | |||
227 | pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { | ||
228 | self.imp.resolve_path(path) | ||
229 | } | ||
230 | |||
231 | pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { | ||
232 | self.imp.resolve_variant(record_lit).map(VariantDef::from) | ||
233 | } | ||
234 | |||
235 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | ||
236 | self.imp.lower_path(path) | ||
237 | } | ||
238 | |||
239 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | ||
240 | self.imp.resolve_bind_pat_to_const(pat) | ||
241 | } | ||
242 | |||
243 | // FIXME: use this instead? | ||
244 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; | ||
245 | |||
246 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { | ||
247 | self.imp.record_literal_missing_fields(literal) | ||
248 | } | ||
249 | |||
250 | pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { | ||
251 | self.imp.record_pattern_missing_fields(pattern) | ||
252 | } | ||
253 | |||
254 | pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { | ||
255 | let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned(); | ||
256 | T::to_def(&self.imp, src) | ||
257 | } | ||
258 | |||
259 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { | ||
260 | self.imp.to_module_def(file) | ||
261 | } | ||
262 | |||
263 | pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { | ||
264 | self.imp.scope(node) | ||
265 | } | ||
266 | |||
267 | pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { | ||
268 | self.imp.scope_at_offset(node, offset) | ||
269 | } | ||
270 | |||
271 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { | ||
272 | self.imp.scope_for_def(def) | ||
273 | } | ||
274 | |||
275 | pub fn assert_contains_node(&self, node: &SyntaxNode) { | ||
276 | self.imp.assert_contains_node(node) | ||
277 | } | ||
278 | } | ||
279 | |||
280 | impl<'db> SemanticsImpl<'db> { | ||
281 | fn new(db: &'db dyn HirDatabase) -> Self { | ||
282 | SemanticsImpl { | ||
283 | db, | ||
284 | s2d_cache: Default::default(), | ||
285 | cache: Default::default(), | ||
286 | expansion_info_cache: Default::default(), | ||
287 | } | ||
288 | } | ||
289 | |||
290 | fn parse(&self, file_id: FileId) -> ast::SourceFile { | ||
291 | let tree = self.db.parse(file_id).tree(); | ||
292 | self.cache(tree.syntax().clone(), file_id.into()); | ||
293 | tree | ||
294 | } | ||
295 | |||
296 | fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | ||
115 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); | 297 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); |
116 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 298 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
117 | let file_id = sa.expand(self.db, macro_call)?; | 299 | let file_id = sa.expand(self.db, macro_call)?; |
@@ -120,7 +302,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
120 | Some(node) | 302 | Some(node) |
121 | } | 303 | } |
122 | 304 | ||
123 | pub fn expand_hypothetical( | 305 | fn expand_hypothetical( |
124 | &self, | 306 | &self, |
125 | actual_macro_call: &ast::MacroCall, | 307 | actual_macro_call: &ast::MacroCall, |
126 | hypothetical_args: &ast::TokenTree, | 308 | hypothetical_args: &ast::TokenTree, |
@@ -130,24 +312,38 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
130 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | 312 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); |
131 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 313 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
132 | let krate = sa.resolver.krate()?; | 314 | let krate = sa.resolver.krate()?; |
133 | let macro_call_id = macro_call | 315 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { |
134 | .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | 316 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) |
135 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | 317 | })?; |
136 | } | 318 | hir_expand::db::expand_hypothetical( |
137 | 319 | self.db.upcast(), | |
138 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 320 | macro_call_id, |
321 | hypothetical_args, | ||
322 | token_to_map, | ||
323 | ) | ||
324 | } | ||
325 | |||
326 | fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | ||
327 | let _p = profile("descend_into_macros"); | ||
139 | let parent = token.parent(); | 328 | let parent = token.parent(); |
140 | let parent = self.find_file(parent); | 329 | let parent = self.find_file(parent); |
141 | let sa = self.analyze2(parent.as_ref(), None); | 330 | let sa = self.analyze2(parent.as_ref(), None); |
142 | 331 | ||
143 | let token = successors(Some(parent.with_value(token)), |token| { | 332 | let token = successors(Some(parent.with_value(token)), |token| { |
333 | self.db.check_canceled(); | ||
144 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | 334 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; |
145 | let tt = macro_call.token_tree()?; | 335 | let tt = macro_call.token_tree()?; |
146 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { | 336 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { |
147 | return None; | 337 | return None; |
148 | } | 338 | } |
149 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | 339 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; |
150 | let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?; | 340 | let token = self |
341 | .expansion_info_cache | ||
342 | .borrow_mut() | ||
343 | .entry(file_id) | ||
344 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
345 | .as_ref()? | ||
346 | .map_token_down(token.as_ref())?; | ||
151 | 347 | ||
152 | self.cache(find_root(&token.value.parent()), token.file_id); | 348 | self.cache(find_root(&token.value.parent()), token.file_id); |
153 | 349 | ||
@@ -159,35 +355,36 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
159 | token.value | 355 | token.value |
160 | } | 356 | } |
161 | 357 | ||
162 | pub fn descend_node_at_offset<N: ast::AstNode>( | 358 | fn descend_node_at_offset( |
163 | &self, | 359 | &self, |
164 | node: &SyntaxNode, | 360 | node: &SyntaxNode, |
165 | offset: TextSize, | 361 | offset: TextSize, |
166 | ) -> Option<N> { | 362 | ) -> impl Iterator<Item = SyntaxNode> + '_ { |
167 | // Handle macro token cases | 363 | // Handle macro token cases |
168 | node.token_at_offset(offset) | 364 | node.token_at_offset(offset) |
169 | .map(|token| self.descend_into_macros(token)) | 365 | .map(|token| self.descend_into_macros(token)) |
170 | .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) | 366 | .map(|it| self.ancestors_with_macros(it.parent())) |
367 | .flatten() | ||
171 | } | 368 | } |
172 | 369 | ||
173 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | 370 | fn original_range(&self, node: &SyntaxNode) -> FileRange { |
174 | let node = self.find_file(node.clone()); | 371 | let node = self.find_file(node.clone()); |
175 | original_range(self.db, node.as_ref()) | 372 | original_range(self.db, node.as_ref()) |
176 | } | 373 | } |
177 | 374 | ||
178 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 375 | fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
179 | let src = diagnostics.source(); | 376 | let src = diagnostics.source(); |
180 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | 377 | let root = self.db.parse_or_expand(src.file_id).unwrap(); |
181 | let node = src.value.to_node(&root); | 378 | let node = src.value.to_node(&root); |
182 | original_range(self.db, src.with_value(&node)) | 379 | original_range(self.db, src.with_value(&node)) |
183 | } | 380 | } |
184 | 381 | ||
185 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 382 | fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
186 | let node = self.find_file(node); | 383 | let node = self.find_file(node); |
187 | node.ancestors_with_macros(self.db).map(|it| it.value) | 384 | node.ancestors_with_macros(self.db.upcast()).map(|it| it.value) |
188 | } | 385 | } |
189 | 386 | ||
190 | pub fn ancestors_at_offset_with_macros( | 387 | fn ancestors_at_offset_with_macros( |
191 | &self, | 388 | &self, |
192 | node: &SyntaxNode, | 389 | node: &SyntaxNode, |
193 | offset: TextSize, | 390 | offset: TextSize, |
@@ -197,120 +394,104 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
197 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 394 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) |
198 | } | 395 | } |
199 | 396 | ||
200 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | 397 | fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
201 | /// search up until it is of the target AstNode type | 398 | self.analyze(expr.syntax()).type_of_expr(self.db, &expr) |
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 | } | 399 | } |
209 | 400 | ||
210 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | 401 | fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { |
211 | /// descend it and find again | 402 | self.analyze(pat.syntax()).type_of_pat(self.db, &pat) |
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 | } | 403 | } |
222 | 404 | ||
223 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 405 | fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { |
224 | self.analyze(expr.syntax()).type_of(self.db, &expr) | 406 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) |
225 | } | 407 | } |
226 | 408 | ||
227 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { | 409 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { |
228 | self.analyze(pat.syntax()).type_of_pat(self.db, &pat) | 410 | self.analyze(call.syntax()).resolve_method_call(self.db, call) |
229 | } | 411 | } |
230 | 412 | ||
231 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 413 | fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { |
232 | self.analyze(call.syntax()).resolve_method_call(self.db, call) | 414 | // FIXME: this erases Substs |
415 | let func = self.resolve_method_call(call)?; | ||
416 | let ty = self.db.value_ty(func.into()); | ||
417 | let resolver = self.analyze(call.syntax()).resolver; | ||
418 | let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?; | ||
419 | let mut res = ty.as_callable(self.db)?; | ||
420 | res.is_bound_method = true; | ||
421 | Some(res) | ||
233 | } | 422 | } |
234 | 423 | ||
235 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | 424 | fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { |
236 | self.analyze(field.syntax()).resolve_field(self.db, field) | 425 | self.analyze(field.syntax()).resolve_field(self.db, field) |
237 | } | 426 | } |
238 | 427 | ||
239 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> { | 428 | fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> { |
240 | self.analyze(field.syntax()).resolve_record_field(self.db, field) | 429 | self.analyze(field.syntax()).resolve_record_field(self.db, field) |
241 | } | 430 | } |
242 | 431 | ||
243 | pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { | 432 | fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { |
244 | self.analyze(field.syntax()).resolve_record_field_pat(self.db, field) | 433 | self.analyze(field.syntax()).resolve_record_field_pat(self.db, field) |
245 | } | 434 | } |
246 | 435 | ||
247 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | 436 | fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { |
248 | let sa = self.analyze(macro_call.syntax()); | 437 | let sa = self.analyze(macro_call.syntax()); |
249 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); | 438 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); |
250 | sa.resolve_macro_call(self.db, macro_call) | 439 | sa.resolve_macro_call(self.db, macro_call) |
251 | } | 440 | } |
252 | 441 | ||
253 | pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { | 442 | fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { |
254 | self.analyze(path.syntax()).resolve_path(self.db, path) | 443 | self.analyze(path.syntax()).resolve_path(self.db, path) |
255 | } | 444 | } |
256 | 445 | ||
257 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { | 446 | fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { |
258 | self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) | 447 | self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) |
259 | } | 448 | } |
260 | 449 | ||
261 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | 450 | fn lower_path(&self, path: &ast::Path) -> Option<Path> { |
262 | let src = self.find_file(path.syntax().clone()); | 451 | let src = self.find_file(path.syntax().clone()); |
263 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) | 452 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) |
264 | } | 453 | } |
265 | 454 | ||
266 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | 455 | fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { |
267 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) | 456 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) |
268 | } | 457 | } |
269 | 458 | ||
270 | // FIXME: use this instead? | 459 | fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { |
271 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; | ||
272 | |||
273 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { | ||
274 | self.analyze(literal.syntax()) | 460 | self.analyze(literal.syntax()) |
275 | .record_literal_missing_fields(self.db, literal) | 461 | .record_literal_missing_fields(self.db, literal) |
276 | .unwrap_or_default() | 462 | .unwrap_or_default() |
277 | } | 463 | } |
278 | 464 | ||
279 | pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { | 465 | fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { |
280 | self.analyze(pattern.syntax()) | 466 | self.analyze(pattern.syntax()) |
281 | .record_pattern_missing_fields(self.db, pattern) | 467 | .record_pattern_missing_fields(self.db, pattern) |
282 | .unwrap_or_default() | 468 | .unwrap_or_default() |
283 | } | 469 | } |
284 | 470 | ||
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 | |||
290 | fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { | 471 | fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { |
291 | let mut cache = self.s2d_cache.borrow_mut(); | 472 | let mut cache = self.s2d_cache.borrow_mut(); |
292 | let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; | 473 | let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; |
293 | f(&mut ctx) | 474 | f(&mut ctx) |
294 | } | 475 | } |
295 | 476 | ||
296 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { | 477 | fn to_module_def(&self, file: FileId) -> Option<Module> { |
297 | self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) | 478 | self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) |
298 | } | 479 | } |
299 | 480 | ||
300 | pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db, DB> { | 481 | fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { |
301 | let node = self.find_file(node.clone()); | 482 | let node = self.find_file(node.clone()); |
302 | let resolver = self.analyze2(node.as_ref(), None).resolver; | 483 | let resolver = self.analyze2(node.as_ref(), None).resolver; |
303 | SemanticsScope { db: self.db, resolver } | 484 | SemanticsScope { db: self.db, resolver } |
304 | } | 485 | } |
305 | 486 | ||
306 | pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db, DB> { | 487 | fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { |
307 | let node = self.find_file(node.clone()); | 488 | let node = self.find_file(node.clone()); |
308 | let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; | 489 | let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; |
309 | SemanticsScope { db: self.db, resolver } | 490 | SemanticsScope { db: self.db, resolver } |
310 | } | 491 | } |
311 | 492 | ||
312 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db, DB> { | 493 | fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { |
313 | let resolver = def.id.resolver(self.db); | 494 | let resolver = def.id.resolver(self.db.upcast()); |
314 | SemanticsScope { db: self.db, resolver } | 495 | SemanticsScope { db: self.db, resolver } |
315 | } | 496 | } |
316 | 497 | ||
@@ -331,12 +512,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
331 | ChildContainer::DefWithBodyId(def) => { | 512 | ChildContainer::DefWithBodyId(def) => { |
332 | return SourceAnalyzer::new_for_body(self.db, def, src, offset) | 513 | return SourceAnalyzer::new_for_body(self.db, def, src, offset) |
333 | } | 514 | } |
334 | ChildContainer::TraitId(it) => it.resolver(self.db), | 515 | ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), |
335 | ChildContainer::ImplId(it) => it.resolver(self.db), | 516 | ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), |
336 | ChildContainer::ModuleId(it) => it.resolver(self.db), | 517 | ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()), |
337 | ChildContainer::EnumId(it) => it.resolver(self.db), | 518 | ChildContainer::EnumId(it) => it.resolver(self.db.upcast()), |
338 | ChildContainer::VariantId(it) => it.resolver(self.db), | 519 | ChildContainer::VariantId(it) => it.resolver(self.db.upcast()), |
339 | ChildContainer::GenericDefId(it) => it.resolver(self.db), | 520 | ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()), |
521 | ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()), | ||
340 | }; | 522 | }; |
341 | SourceAnalyzer::new_for_resolver(resolver, src) | 523 | SourceAnalyzer::new_for_resolver(resolver, src) |
342 | } | 524 | } |
@@ -348,7 +530,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
348 | assert!(prev == None || prev == Some(file_id)) | 530 | assert!(prev == None || prev == Some(file_id)) |
349 | } | 531 | } |
350 | 532 | ||
351 | pub fn assert_contains_node(&self, node: &SyntaxNode) { | 533 | fn assert_contains_node(&self, node: &SyntaxNode) { |
352 | self.find_file(node.clone()); | 534 | self.find_file(node.clone()); |
353 | } | 535 | } |
354 | 536 | ||
@@ -382,14 +564,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
382 | pub trait ToDef: AstNode + Clone { | 564 | pub trait ToDef: AstNode + Clone { |
383 | type Def; | 565 | type Def; |
384 | 566 | ||
385 | fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def>; | 567 | fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>; |
386 | } | 568 | } |
387 | 569 | ||
388 | macro_rules! to_def_impls { | 570 | macro_rules! to_def_impls { |
389 | ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( | 571 | ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( |
390 | impl ToDef for $ast { | 572 | impl ToDef for $ast { |
391 | type Def = $def; | 573 | type Def = $def; |
392 | fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def> { | 574 | fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> { |
393 | sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) | 575 | sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) |
394 | } | 576 | } |
395 | } | 577 | } |
@@ -398,18 +580,18 @@ macro_rules! to_def_impls { | |||
398 | 580 | ||
399 | to_def_impls![ | 581 | to_def_impls![ |
400 | (crate::Module, ast::Module, module_to_def), | 582 | (crate::Module, ast::Module, module_to_def), |
401 | (crate::Struct, ast::StructDef, struct_to_def), | 583 | (crate::Struct, ast::Struct, struct_to_def), |
402 | (crate::Enum, ast::EnumDef, enum_to_def), | 584 | (crate::Enum, ast::Enum, enum_to_def), |
403 | (crate::Union, ast::UnionDef, union_to_def), | 585 | (crate::Union, ast::Union, union_to_def), |
404 | (crate::Trait, ast::TraitDef, trait_to_def), | 586 | (crate::Trait, ast::Trait, trait_to_def), |
405 | (crate::ImplDef, ast::ImplDef, impl_to_def), | 587 | (crate::ImplDef, ast::Impl, impl_to_def), |
406 | (crate::TypeAlias, ast::TypeAliasDef, type_alias_to_def), | 588 | (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), |
407 | (crate::Const, ast::ConstDef, const_to_def), | 589 | (crate::Const, ast::Const, const_to_def), |
408 | (crate::Static, ast::StaticDef, static_to_def), | 590 | (crate::Static, ast::Static, static_to_def), |
409 | (crate::Function, ast::FnDef, fn_to_def), | 591 | (crate::Function, ast::Fn, fn_to_def), |
410 | (crate::Field, ast::RecordFieldDef, record_field_to_def), | 592 | (crate::Field, ast::RecordField, record_field_to_def), |
411 | (crate::Field, ast::TupleFieldDef, tuple_field_to_def), | 593 | (crate::Field, ast::TupleField, tuple_field_to_def), |
412 | (crate::EnumVariant, ast::EnumVariant, enum_variant_to_def), | 594 | (crate::EnumVariant, ast::Variant, enum_variant_to_def), |
413 | (crate::TypeParam, ast::TypeParam, type_param_to_def), | 595 | (crate::TypeParam, ast::TypeParam, type_param_to_def), |
414 | (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros | 596 | (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros |
415 | (crate::Local, ast::BindPat, bind_pat_to_def), | 597 | (crate::Local, ast::BindPat, bind_pat_to_def), |
@@ -419,12 +601,13 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode { | |||
419 | node.ancestors().last().unwrap() | 601 | node.ancestors().last().unwrap() |
420 | } | 602 | } |
421 | 603 | ||
422 | pub struct SemanticsScope<'a, DB> { | 604 | #[derive(Debug)] |
423 | pub db: &'a DB, | 605 | pub struct SemanticsScope<'a> { |
606 | pub db: &'a dyn HirDatabase, | ||
424 | resolver: Resolver, | 607 | resolver: Resolver, |
425 | } | 608 | } |
426 | 609 | ||
427 | impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | 610 | impl<'a> SemanticsScope<'a> { |
428 | pub fn module(&self) -> Option<Module> { | 611 | pub fn module(&self) -> Option<Module> { |
429 | Some(Module { id: self.resolver.module()? }) | 612 | Some(Module { id: self.resolver.module()? }) |
430 | } | 613 | } |
@@ -433,13 +616,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | |||
433 | // FIXME: rename to visible_traits to not repeat scope? | 616 | // FIXME: rename to visible_traits to not repeat scope? |
434 | pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { | 617 | pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { |
435 | let resolver = &self.resolver; | 618 | let resolver = &self.resolver; |
436 | resolver.traits_in_scope(self.db) | 619 | resolver.traits_in_scope(self.db.upcast()) |
437 | } | 620 | } |
438 | 621 | ||
439 | pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { | 622 | pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { |
440 | let resolver = &self.resolver; | 623 | let resolver = &self.resolver; |
441 | 624 | ||
442 | resolver.process_all_names(self.db, &mut |name, def| { | 625 | resolver.process_all_names(self.db.upcast(), &mut |name, def| { |
443 | let def = match def { | 626 | let def = match def { |
444 | resolver::ScopeDef::PerNs(it) => { | 627 | resolver::ScopeDef::PerNs(it) => { |
445 | let items = ScopeDef::all_items(it); | 628 | let items = ScopeDef::all_items(it); |