diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-11 11:48:02 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-11 11:48:02 +0000 |
commit | a599147b4232c0d4f6b071a3a96e86f903f4cf52 (patch) | |
tree | fc8ddd1428c4be2babbdd713c852b31276a315f2 /crates/ra_hir | |
parent | ef2a9aedb6ac7f0b79e636cff7947935fecb909d (diff) | |
parent | 8b7f853cc19d0940ec542e10bc23aa78455bbb3b (diff) |
Merge #2200
2200: Add variables to HIR r=matklad a=matklad
Introduce a `hir::Variable`, which should cover locals, parameters and `self`. Unlike `PatId`, variable knows it's owner so it is self-contained, and should be more convenient to use from `ra_ide_api`.
The goal here is to hide more details about `Body` from hir, which should make it easier to move `Body` into `hir_def`. I don't think that `ra_ide_api` intrracts with bodies directly at the moment anyway, but the glue layer is based basically on `ast::BindPat`, which seems pretty brittle.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 20 |
5 files changed, 90 insertions, 19 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e5bfad3ca..09c4e97fa 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | |||
22 | use crate::{ | 22 | use crate::{ |
23 | adt::VariantDef, | 23 | adt::VariantDef, |
24 | db::{AstDatabase, DefDatabase, HirDatabase}, | 24 | db::{AstDatabase, DefDatabase, HirDatabase}, |
25 | expr::{validation::ExprValidator, Body, BodySourceMap}, | 25 | expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, |
26 | generics::HasGenericParams, | 26 | generics::HasGenericParams, |
27 | ids::{ | 27 | ids::{ |
28 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 28 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
@@ -32,7 +32,7 @@ use crate::{ | |||
32 | resolve::{Resolver, Scope, TypeNs}, | 32 | resolve::{Resolver, Scope, TypeNs}, |
33 | traits::TraitData, | 33 | traits::TraitData, |
34 | ty::{InferenceResult, Namespace, TraitRef}, | 34 | ty::{InferenceResult, Namespace, TraitRef}, |
35 | Either, HasSource, ImportId, Name, ScopeDef, Ty, | 35 | Either, HasSource, ImportId, Name, ScopeDef, Source, Ty, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /// hir::Crate describes a single crate. It's the main interface with which | 38 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -1070,3 +1070,54 @@ impl AssocItem { | |||
1070 | .expect("AssocItem without container") | 1070 | .expect("AssocItem without container") |
1071 | } | 1071 | } |
1072 | } | 1072 | } |
1073 | |||
1074 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1075 | pub struct Local { | ||
1076 | pub(crate) parent: DefWithBody, | ||
1077 | pub(crate) pat_id: PatId, | ||
1078 | } | ||
1079 | |||
1080 | impl Local { | ||
1081 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
1082 | let body = db.body_hir(self.parent); | ||
1083 | match &body[self.pat_id] { | ||
1084 | Pat::Bind { name, .. } => Some(name.clone()), | ||
1085 | _ => None, | ||
1086 | } | ||
1087 | } | ||
1088 | |||
1089 | pub fn is_self(self, db: &impl HirDatabase) -> bool { | ||
1090 | self.name(db) == Some(name::SELF_PARAM) | ||
1091 | } | ||
1092 | |||
1093 | pub fn is_mut(self, db: &impl HirDatabase) -> bool { | ||
1094 | let body = db.body_hir(self.parent); | ||
1095 | match &body[self.pat_id] { | ||
1096 | Pat::Bind { mode, .. } => match mode { | ||
1097 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | ||
1098 | _ => false, | ||
1099 | }, | ||
1100 | _ => false, | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody { | ||
1105 | self.parent | ||
1106 | } | ||
1107 | |||
1108 | pub fn module(self, db: &impl HirDatabase) -> Module { | ||
1109 | self.parent.module(db) | ||
1110 | } | ||
1111 | |||
1112 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | ||
1113 | let infer = db.infer(self.parent); | ||
1114 | infer[self.pat_id].clone() | ||
1115 | } | ||
1116 | |||
1117 | pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { | ||
1118 | let (_body, source_map) = db.body_with_source_map(self.parent); | ||
1119 | let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... | ||
1120 | let root = src.file_syntax(db); | ||
1121 | src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) | ||
1122 | } | ||
1123 | } | ||
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 5a1eade2c..daf8d8d07 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -17,7 +17,7 @@ impl_arena_id!(ScopeId); | |||
17 | 17 | ||
18 | #[derive(Debug, PartialEq, Eq)] | 18 | #[derive(Debug, PartialEq, Eq)] |
19 | pub struct ExprScopes { | 19 | pub struct ExprScopes { |
20 | body: Arc<Body>, | 20 | pub(crate) body: Arc<Body>, |
21 | scopes: Arena<ScopeId, ScopeData>, | 21 | scopes: Arena<ScopeId, ScopeData>, |
22 | scope_by_expr: FxHashMap<ExprId, ScopeId>, | 22 | scope_by_expr: FxHashMap<ExprId, ScopeId>, |
23 | } | 23 | } |
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index c95d2cdd0..2c441b0f4 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -2,13 +2,17 @@ | |||
2 | 2 | ||
3 | use hir_def::{StructId, StructOrUnionId, UnionId}; | 3 | use hir_def::{StructId, StructOrUnionId, UnionId}; |
4 | use hir_expand::name::AsName; | 4 | use hir_expand::name::AsName; |
5 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | ||
7 | match_ast, | ||
8 | }; | ||
6 | 9 | ||
7 | use crate::{ | 10 | use crate::{ |
8 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
9 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
10 | AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, | 13 | AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, |
11 | ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, | 14 | ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, |
15 | Union, VariantDef, | ||
12 | }; | 16 | }; |
13 | 17 | ||
14 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -126,6 +130,26 @@ impl FromSource for StructField { | |||
126 | } | 130 | } |
127 | } | 131 | } |
128 | 132 | ||
133 | impl Local { | ||
134 | pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { | ||
135 | let file_id = src.file_id; | ||
136 | let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| { | ||
137 | let res = match_ast! { | ||
138 | match it { | ||
139 | ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() }, | ||
140 | ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() }, | ||
141 | ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() }, | ||
142 | _ => return None, | ||
143 | } | ||
144 | }; | ||
145 | Some(res) | ||
146 | })?; | ||
147 | let (_body, source_map) = db.body_with_source_map(parent); | ||
148 | let pat_id = source_map.node_pat(&src.ast.into())?; | ||
149 | Some(Local { parent, pat_id }) | ||
150 | } | ||
151 | } | ||
152 | |||
129 | impl Module { | 153 | impl Module { |
130 | pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { | 154 | pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { |
131 | let src_parent = Source { | 155 | let src_parent = Source { |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9dc8d139b..806f1daed 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -65,7 +65,7 @@ pub use crate::{ | |||
65 | docs::{DocDef, Docs, Documentation}, | 65 | docs::{DocDef, Docs, Documentation}, |
66 | src::{HasBodySource, HasSource}, | 66 | src::{HasBodySource, HasSource}, |
67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
68 | EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, | 68 | EnumVariant, FieldSource, FnData, Function, HasBody, Local, MacroDef, Module, ModuleDef, |
69 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, | 69 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, |
70 | }, | 70 | }, |
71 | expr::ExprScopes, | 71 | expr::ExprScopes, |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 66cb4b357..c5fdf3bab 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -28,7 +28,7 @@ use crate::{ | |||
28 | ids::LocationCtx, | 28 | ids::LocationCtx, |
29 | resolve::{ScopeDef, TypeNs, ValueNs}, | 29 | resolve::{ScopeDef, TypeNs, ValueNs}, |
30 | ty::method_resolution::{self, implements_trait}, | 30 | ty::method_resolution::{self, implements_trait}, |
31 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, | 31 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, Local, |
32 | MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, | 32 | MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -94,6 +94,7 @@ fn def_with_body_from_child_node( | |||
94 | #[derive(Debug)] | 94 | #[derive(Debug)] |
95 | pub struct SourceAnalyzer { | 95 | pub struct SourceAnalyzer { |
96 | resolver: Resolver, | 96 | resolver: Resolver, |
97 | body_owner: Option<DefWithBody>, | ||
97 | body_source_map: Option<Arc<BodySourceMap>>, | 98 | body_source_map: Option<Arc<BodySourceMap>>, |
98 | infer: Option<Arc<crate::ty::InferenceResult>>, | 99 | infer: Option<Arc<crate::ty::InferenceResult>>, |
99 | scopes: Option<Arc<crate::expr::ExprScopes>>, | 100 | scopes: Option<Arc<crate::expr::ExprScopes>>, |
@@ -104,7 +105,7 @@ pub enum PathResolution { | |||
104 | /// An item | 105 | /// An item |
105 | Def(crate::ModuleDef), | 106 | Def(crate::ModuleDef), |
106 | /// A local binding (only value namespace) | 107 | /// A local binding (only value namespace) |
107 | LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>), | 108 | Local(Local), |
108 | /// A generic parameter | 109 | /// A generic parameter |
109 | GenericParam(u32), | 110 | GenericParam(u32), |
110 | SelfType(crate::ImplBlock), | 111 | SelfType(crate::ImplBlock), |
@@ -152,6 +153,7 @@ impl SourceAnalyzer { | |||
152 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | 153 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); |
153 | SourceAnalyzer { | 154 | SourceAnalyzer { |
154 | resolver, | 155 | resolver, |
156 | body_owner: Some(def), | ||
155 | body_source_map: Some(source_map), | 157 | body_source_map: Some(source_map), |
156 | infer: Some(def.infer(db)), | 158 | infer: Some(def.infer(db)), |
157 | scopes: Some(scopes), | 159 | scopes: Some(scopes), |
@@ -162,6 +164,7 @@ impl SourceAnalyzer { | |||
162 | .ancestors() | 164 | .ancestors() |
163 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) | 165 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) |
164 | .unwrap_or_default(), | 166 | .unwrap_or_default(), |
167 | body_owner: None, | ||
165 | body_source_map: None, | 168 | body_source_map: None, |
166 | infer: None, | 169 | infer: None, |
167 | scopes: None, | 170 | scopes: None, |
@@ -233,16 +236,9 @@ impl SourceAnalyzer { | |||
233 | }); | 236 | }); |
234 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { | 237 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { |
235 | let res = match val { | 238 | let res = match val { |
236 | ValueNs::LocalBinding(it) => { | 239 | ValueNs::LocalBinding(pat_id) => { |
237 | // We get a `PatId` from resolver, but it actually can only | 240 | let var = Local { parent: self.body_owner?, pat_id }; |
238 | // point at `BindPat`, and not at the arbitrary pattern. | 241 | 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 | } | 242 | } |
247 | ValueNs::Function(it) => PathResolution::Def(it.into()), | 243 | ValueNs::Function(it) => PathResolution::Def(it.into()), |
248 | ValueNs::Const(it) => PathResolution::Def(it.into()), | 244 | ValueNs::Const(it) => PathResolution::Def(it.into()), |