aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-11-11 11:48:02 +0000
committerGitHub <[email protected]>2019-11-11 11:48:02 +0000
commita599147b4232c0d4f6b071a3a96e86f903f4cf52 (patch)
treefc8ddd1428c4be2babbdd713c852b31276a315f2 /crates/ra_hir
parentef2a9aedb6ac7f0b79e636cff7947935fecb909d (diff)
parent8b7f853cc19d0940ec542e10bc23aa78455bbb3b (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.rs55
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs30
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs20
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};
22use crate::{ 22use 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)]
1075pub struct Local {
1076 pub(crate) parent: DefWithBody,
1077 pub(crate) pat_id: PatId,
1078}
1079
1080impl 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)]
19pub struct ExprScopes { 19pub 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
3use hir_def::{StructId, StructOrUnionId, UnionId}; 3use hir_def::{StructId, StructOrUnionId, UnionId};
4use hir_expand::name::AsName; 4use hir_expand::name::AsName;
5use ra_syntax::ast::{self, AstNode, NameOwner}; 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner},
7 match_ast,
8};
6 9
7use crate::{ 10use 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
14pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -126,6 +130,26 @@ impl FromSource for StructField {
126 } 130 }
127} 131}
128 132
133impl 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
129impl Module { 153impl 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)]
95pub struct SourceAnalyzer { 95pub 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()),