aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs83
1 files changed, 48 insertions, 35 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 66cb4b357..ca40e3b54 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,8 +7,11 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use hir_def::path::known; 10use hir_def::{
11use hir_expand::name::AsName; 11 expr::{ExprId, PatId},
12 path::known,
13};
14use hir_expand::{name::AsName, Source};
12use ra_db::FileId; 15use ra_db::FileId;
13use ra_syntax::{ 16use ra_syntax::{
14 ast::{self, AstNode}, 17 ast::{self, AstNode},
@@ -20,16 +23,12 @@ use rustc_hash::FxHashSet;
20 23
21use crate::{ 24use crate::{
22 db::HirDatabase, 25 db::HirDatabase,
23 expr::{ 26 expr::{self, BodySourceMap, ExprScopes, ScopeId},
24 self,
25 scope::{ExprScopes, ScopeId},
26 BodySourceMap,
27 },
28 ids::LocationCtx, 27 ids::LocationCtx,
29 resolve::{ScopeDef, TypeNs, ValueNs}, 28 resolve::{ScopeDef, TypeNs, ValueNs},
30 ty::method_resolution::{self, implements_trait}, 29 ty::method_resolution::{self, implements_trait},
31 AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, 30 AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, GenericParam, HasBody,
32 MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, 31 HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
33}; 32};
34 33
35fn try_get_resolver_for_node( 34fn try_get_resolver_for_node(
@@ -93,7 +92,10 @@ fn def_with_body_from_child_node(
93/// original source files. It should not be used inside the HIR itself. 92/// original source files. It should not be used inside the HIR itself.
94#[derive(Debug)] 93#[derive(Debug)]
95pub struct SourceAnalyzer { 94pub struct SourceAnalyzer {
95 // FIXME: this doesn't handle macros at all
96 file_id: FileId,
96 resolver: Resolver, 97 resolver: Resolver,
98 body_owner: Option<DefWithBody>,
97 body_source_map: Option<Arc<BodySourceMap>>, 99 body_source_map: Option<Arc<BodySourceMap>>,
98 infer: Option<Arc<crate::ty::InferenceResult>>, 100 infer: Option<Arc<crate::ty::InferenceResult>>,
99 scopes: Option<Arc<crate::expr::ExprScopes>>, 101 scopes: Option<Arc<crate::expr::ExprScopes>>,
@@ -104,9 +106,9 @@ pub enum PathResolution {
104 /// An item 106 /// An item
105 Def(crate::ModuleDef), 107 Def(crate::ModuleDef),
106 /// A local binding (only value namespace) 108 /// A local binding (only value namespace)
107 LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>), 109 Local(Local),
108 /// A generic parameter 110 /// A generic parameter
109 GenericParam(u32), 111 GenericParam(GenericParam),
110 SelfType(crate::ImplBlock), 112 SelfType(crate::ImplBlock),
111 Macro(MacroDef), 113 Macro(MacroDef),
112 AssocItem(crate::AssocItem), 114 AssocItem(crate::AssocItem),
@@ -144,17 +146,19 @@ impl SourceAnalyzer {
144 let def_with_body = def_with_body_from_child_node(db, file_id, node); 146 let def_with_body = def_with_body_from_child_node(db, file_id, node);
145 if let Some(def) = def_with_body { 147 if let Some(def) = def_with_body {
146 let source_map = def.body_source_map(db); 148 let source_map = def.body_source_map(db);
147 let scopes = db.expr_scopes(def); 149 let scopes = def.expr_scopes(db);
148 let scope = match offset { 150 let scope = match offset {
149 None => scope_for(&scopes, &source_map, &node), 151 None => scope_for(&scopes, &source_map, file_id.into(), &node),
150 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), 152 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
151 }; 153 };
152 let resolver = expr::resolver_for_scope(def.body(db), db, scope); 154 let resolver = expr::resolver_for_scope(db, def, scope);
153 SourceAnalyzer { 155 SourceAnalyzer {
154 resolver, 156 resolver,
157 body_owner: Some(def),
155 body_source_map: Some(source_map), 158 body_source_map: Some(source_map),
156 infer: Some(def.infer(db)), 159 infer: Some(def.infer(db)),
157 scopes: Some(scopes), 160 scopes: Some(scopes),
161 file_id,
158 } 162 }
159 } else { 163 } else {
160 SourceAnalyzer { 164 SourceAnalyzer {
@@ -162,20 +166,32 @@ impl SourceAnalyzer {
162 .ancestors() 166 .ancestors()
163 .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) 167 .find_map(|node| try_get_resolver_for_node(db, file_id, &node))
164 .unwrap_or_default(), 168 .unwrap_or_default(),
169 body_owner: None,
165 body_source_map: None, 170 body_source_map: None,
166 infer: None, 171 infer: None,
167 scopes: None, 172 scopes: None,
173 file_id,
168 } 174 }
169 } 175 }
170 } 176 }
171 177
178 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
179 let src = Source { file_id: self.file_id.into(), ast: expr };
180 self.body_source_map.as_ref()?.node_expr(src)
181 }
182
183 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
184 let src = Source { file_id: self.file_id.into(), ast: pat };
185 self.body_source_map.as_ref()?.node_pat(src)
186 }
187
172 pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { 188 pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
173 let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; 189 let expr_id = self.expr_id(expr)?;
174 Some(self.infer.as_ref()?[expr_id].clone()) 190 Some(self.infer.as_ref()?[expr_id].clone())
175 } 191 }
176 192
177 pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { 193 pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
178 let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; 194 let pat_id = self.pat_id(pat)?;
179 Some(self.infer.as_ref()?[pat_id].clone()) 195 Some(self.infer.as_ref()?[pat_id].clone())
180 } 196 }
181 197
@@ -188,22 +204,22 @@ impl SourceAnalyzer {
188 } 204 }
189 205
190 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 206 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
191 let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; 207 let expr_id = self.expr_id(&call.clone().into())?;
192 self.infer.as_ref()?.method_resolution(expr_id) 208 self.infer.as_ref()?.method_resolution(expr_id)
193 } 209 }
194 210
195 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { 211 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
196 let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; 212 let expr_id = self.expr_id(&field.clone().into())?;
197 self.infer.as_ref()?.field_resolution(expr_id) 213 self.infer.as_ref()?.field_resolution(expr_id)
198 } 214 }
199 215
200 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { 216 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
201 let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; 217 let expr_id = self.expr_id(&record_lit.clone().into())?;
202 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 218 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
203 } 219 }
204 220
205 pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { 221 pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> {
206 let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; 222 let pat_id = self.pat_id(&record_pat.clone().into())?;
207 self.infer.as_ref()?.variant_resolution_for_pat(pat_id) 223 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
208 } 224 }
209 225
@@ -224,7 +240,10 @@ impl SourceAnalyzer {
224 ) -> Option<PathResolution> { 240 ) -> Option<PathResolution> {
225 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 241 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
226 TypeNs::SelfType(it) => PathResolution::SelfType(it), 242 TypeNs::SelfType(it) => PathResolution::SelfType(it),
227 TypeNs::GenericParam(it) => PathResolution::GenericParam(it), 243 TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam {
244 parent: self.resolver.generic_def().unwrap(),
245 idx,
246 }),
228 TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()), 247 TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()),
229 TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), 248 TypeNs::EnumVariant(it) => PathResolution::Def(it.into()),
230 TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), 249 TypeNs::TypeAlias(it) => PathResolution::Def(it.into()),
@@ -233,16 +252,9 @@ impl SourceAnalyzer {
233 }); 252 });
234 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { 253 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
235 let res = match val { 254 let res = match val {
236 ValueNs::LocalBinding(it) => { 255 ValueNs::LocalBinding(pat_id) => {
237 // We get a `PatId` from resolver, but it actually can only 256 let var = Local { parent: self.body_owner?, pat_id };
238 // point at `BindPat`, and not at the arbitrary pattern. 257 PathResolution::Local(var)
239 let pat_ptr = self
240 .body_source_map
241 .as_ref()?
242 .pat_syntax(it)?
243 .ast // FIXME: ignoring file_id here is definitelly wrong
244 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
245 PathResolution::LocalBinding(pat_ptr)
246 } 258 }
247 ValueNs::Function(it) => PathResolution::Def(it.into()), 259 ValueNs::Function(it) => PathResolution::Def(it.into()),
248 ValueNs::Const(it) => PathResolution::Def(it.into()), 260 ValueNs::Const(it) => PathResolution::Def(it.into()),
@@ -265,13 +277,13 @@ impl SourceAnalyzer {
265 277
266 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { 278 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
267 if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { 279 if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
268 let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; 280 let expr_id = self.expr_id(&path_expr.into())?;
269 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { 281 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
270 return Some(PathResolution::AssocItem(assoc)); 282 return Some(PathResolution::AssocItem(assoc));
271 } 283 }
272 } 284 }
273 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { 285 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
274 let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; 286 let pat_id = self.pat_id(&path_pat.into())?;
275 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { 287 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
276 return Some(PathResolution::AssocItem(assoc)); 288 return Some(PathResolution::AssocItem(assoc));
277 } 289 }
@@ -286,7 +298,7 @@ impl SourceAnalyzer {
286 let name = name_ref.as_name(); 298 let name = name_ref.as_name();
287 let source_map = self.body_source_map.as_ref()?; 299 let source_map = self.body_source_map.as_ref()?;
288 let scopes = self.scopes.as_ref()?; 300 let scopes = self.scopes.as_ref()?;
289 let scope = scope_for(scopes, source_map, name_ref.syntax()); 301 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax());
290 let ret = scopes 302 let ret = scopes
291 .scope_chain(scope) 303 .scope_chain(scope)
292 .flat_map(|scope| scopes.entries(scope).iter()) 304 .flat_map(|scope| scopes.entries(scope).iter())
@@ -419,11 +431,12 @@ impl SourceAnalyzer {
419fn scope_for( 431fn scope_for(
420 scopes: &ExprScopes, 432 scopes: &ExprScopes,
421 source_map: &BodySourceMap, 433 source_map: &BodySourceMap,
434 file_id: HirFileId,
422 node: &SyntaxNode, 435 node: &SyntaxNode,
423) -> Option<ScopeId> { 436) -> Option<ScopeId> {
424 node.ancestors() 437 node.ancestors()
425 .filter_map(ast::Expr::cast) 438 .filter_map(ast::Expr::cast)
426 .filter_map(|it| source_map.node_expr(&it)) 439 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it }))
427 .find_map(|it| scopes.scope_for(it)) 440 .find_map(|it| scopes.scope_for(it))
428} 441}
429 442