Skip to content

Commit f18b7e1

Browse files
bors[bot]matklad
andauthored
Merge #2484
2484: DynMap r=matklad a=matklad Implement a `DynMap` a semi-dynamic, semi-static map, which helps to thread heterogeneously typed info in a uniform way. Totally inspired by https://github.com/JetBrains/kotlin/blob/df3bee30384787d8951ea548a4257c2cb52a16a3/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java. @flodiebold wdyt? Seems like a potentially useful pattern for various source-map-like things. Co-authored-by: Aleksey Kladov <[email protected]>
2 parents d3702c0 + 8c86963 commit f18b7e1

File tree

10 files changed

+362
-318
lines changed

10 files changed

+362
-318
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir/src/from_source.rs

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
//! FIXME: write short doc here
2-
use either::Either;
3-
42
use hir_def::{
5-
child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId,
6-
LocationCtx, ModuleId, TraitId, VariantId,
3+
child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, AstItemDef,
4+
EnumVariantId, LocationCtx, ModuleId, VariantId,
75
};
86
use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
97
use ra_syntax::{
@@ -53,35 +51,39 @@ impl FromSource for Trait {
5351
impl FromSource for Function {
5452
type Ast = ast::FnDef;
5553
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
56-
Container::find(db, src.as_ref().map(|it| it.syntax()))?
57-
.child_from_source(db, src)
54+
Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::FUNCTION]
55+
.get(&src)
56+
.copied()
5857
.map(Function::from)
5958
}
6059
}
6160

6261
impl FromSource for Const {
6362
type Ast = ast::ConstDef;
6463
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
65-
Container::find(db, src.as_ref().map(|it| it.syntax()))?
66-
.child_from_source(db, src)
64+
Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::CONST]
65+
.get(&src)
66+
.copied()
6767
.map(Const::from)
6868
}
6969
}
7070
impl FromSource for Static {
7171
type Ast = ast::StaticDef;
7272
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
73-
match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
74-
Container::Module(it) => it.id.child_from_source(db, src).map(Static::from),
75-
Container::Trait(_) | Container::ImplBlock(_) => None,
76-
}
73+
Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::STATIC]
74+
.get(&src)
75+
.copied()
76+
.map(Static::from)
7777
}
7878
}
7979

8080
impl FromSource for TypeAlias {
8181
type Ast = ast::TypeAliasDef;
8282
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
83-
Container::find(db, src.as_ref().map(|it| it.syntax()))?
84-
.child_from_source(db, src)
83+
Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)
84+
[keys::TYPE_ALIAS]
85+
.get(&src)
86+
.copied()
8587
.map(TypeAlias::from)
8688
}
8789
}
@@ -116,32 +118,41 @@ impl FromSource for EnumVariant {
116118
let parent_enum = src.value.parent_enum();
117119
let src_enum = InFile { file_id: src.file_id, value: parent_enum };
118120
let parent_enum = Enum::from_source(db, src_enum)?;
119-
parent_enum.id.child_from_source(db, src).map(EnumVariant::from)
121+
parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT]
122+
.get(&src)
123+
.copied()
124+
.map(EnumVariant::from)
120125
}
121126
}
122127

123128
impl FromSource for StructField {
124129
type Ast = FieldSource;
125130
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
131+
let src = src.as_ref();
132+
133+
// FIXME this is buggy
126134
let variant_id: VariantId = match src.value {
127-
FieldSource::Named(ref field) => {
135+
FieldSource::Named(field) => {
128136
let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
129137
let src = InFile { file_id: src.file_id, value };
130138
let def = Struct::from_source(db, src)?;
131139
def.id.into()
132140
}
133-
FieldSource::Pos(ref field) => {
141+
FieldSource::Pos(field) => {
134142
let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
135143
let src = InFile { file_id: src.file_id, value };
136144
let def = EnumVariant::from_source(db, src)?;
137145
EnumVariantId::from(def).into()
138146
}
139147
};
140-
let src = src.map(|field_source| match field_source {
141-
FieldSource::Pos(it) => Either::Left(it),
142-
FieldSource::Named(it) => Either::Right(it),
143-
});
144-
variant_id.child_from_source(db, src).map(StructField::from)
148+
149+
let dyn_map = variant_id.child_by_source(db);
150+
match src.value {
151+
FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())),
152+
FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())),
153+
}
154+
.copied()
155+
.map(StructField::from)
145156
}
146157
}
147158

@@ -255,21 +266,12 @@ impl Container {
255266
}
256267
}
257268

