aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml8
-rw-r--r--Cargo.lock7
-rw-r--r--crates/ra_assists/src/assists/add_new.rs45
-rw-r--r--crates/ra_hir/src/code_model.rs24
-rw-r--r--crates/ra_hir/src/code_model/src.rs10
-rw-r--r--crates/ra_hir/src/from_source.rs98
-rw-r--r--crates/ra_hir/src/lib.rs6
-rw-r--r--crates/ra_hir/src/source_binder.rs73
-rw-r--r--crates/ra_hir_def/Cargo.toml1
-rw-r--r--crates/ra_hir_def/src/body.rs6
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs139
-rw-r--r--crates/ra_hir_def/src/child_from_source.rs276
-rw-r--r--crates/ra_hir_def/src/dyn_map.rs108
-rw-r--r--crates/ra_hir_def/src/generics.rs171
-rw-r--r--crates/ra_hir_def/src/keys.rs49
-rw-r--r--crates/ra_hir_def/src/lib.rs29
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs4
-rw-r--r--crates/ra_hir_def/src/per_ns.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs38
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs4
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs67
-rw-r--r--crates/ra_hir_expand/src/db.rs49
-rw-r--r--crates/ra_hir_expand/src/lib.rs52
-rw-r--r--crates/ra_hir_expand/src/name.rs116
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs10
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs34
-rw-r--r--crates/ra_hir_ty/src/lib.rs44
-rw-r--r--crates/ra_hir_ty/src/lower.rs46
-rw-r--r--crates/ra_hir_ty/src/tests.rs8
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs16
-rw-r--r--crates/ra_hir_ty/src/utils.rs81
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs22
-rw-r--r--crates/ra_ide/src/goto_definition.rs55
-rw-r--r--crates/ra_ide/src/hover.rs2
-rw-r--r--crates/ra_ide/src/inlay_hints.rs31
-rw-r--r--crates/ra_ide/src/references.rs2
-rw-r--r--crates/ra_ide/src/references/classify.rs14
-rw-r--r--crates/ra_ide/src/references/name_definition.rs6
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html9
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs12
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs38
-rw-r--r--crates/ra_syntax/src/ptr.rs14
-rw-r--r--crates/test_utils/src/lib.rs11
44 files changed, 1128 insertions, 710 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 5bc41533c..cb397ae14 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -14,6 +14,7 @@ jobs:
14 env: 14 env:
15 RUSTFLAGS: -D warnings 15 RUSTFLAGS: -D warnings
16 CARGO_INCREMENTAL: 0 16 CARGO_INCREMENTAL: 0
17 RUN_SLOW_TESTS: 1
17 steps: 18 steps:
18 19
19 - name: Checkout repository 20 - name: Checkout repository
@@ -46,9 +47,10 @@ jobs:
46 47
47 - name: Prepare build directory for cache 48 - name: Prepare build directory for cache
48 run: | 49 run: |
49 find ./target/debug -maxdepth 1 -type f -delete && \ 50 find ./target/debug -maxdepth 1 -type f -delete \
50 rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*heavy_test*,*gen_lsp*,*thread_worker*} && \ 51 && rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*heavy_test*,*gen_lsp*,*thread_worker*} \
51 rm -f ./target/.rustc_info.json 52 && rm -f ./target/.rustc_info.json \
53 && rm ./target/.slow_tests_cookie
52 54
53 type-script: 55 type-script:
54 name: TypeScript 56 name: TypeScript
diff --git a/Cargo.lock b/Cargo.lock
index 0e7594f80..a95f9139f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,6 +14,11 @@ version = "1.0.25"
14source = "registry+https://github.com/rust-lang/crates.io-index" 14source = "registry+https://github.com/rust-lang/crates.io-index"
15 15
16[[package]] 16[[package]]
17name = "anymap"
18version = "0.12.1"
19source = "registry+https://github.com/rust-lang/crates.io-index"
20
21[[package]]
17name = "arrayvec" 22name = "arrayvec"
18version = "0.5.1" 23version = "0.5.1"
19source = "registry+https://github.com/rust-lang/crates.io-index" 24source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -958,6 +963,7 @@ dependencies = [
958name = "ra_hir_def" 963name = "ra_hir_def"
959version = "0.1.0" 964version = "0.1.0"
960dependencies = [ 965dependencies = [
966 "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
961 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 967 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
962 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 968 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
963 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 969 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1776,6 +1782,7 @@ dependencies = [
1776[metadata] 1782[metadata]
1777"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1783"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
1778"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" 1784"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
1785"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
1779"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 1786"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
1780"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1787"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
1781"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 1788"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index f977547fb..d340cac8f 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -56,42 +56,39 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
56 let vis = vis.as_ref().map(String::as_str).unwrap_or(""); 56 let vis = vis.as_ref().map(String::as_str).unwrap_or("");
57 write!(&mut buf, " {}fn new(", vis).unwrap(); 57 write!(&mut buf, " {}fn new(", vis).unwrap();
58 58
59 join(field_list.fields().map(|f| { 59 join(field_list.fields().filter_map(|f| {
60 format!( 60 Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
61 "{}: {}",
62 f.name().unwrap().syntax().text(),
63 f.ascribed_type().unwrap().syntax().text()
64 )
65 })) 61 }))
66 .separator(", ") 62 .separator(", ")
67 .to_buf(&mut buf); 63 .to_buf(&mut buf);
68 64
69 buf.push_str(") -> Self { Self {"); 65 buf.push_str(") -> Self { Self {");
70 66
71 join(field_list.fields().map(|f| f.name().unwrap().syntax().text())) 67 join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
72 .separator(", ") 68 .separator(", ")
73 .surround_with(" ", " ") 69 .surround_with(" ", " ")
74 .to_buf(&mut buf); 70 .to_buf(&mut buf);
75 71
76 buf.push_str("} }"); 72 buf.push_str("} }");
77 73
78 let (start_offset, end_offset) = if let Some(impl_block) = impl_block { 74 let (start_offset, end_offset) = impl_block
79 buf.push('\n'); 75 .and_then(|impl_block| {
80 let start = impl_block 76 buf.push('\n');
81 .syntax() 77 let start = impl_block
82 .descendants_with_tokens() 78 .syntax()
83 .find(|t| t.kind() == T!['{']) 79 .descendants_with_tokens()
84 .unwrap() 80 .find(|t| t.kind() == T!['{'])?
85 .text_range() 81 .text_range()
86 .end(); 82 .end();
87 83
88 (start, TextUnit::from_usize(1)) 84 Some((start, TextUnit::from_usize(1)))
89 } else { 85 })
90 buf = generate_impl_text(&strukt, &buf); 86 .unwrap_or_else(|| {
91 let start = strukt.syntax().text_range().end(); 87 buf = generate_impl_text(&strukt, &buf);
92 88 let start = strukt.syntax().text_range().end();
93 (start, TextUnit::from_usize(3)) 89
94 }; 90 (start, TextUnit::from_usize(3))
91 });
95 92
96 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset); 93 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
97 edit.insert(start_offset, buf); 94 edit.insert(start_offset, buf);
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 7706399ae..4578a0ba8 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -15,9 +15,9 @@ use hir_def::{
15 per_ns::PerNs, 15 per_ns::PerNs,
16 resolver::HasResolver, 16 resolver::HasResolver,
17 type_ref::{Mutability, TypeRef}, 17 type_ref::{Mutability, TypeRef},
18 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, 18 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId,
19 HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, 19 LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
20 Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, 20 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
21}; 21};
22use hir_expand::{ 22use hir_expand::{
23 diagnostics::DiagnosticSink, 23 diagnostics::DiagnosticSink,
@@ -856,9 +856,19 @@ impl Local {
856} 856}
857 857
858#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 858#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
859pub struct GenericParam { 859pub struct TypeParam {
860 pub(crate) parent: GenericDefId, 860 pub(crate) id: TypeParamId,
861 pub(crate) idx: u32, 861}
862
863impl TypeParam {
864 pub fn name(self, db: &impl HirDatabase) -> Name {
865 let params = db.generic_params(self.id.parent);
866 params.types[self.id.local_id].name.clone()
867 }
868
869 pub fn module(self, db: &impl HirDatabase) -> Module {
870 self.id.parent.module(db).into()
871 }
862} 872}
863 873
864#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 874#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1101,7 +1111,7 @@ impl HirDisplay for Type {
1101pub enum ScopeDef { 1111pub enum ScopeDef {
1102 ModuleDef(ModuleDef), 1112 ModuleDef(ModuleDef),
1103 MacroDef(MacroDef), 1113 MacroDef(MacroDef),
1104 GenericParam(GenericParam), 1114 GenericParam(TypeParam),
1105 ImplSelfType(ImplBlock), 1115 ImplSelfType(ImplBlock),
1106 AdtSelfType(Adt), 1116 AdtSelfType(Adt),
1107 Local(Local), 1117 Local(Local),
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 78a454082..b09582f93 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -10,7 +10,7 @@ use ra_syntax::ast;
10 10
11use crate::{ 11use crate::{
12 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef, 12 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef,
13 Module, Static, Struct, StructField, Trait, TypeAlias, Union, 13 Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
14}; 14};
15 15
16pub use hir_expand::InFile; 16pub use hir_expand::InFile;
@@ -129,3 +129,11 @@ impl HasSource for Import {
129 src.with_value(ptr.map_left(|it| it.to_node(&root)).map_right(|it| it.to_node(&root))) 129 src.with_value(ptr.map_left(|it| it.to_node(&root)).map_right(|it| it.to_node(&root)))
130 } 130 }
131} 131}
132
133impl HasSource for TypeParam {
134 type Ast = Either<ast::TraitDef, ast::TypeParam>;
135 fn source(self, db: &impl DefDatabase) -> InFile<Self::Ast> {
136 let child_source = self.id.parent.child_source(db);
137 child_source.map(|it| it[self.id.local_id].clone())
138 }
139}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 5cb222bd3..4acc038e4 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,9 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use either::Either;
3
4use hir_def::{ 2use hir_def::{
5 child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId, 3 child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, AstItemDef,
6 LocationCtx, ModuleId, TraitId, VariantId, 4 EnumVariantId, GenericDefId, LocationCtx, ModuleId, VariantId,
7}; 5};
8use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 6use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
9use ra_syntax::{ 7use ra_syntax::{
@@ -14,7 +12,7 @@ use ra_syntax::{
14use crate::{ 12use crate::{
15 db::{AstDatabase, DefDatabase, HirDatabase}, 13 db::{AstDatabase, DefDatabase, HirDatabase},
16 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, 14 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
17 MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, Union, 15 MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
18}; 16};
19 17
20pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -53,8 +51,9 @@ impl FromSource for Trait {
53impl FromSource for Function { 51impl FromSource for Function {
54 type Ast = ast::FnDef; 52 type Ast = ast::FnDef;
55 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 53 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
56 Container::find(db, src.as_ref().map(|it| it.syntax()))? 54 Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::FUNCTION]
57 .child_from_source(db, src) 55 .get(&src)
56 .copied()
58 .map(Function::from) 57 .map(Function::from)
59 } 58 }
60} 59}
@@ -62,26 +61,29 @@ impl FromSource for Function {
62impl FromSource for Const { 61impl FromSource for Const {
63 type Ast = ast::ConstDef; 62 type Ast = ast::ConstDef;
64 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 63 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
65 Container::find(db, src.as_ref().map(|it| it.syntax()))? 64 Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::CONST]
66 .child_from_source(db, src) 65 .get(&src)
66 .copied()
67 .map(Const::from) 67 .map(Const::from)
68 } 68 }
69} 69}
70impl FromSource for Static { 70impl FromSource for Static {
71 type Ast = ast::StaticDef; 71 type Ast = ast::StaticDef;
72 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 72 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()))? { 73 Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::STATIC]
74 Container::Module(it) => it.id.child_from_source(db, src).map(Static::from), 74 .get(&src)
75 Container::Trait(_) | Container::ImplBlock(_) => None, 75 .copied()
76 } 76 .map(Static::from)
77 } 77 }
78} 78}
79 79
80impl FromSource for TypeAlias { 80impl FromSource for TypeAlias {
81 type Ast = ast::TypeAliasDef; 81 type Ast = ast::TypeAliasDef;
82 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 82 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
83 Container::find(db, src.as_ref().map(|it| it.syntax()))? 83 Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)
84 .child_from_source(db, src) 84 [keys::TYPE_ALIAS]
85 .get(&src)
86 .copied()
85 .map(TypeAlias::from) 87 .map(TypeAlias::from)
86 } 88 }
87} 89}
@@ -116,32 +118,41 @@ impl FromSource for EnumVariant {
116 let parent_enum = src.value.parent_enum(); 118 let parent_enum = src.value.parent_enum();
117 let src_enum = InFile { file_id: src.file_id, value: parent_enum }; 119 let src_enum = InFile { file_id: src.file_id, value: parent_enum };
118 let parent_enum = Enum::from_source(db, src_enum)?; 120 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)
120 } 125 }
121} 126}
122 127
123impl FromSource for StructField { 128impl FromSource for StructField {
124 type Ast = FieldSource; 129 type Ast = FieldSource;
125 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 130 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
126 let variant_id: VariantId = match src.value { 134 let variant_id: VariantId = match src.value {
127 FieldSource::Named(ref field) => { 135 FieldSource::Named(field) => {
128 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; 136 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
129 let src = InFile { file_id: src.file_id, value }; 137 let src = InFile { file_id: src.file_id, value };
130 let def = Struct::from_source(db, src)?; 138 let def = Struct::from_source(db, src)?;
131 def.id.into() 139 def.id.into()
132 } 140 }
133 FieldSource::Pos(ref field) => { 141 FieldSource::Pos(field) => {
134 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; 142 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
135 let src = InFile { file_id: src.file_id, value }; 143 let src = InFile { file_id: src.file_id, value };
136 let def = EnumVariant::from_source(db, src)?; 144 let def = EnumVariant::from_source(db, src)?;
137 EnumVariantId::from(def).into() 145 EnumVariantId::from(def).into()
138 } 146 }
139 }; 147 };
140 let src = src.map(|field_source| match field_source { 148
141 FieldSource::Pos(it) => Either::Left(it), 149 let dyn_map = variant_id.child_by_source(db);
142 FieldSource::Named(it) => Either::Right(it), 150 match src.value {
143 }); 151 FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())),
144 variant_id.child_from_source(db, src).map(StructField::from) 152 FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())),
153 }
154 .copied()
155 .map(StructField::from)
145 } 156 }
146} 157}
147 158
@@ -166,6 +177,28 @@ impl Local {
166 } 177 }
167} 178}
168 179
180impl TypeParam {
181 pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> {
182 let file_id = src.file_id;
183 let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
184 let res = match_ast! {
185 match it {
186 ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() },
187 ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() },
188 ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() },
189 ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() },
190 ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() },
191 ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() },
192 _ => return None,
193 }
194 };
195 Some(res)
196 })?;
197 let &id = parent.child_by_source(db)[keys::TYPE_PARAM].get(&src)?;
198 Some(TypeParam { id })
199 }
200}
201
169impl Module { 202impl Module {
170 pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> { 203 pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> {
171 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); 204 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast);
@@ -255,21 +288,12 @@ impl Container {
255 } 288 }
256} 289}
257 290
258impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container 291impl ChildBySource for Container {
259where 292 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
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 match self { 293 match self {
270 Container::Trait(it) => it.id.child_from_source(db, child_source), 294 Container::Trait(it) => it.id.child_by_source(db),
271 Container::ImplBlock(it) => it.id.child_from_source(db, child_source), 295 Container::ImplBlock(it) => it.id.child_by_source(db),
272 Container::Module(it) => it.id.child_from_source(db, child_source), 296 Container::Module(it) => it.id.child_by_source(db),
273 } 297 }
274 } 298 }
275} 299}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index f12e4ca3f..9eb34b5dc 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -42,9 +42,9 @@ pub mod from_source;
42pub use crate::{ 42pub use crate::{
43 code_model::{ 43 code_model::{
44 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, 44 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency,
45 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, 45 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, HasAttrs,
46 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 46 ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct,
47 StructField, Trait, Type, TypeAlias, Union, VariantDef, 47 StructField, Trait, Type, TypeAlias, TypeParam, Union, VariantDef,
48 }, 48 },
49 from_source::FromSource, 49 from_source::FromSource,
50 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 50 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 42c392513..c5a920688 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -21,7 +21,6 @@ use hir_def::{
21}; 21};
22use hir_expand::{ 22use hir_expand::{
23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, 23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
24 MacroFileKind,
25}; 24};
26use ra_syntax::{ 25use ra_syntax::{
27 ast::{self, AstNode}, 26 ast::{self, AstNode},
@@ -36,8 +35,8 @@ use crate::{
36 method_resolution::{self, implements_trait}, 35 method_resolution::{self, implements_trait},
37 InEnvironment, TraitEnvironment, Ty, 36 InEnvironment, TraitEnvironment, Ty,
38 }, 37 },
39 Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, GenericParam, 38 Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, ImplBlock, Local,
40 Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, 39 MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
41}; 40};
42 41
43fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> { 42fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> {
@@ -59,6 +58,10 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -
59 let src = node.with_value(it); 58 let src = node.with_value(it);
60 Some(Enum::from_source(db, src)?.id.resolver(db)) 59 Some(Enum::from_source(db, src)?.id.resolver(db))
61 }, 60 },
61 ast::ImplBlock(it) => {
62 let src = node.with_value(it);
63 Some(ImplBlock::from_source(db, src)?.id.resolver(db))
64 },
62 _ => match node.value.kind() { 65 _ => match node.value.kind() {
63 FN_DEF | CONST_DEF | STATIC_DEF => { 66 FN_DEF | CONST_DEF | STATIC_DEF => {
64 let def = def_with_body_from_child_node(db, node)?; 67 let def = def_with_body_from_child_node(db, node)?;
@@ -76,12 +79,13 @@ fn def_with_body_from_child_node(
76 db: &impl HirDatabase, 79 db: &impl HirDatabase,
77 child: InFile<&SyntaxNode>, 80 child: InFile<&SyntaxNode>,
78) -> Option<DefWithBody> { 81) -> Option<DefWithBody> {
79 child.value.ancestors().find_map(|node| { 82 child.cloned().ancestors_with_macros(db).find_map(|node| {
83 let n = &node.value;
80 match_ast! { 84 match_ast! {
81 match node { 85 match n {
82 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 86 ast::FnDef(def) => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
83 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 87 ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
84 ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 88 ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
85 _ => { None }, 89 _ => { None },
86 } 90 }
87 } 91 }
@@ -107,7 +111,7 @@ pub enum PathResolution {
107 /// A local binding (only value namespace) 111 /// A local binding (only value namespace)
108 Local(Local), 112 Local(Local),
109 /// A generic parameter 113 /// A generic parameter
110 GenericParam(GenericParam), 114 TypeParam(TypeParam),
111 SelfType(crate::ImplBlock), 115 SelfType(crate::ImplBlock),
112 Macro(MacroDef), 116 Macro(MacroDef),
113 AssocItem(crate::AssocItem), 117 AssocItem(crate::AssocItem),
@@ -135,8 +139,8 @@ pub struct ReferenceDescriptor {
135 pub name: String, 139 pub name: String,
136} 140}
137 141
142#[derive(Debug)]
138pub struct Expansion { 143pub struct Expansion {
139 macro_file_kind: MacroFileKind,
140 macro_call_id: MacroCallId, 144 macro_call_id: MacroCallId,
141} 145}
142 146
@@ -151,7 +155,7 @@ impl Expansion {
151 } 155 }
152 156
153 pub fn file_id(&self) -> HirFileId { 157 pub fn file_id(&self) -> HirFileId {
154 self.macro_call_id.as_file(self.macro_file_kind) 158 self.macro_call_id.as_file()
155 } 159 }
156} 160}
157 161
@@ -260,10 +264,7 @@ impl SourceAnalyzer {
260 ) -> Option<PathResolution> { 264 ) -> Option<PathResolution> {
261 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 265 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
262 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), 266 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
263 TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { 267 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
264 parent: self.resolver.generic_def().unwrap(),
265 idx,
266 }),
267 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { 268 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
268 PathResolution::Def(Adt::from(it).into()) 269 PathResolution::Def(Adt::from(it).into())
269 } 270 }
@@ -335,10 +336,7 @@ impl SourceAnalyzer {
335 resolver::ScopeDef::PerNs(it) => it.into(), 336 resolver::ScopeDef::PerNs(it) => it.into(),
336 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), 337 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
337 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), 338 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
338 resolver::ScopeDef::GenericParam(idx) => { 339 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }),
339 let parent = self.resolver.generic_def().unwrap();
340 ScopeDef::GenericParam(GenericParam { parent, idx })
341 }
342 resolver::ScopeDef::Local(pat_id) => { 340 resolver::ScopeDef::Local(pat_id) => {
343 let parent = self.resolver.body_owner().unwrap().into(); 341 let parent = self.resolver.body_owner().unwrap().into();
344 ScopeDef::Local(Local { parent, pat_id }) 342 ScopeDef::Local(Local { parent, pat_id })
@@ -456,10 +454,7 @@ impl SourceAnalyzer {
456 macro_call.file_id, 454 macro_call.file_id,
457 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value), 455 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
458 ); 456 );
459 Some(Expansion { 457 Some(Expansion { macro_call_id: def.as_call_id(db, MacroCallKind::FnLike(ast_id)) })
460 macro_call_id: def.as_call_id(db, MacroCallKind::FnLike(ast_id)),
461 macro_file_kind: to_macro_file_kind(macro_call.value),
462 })
463 } 458 }
464} 459}
465 460
@@ -543,35 +538,3 @@ fn adjust(
543 }) 538 })
544 .map(|(_ptr, scope)| *scope) 539 .map(|(_ptr, scope)| *scope)
545} 540}
546
547/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to.
548/// FIXME: Not completed
549fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind {
550 let syn = macro_call.syntax();
551 let parent = match syn.parent() {
552 Some(it) => it,
553 None => {
554 // FIXME:
555 // If it is root, which means the parent HirFile
556 // MacroKindFile must be non-items
557 // return expr now.
558 return MacroFileKind::Expr;
559 }
560 };
561
562 match parent.kind() {
563 MACRO_ITEMS | SOURCE_FILE => MacroFileKind::Items,
564 LET_STMT => {
565 // FIXME: Handle Pattern
566 MacroFileKind::Expr
567 }
568 EXPR_STMT => MacroFileKind::Statements,
569 BLOCK => MacroFileKind::Statements,
570 ARG_LIST => MacroFileKind::Expr,
571 TRY_EXPR => MacroFileKind::Expr,
572 _ => {
573 // Unknown , Just guess it is `Items`
574 MacroFileKind::Items
575 }
576 }
577}
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index cf3a446fc..b1923bbf2 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -12,6 +12,7 @@ log = "0.4.5"
12once_cell = "1.0.1" 12once_cell = "1.0.1"
13rustc-hash = "1.0" 13rustc-hash = "1.0"
14either = "1.5" 14either = "1.5"
15anymap = "0.12"
15 16
16ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
17ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 7b385f3fd..b3bc336cf 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -6,9 +6,7 @@ pub mod scope;
6use std::{ops::Index, sync::Arc}; 6use std::{ops::Index, sync::Arc};
7 7
8use either::Either; 8use either::Either;
9use hir_expand::{ 9use hir_expand::{hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId};
10 hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId, MacroFileKind,
11};
12use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
13use ra_syntax::{ast, AstNode, AstPtr}; 11use ra_syntax::{ast, AstNode, AstPtr};
14use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
@@ -49,7 +47,7 @@ impl Expander {
49 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { 47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
50 if let Some(def) = self.resolve_path_as_macro(db, &path) { 48 if let Some(def) = self.resolve_path_as_macro(db, &path) {
51 let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); 49 let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
52 let file_id = call_id.as_file(MacroFileKind::Expr); 50 let file_id = call_id.as_file();
53 if let Some(node) = db.parse_or_expand(file_id) { 51 if let Some(node) = db.parse_or_expand(file_id) {
54 if let Some(expr) = ast::Expr::cast(node) { 52 if let Some(expr) = ast::Expr::cast(node) {
55 log::debug!("macro expansion {:#?}", expr.syntax()); 53 log::debug!("macro expansion {:#?}", expr.syntax());
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
new file mode 100644
index 000000000..a3574a9db
--- /dev/null
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -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
7use either::Either;
8
9use 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
18pub trait ChildBySource {
19 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap;
20}
21
22impl 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
48impl 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
74impl 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
105impl 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
126impl 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}
diff --git a/crates/ra_hir_def/src/child_from_source.rs b/crates/ra_hir_def/src/child_from_source.rs
deleted file mode 100644
index 37d4b7870..000000000
--- a/crates/ra_hir_def/src/child_from_source.rs
+++ /dev/null
@@ -1,276 +0,0 @@
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
7use either::Either;
8use hir_expand::InFile;
9use ra_syntax::{ast, AstNode, AstPtr};
10
11use crate::{
12 db::DefDatabase,
13 src::{HasChildSource, HasSource},
14 AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, ImplId, Lookup, ModuleDefId, ModuleId,
15 StaticId, StructFieldId, TraitId, TypeAliasId, VariantId,
16};
17
18pub trait ChildFromSource<CHILD, SOURCE> {
19 fn child_from_source(
20 &self,
21 db: &impl DefDatabase,
22 child_source: InFile<SOURCE>,
23 ) -> Option<CHILD>;
24}
25
26impl ChildFromSource<FunctionId, ast::FnDef> for TraitId {
27 fn child_from_source(
28 &self,
29 db: &impl DefDatabase,
30 child_source: InFile<ast::FnDef>,
31 ) -> Option<FunctionId> {
32 let data = db.trait_data(*self);
33 data.items
34 .iter()
35 .filter_map(|(_, item)| match item {
36 AssocItemId::FunctionId(it) => Some(*it),
37 _ => None,
38 })
39 .find(|func| {
40 let source = func.lookup(db).source(db);
41 same_source(&source, &child_source)
42 })
43 }
44}
45
46impl ChildFromSource<FunctionId, ast::FnDef> for ImplId {
47 fn child_from_source(
48 &self,
49 db: &impl DefDatabase,
50 child_source: InFile<ast::FnDef>,
51 ) -> Option<FunctionId> {
52 let data = db.impl_data(*self);
53 data.items
54 .iter()
55 .filter_map(|item| match item {
56 AssocItemId::FunctionId(it) => Some(*it),
57 _ => None,
58 })
59 .find(|func| {
60 let source = func.lookup(db).source(db);
61 same_source(&source, &child_source)
62 })
63 }
64}
65
66impl ChildFromSource<FunctionId, ast::FnDef> for ModuleId {
67 fn child_from_source(
68 &self,
69 db: &impl DefDatabase,
70 child_source: InFile<ast::FnDef>,
71 ) -> Option<FunctionId> {
72 let crate_def_map = db.crate_def_map(self.krate);
73 let res = crate_def_map[self.local_id]
74 .scope
75 .declarations()
76 .filter_map(|item| match item {
77 ModuleDefId::FunctionId(it) => Some(it),
78 _ => None,
79 })
80 .find(|func| {
81 let source = func.lookup(db).source(db);
82 same_source(&source, &child_source)
83 });
84 res
85 }
86}
87
88impl ChildFromSource<ConstId, ast::ConstDef> for TraitId {
89 fn child_from_source(
90 &self,
91 db: &impl DefDatabase,
92 child_source: InFile<ast::ConstDef>,
93 ) -> Option<ConstId> {
94 let data = db.trait_data(*self);
95 data.items
96 .iter()
97 .filter_map(|(_, item)| match item {
98 AssocItemId::ConstId(it) => Some(*it),
99 _ => None,
100 })
101 .find(|func| {
102 let source = func.lookup(db).source(db);
103 same_source(&source, &child_source)
104 })
105 }
106}
107
108impl ChildFromSource<ConstId, ast::ConstDef> for ImplId {
109 fn child_from_source(
110 &self,
111 db: &impl DefDatabase,
112 child_source: InFile<ast::ConstDef>,
113 ) -> Option<ConstId> {
114 let data = db.impl_data(*self);
115 data.items
116 .iter()
117 .filter_map(|item| match item {
118 AssocItemId::ConstId(it) => Some(*it),
119 _ => None,
120 })
121 .find(|func| {
122 let source = func.lookup(db).source(db);
123 same_source(&source, &child_source)
124 })
125 }
126}
127
128impl ChildFromSource<ConstId, ast::ConstDef> for ModuleId {
129 fn child_from_source(
130 &self,
131 db: &impl DefDatabase,
132 child_source: InFile<ast::ConstDef>,
133 ) -> Option<ConstId> {
134 let crate_def_map = db.crate_def_map(self.krate);
135 let res = crate_def_map[self.local_id]
136 .scope
137 .declarations()
138 .filter_map(|item| match item {
139 ModuleDefId::ConstId(it) => Some(it),
140 _ => None,
141 })
142 .find(|func| {
143 let source = func.lookup(db).source(db);
144 same_source(&source, &child_source)
145 });
146 res
147 }
148}
149
150impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for TraitId {
151 fn child_from_source(
152 &self,
153 db: &impl DefDatabase,
154 child_source: InFile<ast::TypeAliasDef>,
155 ) -> Option<TypeAliasId> {
156 let data = db.trait_data(*self);
157 data.items
158 .iter()
159 .filter_map(|(_, item)| match item {
160 AssocItemId::TypeAliasId(it) => Some(*it),
161 _ => None,
162 })
163 .find(|func| {
164 let source = func.lookup(db).source(db);
165 same_source(&source, &child_source)
166 })
167 }
168}
169
170impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ImplId {
171 fn child_from_source(
172 &self,
173 db: &impl DefDatabase,
174 child_source: InFile<ast::TypeAliasDef>,
175 ) -> Option<TypeAliasId> {
176 let data = db.impl_data(*self);
177 data.items
178 .iter()
179 .filter_map(|item| match item {
180 AssocItemId::TypeAliasId(it) => Some(*it),
181 _ => None,
182 })
183 .find(|func| {
184 let source = func.lookup(db).source(db);
185 same_source(&source, &child_source)
186 })
187 }
188}
189
190impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ModuleId {
191 fn child_from_source(
192 &self,
193 db: &impl DefDatabase,
194 child_source: InFile<ast::TypeAliasDef>,
195 ) -> Option<TypeAliasId> {
196 let crate_def_map = db.crate_def_map(self.krate);
197 let res = crate_def_map[self.local_id]
198 .scope
199 .declarations()
200 .filter_map(|item| match item {
201 ModuleDefId::TypeAliasId(it) => Some(it),
202 _ => None,
203 })
204 .find(|func| {
205 let source = func.lookup(db).source(db);
206 same_source(&source, &child_source)
207 });
208 res
209 }
210}
211
212impl ChildFromSource<StaticId, ast::StaticDef> for ModuleId {
213 fn child_from_source(
214 &self,
215 db: &impl DefDatabase,
216 child_source: InFile<ast::StaticDef>,
217 ) -> Option<StaticId> {
218 let crate_def_map = db.crate_def_map(self.krate);
219 let res = crate_def_map[self.local_id]
220 .scope
221 .declarations()
222 .filter_map(|item| match item {
223 ModuleDefId::StaticId(it) => Some(it),
224 _ => None,
225 })
226 .find(|func| {
227 let source = func.lookup(db).source(db);
228 same_source(&source, &child_source)
229 });
230 res
231 }
232}
233
234impl ChildFromSource<StructFieldId, Either<ast::TupleFieldDef, ast::RecordFieldDef>> for VariantId {
235 fn child_from_source(
236 &self,
237 db: &impl DefDatabase,
238 child_source: InFile<Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
239 ) -> Option<StructFieldId> {
240 let arena_map = self.child_source(db);
241 let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
242 child_source.file_id == arena_map.file_id
243 && match (source, &child_source.value) {
244 (Either::Left(a), Either::Left(b)) => AstPtr::new(a) == AstPtr::new(b),
245 (Either::Right(a), Either::Right(b)) => AstPtr::new(a) == AstPtr::new(b),
246 _ => false,
247 }
248 })?;
249 Some(StructFieldId { parent: *self, local_id })
250 }
251}
252
253impl ChildFromSource<EnumVariantId, ast::EnumVariant> for EnumId {
254 fn child_from_source(
255 &self,
256 db: &impl DefDatabase,
257 child_source: InFile<ast::EnumVariant>,
258 ) -> Option<EnumVariantId> {
259 let arena_map = self.child_source(db);
260 let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
261 child_source.file_id == arena_map.file_id
262 && AstPtr::new(*source) == AstPtr::new(&child_source.value)
263 })?;
264 Some(EnumVariantId { parent: *self, local_id })
265 }
266}
267
268/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
269/// equal if they point to exactly the same object.
270///
271/// In general, we do not guarantee that we have exactly one instance of a
272/// syntax tree for each file. We probably should add such guarantee, but, for
273/// the time being, we will use identity-less AstPtr comparison.
274fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool {
275 s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new)
276}
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs
new file mode 100644
index 000000000..6f269d7b0
--- /dev/null
+++ b/crates/ra_hir_def/src/dyn_map.rs
@@ -0,0 +1,108 @@
1//! This module defines a `DynMap` -- a container for heterogeneous maps.
2//!
3//! This means that `DynMap` stores a bunch of hash maps inside, and those maps
4//! can be of different types.
5//!
6//! It is used like this:
7//!
8//! ```
9//! // keys define submaps of a `DynMap`
10//! const STRING_TO_U32: Key<String, u32> = Key::new();
11//! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new();
12//!
13//! // Note: concrete type, no type params!
14//! let mut map = DynMap::new();
15//!
16//! // To access a specific map, index the `DynMap` by `Key`:
17//! map[STRING_TO_U32].insert("hello".to_string(), 92);
18//! let value = map[U32_TO_VEC].get(92);
19//! assert!(value.is_none());
20//! ```
21//!
22//! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are
23//! a coincidence.
24use std::{
25 hash::Hash,
26 marker::PhantomData,
27 ops::{Index, IndexMut},
28};
29
30use anymap::Map;
31use rustc_hash::FxHashMap;
32
33pub struct Key<K, V, P = (K, V)> {
34 _phantom: PhantomData<(K, V, P)>,
35}
36
37impl<K, V, P> Key<K, V, P> {
38 pub(crate) const fn new() -> Key<K, V, P> {
39 Key { _phantom: PhantomData }
40 }
41}
42
43impl<K, V, P> Copy for Key<K, V, P> {}
44
45impl<K, V, P> Clone for Key<K, V, P> {
46 fn clone(&self) -> Key<K, V, P> {
47 *self
48 }
49}
50
51pub trait Policy {
52 type K;
53 type V;
54
55 fn insert(map: &mut DynMap, key: Self::K, value: Self::V);
56 fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>;
57}
58
59impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) {
60 type K = K;
61 type V = V;
62 fn insert(map: &mut DynMap, key: K, value: V) {
63 map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value);
64 }
65 fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> {
66 map.map.get::<FxHashMap<K, V>>()?.get(key)
67 }
68}
69
70pub struct DynMap {
71 pub(crate) map: Map,
72}
73
74impl Default for DynMap {
75 fn default() -> Self {
76 DynMap { map: Map::new() }
77 }
78}
79
80#[repr(transparent)]
81pub struct KeyMap<KEY> {
82 map: DynMap,
83 _phantom: PhantomData<KEY>,
84}
85
86impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
87 pub fn insert(&mut self, key: P::K, value: P::V) {
88 P::insert(&mut self.map, key, value)
89 }
90 pub fn get(&self, key: &P::K) -> Option<&P::V> {
91 P::get(&self.map, key)
92 }
93}
94
95impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap {
96 type Output = KeyMap<Key<P::K, P::V, P>>;
97 fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output {
98 // Safe due to `#[repr(transparent)]`.
99 unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) }
100 }
101}
102
103impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap {
104 fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output {
105 // Safe due to `#[repr(transparent)]`.
106 unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) }
107 }
108}
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 5f648ffc3..976cf72d0 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -4,21 +4,29 @@
4//! in rustc. 4//! in rustc.
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use hir_expand::name::{self, AsName, Name}; 7use either::Either;
8use hir_expand::{
9 name::{self, AsName, Name},
10 InFile,
11};
12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId;
8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 14use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9 15
10use crate::{ 16use crate::{
17 child_by_source::ChildBySource,
11 db::DefDatabase, 18 db::DefDatabase,
19 dyn_map::DynMap,
20 keys,
21 src::HasChildSource,
12 src::HasSource, 22 src::HasSource,
13 type_ref::{TypeBound, TypeRef}, 23 type_ref::{TypeBound, TypeRef},
14 AdtId, AstItemDef, ContainerId, GenericDefId, Lookup, 24 AdtId, AstItemDef, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
15}; 25};
16 26
17/// Data about a generic parameter (to a function, struct, impl, ...). 27/// Data about a generic parameter (to a function, struct, impl, ...).
18#[derive(Clone, PartialEq, Eq, Debug)] 28#[derive(Clone, PartialEq, Eq, Debug)]
19pub struct GenericParam { 29pub struct TypeParamData {
20 // FIXME: give generic params proper IDs
21 pub idx: u32,
22 pub name: Name, 30 pub name: Name,
23 pub default: Option<TypeRef>, 31 pub default: Option<TypeRef>,
24} 32}
@@ -26,8 +34,8 @@ pub struct GenericParam {
26/// Data about the generic parameters of a function, struct, impl, etc. 34/// Data about the generic parameters of a function, struct, impl, etc.
27#[derive(Clone, PartialEq, Eq, Debug)] 35#[derive(Clone, PartialEq, Eq, Debug)]
28pub struct GenericParams { 36pub struct GenericParams {
29 pub parent_params: Option<Arc<GenericParams>>, 37 pub types: Arena<LocalTypeParamId, TypeParamData>,
30 pub params: Vec<GenericParam>, 38 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
31 pub where_predicates: Vec<WherePredicate>, 39 pub where_predicates: Vec<WherePredicate>,
32} 40}
33 41
@@ -41,63 +49,87 @@ pub struct WherePredicate {
41 pub bound: TypeBound, 49 pub bound: TypeBound,
42} 50}
43 51
52type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
53
44impl GenericParams { 54impl GenericParams {
45 pub(crate) fn generic_params_query( 55 pub(crate) fn generic_params_query(
46 db: &impl DefDatabase, 56 db: &impl DefDatabase,
47 def: GenericDefId, 57 def: GenericDefId,
48 ) -> Arc<GenericParams> { 58 ) -> Arc<GenericParams> {
49 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); 59 let (params, _source_map) = GenericParams::new(db, def.into());
50 Arc::new(GenericParams::new(db, def.into(), parent_generics)) 60 Arc::new(params)
51 } 61 }
52 62
53 fn new( 63 fn new(db: &impl DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
54 db: &impl DefDatabase, 64 let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() };
55 def: GenericDefId, 65 let mut sm = ArenaMap::default();
56 parent_params: Option<Arc<GenericParams>>,
57 ) -> GenericParams {
58 let mut generics =
59 GenericParams { params: Vec::new(), parent_params, where_predicates: Vec::new() };
60 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
61 // FIXME: add `: Sized` bound for everything except for `Self` in traits 66 // FIXME: add `: Sized` bound for everything except for `Self` in traits
62 match def { 67 let file_id = match def {
63 GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start), 68 GenericDefId::FunctionId(it) => {
64 GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value, start), 69 let src = it.lookup(db).source(db);
65 GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value, start), 70 generics.fill(&mut sm, &src.value);
66 GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start), 71 src.file_id
72 }
73 GenericDefId::AdtId(AdtId::StructId(it)) => {
74 let src = it.source(db);
75 generics.fill(&mut sm, &src.value);
76 src.file_id
77 }
78 GenericDefId::AdtId(AdtId::UnionId(it)) => {
79 let src = it.source(db);
80 generics.fill(&mut sm, &src.value);
81 src.file_id
82 }
83 GenericDefId::AdtId(AdtId::EnumId(it)) => {
84 let src = it.source(db);
85 generics.fill(&mut sm, &src.value);
86 src.file_id
87 }
67 GenericDefId::TraitId(it) => { 88 GenericDefId::TraitId(it) => {
89 let src = it.source(db);
90
68 // traits get the Self type as an implicit first type parameter 91 // traits get the Self type as an implicit first type parameter
69 generics.params.push(GenericParam { 92 let self_param_id =
70 idx: start, 93 generics.types.alloc(TypeParamData { name: name::SELF_TYPE, default: None });
71 name: name::SELF_TYPE, 94 sm.insert(self_param_id, Either::Left(src.value.clone()));
72 default: None,
73 });
74 generics.fill(&it.source(db).value, start + 1);
75 // add super traits as bounds on Self 95 // add super traits as bounds on Self
76 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
77 let self_param = TypeRef::Path(name::SELF_TYPE.into()); 97 let self_param = TypeRef::Path(name::SELF_TYPE.into());
78 generics.fill_bounds(&it.source(db).value, self_param); 98 generics.fill_bounds(&src.value, self_param);
99
100 generics.fill(&mut sm, &src.value);
101 src.file_id
102 }
103 GenericDefId::TypeAliasId(it) => {
104 let src = it.lookup(db).source(db);
105 generics.fill(&mut sm, &src.value);
106 src.file_id
79 } 107 }
80 GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start),
81 // Note that we don't add `Self` here: in `impl`s, `Self` is not a 108 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
82 // type-parameter, but rather is a type-alias for impl's target 109 // type-parameter, but rather is a type-alias for impl's target
83 // type, so this is handled by the resolver. 110 // type, so this is handled by the resolver.
84 GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start), 111 GenericDefId::ImplId(it) => {
85 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {} 112 let src = it.source(db);
86 } 113 generics.fill(&mut sm, &src.value);
114 src.file_id
115 }
116 // We won't be using this ID anyway
117 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
118 };
87 119
88 generics 120 (generics, InFile::new(file_id, sm))
89 } 121 }
90 122
91 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { 123 fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) {
92 if let Some(params) = node.type_param_list() { 124 if let Some(params) = node.type_param_list() {
93 self.fill_params(params, start) 125 self.fill_params(sm, params)
94 } 126 }
95 if let Some(where_clause) = node.where_clause() { 127 if let Some(where_clause) = node.where_clause() {
96 self.fill_where_predicates(where_clause); 128 self.fill_where_predicates(where_clause);
97 } 129 }
98 } 130 }
99 131
100 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) { 132 fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) {
101 for bound in 133 for bound in
102 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) 134 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
103 { 135 {
@@ -105,13 +137,14 @@ impl GenericParams {
105 } 137 }
106 } 138 }
107 139
108 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { 140 fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) {
109 for (idx, type_param) in params.type_params().enumerate() { 141 for type_param in params.type_params() {
110 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 142 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
111 // FIXME: Use `Path::from_src` 143 // FIXME: Use `Path::from_src`
112 let default = type_param.default_type().map(TypeRef::from_ast); 144 let default = type_param.default_type().map(TypeRef::from_ast);
113 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; 145 let param = TypeParamData { name: name.clone(), default };
114 self.params.push(param); 146 let param_id = self.types.alloc(param);
147 sm.insert(param_id, Either::Right(type_param.clone()));
115 148
116 let type_ref = TypeRef::Path(name.into()); 149 let type_ref = TypeRef::Path(name.into());
117 self.fill_bounds(&type_param, type_ref); 150 self.fill_bounds(&type_param, type_ref);
@@ -140,45 +173,31 @@ impl GenericParams {
140 self.where_predicates.push(WherePredicate { type_ref, bound }); 173 self.where_predicates.push(WherePredicate { type_ref, bound });
141 } 174 }
142 175
143 pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 176 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
144 self.params.iter().find(|p| &p.name == name) 177 self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None })
145 }
146
147 pub fn count_parent_params(&self) -> usize {
148 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
149 }
150
151 pub fn count_params_including_parent(&self) -> usize {
152 let parent_count = self.count_parent_params();
153 parent_count + self.params.len()
154 }
155
156 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
157 if let Some(parent) = &self.parent_params {
158 parent.for_each_param(f);
159 }
160 self.params.iter().for_each(f);
161 } 178 }
179}
162 180
163 pub fn params_including_parent(&self) -> Vec<&GenericParam> { 181impl HasChildSource for GenericDefId {
164 let mut vec = Vec::with_capacity(self.count_params_including_parent()); 182 type ChildId = LocalTypeParamId;
165 self.for_each_param(&mut |p| vec.push(p)); 183 type Value = Either<ast::TraitDef, ast::TypeParam>;
166 vec 184 fn child_source(&self, db: &impl DefDatabase) -> InFile<SourceMap> {
185 let (_, sm) = GenericParams::new(db, *self);
186 sm
167 } 187 }
168} 188}
169 189
170fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> { 190impl ChildBySource for GenericDefId {
171 let container = match def { 191 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
172 GenericDefId::FunctionId(it) => it.lookup(db).container, 192 let mut res = DynMap::default();
173 GenericDefId::TypeAliasId(it) => it.lookup(db).container, 193 let arena_map = self.child_source(db);
174 GenericDefId::ConstId(it) => it.lookup(db).container, 194 let arena_map = arena_map.as_ref();
175 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), 195 for (local_id, src) in arena_map.value.iter() {
176 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, 196 let id = TypeParamId { parent: *self, local_id };
177 }; 197 if let Either::Right(type_param) = src {
178 198 res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id)
179 match container { 199 }
180 ContainerId::ImplId(it) => Some(it.into()), 200 }
181 ContainerId::TraitId(it) => Some(it.into()), 201 res
182 ContainerId::ModuleId(_) => None,
183 } 202 }
184} 203}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
new file mode 100644
index 000000000..be702a4f8
--- /dev/null
+++ b/crates/ra_hir_def/src/keys.rs
@@ -0,0 +1,49 @@
1//! keys to be used with `DynMap`
2
3use std::marker::PhantomData;
4
5use hir_expand::InFile;
6use ra_syntax::{ast, AstNode, AstPtr};
7use rustc_hash::FxHashMap;
8
9use crate::{
10 dyn_map::{DynMap, Policy},
11 ConstId, EnumVariantId, FunctionId, StaticId, StructFieldId, TypeAliasId, TypeParamId,
12};
13
14type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
15
16pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new();
17pub const CONST: Key<ast::ConstDef, ConstId> = Key::new();
18pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new();
19pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new();
20pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
21pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new();
22pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new();
23pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
24
25/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
26/// equal if they point to exactly the same object.
27///
28/// In general, we do not guarantee that we have exactly one instance of a
29/// syntax tree for each file. We probably should add such guarantee, but, for
30/// the time being, we will use identity-less AstPtr comparison.
31pub struct AstPtrPolicy<AST, ID> {
32 _phantom: PhantomData<(AST, ID)>,
33}
34
35impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> {
36 type K = InFile<AST>;
37 type V = ID;
38 fn insert(map: &mut DynMap, key: InFile<AST>, value: ID) {
39 let key = key.as_ref().map(AstPtr::new);
40 map.map
41 .entry::<FxHashMap<InFile<AstPtr<AST>>, ID>>()
42 .or_insert_with(Default::default)
43 .insert(key, value);
44 }
45 fn get<'a>(map: &'a DynMap, key: &InFile<AST>) -> Option<&'a ID> {
46 let key = key.as_ref().map(AstPtr::new);
47 map.map.get::<FxHashMap<InFile<AstPtr<AST>>, ID>>()?.get(&key)
48 }
49}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index e02622f62..569da4f28 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -16,6 +16,9 @@ pub mod builtin_type;
16pub mod diagnostics; 16pub mod diagnostics;
17pub mod per_ns; 17pub mod per_ns;
18 18
19pub mod dyn_map;
20pub mod keys;
21
19pub mod adt; 22pub mod adt;
20pub mod data; 23pub mod data;
21pub mod generics; 24pub mod generics;
@@ -30,7 +33,7 @@ mod trace;
30pub mod nameres; 33pub mod nameres;
31 34
32pub mod src; 35pub mod src;
33pub mod child_from_source; 36pub mod child_by_source;
34 37
35#[cfg(test)] 38#[cfg(test)]
36mod test_db; 39mod test_db;
@@ -315,6 +318,16 @@ macro_rules! impl_froms {
315} 318}
316 319
317#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 320#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
321pub struct TypeParamId {
322 pub parent: GenericDefId,
323 pub local_id: LocalTypeParamId,
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
327pub struct LocalTypeParamId(RawId);
328impl_arena_id!(LocalTypeParamId);
329
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
318pub enum ContainerId { 331pub enum ContainerId {
319 ModuleId(ModuleId), 332 ModuleId(ModuleId),
320 ImplId(ImplId), 333 ImplId(ImplId),
@@ -512,6 +525,20 @@ impl HasModule for DefWithBodyId {
512 } 525 }
513} 526}
514 527
528impl HasModule for GenericDefId {
529 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
530 match self {
531 GenericDefId::FunctionId(it) => it.lookup(db).module(db),
532 GenericDefId::AdtId(it) => it.module(db),
533 GenericDefId::TraitId(it) => it.module(db),
534 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
535 GenericDefId::ImplId(it) => it.module(db),
536 GenericDefId::EnumVariantId(it) => it.parent.module(db),
537 GenericDefId::ConstId(it) => it.lookup(db).module(db),
538 }
539 }
540}
541
515impl HasModule for StaticLoc { 542impl HasModule for StaticLoc {
516 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { 543 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId {
517 self.container 544 self.container
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 3b3f30eec..3ff071f9e 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -7,7 +7,7 @@ use hir_expand::{
7 builtin_derive::find_builtin_derive, 7 builtin_derive::find_builtin_derive,
8 builtin_macro::find_builtin_macro, 8 builtin_macro::find_builtin_macro,
9 name::{self, AsName, Name}, 9 name::{self, AsName, Name},
10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, MacroFileKind, 10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
11}; 11};
12use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
13use ra_db::{CrateId, FileId}; 13use ra_db::{CrateId, FileId};
@@ -624,7 +624,7 @@ where
624 self.macro_stack_monitor.increase(macro_def_id); 624 self.macro_stack_monitor.increase(macro_def_id);
625 625
626 if !self.macro_stack_monitor.is_poison(macro_def_id) { 626 if !self.macro_stack_monitor.is_poison(macro_def_id) {
627 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); 627 let file_id: HirFileId = macro_call_id.as_file();
628 let raw_items = self.db.raw_items(file_id); 628 let raw_items = self.db.raw_items(file_id);
629 let mod_dir = self.mod_dirs[&module_id].clone(); 629 let mod_dir = self.mod_dirs[&module_id].clone();
630 ModCollector { 630 ModCollector {
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 00e866bf9..3a5105028 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -11,8 +11,6 @@ use crate::ModuleDefId;
11pub struct PerNs { 11pub struct PerNs {
12 pub types: Option<ModuleDefId>, 12 pub types: Option<ModuleDefId>,
13 pub values: Option<ModuleDefId>, 13 pub values: Option<ModuleDefId>,
14 /// Since macros has different type, many methods simply ignore it.
15 /// We can only use special method like `get_macros` to access it.
16 pub macros: Option<MacroDefId>, 14 pub macros: Option<MacroDefId>,
17} 15}
18 16
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 7d4df222e..4c859e497 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -19,11 +19,12 @@ use crate::{
19 per_ns::PerNs, 19 per_ns::PerNs,
20 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, 20 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
21 GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, 21 GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId,
22 StructId, TraitId, TypeAliasId, 22 StructId, TraitId, TypeAliasId, TypeParamId,
23}; 23};
24 24
25#[derive(Debug, Clone, Default)] 25#[derive(Debug, Clone, Default)]
26pub struct Resolver { 26pub struct Resolver {
27 // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton?
27 scopes: Vec<Scope>, 28 scopes: Vec<Scope>,
28} 29}
29 30
@@ -58,7 +59,7 @@ enum Scope {
58#[derive(Debug, Clone, PartialEq, Eq, Hash)] 59#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59pub enum TypeNs { 60pub enum TypeNs {
60 SelfType(ImplId), 61 SelfType(ImplId),
61 GenericParam(u32), 62 GenericParam(TypeParamId),
62 AdtId(AdtId), 63 AdtId(AdtId),
63 AdtSelfType(AdtId), 64 AdtSelfType(AdtId),
64 // Yup, enum variants are added to the types ns, but any usage of variant as 65 // Yup, enum variants are added to the types ns, but any usage of variant as
@@ -152,10 +153,13 @@ impl Resolver {
152 Scope::ExprScope(_) => continue, 153 Scope::ExprScope(_) => continue,
153 Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, 154 Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue,
154 155
155 Scope::GenericParams { params, .. } => { 156 Scope::GenericParams { params, def } => {
156 if let Some(param) = params.find_by_name(first_name) { 157 if let Some(local_id) = params.find_by_name(first_name) {
157 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 158 let idx = if path.segments.len() == 1 { None } else { Some(1) };
158 return Some((TypeNs::GenericParam(param.idx), idx)); 159 return Some((
160 TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
161 idx,
162 ));
159 } 163 }
160 } 164 }
161 Scope::ImplBlockScope(impl_) => { 165 Scope::ImplBlockScope(impl_) => {
@@ -246,9 +250,9 @@ impl Resolver {
246 } 250 }
247 Scope::ExprScope(_) => continue, 251 Scope::ExprScope(_) => continue,
248 252
249 Scope::GenericParams { params, .. } if n_segments > 1 => { 253 Scope::GenericParams { params, def } if n_segments > 1 => {
250 if let Some(param) = params.find_by_name(first_name) { 254 if let Some(local_id) = params.find_by_name(first_name) {
251 let ty = TypeNs::GenericParam(param.idx); 255 let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
252 return Some(ResolveValueResult::Partial(ty, 1)); 256 return Some(ResolveValueResult::Partial(ty, 1));
253 } 257 }
254 } 258 }
@@ -368,6 +372,7 @@ impl Resolver {
368 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { 372 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a {
369 self.scopes 373 self.scopes
370 .iter() 374 .iter()
375 .rev()
371 .filter_map(|scope| match scope { 376 .filter_map(|scope| match scope {
372 Scope::GenericParams { params, .. } => Some(params), 377 Scope::GenericParams { params, .. } => Some(params),
373 _ => None, 378 _ => None,
@@ -376,14 +381,14 @@ impl Resolver {
376 } 381 }
377 382
378 pub fn generic_def(&self) -> Option<GenericDefId> { 383 pub fn generic_def(&self) -> Option<GenericDefId> {
379 self.scopes.iter().find_map(|scope| match scope { 384 self.scopes.iter().rev().find_map(|scope| match scope {
380 Scope::GenericParams { def, .. } => Some(*def), 385 Scope::GenericParams { def, .. } => Some(*def),
381 _ => None, 386 _ => None,
382 }) 387 })
383 } 388 }
384 389
385 pub fn body_owner(&self) -> Option<DefWithBodyId> { 390 pub fn body_owner(&self) -> Option<DefWithBodyId> {
386 self.scopes.iter().find_map(|scope| match scope { 391 self.scopes.iter().rev().find_map(|scope| match scope {
387 Scope::ExprScope(it) => Some(it.owner), 392 Scope::ExprScope(it) => Some(it.owner),
388 _ => None, 393 _ => None,
389 }) 394 })
@@ -394,7 +399,7 @@ pub enum ScopeDef {
394 PerNs(PerNs), 399 PerNs(PerNs),
395 ImplSelfType(ImplId), 400 ImplSelfType(ImplId),
396 AdtSelfType(AdtId), 401 AdtSelfType(AdtId),
397 GenericParam(u32), 402 GenericParam(TypeParamId),
398 Local(PatId), 403 Local(PatId),
399} 404}
400 405
@@ -425,9 +430,12 @@ impl Scope {
425 }); 430 });
426 } 431 }
427 } 432 }
428 Scope::GenericParams { params, .. } => { 433 Scope::GenericParams { params, def } => {
429 for param in params.params.iter() { 434 for (local_id, param) in params.types.iter() {
430 f(param.name.clone(), ScopeDef::GenericParam(param.idx)) 435 f(
436 param.name.clone(),
437 ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
438 )
431 } 439 }
432 } 440 }
433 Scope::ImplBlockScope(i) => { 441 Scope::ImplBlockScope(i) => {
@@ -473,7 +481,7 @@ impl Resolver {
473 481
474 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { 482 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
475 let params = db.generic_params(def); 483 let params = db.generic_params(def);
476 if params.params.is_empty() { 484 if params.types.is_empty() {
477 self 485 self
478 } else { 486 } else {
479 self.push_scope(Scope::GenericParams { def, params }) 487 self.push_scope(Scope::GenericParams { def, params })
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 78fa9b09a..574637602 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -208,7 +208,7 @@ fn partial_ord_expand(
208#[cfg(test)] 208#[cfg(test)]
209mod tests { 209mod tests {
210 use super::*; 210 use super::*;
211 use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc, MacroFileKind}; 211 use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc};
212 use ra_db::{fixture::WithFixture, SourceDatabase}; 212 use ra_db::{fixture::WithFixture, SourceDatabase};
213 213
214 fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String { 214 fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String {
@@ -229,7 +229,7 @@ mod tests {
229 }; 229 };
230 230
231 let id = db.intern_macro(loc); 231 let id = db.intern_macro(loc);
232 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Items)).unwrap(); 232 let parsed = db.parse_or_expand(id.as_file()).unwrap();
233 233
234 // FIXME text() for syntax nodes parsed from token tree looks weird 234 // FIXME text() for syntax nodes parsed from token tree looks weird
235 // because there's no whitespace, see below 235 // because there's no whitespace, see below
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 35f99b2bc..c7071fe85 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -2,8 +2,7 @@
2use crate::db::AstDatabase; 2use crate::db::AstDatabase;
3use crate::{ 3use crate::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, TextUnit,
6 TextUnit,
7}; 6};
8 7
9use crate::quote; 8use crate::quote;
@@ -49,7 +48,11 @@ register_builtin! {
49 (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, 48 (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand,
50 (FILE_MACRO, File) => file_expand, 49 (FILE_MACRO, File) => file_expand,
51 (LINE_MACRO, Line) => line_expand, 50 (LINE_MACRO, Line) => line_expand,
52 (STRINGIFY_MACRO, Stringify) => stringify_expand 51 (STRINGIFY_MACRO, Stringify) => stringify_expand,
52 (FORMAT_ARGS_MACRO, FormatArgs) => format_args_expand,
53 // format_args_nl only differs in that it adds a newline in the end,
54 // so we use the same stub expansion for now
55 (FORMAT_ARGS_NL_MACRO, FormatArgsNl) => format_args_expand
53} 56}
54 57
55fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 58fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
@@ -86,7 +89,7 @@ fn line_expand(
86 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 89 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
87 let arg_start = arg.text_range().start(); 90 let arg_start = arg.text_range().start();
88 91
89 let file = id.as_file(MacroFileKind::Expr); 92 let file = id.as_file();
90 let line_num = to_line_number(db, file, arg_start); 93 let line_num = to_line_number(db, file, arg_start);
91 94
92 let expanded = quote! { 95 let expanded = quote! {
@@ -154,7 +157,7 @@ fn column_expand(
154 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 157 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
155 let col_start = macro_call.syntax().text_range().start(); 158 let col_start = macro_call.syntax().text_range().start();
156 159
157 let file = id.as_file(MacroFileKind::Expr); 160 let file = id.as_file();
158 let col_num = to_col_number(db, file, col_start); 161 let col_num = to_col_number(db, file, col_start);
159 162
160 let expanded = quote! { 163 let expanded = quote! {
@@ -200,6 +203,41 @@ fn compile_error_expand(
200 Err(mbe::ExpandError::BindingError("Must be a string".into())) 203 Err(mbe::ExpandError::BindingError("Must be a string".into()))
201} 204}
202 205
206fn format_args_expand(
207 _db: &dyn AstDatabase,
208 _id: MacroCallId,
209 tt: &tt::Subtree,
210) -> Result<tt::Subtree, mbe::ExpandError> {
211 // We expand `format_args!("", arg1, arg2)` to
212 // `std::fmt::Arguments::new_v1(&[], &[&arg1, &arg2])`,
213 // which is still not really correct, but close enough for now
214 let mut args = Vec::new();
215 let mut current = Vec::new();
216 for tt in tt.token_trees.iter().cloned() {
217 match tt {
218 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
219 args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current });
220 current = Vec::new();
221 }
222 _ => {
223 current.push(tt);
224 }
225 }
226 }
227 if !current.is_empty() {
228 args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current });
229 }
230 if args.is_empty() {
231 return Err(mbe::ExpandError::NoMatchingRule);
232 }
233 let _format_string = args.remove(0);
234 let arg_tts = args.into_iter().flat_map(|arg| (quote! { & #arg , }).token_trees);
235 let expanded = quote! {
236 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
237 };
238 Ok(expanded)
239}
240
203#[cfg(test)] 241#[cfg(test)]
204mod tests { 242mod tests {
205 use super::*; 243 use super::*;
@@ -230,7 +268,7 @@ mod tests {
230 }; 268 };
231 269
232 let id = db.intern_macro(loc); 270 let id = db.intern_macro(loc);
233 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Expr)).unwrap(); 271 let parsed = db.parse_or_expand(id.as_file()).unwrap();
234 272
235 parsed.text().to_string() 273 parsed.text().to_string()
236 } 274 }
@@ -307,4 +345,21 @@ mod tests {
307 345
308 assert_eq!(expanded, r#"loop{"error!"}"#); 346 assert_eq!(expanded, r#"loop{"error!"}"#);
309 } 347 }
348
349 #[test]
350 fn test_format_args_expand() {
351 let expanded = expand_builtin_macro(
352 r#"
353 #[rustc_builtin_macro]
354 macro_rules! format_args {
355 ($fmt:expr) => ({ /* compiler built-in */ });
356 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
357 }
358 format_args!("{} {:?}", arg1(a, b, c), arg2);
359"#,
360 BuiltinFnLikeExpander::FormatArgs,
361 );
362
363 assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[&arg1(a,b,c),&arg2,])"#);
364 }
310} 365}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 99dabf3fb..4bdb41619 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,11 +6,11 @@ use mbe::MacroRules;
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr,
13 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, 13 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
14}; 14};
15 15
16#[derive(Debug, Clone, Eq, PartialEq)] 16#[derive(Debug, Clone, Eq, PartialEq)]
@@ -45,8 +45,8 @@ impl TokenExpander {
45 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 45 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
46 match self { 46 match self {
47 TokenExpander::MacroRules(it) => it.map_id_up(id), 47 TokenExpander::MacroRules(it) => it.map_id_up(id),
48 TokenExpander::Builtin(..) => (id, mbe::Origin::Def), 48 TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
49 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Def), 49 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
50 } 50 }
51 } 51 }
52} 52}
@@ -155,11 +155,42 @@ pub(crate) fn parse_macro(
155 }) 155 })
156 .ok()?; 156 .ok()?;
157 157
158 let fragment_kind = match macro_file.macro_file_kind { 158 let fragment_kind = to_fragment_kind(db, macro_call_id);
159 MacroFileKind::Items => FragmentKind::Items, 159
160 MacroFileKind::Expr => FragmentKind::Expr,
161 MacroFileKind::Statements => FragmentKind::Statements,
162 };
163 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; 160 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
164 Some((parse, Arc::new(rev_token_map))) 161 Some((parse, Arc::new(rev_token_map)))
165} 162}
163
164/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
165/// FIXME: Not completed
166fn to_fragment_kind(db: &dyn AstDatabase, macro_call_id: MacroCallId) -> FragmentKind {
167 let syn = db.lookup_intern_macro(macro_call_id).kind.node(db).value;
168
169 let parent = match syn.parent() {
170 Some(it) => it,
171 None => {
172 // FIXME:
173 // If it is root, which means the parent HirFile
174 // MacroKindFile must be non-items
175 // return expr now.
176 return FragmentKind::Expr;
177 }
178 };
179
180 match parent.kind() {
181 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
182 LET_STMT => {
183 // FIXME: Handle Pattern
184 FragmentKind::Expr
185 }
186 EXPR_STMT => FragmentKind::Statements,
187 BLOCK => FragmentKind::Statements,
188 ARG_LIST => FragmentKind::Expr,
189 TRY_EXPR => FragmentKind::Expr,
190 TUPLE_EXPR => FragmentKind::Expr,
191 _ => {
192 // Unknown , Just guess it is `Items`
193 FragmentKind::Items
194 }
195 }
196}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 59c69b91b..94e1e466a 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -76,6 +76,17 @@ impl HirFileId {
76 } 76 }
77 } 77 }
78 78
79 /// If this is a macro call, returns the syntax node of the call.
80 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
81 match self.0 {
82 HirFileIdRepr::FileId(_) => None,
83 HirFileIdRepr::MacroFile(macro_file) => {
84 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
85 Some(loc.kind.node(db))
86 }
87 }
88 }
89
79 /// Return expansion information if it is a macro-expansion file 90 /// Return expansion information if it is a macro-expansion file
80 pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> { 91 pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
81 match self.0 { 92 match self.0 {
@@ -106,14 +117,6 @@ impl HirFileId {
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107pub struct MacroFile { 118pub struct MacroFile {
108 macro_call_id: MacroCallId, 119 macro_call_id: MacroCallId,
109 macro_file_kind: MacroFileKind,
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub enum MacroFileKind {
114 Items,
115 Expr,
116 Statements,
117} 120}
118 121
119/// `MacroCallId` identifies a particular macro invocation, like 122/// `MacroCallId` identifies a particular macro invocation, like
@@ -176,6 +179,13 @@ impl MacroCallKind {
176 } 179 }
177 } 180 }
178 181
182 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
183 match self {
184 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
185 MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
186 }
187 }
188
179 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 189 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
180 match self { 190 match self {
181 MacroCallKind::FnLike(ast_id) => { 191 MacroCallKind::FnLike(ast_id) => {
@@ -187,9 +197,8 @@ impl MacroCallKind {
187} 197}
188 198
189impl MacroCallId { 199impl MacroCallId {
190 pub fn as_file(self, kind: MacroFileKind) -> HirFileId { 200 pub fn as_file(self) -> HirFileId {
191 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; 201 MacroFile { macro_call_id: self }.into()
192 macro_file.into()
193 } 202 }
194} 203}
195 204
@@ -283,3 +292,24 @@ impl<T> InFile<T> {
283 db.parse_or_expand(self.file_id).expect("source created from invalid file") 292 db.parse_or_expand(self.file_id).expect("source created from invalid file")
284 } 293 }
285} 294}
295
296impl<T: Clone> InFile<&T> {
297 pub fn cloned(&self) -> InFile<T> {
298 self.with_value(self.value.clone())
299 }
300}
301
302impl InFile<SyntaxNode> {
303 pub fn ancestors_with_macros<'a>(
304 self,
305 db: &'a impl crate::db::AstDatabase,
306 ) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a {
307 std::iter::successors(Some(self), move |node| match node.value.parent() {
308 Some(parent) => Some(node.with_value(parent)),
309 None => {
310 let parent_node = node.file_id.call_node(db)?;
311 Some(parent_node)
312 }
313 })
314 }
315}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index c5a191160..4f2f702c0 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -38,8 +38,8 @@ impl Name {
38 } 38 }
39 39
40 /// Shortcut to create inline plain text name 40 /// Shortcut to create inline plain text name
41 const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { 41 const fn new_inline_ascii(text: &[u8]) -> Name {
42 Name::new_text(SmolStr::new_inline_from_ascii(len, text)) 42 Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
43 } 43 }
44 44
45 /// Resolve a name from the text of token. 45 /// Resolve a name from the text of token.
@@ -105,68 +105,70 @@ impl AsName for ra_db::Dependency {
105} 105}
106 106
107// Primitives 107// Primitives
108pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); 108pub const ISIZE: Name = Name::new_inline_ascii(b"isize");
109pub const I8: Name = Name::new_inline_ascii(2, b"i8"); 109pub const I8: Name = Name::new_inline_ascii(b"i8");
110pub const I16: Name = Name::new_inline_ascii(3, b"i16"); 110pub const I16: Name = Name::new_inline_ascii(b"i16");
111pub const I32: Name = Name::new_inline_ascii(3, b"i32"); 111pub const I32: Name = Name::new_inline_ascii(b"i32");
112pub const I64: Name = Name::new_inline_ascii(3, b"i64"); 112pub const I64: Name = Name::new_inline_ascii(b"i64");
113pub const I128: Name = Name::new_inline_ascii(4, b"i128"); 113pub const I128: Name = Name::new_inline_ascii(b"i128");
114pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); 114pub const USIZE: Name = Name::new_inline_ascii(b"usize");
115pub const U8: Name = Name::new_inline_ascii(2, b"u8"); 115pub const U8: Name = Name::new_inline_ascii(b"u8");
116pub const U16: Name = Name::new_inline_ascii(3, b"u16"); 116pub const U16: Name = Name::new_inline_ascii(b"u16");
117pub const U32: Name = Name::new_inline_ascii(3, b"u32"); 117pub const U32: Name = Name::new_inline_ascii(b"u32");
118pub const U64: Name = Name::new_inline_ascii(3, b"u64"); 118pub const U64: Name = Name::new_inline_ascii(b"u64");
119pub const U128: Name = Name::new_inline_ascii(4, b"u128"); 119pub const U128: Name = Name::new_inline_ascii(b"u128");
120pub const F32: Name = Name::new_inline_ascii(3, b"f32"); 120pub const F32: Name = Name::new_inline_ascii(b"f32");
121pub const F64: Name = Name::new_inline_ascii(3, b"f64"); 121pub const F64: Name = Name::new_inline_ascii(b"f64");
122pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); 122pub const BOOL: Name = Name::new_inline_ascii(b"bool");
123pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); 123pub const CHAR: Name = Name::new_inline_ascii(b"char");
124pub const STR: Name = Name::new_inline_ascii(3, b"str"); 124pub const STR: Name = Name::new_inline_ascii(b"str");
125 125
126// Special names 126// Special names
127pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); 127pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self");
128pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); 128pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self");
129pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); 129pub const MACRO_RULES: Name = Name::new_inline_ascii(b"macro_rules");
130 130
131// Components of known path (value or mod name) 131// Components of known path (value or mod name)
132pub const STD: Name = Name::new_inline_ascii(3, b"std"); 132pub const STD: Name = Name::new_inline_ascii(b"std");
133pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); 133pub const ITER: Name = Name::new_inline_ascii(b"iter");
134pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); 134pub const OPS: Name = Name::new_inline_ascii(b"ops");
135pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); 135pub const FUTURE: Name = Name::new_inline_ascii(b"future");
136pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); 136pub const RESULT: Name = Name::new_inline_ascii(b"result");
137pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); 137pub const BOXED: Name = Name::new_inline_ascii(b"boxed");
138 138
139// Components of known path (type name) 139// Components of known path (type name)
140pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); 140pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator");
141pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); 141pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item");
142pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); 142pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try");
143pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); 143pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok");
144pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); 144pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future");
145pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); 145pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result");
146pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); 146pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output");
147pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); 147pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target");
148pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); 148pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box");
149pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom"); 149pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom");
150pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull"); 150pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull");
151pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive"); 151pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive");
152pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive"); 152pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive");
153pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo"); 153pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo");
154pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range"); 154pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range");
155 155
156// Builtin Macros 156// Builtin Macros
157pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); 157pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file");
158pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); 158pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column");
159pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); 159pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error");
160pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); 160pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line");
161pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); 161pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify");
162pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args");
163pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl");
162 164
163// Builtin derives 165// Builtin derives
164pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy"); 166pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy");
165pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone"); 167pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone");
166pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(7, b"Default"); 168pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default");
167pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(5, b"Debug"); 169pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug");
168pub const HASH_TRAIT: Name = Name::new_inline_ascii(4, b"Hash"); 170pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash");
169pub const ORD_TRAIT: Name = Name::new_inline_ascii(3, b"Ord"); 171pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord");
170pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(10, b"PartialOrd"); 172pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd");
171pub const EQ_TRAIT: Name = Name::new_inline_ascii(2, b"Eq"); 173pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq");
172pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(9, b"PartialEq"); 174pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(b"PartialEq");
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 9d1d4e48c..d557962b4 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -10,10 +10,10 @@ use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
13use crate::db::HirDatabase; 13use crate::{
14 14 db::HirDatabase,
15use super::{
16 traits::{InEnvironment, Solution}, 15 traits::{InEnvironment, Solution},
16 utils::generics,
17 Canonical, Substs, Ty, TypeWalk, 17 Canonical, Substs, Ty, TypeWalk,
18}; 18};
19 19
@@ -54,8 +54,8 @@ fn deref_by_trait(
54 }; 54 };
55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?;
56 56
57 let generic_params = db.generic_params(target.into()); 57 let generic_params = generics(db, target.into());
58 if generic_params.count_params_including_parent() != 1 { 58 if generic_params.len() != 1 {
59 // the Target type + Deref trait should only have one generic parameter, 59 // the Target type + Deref trait should only have one generic parameter,
60 // namely Deref's Self type 60 // namely Deref's Self type
61 return None; 61 return None;
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index b8df27706..2c296987c 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -6,7 +6,6 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 builtin_type::Signedness, 7 builtin_type::Signedness,
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 generics::GenericParams,
10 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
11 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
12 AdtId, ContainerId, Lookup, StructFieldId, 11 AdtId, ContainerId, Lookup, StructFieldId,
@@ -15,7 +14,11 @@ use hir_expand::name::{self, Name};
15use ra_syntax::ast::RangeOp; 14use ra_syntax::ast::RangeOp;
16 15
17use crate::{ 16use crate::{
18 autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, 17 autoderef,
18 db::HirDatabase,
19 method_resolution, op,
20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics},
19 CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, 22 CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs,
20 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 23 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
21}; 24};
@@ -596,7 +599,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
596 Some((ty, func)) => { 599 Some((ty, func)) => {
597 let ty = canonicalized_receiver.decanonicalize_ty(ty); 600 let ty = canonicalized_receiver.decanonicalize_ty(ty);
598 self.write_method_resolution(tgt_expr, func); 601 self.write_method_resolution(tgt_expr, func);
599 (ty, self.db.value_ty(func.into()), Some(self.db.generic_params(func.into()))) 602 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into())))
600 } 603 }
601 None => (receiver_ty, Ty::Unknown, None), 604 None => (receiver_ty, Ty::Unknown, None),
602 }; 605 };
@@ -653,16 +656,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
653 656
654 fn substs_for_method_call( 657 fn substs_for_method_call(
655 &mut self, 658 &mut self,
656 def_generics: Option<Arc<GenericParams>>, 659 def_generics: Option<Generics>,
657 generic_args: Option<&GenericArgs>, 660 generic_args: Option<&GenericArgs>,
658 receiver_ty: &Ty, 661 receiver_ty: &Ty,
659 ) -> Substs { 662 ) -> Substs {
660 let (parent_param_count, param_count) = 663 let (total_len, _parent_len, child_len) =
661 def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 664 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split());
662 let mut substs = Vec::with_capacity(parent_param_count + param_count); 665 let mut substs = Vec::with_capacity(total_len);
663 // Parent arguments are unknown, except for the receiver type 666 // Parent arguments are unknown, except for the receiver type
664 if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { 667 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
665 for param in &parent_generics.params { 668 for (_id, param) in parent_generics {
666 if param.name == name::SELF_TYPE { 669 if param.name == name::SELF_TYPE {
667 substs.push(receiver_ty.clone()); 670 substs.push(receiver_ty.clone());
668 } else { 671 } else {
@@ -673,7 +676,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
673 // handle provided type arguments 676 // handle provided type arguments
674 if let Some(generic_args) = generic_args { 677 if let Some(generic_args) = generic_args {
675 // if args are provided, it should be all of them, but we can't rely on that 678 // if args are provided, it should be all of them, but we can't rely on that
676 for arg in generic_args.args.iter().take(param_count) { 679 for arg in generic_args.args.iter().take(child_len) {
677 match arg { 680 match arg {
678 GenericArg::Type(type_ref) => { 681 GenericArg::Type(type_ref) => {
679 let ty = self.make_ty(type_ref); 682 let ty = self.make_ty(type_ref);
@@ -683,10 +686,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
683 } 686 }
684 }; 687 };
685 let supplied_params = substs.len(); 688 let supplied_params = substs.len();
686 for _ in supplied_params..parent_param_count + param_count { 689 for _ in supplied_params..total_len {
687 substs.push(Ty::Unknown); 690 substs.push(Ty::Unknown);
688 } 691 }
689 assert_eq!(substs.len(), parent_param_count + param_count); 692 assert_eq!(substs.len(), total_len);
690 Substs(substs.into()) 693 Substs(substs.into())
691 } 694 }
692 695
@@ -705,11 +708,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
705 CallableDef::FunctionId(f) => { 708 CallableDef::FunctionId(f) => {
706 if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { 709 if let ContainerId::TraitId(trait_) = f.lookup(self.db).container {
707 // construct a TraitDef 710 // construct a TraitDef
708 let substs = a_ty.parameters.prefix( 711 let substs =
709 self.db 712 a_ty.parameters.prefix(generics(self.db, trait_.into()).len());
710 .generic_params(trait_.into())
711 .count_params_including_parent(),
712 );
713 self.obligations.push(Obligation::Trait(TraitRef { 713 self.obligations.push(Obligation::Trait(TraitRef {
714 trait_: trait_.into(), 714 trait_: trait_.into(),
715 substs, 715 substs,
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 3c1f738df..3ad913e55 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -44,8 +44,8 @@ use std::sync::Arc;
44use std::{fmt, iter, mem}; 44use std::{fmt, iter, mem};
45 45
46use hir_def::{ 46use hir_def::{
47 expr::ExprId, generics::GenericParams, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, 47 expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, GenericDefId, HasModule,
48 GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 48 Lookup, TraitId, TypeAliasId,
49}; 49};
50use hir_expand::name::Name; 50use hir_expand::name::Name;
51use ra_db::{impl_intern_key, salsa, CrateId}; 51use ra_db::{impl_intern_key, salsa, CrateId};
@@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
53use crate::{ 53use crate::{
54 db::HirDatabase, 54 db::HirDatabase,
55 primitive::{FloatTy, IntTy, Uncertain}, 55 primitive::{FloatTy, IntTy, Uncertain},
56 utils::make_mut_slice, 56 utils::{generics, make_mut_slice, Generics},
57}; 57};
58use display::{HirDisplay, HirFormatter}; 58use display::{HirDisplay, HirFormatter};
59 59
@@ -166,16 +166,16 @@ impl TypeCtor {
166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure 166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure
167 => 1, 167 => 1,
168 TypeCtor::Adt(adt) => { 168 TypeCtor::Adt(adt) => {
169 let generic_params = db.generic_params(AdtId::from(adt).into()); 169 let generic_params = generics(db, AdtId::from(adt).into());
170 generic_params.count_params_including_parent() 170 generic_params.len()
171 } 171 }
172 TypeCtor::FnDef(callable) => { 172 TypeCtor::FnDef(callable) => {
173 let generic_params = db.generic_params(callable.into()); 173 let generic_params = generics(db, callable.into());
174 generic_params.count_params_including_parent() 174 generic_params.len()
175 } 175 }
176 TypeCtor::AssociatedType(type_alias) => { 176 TypeCtor::AssociatedType(type_alias) => {
177 let generic_params = db.generic_params(type_alias.into()); 177 let generic_params = generics(db, type_alias.into());
178 generic_params.count_params_including_parent() 178 generic_params.len()
179 } 179 }
180 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 180 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
181 TypeCtor::Tuple { cardinality } => cardinality as usize, 181 TypeCtor::Tuple { cardinality } => cardinality as usize,
@@ -364,36 +364,26 @@ impl Substs {
364 } 364 }
365 365
366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
367 pub fn identity(generic_params: &GenericParams) -> Substs { 367 pub(crate) fn identity(generic_params: &Generics) -> Substs {
368 Substs( 368 Substs(
369 generic_params 369 generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(),
370 .params_including_parent()
371 .into_iter()
372 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
373 .collect(),
374 ) 370 )
375 } 371 }
376 372
377 /// Return Substs that replace each parameter by a bound variable. 373 /// Return Substs that replace each parameter by a bound variable.
378 pub fn bound_vars(generic_params: &GenericParams) -> Substs { 374 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
379 Substs( 375 Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect())
380 generic_params
381 .params_including_parent()
382 .into_iter()
383 .map(|p| Ty::Bound(p.idx))
384 .collect(),
385 )
386 } 376 }
387 377
388 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { 378 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
389 let def = def.into(); 379 let def = def.into();
390 let params = db.generic_params(def); 380 let params = generics(db, def);
391 let param_count = params.count_params_including_parent(); 381 let param_count = params.len();
392 Substs::builder(param_count) 382 Substs::builder(param_count)
393 } 383 }
394 384
395 pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder { 385 pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder {
396 Substs::builder(generic_params.count_params_including_parent()) 386 Substs::builder(generic_params.len())
397 } 387 }
398 388
399 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder { 389 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 32569ac66..eab91229e 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -24,7 +24,7 @@ use crate::{
24 db::HirDatabase, 24 db::HirDatabase,
25 primitive::{FloatTy, IntTy}, 25 primitive::{FloatTy, IntTy},
26 utils::{ 26 utils::{
27 all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, 27 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
28 variant_data, 28 variant_data,
29 }, 29 },
30 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, 30 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
@@ -111,7 +111,9 @@ impl Ty {
111 Some((it, None)) => it, 111 Some((it, None)) => it,
112 _ => return None, 112 _ => return None,
113 }; 113 };
114 if let TypeNs::GenericParam(idx) = resolution { 114 if let TypeNs::GenericParam(param_id) = resolution {
115 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
116 let idx = generics.param_idx(param_id);
115 Some(idx) 117 Some(idx)
116 } else { 118 } else {
117 None 119 None
@@ -174,9 +176,11 @@ impl Ty {
174 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) 176 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
175 }; 177 };
176 } 178 }
177 TypeNs::GenericParam(idx) => { 179 TypeNs::GenericParam(param_id) => {
180 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
181 let idx = generics.param_idx(param_id);
178 // FIXME: maybe return name in resolution? 182 // FIXME: maybe return name in resolution?
179 let name = resolved_segment.name.clone(); 183 let name = generics.param_name(param_id);
180 Ty::Param { idx, name } 184 Ty::Param { idx, name }
181 } 185 }
182 TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(), 186 TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(),
@@ -315,11 +319,10 @@ pub(super) fn substs_from_path_segment(
315 add_self_param: bool, 319 add_self_param: bool,
316) -> Substs { 320) -> Substs {
317 let mut substs = Vec::new(); 321 let mut substs = Vec::new();
318 let def_generics = def_generic.map(|def| db.generic_params(def.into())); 322 let def_generics = def_generic.map(|def| generics(db, def.into()));
319 323
320 let (parent_param_count, param_count) = 324 let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split());
321 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 325 substs.extend(iter::repeat(Ty::Unknown).take(parent_len));
322 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
323 if add_self_param { 326 if add_self_param {
324 // FIXME this add_self_param argument is kind of a hack: Traits have the 327 // FIXME this add_self_param argument is kind of a hack: Traits have the
325 // Self type as an implicit first type parameter, but it can't be 328 // Self type as an implicit first type parameter, but it can't be
@@ -330,8 +333,8 @@ pub(super) fn substs_from_path_segment(
330 if let Some(generic_args) = &segment.args_and_bindings { 333 if let Some(generic_args) = &segment.args_and_bindings {
331 // if args are provided, it should be all of them, but we can't rely on that 334 // if args are provided, it should be all of them, but we can't rely on that
332 let self_param_correction = if add_self_param { 1 } else { 0 }; 335 let self_param_correction = if add_self_param { 1 } else { 0 };
333 let param_count = param_count - self_param_correction; 336 let child_len = child_len + self_param_correction;
334 for arg in generic_args.args.iter().take(param_count) { 337 for arg in generic_args.args.iter().take(child_len) {
335 match arg { 338 match arg {
336 GenericArg::Type(type_ref) => { 339 GenericArg::Type(type_ref) => {
337 let ty = Ty::from_hir(db, resolver, type_ref); 340 let ty = Ty::from_hir(db, resolver, type_ref);
@@ -342,10 +345,10 @@ pub(super) fn substs_from_path_segment(
342 } 345 }
343 // add placeholders for args that were not provided 346 // add placeholders for args that were not provided
344 let supplied_params = substs.len(); 347 let supplied_params = substs.len();
345 for _ in supplied_params..parent_param_count + param_count { 348 for _ in supplied_params..total_len {
346 substs.push(Ty::Unknown); 349 substs.push(Ty::Unknown);
347 } 350 }
348 assert_eq!(substs.len(), parent_param_count + param_count); 351 assert_eq!(substs.len(), total_len);
349 352
350 // handle defaults 353 // handle defaults
351 if let Some(def_generic) = def_generic { 354 if let Some(def_generic) = def_generic {
@@ -567,12 +570,11 @@ pub(crate) fn generic_predicates_query(
567/// Resolve the default type params from generics 570/// Resolve the default type params from generics
568pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { 571pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs {
569 let resolver = def.resolver(db); 572 let resolver = def.resolver(db);
570 let generic_params = db.generic_params(def.into()); 573 let generic_params = generics(db, def.into());
571 574
572 let defaults = generic_params 575 let defaults = generic_params
573 .params_including_parent() 576 .iter()
574 .into_iter() 577 .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
575 .map(|p| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
576 .collect(); 578 .collect();
577 579
578 Substs(defaults) 580 Substs(defaults)
@@ -589,7 +591,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig {
589/// Build the declared type of a function. This should not need to look at the 591/// Build the declared type of a function. This should not need to look at the
590/// function body. 592/// function body.
591fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { 593fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty {
592 let generics = db.generic_params(def.into()); 594 let generics = generics(db, def.into());
593 let substs = Substs::identity(&generics); 595 let substs = Substs::identity(&generics);
594 Ty::apply(TypeCtor::FnDef(def.into()), substs) 596 Ty::apply(TypeCtor::FnDef(def.into()), substs)
595} 597}
@@ -639,7 +641,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty {
639 if struct_data.variant_data.is_unit() { 641 if struct_data.variant_data.is_unit() {
640 return type_for_adt(db, def.into()); // Unit struct 642 return type_for_adt(db, def.into()); // Unit struct
641 } 643 }
642 let generics = db.generic_params(def.into()); 644 let generics = generics(db, def.into());
643 let substs = Substs::identity(&generics); 645 let substs = Substs::identity(&generics);
644 Ty::apply(TypeCtor::FnDef(def.into()), substs) 646 Ty::apply(TypeCtor::FnDef(def.into()), substs)
645} 647}
@@ -653,7 +655,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId
653 .iter() 655 .iter()
654 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 656 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
655 .collect::<Vec<_>>(); 657 .collect::<Vec<_>>();
656 let generics = db.generic_params(def.parent.into()); 658 let generics = generics(db, def.parent.into());
657 let substs = Substs::identity(&generics); 659 let substs = Substs::identity(&generics);
658 let ret = type_for_adt(db, def.parent.into()).subst(&substs); 660 let ret = type_for_adt(db, def.parent.into()).subst(&substs);
659 FnSig::from_params_and_return(params, ret) 661 FnSig::from_params_and_return(params, ret)
@@ -666,18 +668,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId)
666 if var_data.is_unit() { 668 if var_data.is_unit() {
667 return type_for_adt(db, def.parent.into()); // Unit variant 669 return type_for_adt(db, def.parent.into()); // Unit variant
668 } 670 }
669 let generics = db.generic_params(def.parent.into()); 671 let generics = generics(db, def.parent.into());
670 let substs = Substs::identity(&generics); 672 let substs = Substs::identity(&generics);
671 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) 673 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs)
672} 674}
673 675
674fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { 676fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty {
675 let generics = db.generic_params(adt.into()); 677 let generics = generics(db, adt.into());
676 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) 678 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics))
677} 679}
678 680
679fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { 681fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty {
680 let generics = db.generic_params(t.into()); 682 let generics = generics(db, t.into());
681 let resolver = t.resolver(db); 683 let resolver = t.resolver(db);
682 let type_ref = &db.type_alias_data(t).type_ref; 684 let type_ref = &db.type_alias_data(t).type_ref;
683 let substs = Substs::identity(&generics); 685 let substs = Substs::identity(&generics);
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index f1b67555f..d724ee122 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -11,8 +11,8 @@ use std::fmt::Write;
11use std::sync::Arc; 11use std::sync::Arc;
12 12
13use hir_def::{ 13use hir_def::{
14 body::BodySourceMap, child_from_source::ChildFromSource, db::DefDatabase, nameres::CrateDefMap, 14 body::BodySourceMap, child_by_source::ChildBySource, db::DefDatabase, keys,
15 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 15 nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
16}; 16};
17use hir_expand::InFile; 17use hir_expand::InFile;
18use insta::assert_snapshot; 18use insta::assert_snapshot;
@@ -33,7 +33,9 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
33 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 33 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
34 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 34 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
35 let module = db.module_for_file(pos.file_id); 35 let module = db.module_for_file(pos.file_id);
36 let func = module.child_from_source(db, InFile::new(pos.file_id.into(), fn_def)).unwrap(); 36 let func = *module.child_by_source(db)[keys::FUNCTION]
37 .get(&InFile::new(pos.file_id.into(), fn_def))
38 .unwrap();
37 39
38 let (_body, source_map) = db.body_with_source_map(func.into()); 40 let (_body, source_map) = db.body_with_source_map(func.into());
39 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 41 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index e3f02fa15..1e7ff93d5 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -19,8 +19,8 @@ use ra_db::{
19 19
20use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 20use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
21use crate::{ 21use crate::{
22 db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, 22 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate,
23 TraitRef, Ty, TypeCtor, TypeWalk, 23 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
24}; 24};
25 25
26/// This represents a trait whose name we could not resolve. 26/// This represents a trait whose name we could not resolve.
@@ -547,7 +547,7 @@ pub(crate) fn associated_ty_data_query(
547 ContainerId::TraitId(t) => t, 547 ContainerId::TraitId(t) => t,
548 _ => panic!("associated type not in trait"), 548 _ => panic!("associated type not in trait"),
549 }; 549 };
550 let generic_params = db.generic_params(type_alias.into()); 550 let generic_params = generics(db, type_alias.into());
551 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 551 let bound_data = chalk_rust_ir::AssociatedTyDatumBound {
552 // FIXME add bounds and where clauses 552 // FIXME add bounds and where clauses
553 bounds: vec![], 553 bounds: vec![],
@@ -557,7 +557,7 @@ pub(crate) fn associated_ty_data_query(
557 trait_id: trait_.to_chalk(db), 557 trait_id: trait_.to_chalk(db),
558 id, 558 id,
559 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()), 559 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()),
560 binders: make_binders(bound_data, generic_params.count_params_including_parent()), 560 binders: make_binders(bound_data, generic_params.len()),
561 }; 561 };
562 Arc::new(datum) 562 Arc::new(datum)
563} 563}
@@ -589,7 +589,7 @@ pub(crate) fn trait_datum_query(
589 let trait_: TraitId = from_chalk(db, trait_id); 589 let trait_: TraitId = from_chalk(db, trait_id);
590 let trait_data = db.trait_data(trait_); 590 let trait_data = db.trait_data(trait_);
591 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 591 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
592 let generic_params = db.generic_params(trait_.into()); 592 let generic_params = generics(db, trait_.into());
593 let bound_vars = Substs::bound_vars(&generic_params); 593 let bound_vars = Substs::bound_vars(&generic_params);
594 let flags = chalk_rust_ir::TraitFlags { 594 let flags = chalk_rust_ir::TraitFlags {
595 auto: trait_data.auto, 595 auto: trait_data.auto,
@@ -626,7 +626,7 @@ pub(crate) fn struct_datum_query(
626 let where_clauses = type_ctor 626 let where_clauses = type_ctor
627 .as_generic_def() 627 .as_generic_def()
628 .map(|generic_def| { 628 .map(|generic_def| {
629 let generic_params = db.generic_params(generic_def.into()); 629 let generic_params = generics(db, generic_def.into());
630 let bound_vars = Substs::bound_vars(&generic_params); 630 let bound_vars = Substs::bound_vars(&generic_params);
631 convert_where_clauses(db, generic_def, &bound_vars) 631 convert_where_clauses(db, generic_def, &bound_vars)
632 }) 632 })
@@ -669,7 +669,7 @@ fn impl_block_datum(
669 let trait_ref = db.impl_trait(impl_id)?; 669 let trait_ref = db.impl_trait(impl_id)?;
670 let impl_data = db.impl_data(impl_id); 670 let impl_data = db.impl_data(impl_id);
671 671
672 let generic_params = db.generic_params(impl_id.into()); 672 let generic_params = generics(db, impl_id.into());
673 let bound_vars = Substs::bound_vars(&generic_params); 673 let bound_vars = Substs::bound_vars(&generic_params);
674 let trait_ref = trait_ref.subst(&bound_vars); 674 let trait_ref = trait_ref.subst(&bound_vars);
675 let trait_ = trait_ref.trait_; 675 let trait_ = trait_ref.trait_;
@@ -767,7 +767,7 @@ fn type_alias_associated_ty_value(
767 .trait_data(trait_ref.trait_) 767 .trait_data(trait_ref.trait_)
768 .associated_type_by_name(&type_alias_data.name) 768 .associated_type_by_name(&type_alias_data.name)
769 .expect("assoc ty value should not exist"); // validated when building the impl data as well 769 .expect("assoc ty value should not exist"); // validated when building the impl data as well
770 let generic_params = db.generic_params(impl_id.into()); 770 let generic_params = generics(db, impl_id.into());
771 let bound_vars = Substs::bound_vars(&generic_params); 771 let bound_vars = Substs::bound_vars(&generic_params);
772 let ty = db.ty(type_alias.into()).subst(&bound_vars); 772 let ty = db.ty(type_alias.into()).subst(&bound_vars);
773 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; 773 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index e4ba890ef..aeb211a91 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -5,9 +5,10 @@ use std::sync::Arc;
5use hir_def::{ 5use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData},
8 resolver::{HasResolver, TypeNs}, 9 resolver::{HasResolver, TypeNs},
9 type_ref::TypeRef, 10 type_ref::TypeRef,
10 TraitId, TypeAliasId, VariantId, 11 ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
11}; 12};
12use hir_expand::name::{self, Name}; 13use hir_expand::name::{self, Name};
13 14
@@ -82,3 +83,81 @@ pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
82 } 83 }
83 Arc::get_mut(a).unwrap() 84 Arc::get_mut(a).unwrap()
84} 85}
86
87pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics {
88 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
89 Generics { def, params: db.generic_params(def), parent_generics }
90}
91
92pub(crate) struct Generics {
93 def: GenericDefId,
94 pub(crate) params: Arc<GenericParams>,
95 parent_generics: Option<Box<Generics>>,
96}
97
98impl Generics {
99 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
100 self.parent_generics
101 .as_ref()
102 .into_iter()
103 .flat_map(|it| it.params.types.iter())
104 .chain(self.params.types.iter())
105 .enumerate()
106 .map(|(i, (_local_id, p))| (i as u32, p))
107 }
108
109 pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
110 self.parent_generics
111 .as_ref()
112 .into_iter()
113 .flat_map(|it| it.params.types.iter())
114 .enumerate()
115 .map(|(i, (_local_id, p))| (i as u32, p))
116 }
117
118 pub(crate) fn len(&self) -> usize {
119 self.len_split().0
120 }
121 /// (total, parents, child)
122 pub(crate) fn len_split(&self) -> (usize, usize, usize) {
123 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
124 let child = self.params.types.len();
125 (parent + child, parent, child)
126 }
127 pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 {
128 self.find_param(param).0
129 }
130 pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
131 self.find_param(param).1.name.clone()
132 }
133 fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
134 if param.parent == self.def {
135 let (idx, (_local_id, data)) = self
136 .params
137 .types
138 .iter()
139 .enumerate()
140 .find(|(_, (idx, _))| *idx == param.local_id)
141 .unwrap();
142 let (_total, parent_len, _child) = self.len_split();
143 return ((parent_len + idx) as u32, data);
144 }
145 self.parent_generics.as_ref().unwrap().find_param(param)
146 }
147}
148
149fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
150 let container = match def {
151 GenericDefId::FunctionId(it) => it.lookup(db).container,
152 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
153 GenericDefId::ConstId(it) => it.lookup(db).container,
154 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
155 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None,
156 };
157
158 match container {
159 ContainerId::ImplId(it) => Some(it.into()),
160 ContainerId::TraitId(it) => Some(it.into()),
161 ContainerId::ModuleId(_) => None,
162 }
163}
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index add11fbc3..6a6b49afd 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -6,7 +6,7 @@ use ra_db::{FileId, SourceDatabase};
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, DocCommentsOwner, NameOwner}, 7 ast::{self, DocCommentsOwner, NameOwner},
8 match_ast, AstNode, SmolStr, 8 match_ast, AstNode, SmolStr,
9 SyntaxKind::{self, BIND_PAT}, 9 SyntaxKind::{self, BIND_PAT, TYPE_PARAM},
10 TextRange, 10 TextRange,
11}; 11};
12 12
@@ -351,6 +351,26 @@ impl ToNav for hir::Local {
351 } 351 }
352} 352}
353 353
354impl ToNav for hir::TypeParam {
355 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
356 let src = self.source(db);
357 let range = match src.value {
358 Either::Left(it) => it.syntax().text_range(),
359 Either::Right(it) => it.syntax().text_range(),
360 };
361 NavigationTarget {
362 file_id: src.file_id.original_file(db),
363 name: self.name(db).to_string().into(),
364 kind: TYPE_PARAM,
365 full_range: range,
366 focus_range: None,
367 container_name: None,
368 description: None,
369 docs: None,
370 }
371 }
372}
373
354pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 374pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
355 let parse = db.parse(symbol.file_id); 375 let parse = db.parse(symbol.file_id);
356 let node = symbol.ptr.to_node(parse.tree().syntax()); 376 let node = symbol.ptr.to_node(parse.tree().syntax());
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 76a741207..1b968134d 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -64,9 +64,11 @@ pub(crate) fn reference_definition(
64 64
65 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); 65 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind);
66 match name_kind { 66 match name_kind {
67 Some(Macro(mac)) => return Exact(mac.to_nav(db)), 67 Some(Macro(it)) => return Exact(it.to_nav(db)),
68 Some(Field(field)) => return Exact(field.to_nav(db)), 68 Some(Field(it)) => return Exact(it.to_nav(db)),
69 Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), 69 Some(TypeParam(it)) => return Exact(it.to_nav(db)),
70 Some(AssocItem(it)) => return Exact(it.to_nav(db)),
71 Some(Local(it)) => return Exact(it.to_nav(db)),
70 Some(Def(def)) => match NavigationTarget::from_def(db, def) { 72 Some(Def(def)) => match NavigationTarget::from_def(db, def) {
71 Some(nav) => return Exact(nav), 73 Some(nav) => return Exact(nav),
72 None => return Approximate(vec![]), 74 None => return Approximate(vec![]),
@@ -77,10 +79,6 @@ pub(crate) fn reference_definition(
77 // us to the actual type 79 // us to the actual type
78 return Exact(imp.to_nav(db)); 80 return Exact(imp.to_nav(db));
79 } 81 }
80 Some(Local(local)) => return Exact(local.to_nav(db)),
81 Some(GenericParam(_)) => {
82 // FIXME: go to the generic param def
83 }
84 None => {} 82 None => {}
85 }; 83 };
86 84
@@ -689,8 +687,51 @@ mod tests {
689 fo<|>o(); 687 fo<|>o();
690 } 688 }
691 } 689 }
690 mod confuse_index { fn foo(); }
692 ", 691 ",
693 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 692 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
694 ); 693 );
695 } 694 }
695
696 #[should_panic] // currently failing because of expr mapping problems
697 #[test]
698 fn goto_through_format() {
699 check_goto(
700 "
701 //- /lib.rs
702 #[macro_export]
703 macro_rules! format {
704 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
705 }
706 #[rustc_builtin_macro]
707 #[macro_export]
708 macro_rules! format_args {
709 ($fmt:expr) => ({ /* compiler built-in */ });
710 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
711 }
712 pub mod __export {
713 pub use crate::format_args;
714 fn foo() {} // for index confusion
715 }
716 fn foo() -> i8 {}
717 fn test() {
718 format!(\"{}\", fo<|>o())
719 }
720 ",
721 "foo FN_DEF FileId(1) [359; 376) [362; 365)",
722 );
723 }
724
725 #[test]
726 fn goto_for_type_param() {
727 check_goto(
728 "
729 //- /lib.rs
730 struct Foo<T> {
731 t: <|>T,
732 }
733 ",
734 "T TYPE_PARAM FileId(1) [11; 12)",
735 );
736 }
696} 737}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index d8185c688..d372ca758 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -138,7 +138,7 @@ fn hover_text_from_name_kind(
138 *no_fallback = true; 138 *no_fallback = true;
139 None 139 None
140 } 140 }
141 GenericParam(_) | SelfType(_) => { 141 TypeParam(_) | SelfType(_) => {
142 // FIXME: Hover for generic param 142 // FIXME: Hover for generic param
143 None 143 None
144 } 144 }
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 59eced9d7..3730121af 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -122,18 +122,11 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
122 122
123 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() { 123 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() {
124 match &maybe_leaf_pat { 124 match &maybe_leaf_pat {
125 ast::Pat::BindPat(bind_pat) => { 125 ast::Pat::BindPat(bind_pat) => match bind_pat.pat() {
126 if let Some(pat) = bind_pat.pat() { 126 Some(pat) => pats_to_process.push_back(pat),
127 pats_to_process.push_back(pat); 127 _ => leaf_pats.push(maybe_leaf_pat),
128 } else { 128 },
129 leaf_pats.push(maybe_leaf_pat); 129 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
130 }
131 }
132 ast::Pat::TuplePat(tuple_pat) => {
133 for arg_pat in tuple_pat.args() {
134 pats_to_process.push_back(arg_pat);
135 }
136 }
137 ast::Pat::RecordPat(record_pat) => { 130 ast::Pat::RecordPat(record_pat) => {
138 if let Some(pat_list) = record_pat.record_field_pat_list() { 131 if let Some(pat_list) = record_pat.record_field_pat_list() {
139 pats_to_process.extend( 132 pats_to_process.extend(
@@ -151,10 +144,9 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
151 } 144 }
152 } 145 }
153 ast::Pat::TupleStructPat(tuple_struct_pat) => { 146 ast::Pat::TupleStructPat(tuple_struct_pat) => {
154 for arg_pat in tuple_struct_pat.args() { 147 pats_to_process.extend(tuple_struct_pat.args())
155 pats_to_process.push_back(arg_pat);
156 }
157 } 148 }
149 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
158 _ => (), 150 _ => (),
159 } 151 }
160 } 152 }
@@ -163,9 +155,10 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
163 155
164#[cfg(test)] 156#[cfg(test)]
165mod tests { 157mod tests {
166 use crate::mock_analysis::single_file;
167 use insta::assert_debug_snapshot; 158 use insta::assert_debug_snapshot;
168 159
160 use crate::mock_analysis::single_file;
161
169 #[test] 162 #[test]
170 fn let_statement() { 163 fn let_statement() {
171 let (analysis, file_id) = single_file( 164 let (analysis, file_id) = single_file(
@@ -202,6 +195,7 @@ fn main() {
202 195
203 let test = (42, 'a'); 196 let test = (42, 'a');
204 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); 197 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5));
198 let &x = &92;
205}"#, 199}"#,
206 ); 200 );
207 201
@@ -257,6 +251,11 @@ fn main() {
257 kind: TypeHint, 251 kind: TypeHint,
258 label: "f64", 252 label: "f64",
259 }, 253 },
254 InlayHint {
255 range: [627; 628),
256 kind: TypeHint,
257 label: "i32",
258 },
260 ] 259 ]
261 "### 260 "###
262 ); 261 );
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 3e7bfd872..e3ecde50d 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -85,7 +85,7 @@ pub(crate) fn find_all_refs(
85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?, 85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
86 NameKind::SelfType(imp) => imp.to_nav(db), 86 NameKind::SelfType(imp) => imp.to_nav(db),
87 NameKind::Local(local) => local.to_nav(db), 87 NameKind::Local(local) => local.to_nav(db),
88 NameKind::GenericParam(_) => return None, 88 NameKind::TypeParam(_) => return None,
89 }; 89 };
90 90
91 let search_scope = { 91 let search_scope = {
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs
index b716d32e5..c1f091ec0 100644
--- a/crates/ra_ide/src/references/classify.rs
+++ b/crates/ra_ide/src/references/classify.rs
@@ -110,6 +110,15 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
110 kind: NameKind::Macro(def), 110 kind: NameKind::Macro(def),
111 }) 111 })
112 }, 112 },
113 ast::TypeParam(it) => {
114 let src = name.with_value(it);
115 let def = hir::TypeParam::from_source(db, src)?;
116 Some(NameDefinition {
117 visibility: None,
118 container: def.module(db),
119 kind: NameKind::TypeParam(def),
120 })
121 },
113 _ => None, 122 _ => None,
114 } 123 }
115 } 124 }
@@ -168,9 +177,8 @@ pub(crate) fn classify_name_ref(
168 let kind = NameKind::Local(local); 177 let kind = NameKind::Local(local);
169 Some(NameDefinition { kind, container, visibility: None }) 178 Some(NameDefinition { kind, container, visibility: None })
170 } 179 }
171 PathResolution::GenericParam(par) => { 180 PathResolution::TypeParam(par) => {
172 // FIXME: get generic param def 181 let kind = NameKind::TypeParam(par);
173 let kind = NameKind::GenericParam(par);
174 Some(NameDefinition { kind, container, visibility }) 182 Some(NameDefinition { kind, container, visibility })
175 } 183 }
176 PathResolution::Macro(def) => { 184 PathResolution::Macro(def) => {
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs
index 10d3a2364..8c67c8863 100644
--- a/crates/ra_ide/src/references/name_definition.rs
+++ b/crates/ra_ide/src/references/name_definition.rs
@@ -4,8 +4,8 @@
4//! Note that the reference search is possible for not all of the classified items. 4//! Note that the reference search is possible for not all of the classified items.
5 5
6use hir::{ 6use hir::{
7 Adt, AssocItem, GenericParam, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, 7 Adt, AssocItem, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, StructField,
8 StructField, VariantDef, 8 TypeParam, VariantDef,
9}; 9};
10use ra_syntax::{ast, ast::VisibilityOwner}; 10use ra_syntax::{ast, ast::VisibilityOwner};
11 11
@@ -19,7 +19,7 @@ pub enum NameKind {
19 Def(ModuleDef), 19 Def(ModuleDef),
20 SelfType(ImplBlock), 20 SelfType(ImplBlock),
21 Local(Local), 21 Local(Local),
22 GenericParam(GenericParam), 22 TypeParam(TypeParam),
23} 23}
24 24
25#[derive(PartialEq, Eq)] 25#[derive(PartialEq, Eq)]
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index b39c4d371..4166a8f90 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -9,6 +9,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
9.parameter { color: #94BFF3; } 9.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; } 10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
12.attribute { color: #94BFF3; } 13.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 14.literal { color: #BFEBBF; }
14.macro { color: #94BFF3; } 15.macro { color: #94BFF3; }
@@ -45,4 +46,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
45 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>; 46 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>;
46 47
47 <span class="variable.mut">y</span>; 48 <span class="variable.mut">y</span>;
49}
50
51<span class="keyword">enum</span> <span class="type">E</span>&lt;<span class="type">X</span>&gt; {
52 <span class="constant">V</span>(<span class="type">X</span>)
53}
54
55<span class="keyword">impl</span>&lt;<span class="type">X</span>&gt; <span class="type">E</span>&lt;<span class="type">X</span>&gt; {
56 <span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">E</span>&lt;<span class="type">T</span>&gt; {}
48}</code></pre> \ No newline at end of file 57}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 79f11ea80..9dfbc8047 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -9,6 +9,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
9.parameter { color: #94BFF3; } 9.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; } 10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
12.attribute { color: #94BFF3; } 13.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 14.literal { color: #BFEBBF; }
14.macro { color: #94BFF3; } 15.macro { color: #94BFF3; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index e6a79541f..7ecb1a027 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -225,8 +225,7 @@ fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
225 Def(hir::ModuleDef::Trait(_)) => "type", 225 Def(hir::ModuleDef::Trait(_)) => "type",
226 Def(hir::ModuleDef::TypeAlias(_)) => "type", 226 Def(hir::ModuleDef::TypeAlias(_)) => "type",
227 Def(hir::ModuleDef::BuiltinType(_)) => "type", 227 Def(hir::ModuleDef::BuiltinType(_)) => "type",
228 SelfType(_) => "type", 228 SelfType(_) | TypeParam(_) => "type",
229 GenericParam(_) => "type",
230 Local(local) => { 229 Local(local) => {
231 if local.is_mut(db) { 230 if local.is_mut(db) {
232 "variable.mut" 231 "variable.mut"
@@ -255,6 +254,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
255.parameter { color: #94BFF3; } 254.parameter { color: #94BFF3; }
256.builtin { color: #DD6718; } 255.builtin { color: #DD6718; }
257.text { color: #DCDCCC; } 256.text { color: #DCDCCC; }
257.type { color: #7CB8BB; }
258.attribute { color: #94BFF3; } 258.attribute { color: #94BFF3; }
259.literal { color: #BFEBBF; } 259.literal { color: #BFEBBF; }
260.macro { color: #94BFF3; } 260.macro { color: #94BFF3; }
@@ -303,6 +303,14 @@ fn main() {
303 303
304 y; 304 y;
305} 305}
306
307enum E<X> {
308 V(X)
309}
310
311impl<X> E<X> {
312 fn new<T>() -> E<T> {}
313}
306"# 314"#
307 .trim(), 315 .trim(),
308 ); 316 );
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index fec50bd25..cfbf16ea5 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -12,6 +12,7 @@ use ra_lsp_server::req::{
12}; 12};
13use serde_json::json; 13use serde_json::json;
14use tempfile::TempDir; 14use tempfile::TempDir;
15use test_utils::skip_slow_tests;
15 16
16use crate::support::{project, Project}; 17use crate::support::{project, Project};
17 18
@@ -20,6 +21,10 @@ const PROFILE: &'static str = "";
20 21
21#[test] 22#[test]
22fn completes_items_from_standard_library() { 23fn completes_items_from_standard_library() {
24 if skip_slow_tests() {
25 return;
26 }
27
23 let project_start = Instant::now(); 28 let project_start = Instant::now();
24 let server = Project::with_fixture( 29 let server = Project::with_fixture(
25 r#" 30 r#"
@@ -50,6 +55,10 @@ use std::collections::Spam;
50 55
51#[test] 56#[test]
52fn test_runnables_no_project() { 57fn test_runnables_no_project() {
58 if skip_slow_tests() {
59 return;
60 }
61
53 let server = project( 62 let server = project(
54 r" 63 r"
55//- lib.rs 64//- lib.rs
@@ -99,6 +108,10 @@ fn foo() {
99 108
100#[test] 109#[test]
101fn test_runnables_project() { 110fn test_runnables_project() {
111 if skip_slow_tests() {
112 return;
113 }
114
102 let code = r#" 115 let code = r#"
103//- foo/Cargo.toml 116//- foo/Cargo.toml
104[package] 117[package]
@@ -170,6 +183,10 @@ fn main() {}
170 183
171#[test] 184#[test]
172fn test_format_document() { 185fn test_format_document() {
186 if skip_slow_tests() {
187 return;
188 }
189
173 let server = project( 190 let server = project(
174 r#" 191 r#"
175//- Cargo.toml 192//- Cargo.toml
@@ -222,6 +239,10 @@ pub use std::collections::HashMap;
222 239
223#[test] 240#[test]
224fn test_format_document_2018() { 241fn test_format_document_2018() {
242 if skip_slow_tests() {
243 return;
244 }
245
225 let server = project( 246 let server = project(
226 r#" 247 r#"
227//- Cargo.toml 248//- Cargo.toml
@@ -277,8 +298,13 @@ pub use std::collections::HashMap;
277 ]), 298 ]),
278 ); 299 );
279} 300}
301
280#[test] 302#[test]
281fn test_missing_module_code_action() { 303fn test_missing_module_code_action() {
304 if skip_slow_tests() {
305 return;
306 }
307
282 let server = project( 308 let server = project(
283 r#" 309 r#"
284//- Cargo.toml 310//- Cargo.toml
@@ -337,6 +363,10 @@ fn main() {}
337 363
338#[test] 364#[test]
339fn test_missing_module_code_action_in_json_project() { 365fn test_missing_module_code_action_in_json_project() {
366 if skip_slow_tests() {
367 return;
368 }
369
340 let tmp_dir = TempDir::new().unwrap(); 370 let tmp_dir = TempDir::new().unwrap();
341 371
342 let path = tmp_dir.path(); 372 let path = tmp_dir.path();
@@ -412,6 +442,10 @@ fn main() {{}}
412 442
413#[test] 443#[test]
414fn diagnostics_dont_block_typing() { 444fn diagnostics_dont_block_typing() {
445 if skip_slow_tests() {
446 return;
447 }
448
415 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect(); 449 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
416 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect(); 450 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
417 let server = Project::with_fixture(&format!( 451 let server = Project::with_fixture(&format!(
@@ -480,6 +514,10 @@ fn main() {{}}
480 514
481#[test] 515#[test]
482fn preserves_dos_line_endings() { 516fn preserves_dos_line_endings() {
517 if skip_slow_tests() {
518 return;
519 }
520
483 let server = Project::with_fixture( 521 let server = Project::with_fixture(
484 &" 522 &"
485//- Cargo.toml 523//- Cargo.toml
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index e049fce61..db6230aab 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -1,6 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{iter::successors, marker::PhantomData}; 3use std::{
4 hash::{Hash, Hasher},
5 iter::successors,
6 marker::PhantomData,
7};
4 8
5use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; 9use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};
6 10
@@ -43,7 +47,7 @@ impl SyntaxNodePtr {
43} 47}
44 48
45/// Like `SyntaxNodePtr`, but remembers the type of node 49/// Like `SyntaxNodePtr`, but remembers the type of node
46#[derive(Debug, Hash)] 50#[derive(Debug)]
47pub struct AstPtr<N: AstNode> { 51pub struct AstPtr<N: AstNode> {
48 raw: SyntaxNodePtr, 52 raw: SyntaxNodePtr,
49 _ty: PhantomData<fn() -> N>, 53 _ty: PhantomData<fn() -> N>,
@@ -64,6 +68,12 @@ impl<N: AstNode> PartialEq for AstPtr<N> {
64 } 68 }
65} 69}
66 70
71impl<N: AstNode> Hash for AstPtr<N> {
72 fn hash<H: Hasher>(&self, state: &mut H) {
73 self.raw.hash(state)
74 }
75}
76
67impl<N: AstNode> AstPtr<N> { 77impl<N: AstNode> AstPtr<N> {
68 pub fn new(node: &N) -> AstPtr<N> { 78 pub fn new(node: &N) -> AstPtr<N> {
69 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData } 79 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 1244ea8cf..657ddf2a6 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -356,6 +356,17 @@ pub fn read_text(path: &Path) -> String {
356 .replace("\r\n", "\n") 356 .replace("\r\n", "\n")
357} 357}
358 358
359pub fn skip_slow_tests() -> bool {
360 let should_skip = std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err();
361 if should_skip {
362 eprintln!("ignoring slow test")
363 } else {
364 let path = project_dir().join("./target/.slow_tests_cookie");
365 fs::write(&path, ".").unwrap();
366 }
367 should_skip
368}
369
359const REWRITE: bool = false; 370const REWRITE: bool = false;
360 371
361fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 372fn assert_equal_text(expected: &str, actual: &str, path: &Path) {