diff options
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" | |||
14 | source = "registry+https://github.com/rust-lang/crates.io-index" | 14 | source = "registry+https://github.com/rust-lang/crates.io-index" |
15 | 15 | ||
16 | [[package]] | 16 | [[package]] |
17 | name = "anymap" | ||
18 | version = "0.12.1" | ||
19 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
20 | |||
21 | [[package]] | ||
17 | name = "arrayvec" | 22 | name = "arrayvec" |
18 | version = "0.5.1" | 23 | version = "0.5.1" |
19 | source = "registry+https://github.com/rust-lang/crates.io-index" | 24 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -958,6 +963,7 @@ dependencies = [ | |||
958 | name = "ra_hir_def" | 963 | name = "ra_hir_def" |
959 | version = "0.1.0" | 964 | version = "0.1.0" |
960 | dependencies = [ | 965 | dependencies = [ |
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 | }; |
22 | use hir_expand::{ | 22 | use 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)] |
859 | pub struct GenericParam { | 859 | pub struct TypeParam { |
860 | pub(crate) parent: GenericDefId, | 860 | pub(crate) id: TypeParamId, |
861 | pub(crate) idx: u32, | 861 | } |
862 | |||
863 | impl 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 { | |||
1101 | pub enum ScopeDef { | 1111 | pub 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 | ||
11 | use crate::{ | 11 | use 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 | ||
16 | pub use hir_expand::InFile; | 16 | pub 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 | |||
133 | impl 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 |
2 | use either::Either; | ||
3 | |||
4 | use hir_def::{ | 2 | use 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 | }; |
8 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 6 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
9 | use ra_syntax::{ | 7 | use ra_syntax::{ |
@@ -14,7 +12,7 @@ use ra_syntax::{ | |||
14 | use crate::{ | 12 | use 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 | ||
20 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -53,8 +51,9 @@ impl FromSource for Trait { | |||
53 | impl FromSource for Function { | 51 | impl 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 { | |||
62 | impl FromSource for Const { | 61 | impl 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 | } |
70 | impl FromSource for Static { | 70 | impl 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 | ||
80 | impl FromSource for TypeAlias { | 80 | impl 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 | ||
123 | impl FromSource for StructField { | 128 | impl 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 | ||
180 | impl 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 | |||
169 | impl Module { | 202 | impl 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 | ||
258 | impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container | 291 | impl ChildBySource for Container { |
259 | where | 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; | |||
42 | pub use crate::{ | 42 | pub 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 | }; |
22 | use hir_expand::{ | 22 | use 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 | }; |
26 | use ra_syntax::{ | 25 | use 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 | ||
43 | fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> { | 42 | fn 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)] | ||
138 | pub struct Expansion { | 143 | pub 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 | ||
549 | fn 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" | |||
12 | once_cell = "1.0.1" | 12 | once_cell = "1.0.1" |
13 | rustc-hash = "1.0" | 13 | rustc-hash = "1.0" |
14 | either = "1.5" | 14 | either = "1.5" |
15 | anymap = "0.12" | ||
15 | 16 | ||
16 | ra_arena = { path = "../ra_arena" } | 17 | ra_arena = { path = "../ra_arena" } |
17 | ra_db = { path = "../ra_db" } | 18 | ra_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; | |||
6 | use std::{ops::Index, sync::Arc}; | 6 | use std::{ops::Index, sync::Arc}; |
7 | 7 | ||
8 | use either::Either; | 8 | use either::Either; |
9 | use hir_expand::{ | 9 | use hir_expand::{hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId}; |
10 | hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId, MacroFileKind, | ||
11 | }; | ||
12 | use ra_arena::{map::ArenaMap, Arena}; | 10 | use ra_arena::{map::ArenaMap, Arena}; |
13 | use ra_syntax::{ast, AstNode, AstPtr}; | 11 | use ra_syntax::{ast, AstNode, AstPtr}; |
14 | use rustc_hash::FxHashMap; | 12 | use 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 | |||
7 | use either::Either; | ||
8 | |||
9 | use crate::{ | ||
10 | db::DefDatabase, | ||
11 | dyn_map::DynMap, | ||
12 | keys, | ||
13 | src::{HasChildSource, HasSource}, | ||
14 | AssocItemId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, ModuleId, StructFieldId, | ||
15 | TraitId, VariantId, | ||
16 | }; | ||
17 | |||
18 | pub trait ChildBySource { | ||
19 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap; | ||
20 | } | ||
21 | |||
22 | impl ChildBySource for TraitId { | ||
23 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
24 | let mut res = DynMap::default(); | ||
25 | |||
26 | let data = db.trait_data(*self); | ||
27 | for (_name, item) in data.items.iter() { | ||
28 | match *item { | ||
29 | AssocItemId::FunctionId(func) => { | ||
30 | let src = func.lookup(db).source(db); | ||
31 | res[keys::FUNCTION].insert(src, func) | ||
32 | } | ||
33 | AssocItemId::ConstId(konst) => { | ||
34 | let src = konst.lookup(db).source(db); | ||
35 | res[keys::CONST].insert(src, konst) | ||
36 | } | ||
37 | AssocItemId::TypeAliasId(ty) => { | ||
38 | let src = ty.lookup(db).source(db); | ||
39 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | res | ||
45 | } | ||
46 | } | ||
47 | |||
48 | impl ChildBySource for ImplId { | ||
49 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
50 | let mut res = DynMap::default(); | ||
51 | |||
52 | let data = db.impl_data(*self); | ||
53 | for &item in data.items.iter() { | ||
54 | match item { | ||
55 | AssocItemId::FunctionId(func) => { | ||
56 | let src = func.lookup(db).source(db); | ||
57 | res[keys::FUNCTION].insert(src, func) | ||
58 | } | ||
59 | AssocItemId::ConstId(konst) => { | ||
60 | let src = konst.lookup(db).source(db); | ||
61 | res[keys::CONST].insert(src, konst) | ||
62 | } | ||
63 | AssocItemId::TypeAliasId(ty) => { | ||
64 | let src = ty.lookup(db).source(db); | ||
65 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | res | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl ChildBySource for ModuleId { | ||
75 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
76 | let mut res = DynMap::default(); | ||
77 | |||
78 | let crate_def_map = db.crate_def_map(self.krate); | ||
79 | for item in crate_def_map[self.local_id].scope.declarations() { | ||
80 | match item { | ||
81 | ModuleDefId::FunctionId(func) => { | ||
82 | let src = func.lookup(db).source(db); | ||
83 | res[keys::FUNCTION].insert(src, func) | ||
84 | } | ||
85 | ModuleDefId::ConstId(konst) => { | ||
86 | let src = konst.lookup(db).source(db); | ||
87 | res[keys::CONST].insert(src, konst) | ||
88 | } | ||
89 | ModuleDefId::StaticId(statik) => { | ||
90 | let src = statik.lookup(db).source(db); | ||
91 | res[keys::STATIC].insert(src, statik) | ||
92 | } | ||
93 | ModuleDefId::TypeAliasId(ty) => { | ||
94 | let src = ty.lookup(db).source(db); | ||
95 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
96 | } | ||
97 | _ => (), | ||
98 | } | ||
99 | } | ||
100 | |||
101 | res | ||
102 | } | ||
103 | } | ||
104 | |||
105 | impl ChildBySource for VariantId { | ||
106 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
107 | let mut res = DynMap::default(); | ||
108 | |||
109 | let arena_map = self.child_source(db); | ||
110 | let arena_map = arena_map.as_ref(); | ||
111 | for (local_id, source) in arena_map.value.iter() { | ||
112 | let id = StructFieldId { parent: *self, local_id }; | ||
113 | match source { | ||
114 | Either::Left(source) => { | ||
115 | res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
116 | } | ||
117 | Either::Right(source) => { | ||
118 | res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | res | ||
123 | } | ||
124 | } | ||
125 | |||
126 | impl ChildBySource for EnumId { | ||
127 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
128 | let mut res = DynMap::default(); | ||
129 | |||
130 | let arena_map = self.child_source(db); | ||
131 | let arena_map = arena_map.as_ref(); | ||
132 | for (local_id, source) in arena_map.value.iter() { | ||
133 | let id = EnumVariantId { parent: *self, local_id }; | ||
134 | res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id) | ||
135 | } | ||
136 | |||
137 | res | ||
138 | } | ||
139 | } | ||
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 | |||
7 | use either::Either; | ||
8 | use hir_expand::InFile; | ||
9 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
10 | |||
11 | use 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 | |||
18 | pub 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 | |||
26 | impl 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 | |||
46 | impl 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 | |||
66 | impl 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 | |||
88 | impl 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 | |||
108 | impl 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 | |||
128 | impl 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 | |||
150 | impl 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 | |||
170 | impl 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 | |||
190 | impl 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 | |||
212 | impl 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 | |||
234 | impl 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 | |||
253 | impl 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. | ||
274 | fn 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. | ||
24 | use std::{ | ||
25 | hash::Hash, | ||
26 | marker::PhantomData, | ||
27 | ops::{Index, IndexMut}, | ||
28 | }; | ||
29 | |||
30 | use anymap::Map; | ||
31 | use rustc_hash::FxHashMap; | ||
32 | |||
33 | pub struct Key<K, V, P = (K, V)> { | ||
34 | _phantom: PhantomData<(K, V, P)>, | ||
35 | } | ||
36 | |||
37 | impl<K, V, P> Key<K, V, P> { | ||
38 | pub(crate) const fn new() -> Key<K, V, P> { | ||
39 | Key { _phantom: PhantomData } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl<K, V, P> Copy for Key<K, V, P> {} | ||
44 | |||
45 | impl<K, V, P> Clone for Key<K, V, P> { | ||
46 | fn clone(&self) -> Key<K, V, P> { | ||
47 | *self | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub 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 | |||
59 | impl<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 | |||
70 | pub struct DynMap { | ||
71 | pub(crate) map: Map, | ||
72 | } | ||
73 | |||
74 | impl Default for DynMap { | ||
75 | fn default() -> Self { | ||
76 | DynMap { map: Map::new() } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | #[repr(transparent)] | ||
81 | pub struct KeyMap<KEY> { | ||
82 | map: DynMap, | ||
83 | _phantom: PhantomData<KEY>, | ||
84 | } | ||
85 | |||
86 | impl<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 | |||
95 | impl<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 | |||
103 | impl<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. |
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use hir_expand::name::{self, AsName, Name}; | 7 | use either::Either; |
8 | use hir_expand::{ | ||
9 | name::{self, AsName, Name}, | ||
10 | InFile, | ||
11 | }; | ||
12 | use ra_arena::{map::ArenaMap, Arena}; | ||
13 | use ra_db::FileId; | ||
8 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | 14 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; |
9 | 15 | ||
10 | use crate::{ | 16 | use 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)] |
19 | pub struct GenericParam { | 29 | pub 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)] |
28 | pub struct GenericParams { | 36 | pub 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 | ||
52 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; | ||
53 | |||
44 | impl GenericParams { | 54 | impl 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> { | 181 | impl 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 | ||
170 | fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> { | 190 | impl 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 | |||
3 | use std::marker::PhantomData; | ||
4 | |||
5 | use hir_expand::InFile; | ||
6 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
7 | use rustc_hash::FxHashMap; | ||
8 | |||
9 | use crate::{ | ||
10 | dyn_map::{DynMap, Policy}, | ||
11 | ConstId, EnumVariantId, FunctionId, StaticId, StructFieldId, TypeAliasId, TypeParamId, | ||
12 | }; | ||
13 | |||
14 | type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | ||
15 | |||
16 | pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new(); | ||
17 | pub const CONST: Key<ast::ConstDef, ConstId> = Key::new(); | ||
18 | pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new(); | ||
19 | pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new(); | ||
20 | pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new(); | ||
21 | pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new(); | ||
22 | pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new(); | ||
23 | pub 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. | ||
31 | pub struct AstPtrPolicy<AST, ID> { | ||
32 | _phantom: PhantomData<(AST, ID)>, | ||
33 | } | ||
34 | |||
35 | impl<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; | |||
16 | pub mod diagnostics; | 16 | pub mod diagnostics; |
17 | pub mod per_ns; | 17 | pub mod per_ns; |
18 | 18 | ||
19 | pub mod dyn_map; | ||
20 | pub mod keys; | ||
21 | |||
19 | pub mod adt; | 22 | pub mod adt; |
20 | pub mod data; | 23 | pub mod data; |
21 | pub mod generics; | 24 | pub mod generics; |
@@ -30,7 +33,7 @@ mod trace; | |||
30 | pub mod nameres; | 33 | pub mod nameres; |
31 | 34 | ||
32 | pub mod src; | 35 | pub mod src; |
33 | pub mod child_from_source; | 36 | pub mod child_by_source; |
34 | 37 | ||
35 | #[cfg(test)] | 38 | #[cfg(test)] |
36 | mod test_db; | 39 | mod 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)] |
321 | pub struct TypeParamId { | ||
322 | pub parent: GenericDefId, | ||
323 | pub local_id: LocalTypeParamId, | ||
324 | } | ||
325 | |||
326 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
327 | pub struct LocalTypeParamId(RawId); | ||
328 | impl_arena_id!(LocalTypeParamId); | ||
329 | |||
330 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
318 | pub enum ContainerId { | 331 | pub 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 | ||
528 | impl 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 | |||
515 | impl HasModule for StaticLoc { | 542 | impl 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 | }; |
12 | use ra_cfg::CfgOptions; | 12 | use ra_cfg::CfgOptions; |
13 | use ra_db::{CrateId, FileId}; | 13 | use 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; | |||
11 | pub struct PerNs { | 11 | pub 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)] |
26 | pub struct Resolver { | 26 | pub 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)] |
59 | pub enum TypeNs { | 60 | pub 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)] |
209 | mod tests { | 209 | mod 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 @@ | |||
2 | use crate::db::AstDatabase; | 2 | use crate::db::AstDatabase; |
3 | use crate::{ | 3 | use 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 | ||
9 | use crate::quote; | 8 | use 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 | ||
55 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { | 58 | fn 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 | ||
206 | fn 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)] |
204 | mod tests { | 242 | mod 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; | |||
6 | use ra_db::{salsa, SourceDatabase}; | 6 | use ra_db::{salsa, SourceDatabase}; |
7 | use ra_parser::FragmentKind; | 7 | use ra_parser::FragmentKind; |
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use ra_syntax::{AstNode, Parse, SyntaxNode}; | 9 | use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode}; |
10 | 10 | ||
11 | use crate::{ | 11 | use 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 | ||
166 | fn 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)] |
107 | pub struct MacroFile { | 118 | pub 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)] | ||
113 | pub 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 | ||
189 | impl MacroCallId { | 199 | impl 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 | |||
296 | impl<T: Clone> InFile<&T> { | ||
297 | pub fn cloned(&self) -> InFile<T> { | ||
298 | self.with_value(self.value.clone()) | ||
299 | } | ||
300 | } | ||
301 | |||
302 | impl 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 |
108 | pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); | 108 | pub const ISIZE: Name = Name::new_inline_ascii(b"isize"); |
109 | pub const I8: Name = Name::new_inline_ascii(2, b"i8"); | 109 | pub const I8: Name = Name::new_inline_ascii(b"i8"); |
110 | pub const I16: Name = Name::new_inline_ascii(3, b"i16"); | 110 | pub const I16: Name = Name::new_inline_ascii(b"i16"); |
111 | pub const I32: Name = Name::new_inline_ascii(3, b"i32"); | 111 | pub const I32: Name = Name::new_inline_ascii(b"i32"); |
112 | pub const I64: Name = Name::new_inline_ascii(3, b"i64"); | 112 | pub const I64: Name = Name::new_inline_ascii(b"i64"); |
113 | pub const I128: Name = Name::new_inline_ascii(4, b"i128"); | 113 | pub const I128: Name = Name::new_inline_ascii(b"i128"); |
114 | pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); | 114 | pub const USIZE: Name = Name::new_inline_ascii(b"usize"); |
115 | pub const U8: Name = Name::new_inline_ascii(2, b"u8"); | 115 | pub const U8: Name = Name::new_inline_ascii(b"u8"); |
116 | pub const U16: Name = Name::new_inline_ascii(3, b"u16"); | 116 | pub const U16: Name = Name::new_inline_ascii(b"u16"); |
117 | pub const U32: Name = Name::new_inline_ascii(3, b"u32"); | 117 | pub const U32: Name = Name::new_inline_ascii(b"u32"); |
118 | pub const U64: Name = Name::new_inline_ascii(3, b"u64"); | 118 | pub const U64: Name = Name::new_inline_ascii(b"u64"); |
119 | pub const U128: Name = Name::new_inline_ascii(4, b"u128"); | 119 | pub const U128: Name = Name::new_inline_ascii(b"u128"); |
120 | pub const F32: Name = Name::new_inline_ascii(3, b"f32"); | 120 | pub const F32: Name = Name::new_inline_ascii(b"f32"); |
121 | pub const F64: Name = Name::new_inline_ascii(3, b"f64"); | 121 | pub const F64: Name = Name::new_inline_ascii(b"f64"); |
122 | pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); | 122 | pub const BOOL: Name = Name::new_inline_ascii(b"bool"); |
123 | pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); | 123 | pub const CHAR: Name = Name::new_inline_ascii(b"char"); |
124 | pub const STR: Name = Name::new_inline_ascii(3, b"str"); | 124 | pub const STR: Name = Name::new_inline_ascii(b"str"); |
125 | 125 | ||
126 | // Special names | 126 | // Special names |
127 | pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); | 127 | pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self"); |
128 | pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); | 128 | pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self"); |
129 | pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); | 129 | pub 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) |
132 | pub const STD: Name = Name::new_inline_ascii(3, b"std"); | 132 | pub const STD: Name = Name::new_inline_ascii(b"std"); |
133 | pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); | 133 | pub const ITER: Name = Name::new_inline_ascii(b"iter"); |
134 | pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); | 134 | pub const OPS: Name = Name::new_inline_ascii(b"ops"); |
135 | pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); | 135 | pub const FUTURE: Name = Name::new_inline_ascii(b"future"); |
136 | pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); | 136 | pub const RESULT: Name = Name::new_inline_ascii(b"result"); |
137 | pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); | 137 | pub 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) |
140 | pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); | 140 | pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator"); |
141 | pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); | 141 | pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item"); |
142 | pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); | 142 | pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try"); |
143 | pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); | 143 | pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok"); |
144 | pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); | 144 | pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future"); |
145 | pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); | 145 | pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result"); |
146 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); | 146 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output"); |
147 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); | 147 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target"); |
148 | pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); | 148 | pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box"); |
149 | pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom"); | 149 | pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom"); |
150 | pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull"); | 150 | pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull"); |
151 | pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive"); | 151 | pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive"); |
152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive"); | 152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); |
153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo"); | 153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); |
154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range"); | 154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); |
155 | 155 | ||
156 | // Builtin Macros | 156 | // Builtin Macros |
157 | pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); | 157 | pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); |
158 | pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); | 158 | pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column"); |
159 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); | 159 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error"); |
160 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); | 160 | pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line"); |
161 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); | 161 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify"); |
162 | pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args"); | ||
163 | pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl"); | ||
162 | 164 | ||
163 | // Builtin derives | 165 | // Builtin derives |
164 | pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy"); | 166 | pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy"); |
165 | pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone"); | 167 | pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone"); |
166 | pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(7, b"Default"); | 168 | pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default"); |
167 | pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(5, b"Debug"); | 169 | pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug"); |
168 | pub const HASH_TRAIT: Name = Name::new_inline_ascii(4, b"Hash"); | 170 | pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash"); |
169 | pub const ORD_TRAIT: Name = Name::new_inline_ascii(3, b"Ord"); | 171 | pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord"); |
170 | pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(10, b"PartialOrd"); | 172 | pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd"); |
171 | pub const EQ_TRAIT: Name = Name::new_inline_ascii(2, b"Eq"); | 173 | pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq"); |
172 | pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(9, b"PartialEq"); | 174 | pub 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; | |||
10 | use log::{info, warn}; | 10 | use log::{info, warn}; |
11 | use ra_db::CrateId; | 11 | use ra_db::CrateId; |
12 | 12 | ||
13 | use crate::db::HirDatabase; | 13 | use crate::{ |
14 | 14 | db::HirDatabase, | |
15 | use 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; | |||
6 | use hir_def::{ | 6 | use 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}; | |||
15 | use ra_syntax::ast::RangeOp; | 14 | use ra_syntax::ast::RangeOp; |
16 | 15 | ||
17 | use crate::{ | 16 | use 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; | |||
44 | use std::{fmt, iter, mem}; | 44 | use std::{fmt, iter, mem}; |
45 | 45 | ||
46 | use hir_def::{ | 46 | use 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 | }; |
50 | use hir_expand::name::Name; | 50 | use hir_expand::name::Name; |
51 | use ra_db::{impl_intern_key, salsa, CrateId}; | 51 | use ra_db::{impl_intern_key, salsa, CrateId}; |
@@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; | |||
53 | use crate::{ | 53 | use 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 | }; |
58 | use display::{HirDisplay, HirFormatter}; | 58 | use 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 |
568 | pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { | 571 | pub(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. |
591 | fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { | 593 | fn 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 | ||
674 | fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { | 676 | fn 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 | ||
679 | fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { | 681 | fn 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; | |||
11 | use std::sync::Arc; | 11 | use std::sync::Arc; |
12 | 12 | ||
13 | use hir_def::{ | 13 | use 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 | }; |
17 | use hir_expand::InFile; | 17 | use hir_expand::InFile; |
18 | use insta::assert_snapshot; | 18 | use 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 | ||
20 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 20 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; |
21 | use crate::{ | 21 | use 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; | |||
5 | use hir_def::{ | 5 | use 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 | }; |
12 | use hir_expand::name::{self, Name}; | 13 | use 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 | |||
87 | pub(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 | |||
92 | pub(crate) struct Generics { | ||
93 | def: GenericDefId, | ||
94 | pub(crate) params: Arc<GenericParams>, | ||
95 | parent_generics: Option<Box<Generics>>, | ||
96 | } | ||
97 | |||
98 | impl 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 | |||
149 | fn 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}; | |||
6 | use ra_syntax::{ | 6 | use 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 | ||
354 | impl 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 | |||
354 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { | 374 | pub(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)] |
165 | mod tests { | 157 | mod 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 | ||
6 | use hir::{ | 6 | use 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 | }; |
10 | use ra_syntax::{ast, ast::VisibilityOwner}; | 10 | use 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><<span class="type">X</span>> { | ||
52 | <span class="constant">V</span>(<span class="type">X</span>) | ||
53 | } | ||
54 | |||
55 | <span class="keyword">impl</span><<span class="type">X</span>> <span class="type">E</span><<span class="type">X</span>> { | ||
56 | <span class="keyword">fn</span> <span class="function">new</span><<span class="type">T</span>>() -> <span class="type">E</span><<span class="type">T</span>> {} | ||
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 | |||
307 | enum E<X> { | ||
308 | V(X) | ||
309 | } | ||
310 | |||
311 | impl<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 | }; |
13 | use serde_json::json; | 13 | use serde_json::json; |
14 | use tempfile::TempDir; | 14 | use tempfile::TempDir; |
15 | use test_utils::skip_slow_tests; | ||
15 | 16 | ||
16 | use crate::support::{project, Project}; | 17 | use crate::support::{project, Project}; |
17 | 18 | ||
@@ -20,6 +21,10 @@ const PROFILE: &'static str = ""; | |||
20 | 21 | ||
21 | #[test] | 22 | #[test] |
22 | fn completes_items_from_standard_library() { | 23 | fn 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] |
52 | fn test_runnables_no_project() { | 57 | fn 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] |
101 | fn test_runnables_project() { | 110 | fn 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] |
172 | fn test_format_document() { | 185 | fn 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] |
224 | fn test_format_document_2018() { | 241 | fn 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] |
281 | fn test_missing_module_code_action() { | 303 | fn 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] |
339 | fn test_missing_module_code_action_in_json_project() { | 365 | fn 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] |
414 | fn diagnostics_dont_block_typing() { | 444 | fn 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] |
482 | fn preserves_dos_line_endings() { | 516 | fn 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 | ||
3 | use std::{iter::successors, marker::PhantomData}; | 3 | use std::{ |
4 | hash::{Hash, Hasher}, | ||
5 | iter::successors, | ||
6 | marker::PhantomData, | ||
7 | }; | ||
4 | 8 | ||
5 | use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; | 9 | use 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)] |
47 | pub struct AstPtr<N: AstNode> { | 51 | pub 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 | ||
71 | impl<N: AstNode> Hash for AstPtr<N> { | ||
72 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
73 | self.raw.hash(state) | ||
74 | } | ||
75 | } | ||
76 | |||
67 | impl<N: AstNode> AstPtr<N> { | 77 | impl<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 | ||
359 | pub 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 | |||
359 | const REWRITE: bool = false; | 370 | const REWRITE: bool = false; |
360 | 371 | ||
361 | fn assert_equal_text(expected: &str, actual: &str, path: &Path) { | 372 | fn assert_equal_text(expected: &str, actual: &str, path: &Path) { |