258-
impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container
259-
where
260-
TraitId: ChildFromSource<CHILD, SOURCE>,
261-
ImplId: ChildFromSource<CHILD, SOURCE>,
262-
ModuleId: ChildFromSource<CHILD, SOURCE>,
263-
{
264-
fn child_from_source(
265-
&self,
266-
db: &impl DefDatabase,
267-
child_source: InFile<SOURCE>,
268-
) -> Option<CHILD> {
269+
impl ChildBySource for Container {
270+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
269271
match self {
270-
Container::Trait(it) => it.id.child_from_source(db, child_source),
271-
Container::ImplBlock(it) => it.id.child_from_source(db, child_source),
272-
Container::Module(it) => it.id.child_from_source(db, child_source),
272+
Container::Trait(it) => it.id.child_by_source(db),
273+
Container::ImplBlock(it) => it.id.child_by_source(db),
274+
Container::Module(it) => it.id.child_by_source(db),
273275
}
274276
}
275277
}

crates/ra_hir_def/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ log = "0.4.5"
1212
once_cell = "1.0.1"
1313
rustc-hash = "1.0"
1414
either = "1.5"
15+
anymap = "0.12"
1516

1617
ra_arena = { path = "../ra_arena" }
1718
ra_db = { path = "../ra_db" }
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
//! When *constructing* `hir`, we start at some parent syntax node and recursively
2+
//! lower the children.
3+
//!
4+
//! This modules allows one to go in the opposite direction: start with a syntax
5+
//! node for a *child*, and get its hir.
6+
7+
use either::Either;
8+
9+
use crate::{
10+
db::DefDatabase,
11+
dyn_map::DynMap,
12+
keys,
13+
src::{HasChildSource, HasSource},
14+
AssocItemId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, ModuleId, StructFieldId,
15+
TraitId, VariantId,
16+
};
17+
18+
pub trait ChildBySource {
19+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap;
20+
}
21+
22+
impl ChildBySource for TraitId {
23+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
24+
let mut res = DynMap::default();
25+
26+
let data = db.trait_data(*self);
27+
for (_name, item) in data.items.iter() {
28+
match *item {
29+
AssocItemId::FunctionId(func) => {
30+
let src = func.lookup(db).source(db);
31+
res[keys::FUNCTION].insert(src, func)
32+
}
33+
AssocItemId::ConstId(konst) => {
34+
let src = konst.lookup(db).source(db);
35+
res[keys::CONST].insert(src, konst)
36+
}
37+
AssocItemId::TypeAliasId(ty) => {
38+
let src = ty.lookup(db).source(db);
39+
res[keys::TYPE_ALIAS].insert(src, ty)
40+
}
41+
}
42+
}
43+
44+
res
45+
}
46+
}
47+
48+
impl ChildBySource for ImplId {
49+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
50+
let mut res = DynMap::default();
51+
52+
let data = db.impl_data(*self);
53+
for &item in data.items.iter() {
54+
match item {
55+
AssocItemId::FunctionId(func) => {
56+
let src = func.lookup(db).source(db);
57+
res[keys::FUNCTION].insert(src, func)
58+
}
59+
AssocItemId::ConstId(konst) => {
60+
let src = konst.lookup(db).source(db);
61+
res[keys::CONST].insert(src, konst)
62+
}
63+
AssocItemId::TypeAliasId(ty) => {
64+
let src = ty.lookup(db).source(db);
65+
res[keys::TYPE_ALIAS].insert(src, ty)
66+
}
67+
}
68+
}
69+
70+
res
71+
}
72+
}
73+
74+
impl ChildBySource for ModuleId {
75+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
76+
let mut res = DynMap::default();
77+
78+
let crate_def_map = db.crate_def_map(self.krate);
79+
for item in crate_def_map[self.local_id].scope.declarations() {
80+
match item {
81+
ModuleDefId::FunctionId(func) => {
82+
let src = func.lookup(db).source(db);
83+
res[keys::FUNCTION].insert(src, func)
84+
}
85+
ModuleDefId::ConstId(konst) => {
86+
let src = konst.lookup(db).source(db);
87+
res[keys::CONST].insert(src, konst)
88+
}
89+
ModuleDefId::StaticId(statik) => {
90+
let src = statik.lookup(db).source(db);
91+
res[keys::STATIC].insert(src, statik)
92+
}
93+
ModuleDefId::TypeAliasId(ty) => {
94+
let src = ty.lookup(db).source(db);
95+
res[keys::TYPE_ALIAS].insert(src, ty)
96+
}
97+
_ => (),
98+
}
99+
}
100+
101+
res
102+
}
103+
}
104+
105+
impl ChildBySource for VariantId {
106+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
107+
let mut res = DynMap::default();
108+
109+
let arena_map = self.child_source(db);
110+
let arena_map = arena_map.as_ref();
111+
for (local_id, source) in arena_map.value.iter() {
112+
let id = StructFieldId { parent: *self, local_id };
113+
match source {
114+
Either::Left(source) => {
115+
res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
116+
}
117+
Either::Right(source) => {
118+
res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
119+
}
120+
}
121+
}
122+
res
123+
}
124+
}
125+
126+
impl ChildBySource for EnumId {
127+
fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
128+
let mut res = DynMap::default();
129+
130+
let arena_map = self.child_source(db);
131+
let arena_map = arena_map.as_ref();
132+
for (local_id, source) in arena_map.value.iter() {
133+
let id = EnumVariantId { parent: *self, local_id };
134+
res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id)
135+
}
136+
137+
res
138+
}
139+
}

0 commit comments

Comments
 (0)