diff options
Diffstat (limited to 'crates')
46 files changed, 670 insertions, 505 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 1908bdec9..0ea84d548 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. | 1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. |
2 | 2 | use hir::{db::HirDatabase, SourceAnalyzer}; | |
3 | use hir::db::HirDatabase; | ||
4 | use ra_db::FileRange; | 3 | use ra_db::FileRange; |
5 | use ra_fmt::{leading_indent, reindent}; | 4 | use ra_fmt::{leading_indent, reindent}; |
6 | use ra_syntax::{ | 5 | use ra_syntax::{ |
@@ -113,6 +112,13 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
113 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 112 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
114 | find_covering_element(self.source_file.syntax(), self.frange.range) | 113 | find_covering_element(self.source_file.syntax(), self.frange.range) |
115 | } | 114 | } |
115 | pub(crate) fn source_analyzer( | ||
116 | &self, | ||
117 | node: &SyntaxNode, | ||
118 | offset: Option<TextUnit>, | ||
119 | ) -> SourceAnalyzer { | ||
120 | SourceAnalyzer::new(self.db, hir::Source::new(self.frange.file_id.into(), node), offset) | ||
121 | } | ||
116 | 122 | ||
117 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { | 123 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { |
118 | find_covering_element(self.source_file.syntax(), range) | 124 | find_covering_element(self.source_file.syntax(), range) |
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index ddda1a0f2..562a09685 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -40,7 +40,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
40 | } | 40 | } |
41 | // Infer type | 41 | // Infer type |
42 | let db = ctx.db; | 42 | let db = ctx.db; |
43 | let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None); | 43 | let analyzer = ctx.source_analyzer(stmt.syntax(), None); |
44 | let ty = analyzer.type_of(db, &expr)?; | 44 | let ty = analyzer.type_of(db, &expr)?; |
45 | // Assist not applicable if the type is unknown | 45 | // Assist not applicable if the type is unknown |
46 | if is_unknown(&ty) { | 46 | if is_unknown(&ty) { |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 41de23921..91af161ee 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -100,8 +100,7 @@ fn add_missing_impl_members_inner( | |||
100 | let impl_item_list = impl_node.item_list()?; | 100 | let impl_item_list = impl_node.item_list()?; |
101 | 101 | ||
102 | let trait_def = { | 102 | let trait_def = { |
103 | let file_id = ctx.frange.file_id; | 103 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); |
104 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, impl_node.syntax(), None); | ||
105 | 104 | ||
106 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? | 105 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? |
107 | }; | 106 | }; |
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs index a8839cfba..2038afdc6 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/assists/add_new.rs | |||
@@ -158,9 +158,12 @@ fn find_struct_impl( | |||
158 | let same_ty = blk.target_ty(db) == struct_ty; | 158 | let same_ty = blk.target_ty(db) == struct_ty; |
159 | let not_trait_impl = blk.target_trait(db).is_none(); | 159 | let not_trait_impl = blk.target_trait(db).is_none(); |
160 | 160 | ||
161 | found_new_fn = has_new_fn(impl_blk); | 161 | if !(same_ty && not_trait_impl) { |
162 | return false; | ||
163 | } | ||
162 | 164 | ||
163 | same_ty && not_trait_impl | 165 | found_new_fn = has_new_fn(impl_blk); |
166 | true | ||
164 | }); | 167 | }); |
165 | 168 | ||
166 | if found_new_fn { | 169 | if found_new_fn { |
@@ -186,9 +189,10 @@ fn has_new_fn(imp: &ast::ImplBlock) -> bool { | |||
186 | 189 | ||
187 | #[cfg(test)] | 190 | #[cfg(test)] |
188 | mod tests { | 191 | mod tests { |
189 | use super::*; | ||
190 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 192 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; |
191 | 193 | ||
194 | use super::*; | ||
195 | |||
192 | #[test] | 196 | #[test] |
193 | #[rustfmt::skip] | 197 | #[rustfmt::skip] |
194 | fn test_add_new() { | 198 | fn test_add_new() { |
@@ -345,7 +349,7 @@ struct Foo {<|>} | |||
345 | impl Foo { | 349 | impl Foo { |
346 | fn new() -> Self { | 350 | fn new() -> Self { |
347 | Self | 351 | Self |
348 | } | 352 | } |
349 | }", | 353 | }", |
350 | ); | 354 | ); |
351 | 355 | ||
@@ -357,7 +361,7 @@ struct Foo {<|>} | |||
357 | impl Foo { | 361 | impl Foo { |
358 | fn New() -> Self { | 362 | fn New() -> Self { |
359 | Self | 363 | Self |
360 | } | 364 | } |
361 | }", | 365 | }", |
362 | ); | 366 | ); |
363 | } | 367 | } |
@@ -376,4 +380,59 @@ struct EvenMoreIrrelevant; | |||
376 | struct Foo<'a, T: Foo<'a>> {}", | 380 | struct Foo<'a, T: Foo<'a>> {}", |
377 | ); | 381 | ); |
378 | } | 382 | } |
383 | |||
384 | #[test] | ||
385 | fn test_unrelated_new() { | ||
386 | check_assist( | ||
387 | add_new, | ||
388 | r##" | ||
389 | pub struct AstId<N: AstNode> { | ||
390 | file_id: HirFileId, | ||
391 | file_ast_id: FileAstId<N>, | ||
392 | } | ||
393 | |||
394 | impl<N: AstNode> AstId<N> { | ||
395 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
396 | AstId { file_id, file_ast_id } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | pub struct Source<T> { | ||
401 | pub file_id: HirFileId,<|> | ||
402 | pub ast: T, | ||
403 | } | ||
404 | |||
405 | impl<T> Source<T> { | ||
406 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
407 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
408 | } | ||
409 | } | ||
410 | "##, | ||
411 | r##" | ||
412 | pub struct AstId<N: AstNode> { | ||
413 | file_id: HirFileId, | ||
414 | file_ast_id: FileAstId<N>, | ||
415 | } | ||
416 | |||
417 | impl<N: AstNode> AstId<N> { | ||
418 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
419 | AstId { file_id, file_ast_id } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | pub struct Source<T> { | ||
424 | pub file_id: HirFileId, | ||
425 | pub ast: T, | ||
426 | } | ||
427 | |||
428 | impl<T> Source<T> { | ||
429 | pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> | ||
430 | |||
431 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
432 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
433 | } | ||
434 | } | ||
435 | "##, | ||
436 | ); | ||
437 | } | ||
379 | } | 438 | } |
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 2b74f355c..b851c2082 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -47,8 +47,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
47 | 47 | ||
48 | let expr = match_expr.expr()?; | 48 | let expr = match_expr.expr()?; |
49 | let enum_def = { | 49 | let enum_def = { |
50 | let file_id = ctx.frange.file_id; | 50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); |
51 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, expr.syntax(), None); | ||
52 | resolve_enum_def(ctx.db, &analyzer, &expr)? | 51 | resolve_enum_def(ctx.db, &analyzer, &expr)? |
53 | }; | 52 | }; |
54 | let variant_list = enum_def.variant_list()?; | 53 | let variant_list = enum_def.variant_list()?; |
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index a7fd9b6d2..18a34502c 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs | |||
@@ -45,7 +45,7 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
45 | } else { | 45 | } else { |
46 | let_stmt.syntax().text_range() | 46 | let_stmt.syntax().text_range() |
47 | }; | 47 | }; |
48 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None); | 48 | let analyzer = ctx.source_analyzer(bind_pat.syntax(), None); |
49 | let refs = analyzer.find_all_refs(&bind_pat); | 49 | let refs = analyzer.find_all_refs(&bind_pat); |
50 | 50 | ||
51 | let mut wrap_in_parens = vec![true; refs.len()]; | 51 | let mut wrap_in_parens = vec![true; refs.len()]; |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 078bd8609..731cc1fff 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -11,7 +11,7 @@ use hir_def::{ | |||
11 | body::scope::ExprScopes, | 11 | body::scope::ExprScopes, |
12 | builtin_type::BuiltinType, | 12 | builtin_type::BuiltinType, |
13 | type_ref::{Mutability, TypeRef}, | 13 | type_ref::{Mutability, TypeRef}, |
14 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, | 14 | CrateModuleId, ImplId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, |
15 | }; | 15 | }; |
16 | use hir_expand::{ | 16 | use hir_expand::{ |
17 | diagnostics::DiagnosticSink, | 17 | diagnostics::DiagnosticSink, |
@@ -29,7 +29,6 @@ use crate::{ | |||
29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
30 | TypeAliasId, | 30 | TypeAliasId, |
31 | }, | 31 | }, |
32 | impl_block::ImplBlock, | ||
33 | resolve::{Resolver, Scope, TypeNs}, | 32 | resolve::{Resolver, Scope, TypeNs}, |
34 | traits::TraitData, | 33 | traits::TraitData, |
35 | ty::{InferenceResult, Namespace, TraitRef}, | 34 | ty::{InferenceResult, Namespace, TraitRef}, |
@@ -243,12 +242,8 @@ impl Module { | |||
243 | } | 242 | } |
244 | 243 | ||
245 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { | 244 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { |
246 | let module_impl_blocks = db.impls_in_module(self); | 245 | let def_map = db.crate_def_map(self.id.krate); |
247 | module_impl_blocks | 246 | def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() |
248 | .impls | ||
249 | .iter() | ||
250 | .map(|(impl_id, _)| ImplBlock::from_id(self, impl_id)) | ||
251 | .collect() | ||
252 | } | 247 | } |
253 | 248 | ||
254 | fn with_module_id(self, module_id: CrateModuleId) -> Module { | 249 | fn with_module_id(self, module_id: CrateModuleId) -> Module { |
@@ -693,8 +688,7 @@ impl Function { | |||
693 | 688 | ||
694 | /// The containing impl block, if this is a method. | 689 | /// The containing impl block, if this is a method. |
695 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 690 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
696 | let module_impls = db.impls_in_module(self.module(db)); | 691 | ImplBlock::containing(db, self.into()) |
697 | ImplBlock::containing(module_impls, self.into()) | ||
698 | } | 692 | } |
699 | 693 | ||
700 | /// The containing trait, if this is a trait method definition. | 694 | /// The containing trait, if this is a trait method definition. |
@@ -759,8 +753,7 @@ impl Const { | |||
759 | 753 | ||
760 | /// The containing impl block, if this is a method. | 754 | /// The containing impl block, if this is a method. |
761 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 755 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
762 | let module_impls = db.impls_in_module(self.module(db)); | 756 | ImplBlock::containing(db, self.into()) |
763 | ImplBlock::containing(module_impls, self.into()) | ||
764 | } | 757 | } |
765 | 758 | ||
766 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { | 759 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { |
@@ -973,8 +966,7 @@ impl TypeAlias { | |||
973 | 966 | ||
974 | /// The containing impl block, if this is a method. | 967 | /// The containing impl block, if this is a method. |
975 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 968 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
976 | let module_impls = db.impls_in_module(self.module(db)); | 969 | ImplBlock::containing(db, self.into()) |
977 | ImplBlock::containing(module_impls, self.into()) | ||
978 | } | 970 | } |
979 | 971 | ||
980 | /// The containing trait, if this is a trait method definition. | 972 | /// The containing trait, if this is a trait method definition. |
@@ -1137,3 +1129,8 @@ pub struct GenericParam { | |||
1137 | pub(crate) parent: GenericDef, | 1129 | pub(crate) parent: GenericDef, |
1138 | pub(crate) idx: u32, | 1130 | pub(crate) idx: u32, |
1139 | } | 1131 | } |
1132 | |||
1133 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1134 | pub struct ImplBlock { | ||
1135 | pub(crate) id: ImplId, | ||
1136 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index c60029c01..276b0774f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -10,7 +10,6 @@ use crate::{ | |||
10 | debug::HirDebugDatabase, | 10 | debug::HirDebugDatabase, |
11 | generics::{GenericDef, GenericParams}, | 11 | generics::{GenericDef, GenericParams}, |
12 | ids, | 12 | ids, |
13 | impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, | ||
14 | lang_item::{LangItemTarget, LangItems}, | 13 | lang_item::{LangItemTarget, LangItems}, |
15 | traits::TraitData, | 14 | traits::TraitData, |
16 | ty::{ | 15 | ty::{ |
@@ -18,14 +17,14 @@ use crate::{ | |||
18 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, | 17 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, |
19 | }, | 18 | }, |
20 | type_alias::TypeAliasData, | 19 | type_alias::TypeAliasData, |
21 | Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait, | 20 | Const, ConstData, Crate, DefWithBody, FnData, Function, ImplBlock, Module, Static, StructField, |
22 | TypeAlias, | 21 | Trait, TypeAlias, |
23 | }; | 22 | }; |
24 | 23 | ||
25 | pub use hir_def::db::{ | 24 | pub use hir_def::db::{ |
26 | BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, | 25 | BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, |
27 | EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, | 26 | EnumDataQuery, ExprScopesQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, |
28 | RawItemsWithSourceMapQuery, StructDataQuery, | 27 | RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, |
29 | }; | 28 | }; |
30 | pub use hir_expand::db::{ | 29 | pub use hir_expand::db::{ |
31 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, | 30 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, |
@@ -42,15 +41,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
42 | #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] | 41 | #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] |
43 | fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; | 42 | fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; |
44 | 43 | ||
45 | #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)] | ||
46 | fn impls_in_module_with_source_map( | ||
47 | &self, | ||
48 | module: Module, | ||
49 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>); | ||
50 | |||
51 | #[salsa::invoke(ModuleImplBlocks::impls_in_module_query)] | ||
52 | fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; | ||
53 | |||
54 | #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] | 44 | #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] |
55 | fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; | 45 | fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; |
56 | 46 | ||
@@ -128,7 +118,7 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
128 | #[salsa::interned] | 118 | #[salsa::interned] |
129 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; | 119 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; |
130 | #[salsa::interned] | 120 | #[salsa::interned] |
131 | fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; | 121 | fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId; |
132 | 122 | ||
133 | #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] | 123 | #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] |
134 | fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; | 124 | fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; |
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index 9633ef586..f2203e995 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs | |||
@@ -3,9 +3,9 @@ | |||
3 | //! It's unclear if we need this long-term, but it's definitelly useful while we | 3 | //! It's unclear if we need this long-term, but it's definitelly useful while we |
4 | //! are splitting the hir. | 4 | //! are splitting the hir. |
5 | 5 | ||
6 | use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; | 6 | use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId}; |
7 | 7 | ||
8 | use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; | 8 | use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef}; |
9 | 9 | ||
10 | macro_rules! from_id { | 10 | macro_rules! from_id { |
11 | ($(($id:path, $ty:path)),*) => {$( | 11 | ($(($id:path, $ty:path)),*) => {$( |
@@ -27,6 +27,7 @@ from_id![ | |||
27 | (hir_def::StaticId, crate::Static), | 27 | (hir_def::StaticId, crate::Static), |
28 | (hir_def::ConstId, crate::Const), | 28 | (hir_def::ConstId, crate::Const), |
29 | (hir_def::FunctionId, crate::Function), | 29 | (hir_def::FunctionId, crate::Function), |
30 | (hir_def::ImplId, crate::ImplBlock), | ||
30 | (hir_expand::MacroDefId, crate::MacroDef) | 31 | (hir_expand::MacroDefId, crate::MacroDef) |
31 | ]; | 32 | ]; |
32 | 33 | ||
@@ -71,3 +72,13 @@ impl From<DefWithBody> for DefWithBodyId { | |||
71 | } | 72 | } |
72 | } | 73 | } |
73 | } | 74 | } |
75 | |||
76 | impl From<AssocItemId> for AssocItem { | ||
77 | fn from(def: AssocItemId) -> Self { | ||
78 | match def { | ||
79 | AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), | ||
80 | AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), | ||
81 | AssocItemId::ConstId(it) => AssocItem::Const(it.into()), | ||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 7e5523c54..1c26756c9 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; | 3 | use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; |
4 | use hir_expand::name::AsName; | 4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 6 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, | 7 | match_ast, |
@@ -11,8 +11,8 @@ use crate::{ | |||
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, | 13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, |
14 | Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, | 14 | Local, MacroDef, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, |
15 | VariantDef, | 15 | Union, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -77,19 +77,28 @@ impl FromSource for TypeAlias { | |||
77 | Some(TypeAlias { id }) | 77 | Some(TypeAlias { id }) |
78 | } | 78 | } |
79 | } | 79 | } |
80 | // FIXME: add impl FromSource for MacroDef | 80 | |
81 | impl FromSource for MacroDef { | ||
82 | type Ast = ast::MacroCall; | ||
83 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
84 | let kind = MacroDefKind::Declarative; | ||
85 | |||
86 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
87 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | ||
88 | let krate = module.krate().crate_id(); | ||
89 | |||
90 | let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.ast)); | ||
91 | |||
92 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; | ||
93 | Some(MacroDef { id }) | ||
94 | } | ||
95 | } | ||
81 | 96 | ||
82 | impl FromSource for ImplBlock { | 97 | impl FromSource for ImplBlock { |
83 | type Ast = ast::ImplBlock; | 98 | type Ast = ast::ImplBlock; |
84 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 99 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
85 | let module_src = crate::ModuleSource::from_child_node( | 100 | let id = from_source(db, src)?; |
86 | db, | 101 | Some(ImplBlock { id }) |
87 | src.file_id.original_file(db), | ||
88 | &src.ast.syntax(), | ||
89 | ); | ||
90 | let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; | ||
91 | let impls = module.impl_blocks(db); | ||
92 | impls.into_iter().find(|b| b.source(db) == src) | ||
93 | } | 102 | } |
94 | } | 103 | } |
95 | 104 | ||
@@ -202,9 +211,8 @@ where | |||
202 | N: AstNode, | 211 | N: AstNode, |
203 | DEF: AstItemDef<N>, | 212 | DEF: AstItemDef<N>, |
204 | { | 213 | { |
205 | let module_src = | 214 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); |
206 | crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax()); | 215 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; |
207 | let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; | ||
208 | let ctx = LocationCtx::new(db, module.id, src.file_id); | 216 | let ctx = LocationCtx::new(db, module.id, src.file_id); |
209 | Some(DEF::from_ast(ctx, &src.ast)) | 217 | Some(DEF::from_ast(ctx, &src.ast)) |
210 | } | 218 | } |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index b1a014074..0c2bb8fee 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -1,88 +1,38 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use rustc_hash::FxHashMap; | 3 | use hir_def::{type_ref::TypeRef, AstItemDef}; |
4 | use std::sync::Arc; | 4 | use ra_syntax::ast::{self}; |
5 | |||
6 | use hir_def::{attr::Attr, type_ref::TypeRef}; | ||
7 | use hir_expand::hygiene::Hygiene; | ||
8 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | ||
9 | use ra_cfg::CfgOptions; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, AstNode}, | ||
12 | AstPtr, | ||
13 | }; | ||
14 | 5 | ||
15 | use crate::{ | 6 | use crate::{ |
16 | code_model::{Module, ModuleSource}, | ||
17 | db::{AstDatabase, DefDatabase, HirDatabase}, | 7 | db::{AstDatabase, DefDatabase, HirDatabase}, |
18 | generics::HasGenericParams, | 8 | generics::HasGenericParams, |
19 | ids::LocationCtx, | ||
20 | ids::MacroCallLoc, | ||
21 | resolve::Resolver, | 9 | resolve::Resolver, |
22 | ty::Ty, | 10 | ty::Ty, |
23 | AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, | 11 | AssocItem, Crate, HasSource, ImplBlock, Module, Source, TraitRef, |
24 | TypeAlias, | ||
25 | }; | 12 | }; |
26 | 13 | ||
27 | #[derive(Debug, Default, PartialEq, Eq)] | ||
28 | pub struct ImplSourceMap { | ||
29 | map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>, | ||
30 | } | ||
31 | |||
32 | impl ImplSourceMap { | ||
33 | fn insert(&mut self, impl_id: ImplId, file_id: HirFileId, impl_block: &ast::ImplBlock) { | ||
34 | let source = Source { file_id, ast: AstPtr::new(impl_block) }; | ||
35 | self.map.insert(impl_id, source) | ||
36 | } | ||
37 | |||
38 | pub fn get(&self, db: &impl AstDatabase, impl_id: ImplId) -> Source<ast::ImplBlock> { | ||
39 | let src = self.map[impl_id]; | ||
40 | let root = src.file_syntax(db); | ||
41 | src.map(|ptr| ptr.to_node(&root)) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
46 | pub struct ImplBlock { | ||
47 | module: Module, | ||
48 | impl_id: ImplId, | ||
49 | } | ||
50 | |||
51 | impl HasSource for ImplBlock { | 14 | impl HasSource for ImplBlock { |
52 | type Ast = ast::ImplBlock; | 15 | type Ast = ast::ImplBlock; |
53 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { | 16 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { |
54 | let source_map = db.impls_in_module_with_source_map(self.module).1; | 17 | self.id.source(db) |
55 | source_map.get(db, self.impl_id) | ||
56 | } | 18 | } |
57 | } | 19 | } |
58 | 20 | ||
59 | impl ImplBlock { | 21 | impl ImplBlock { |
60 | pub(crate) fn containing( | 22 | pub(crate) fn containing(db: &impl DefDatabase, item: AssocItem) -> Option<ImplBlock> { |
61 | module_impl_blocks: Arc<ModuleImplBlocks>, | 23 | let module = item.module(db); |
62 | item: AssocItem, | 24 | let crate_def_map = db.crate_def_map(module.id.krate); |
63 | ) -> Option<ImplBlock> { | 25 | crate_def_map[module.id.module_id].impls.iter().copied().map(ImplBlock::from).find(|it| { |
64 | let impl_id = *module_impl_blocks.impls_by_def.get(&item)?; | 26 | db.impl_data(it.id).items().iter().copied().map(AssocItem::from).any(|it| it == item) |
65 | Some(ImplBlock { module: module_impl_blocks.module, impl_id }) | 27 | }) |
66 | } | ||
67 | |||
68 | pub(crate) fn from_id(module: Module, impl_id: ImplId) -> ImplBlock { | ||
69 | ImplBlock { module, impl_id } | ||
70 | } | ||
71 | |||
72 | pub fn id(&self) -> ImplId { | ||
73 | self.impl_id | ||
74 | } | ||
75 | |||
76 | pub fn module(&self) -> Module { | ||
77 | self.module | ||
78 | } | 28 | } |
79 | 29 | ||
80 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { | 30 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { |
81 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() | 31 | db.impl_data(self.id).target_trait().cloned() |
82 | } | 32 | } |
83 | 33 | ||
84 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { | 34 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { |
85 | db.impls_in_module(self.module).impls[self.impl_id].target_type().clone() | 35 | db.impl_data(self.id).target_type().clone() |
86 | } | 36 | } |
87 | 37 | ||
88 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { | 38 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { |
@@ -95,15 +45,23 @@ impl ImplBlock { | |||
95 | } | 45 | } |
96 | 46 | ||
97 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { | 47 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { |
98 | db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() | 48 | db.impl_data(self.id).items().iter().map(|it| (*it).into()).collect() |
99 | } | 49 | } |
100 | 50 | ||
101 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { | 51 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { |
102 | db.impls_in_module(self.module).impls[self.impl_id].negative | 52 | db.impl_data(self.id).is_negative() |
53 | } | ||
54 | |||
55 | pub fn module(&self, db: &impl DefDatabase) -> Module { | ||
56 | self.id.module(db).into() | ||
57 | } | ||
58 | |||
59 | pub fn krate(&self, db: &impl DefDatabase) -> Crate { | ||
60 | Crate { crate_id: self.module(db).id.krate } | ||
103 | } | 61 | } |
104 | 62 | ||
105 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { | 63 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { |
106 | let r = self.module().resolver(db); | 64 | let r = self.module(db).resolver(db); |
107 | // add generic params, if present | 65 | // add generic params, if present |
108 | let p = self.generic_params(db); | 66 | let p = self.generic_params(db); |
109 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | 67 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; |
@@ -111,175 +69,3 @@ impl ImplBlock { | |||
111 | r | 69 | r |
112 | } | 70 | } |
113 | } | 71 | } |
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
116 | pub struct ImplData { | ||
117 | target_trait: Option<TypeRef>, | ||
118 | target_type: TypeRef, | ||
119 | items: Vec<AssocItem>, | ||
120 | negative: bool, | ||
121 | } | ||
122 | |||
123 | impl ImplData { | ||
124 | pub(crate) fn from_ast( | ||
125 | db: &(impl DefDatabase + AstDatabase), | ||
126 | file_id: HirFileId, | ||
127 | module: Module, | ||
128 | node: &ast::ImplBlock, | ||
129 | ) -> Self { | ||
130 | let target_trait = node.target_trait().map(TypeRef::from_ast); | ||
131 | let target_type = TypeRef::from_ast_opt(node.target_type()); | ||
132 | let ctx = LocationCtx::new(db, module.id, file_id); | ||
133 | let negative = node.is_negative(); | ||
134 | let items = if let Some(item_list) = node.item_list() { | ||
135 | item_list | ||
136 | .impl_items() | ||
137 | .map(|item_node| match item_node { | ||
138 | ast::ImplItem::FnDef(it) => Function { id: ctx.to_def(&it) }.into(), | ||
139 | ast::ImplItem::ConstDef(it) => Const { id: ctx.to_def(&it) }.into(), | ||
140 | ast::ImplItem::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(&it) }.into(), | ||
141 | }) | ||
142 | .collect() | ||
143 | } else { | ||
144 | Vec::new() | ||
145 | }; | ||
146 | ImplData { target_trait, target_type, items, negative } | ||
147 | } | ||
148 | |||
149 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
150 | self.target_trait.as_ref() | ||
151 | } | ||
152 | |||
153 | pub fn target_type(&self) -> &TypeRef { | ||
154 | &self.target_type | ||
155 | } | ||
156 | |||
157 | pub fn items(&self) -> &[AssocItem] { | ||
158 | &self.items | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
163 | pub struct ImplId(pub RawId); | ||
164 | impl_arena_id!(ImplId); | ||
165 | |||
166 | /// The collection of impl blocks is a two-step process: first we collect the | ||
167 | /// blocks per-module; then we build an index of all impl blocks in the crate. | ||
168 | /// This way, we avoid having to do this process for the whole crate whenever | ||
169 | /// a file is changed; as long as the impl blocks in the file don't change, | ||
170 | /// we don't need to do the second step again. | ||
171 | #[derive(Debug, PartialEq, Eq)] | ||
172 | pub struct ModuleImplBlocks { | ||
173 | pub(crate) module: Module, | ||
174 | pub(crate) impls: Arena<ImplId, ImplData>, | ||
175 | impls_by_def: FxHashMap<AssocItem, ImplId>, | ||
176 | } | ||
177 | |||
178 | impl ModuleImplBlocks { | ||
179 | pub(crate) fn impls_in_module_with_source_map_query( | ||
180 | db: &(impl DefDatabase + AstDatabase), | ||
181 | module: Module, | ||
182 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | ||
183 | let mut source_map = ImplSourceMap::default(); | ||
184 | let crate_graph = db.crate_graph(); | ||
185 | let cfg_options = crate_graph.cfg_options(module.id.krate); | ||
186 | |||
187 | let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); | ||
188 | (Arc::new(result), Arc::new(source_map)) | ||
189 | } | ||
190 | |||
191 | pub(crate) fn impls_in_module_query( | ||
192 | db: &impl DefDatabase, | ||
193 | module: Module, | ||
194 | ) -> Arc<ModuleImplBlocks> { | ||
195 | db.impls_in_module_with_source_map(module).0 | ||
196 | } | ||
197 | |||
198 | fn collect( | ||
199 | db: &(impl DefDatabase + AstDatabase), | ||
200 | cfg_options: &CfgOptions, | ||
201 | module: Module, | ||
202 | source_map: &mut ImplSourceMap, | ||
203 | ) -> Self { | ||
204 | let mut m = ModuleImplBlocks { | ||
205 | module, | ||
206 | impls: Arena::default(), | ||
207 | impls_by_def: FxHashMap::default(), | ||
208 | }; | ||
209 | |||
210 | let src = m.module.definition_source(db); | ||
211 | match &src.ast { | ||
212 | ModuleSource::SourceFile(node) => { | ||
213 | m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id) | ||
214 | } | ||
215 | ModuleSource::Module(node) => { | ||
216 | let item_list = node.item_list().expect("inline module should have item list"); | ||
217 | m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id) | ||
218 | } | ||
219 | }; | ||
220 | m | ||
221 | } | ||
222 | |||
223 | fn collect_from_item_owner( | ||
224 | &mut self, | ||
225 | db: &(impl DefDatabase + AstDatabase), | ||
226 | cfg_options: &CfgOptions, | ||
227 | source_map: &mut ImplSourceMap, | ||
228 | owner: &dyn ast::ModuleItemOwner, | ||
229 | file_id: HirFileId, | ||
230 | ) { | ||
231 | let hygiene = Hygiene::new(db, file_id); | ||
232 | for item in owner.items_with_macros() { | ||
233 | match item { | ||
234 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | ||
235 | let attrs = Attr::from_attrs_owner(&impl_block_ast, &hygiene); | ||
236 | if attrs.map_or(false, |attrs| { | ||
237 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
238 | }) { | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | ||
243 | let id = self.impls.alloc(impl_block); | ||
244 | for &impl_item in &self.impls[id].items { | ||
245 | self.impls_by_def.insert(impl_item, id); | ||
246 | } | ||
247 | |||
248 | source_map.insert(id, file_id, &impl_block_ast); | ||
249 | } | ||
250 | ast::ItemOrMacro::Item(_) => (), | ||
251 | ast::ItemOrMacro::Macro(macro_call) => { | ||
252 | let attrs = Attr::from_attrs_owner(¯o_call, &hygiene); | ||
253 | if attrs.map_or(false, |attrs| { | ||
254 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
255 | }) { | ||
256 | continue; | ||
257 | } | ||
258 | |||
259 | //FIXME: we should really cut down on the boilerplate required to process a macro | ||
260 | let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_call)); | ||
261 | if let Some(path) = | ||
262 | macro_call.path().and_then(|path| Path::from_src(path, &hygiene)) | ||
263 | { | ||
264 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | ||
265 | { | ||
266 | let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id }); | ||
267 | let file_id = call_id.as_file(MacroFileKind::Items); | ||
268 | if let Some(item_list) = | ||
269 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | ||
270 | { | ||
271 | self.collect_from_item_owner( | ||
272 | db, | ||
273 | cfg_options, | ||
274 | source_map, | ||
275 | &item_list, | ||
276 | file_id, | ||
277 | ) | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index e1780ed38..fa2ef8a17 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -25,7 +25,7 @@ impl LangItemTarget { | |||
25 | Some(match self { | 25 | Some(match self { |
26 | LangItemTarget::Enum(e) => e.module(db).krate(), | 26 | LangItemTarget::Enum(e) => e.module(db).krate(), |
27 | LangItemTarget::Function(f) => f.module(db).krate(), | 27 | LangItemTarget::Function(f) => f.module(db).krate(), |
28 | LangItemTarget::ImplBlock(i) => i.module().krate(), | 28 | LangItemTarget::ImplBlock(i) => i.krate(db), |
29 | LangItemTarget::Static(s) => s.module(db).krate(), | 29 | LangItemTarget::Static(s) => s.module(db).krate(), |
30 | LangItemTarget::Struct(s) => s.module(db).krate(), | 30 | LangItemTarget::Struct(s) => s.module(db).krate(), |
31 | LangItemTarget::Trait(t) => t.module(db).krate(), | 31 | LangItemTarget::Trait(t) => t.module(db).krate(), |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5ba847d35..da33c9591 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -54,12 +54,11 @@ mod test_db; | |||
54 | #[cfg(test)] | 54 | #[cfg(test)] |
55 | mod marks; | 55 | mod marks; |
56 | 56 | ||
57 | use hir_expand::AstId; | 57 | use crate::resolve::Resolver; |
58 | |||
59 | use crate::{ids::MacroFileKind, resolve::Resolver}; | ||
60 | 58 | ||
61 | pub use crate::{ | 59 | pub use crate::{ |
62 | adt::VariantDef, | 60 | adt::VariantDef, |
61 | code_model::ImplBlock, | ||
63 | code_model::{ | 62 | code_model::{ |
64 | attrs::{AttrDef, Attrs}, | 63 | attrs::{AttrDef, Attrs}, |
65 | docs::{DocDef, Docs, Documentation}, | 64 | docs::{DocDef, Docs, Documentation}, |
@@ -72,7 +71,6 @@ pub use crate::{ | |||
72 | from_source::FromSource, | 71 | from_source::FromSource, |
73 | generics::GenericDef, | 72 | generics::GenericDef, |
74 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, | 73 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, |
75 | impl_block::ImplBlock, | ||
76 | resolve::ScopeDef, | 74 | resolve::ScopeDef, |
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 75 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | ty::{ | 76 | ty::{ |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2fb913108..79b92180a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,9 +15,8 @@ use crate::{ | |||
15 | db::{DefDatabase, HirDatabase}, | 15 | db::{DefDatabase, HirDatabase}, |
16 | expr::{ExprScopes, PatId, ScopeId}, | 16 | expr::{ExprScopes, PatId, ScopeId}, |
17 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | impl_block::ImplBlock, | 18 | Adt, Const, DefWithBody, Enum, EnumVariant, Function, ImplBlock, Local, MacroDef, ModuleDef, |
19 | Adt, Const, DefWithBody, Enum, EnumVariant, Function, Local, MacroDef, ModuleDef, PerNs, | 19 | PerNs, Static, Struct, Trait, TypeAlias, |
20 | Static, Struct, Trait, TypeAlias, | ||
21 | }; | 20 | }; |
22 | 21 | ||
23 | #[derive(Debug, Clone, Default)] | 22 | #[derive(Debug, Clone, Default)] |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 662d3f880..5764dc26d 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -12,7 +12,6 @@ use hir_def::{ | |||
12 | path::known, | 12 | path::known, |
13 | }; | 13 | }; |
14 | use hir_expand::{name::AsName, Source}; | 14 | use hir_expand::{name::AsName, Source}; |
15 | use ra_db::FileId; | ||
16 | use ra_syntax::{ | 15 | use ra_syntax::{ |
17 | ast::{self, AstNode}, | 16 | ast::{self, AstNode}, |
18 | match_ast, AstPtr, | 17 | match_ast, AstPtr, |
@@ -30,52 +29,45 @@ use crate::{ | |||
30 | HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, | 29 | HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, |
31 | }; | 30 | }; |
32 | 31 | ||
33 | fn try_get_resolver_for_node( | 32 | fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { |
34 | db: &impl HirDatabase, | ||
35 | file_id: FileId, | ||
36 | node: &SyntaxNode, | ||
37 | ) -> Option<Resolver> { | ||
38 | match_ast! { | 33 | match_ast! { |
39 | match node { | 34 | match (node.ast) { |
40 | ast::Module(it) => { | 35 | ast::Module(it) => { |
41 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 36 | let src = node.with_ast(it); |
42 | Some(crate::Module::from_declaration(db, src)?.resolver(db)) | 37 | Some(crate::Module::from_declaration(db, src)?.resolver(db)) |
43 | }, | 38 | }, |
44 | ast::SourceFile(it) => { | 39 | ast::SourceFile(it) => { |
45 | let src = | 40 | let src = node.with_ast(crate::ModuleSource::SourceFile(it)); |
46 | crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(it) }; | ||
47 | Some(crate::Module::from_definition(db, src)?.resolver(db)) | 41 | Some(crate::Module::from_definition(db, src)?.resolver(db)) |
48 | }, | 42 | }, |
49 | ast::StructDef(it) => { | 43 | ast::StructDef(it) => { |
50 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 44 | let src = node.with_ast(it); |
51 | Some(Struct::from_source(db, src)?.resolver(db)) | 45 | Some(Struct::from_source(db, src)?.resolver(db)) |
52 | }, | 46 | }, |
53 | ast::EnumDef(it) => { | 47 | ast::EnumDef(it) => { |
54 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 48 | let src = node.with_ast(it); |
55 | Some(Enum::from_source(db, src)?.resolver(db)) | 49 | Some(Enum::from_source(db, src)?.resolver(db)) |
56 | }, | 50 | }, |
57 | _ => { | 51 | _ => match node.ast.kind() { |
58 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { | 52 | FN_DEF | CONST_DEF | STATIC_DEF => { |
59 | Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) | 53 | Some(def_with_body_from_child_node(db, node)?.resolver(db)) |
60 | } else { | ||
61 | // FIXME add missing cases | ||
62 | None | ||
63 | } | 54 | } |
64 | }, | 55 | // FIXME add missing cases |
56 | _ => None | ||
57 | } | ||
65 | } | 58 | } |
66 | } | 59 | } |
67 | } | 60 | } |
68 | 61 | ||
69 | fn def_with_body_from_child_node( | 62 | fn def_with_body_from_child_node( |
70 | db: &impl HirDatabase, | 63 | db: &impl HirDatabase, |
71 | file_id: FileId, | 64 | child: Source<&SyntaxNode>, |
72 | node: &SyntaxNode, | ||
73 | ) -> Option<DefWithBody> { | 65 | ) -> Option<DefWithBody> { |
74 | let src = crate::ModuleSource::from_child_node(db, file_id, node); | 66 | let module_source = crate::ModuleSource::from_child_node(db, child); |
75 | let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?; | 67 | let module = Module::from_definition(db, Source::new(child.file_id, module_source))?; |
76 | let ctx = LocationCtx::new(db, module.id, file_id.into()); | 68 | let ctx = LocationCtx::new(db, module.id, child.file_id); |
77 | 69 | ||
78 | node.ancestors().find_map(|node| { | 70 | child.ast.ancestors().find_map(|node| { |
79 | match_ast! { | 71 | match_ast! { |
80 | match node { | 72 | match node { |
81 | ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, | 73 | ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, |
@@ -91,8 +83,7 @@ fn def_with_body_from_child_node( | |||
91 | /// original source files. It should not be used inside the HIR itself. | 83 | /// original source files. It should not be used inside the HIR itself. |
92 | #[derive(Debug)] | 84 | #[derive(Debug)] |
93 | pub struct SourceAnalyzer { | 85 | pub struct SourceAnalyzer { |
94 | // FIXME: this doesn't handle macros at all | 86 | file_id: HirFileId, |
95 | file_id: FileId, | ||
96 | resolver: Resolver, | 87 | resolver: Resolver, |
97 | body_owner: Option<DefWithBody>, | 88 | body_owner: Option<DefWithBody>, |
98 | body_source_map: Option<Arc<BodySourceMap>>, | 89 | body_source_map: Option<Arc<BodySourceMap>>, |
@@ -138,17 +129,16 @@ pub struct ReferenceDescriptor { | |||
138 | impl SourceAnalyzer { | 129 | impl SourceAnalyzer { |
139 | pub fn new( | 130 | pub fn new( |
140 | db: &impl HirDatabase, | 131 | db: &impl HirDatabase, |
141 | file_id: FileId, | 132 | node: Source<&SyntaxNode>, |
142 | node: &SyntaxNode, | ||
143 | offset: Option<TextUnit>, | 133 | offset: Option<TextUnit>, |
144 | ) -> SourceAnalyzer { | 134 | ) -> SourceAnalyzer { |
145 | let def_with_body = def_with_body_from_child_node(db, file_id, node); | 135 | let def_with_body = def_with_body_from_child_node(db, node); |
146 | if let Some(def) = def_with_body { | 136 | if let Some(def) = def_with_body { |
147 | let source_map = def.body_source_map(db); | 137 | let source_map = def.body_source_map(db); |
148 | let scopes = def.expr_scopes(db); | 138 | let scopes = def.expr_scopes(db); |
149 | let scope = match offset { | 139 | let scope = match offset { |
150 | None => scope_for(&scopes, &source_map, file_id.into(), &node), | 140 | None => scope_for(&scopes, &source_map, node), |
151 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), | 141 | Some(offset) => scope_for_offset(&scopes, &source_map, node.with_ast(offset)), |
152 | }; | 142 | }; |
153 | let resolver = expr::resolver_for_scope(db, def, scope); | 143 | let resolver = expr::resolver_for_scope(db, def, scope); |
154 | SourceAnalyzer { | 144 | SourceAnalyzer { |
@@ -157,30 +147,31 @@ impl SourceAnalyzer { | |||
157 | body_source_map: Some(source_map), | 147 | body_source_map: Some(source_map), |
158 | infer: Some(def.infer(db)), | 148 | infer: Some(def.infer(db)), |
159 | scopes: Some(scopes), | 149 | scopes: Some(scopes), |
160 | file_id, | 150 | file_id: node.file_id, |
161 | } | 151 | } |
162 | } else { | 152 | } else { |
163 | SourceAnalyzer { | 153 | SourceAnalyzer { |
164 | resolver: node | 154 | resolver: node |
155 | .ast | ||
165 | .ancestors() | 156 | .ancestors() |
166 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) | 157 | .find_map(|it| try_get_resolver_for_node(db, node.with_ast(&it))) |
167 | .unwrap_or_default(), | 158 | .unwrap_or_default(), |
168 | body_owner: None, | 159 | body_owner: None, |
169 | body_source_map: None, | 160 | body_source_map: None, |
170 | infer: None, | 161 | infer: None, |
171 | scopes: None, | 162 | scopes: None, |
172 | file_id, | 163 | file_id: node.file_id, |
173 | } | 164 | } |
174 | } | 165 | } |
175 | } | 166 | } |
176 | 167 | ||
177 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { | 168 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { |
178 | let src = Source { file_id: self.file_id.into(), ast: expr }; | 169 | let src = Source { file_id: self.file_id, ast: expr }; |
179 | self.body_source_map.as_ref()?.node_expr(src) | 170 | self.body_source_map.as_ref()?.node_expr(src) |
180 | } | 171 | } |
181 | 172 | ||
182 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { | 173 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { |
183 | let src = Source { file_id: self.file_id.into(), ast: pat }; | 174 | let src = Source { file_id: self.file_id, ast: pat }; |
184 | self.body_source_map.as_ref()?.node_pat(src) | 175 | self.body_source_map.as_ref()?.node_pat(src) |
185 | } | 176 | } |
186 | 177 | ||
@@ -288,7 +279,7 @@ impl SourceAnalyzer { | |||
288 | let name = name_ref.as_name(); | 279 | let name = name_ref.as_name(); |
289 | let source_map = self.body_source_map.as_ref()?; | 280 | let source_map = self.body_source_map.as_ref()?; |
290 | let scopes = self.scopes.as_ref()?; | 281 | let scopes = self.scopes.as_ref()?; |
291 | let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; | 282 | let scope = scope_for(scopes, source_map, Source::new(self.file_id, name_ref.syntax()))?; |
292 | let entry = scopes.resolve_name_in_scope(scope, &name)?; | 283 | let entry = scopes.resolve_name_in_scope(scope, &name)?; |
293 | Some(ScopeEntryWithSyntax { | 284 | Some(ScopeEntryWithSyntax { |
294 | name: entry.name().clone(), | 285 | name: entry.name().clone(), |
@@ -409,20 +400,19 @@ impl SourceAnalyzer { | |||
409 | fn scope_for( | 400 | fn scope_for( |
410 | scopes: &ExprScopes, | 401 | scopes: &ExprScopes, |
411 | source_map: &BodySourceMap, | 402 | source_map: &BodySourceMap, |
412 | file_id: HirFileId, | 403 | node: Source<&SyntaxNode>, |
413 | node: &SyntaxNode, | ||
414 | ) -> Option<ScopeId> { | 404 | ) -> Option<ScopeId> { |
415 | node.ancestors() | 405 | node.ast |
406 | .ancestors() | ||
416 | .filter_map(ast::Expr::cast) | 407 | .filter_map(ast::Expr::cast) |
417 | .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) | 408 | .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it))) |
418 | .find_map(|it| scopes.scope_for(it)) | 409 | .find_map(|it| scopes.scope_for(it)) |
419 | } | 410 | } |
420 | 411 | ||
421 | fn scope_for_offset( | 412 | fn scope_for_offset( |
422 | scopes: &ExprScopes, | 413 | scopes: &ExprScopes, |
423 | source_map: &BodySourceMap, | 414 | source_map: &BodySourceMap, |
424 | file_id: HirFileId, | 415 | offset: Source<TextUnit>, |
425 | offset: TextUnit, | ||
426 | ) -> Option<ScopeId> { | 416 | ) -> Option<ScopeId> { |
427 | scopes | 417 | scopes |
428 | .scope_by_expr() | 418 | .scope_by_expr() |
@@ -430,7 +420,7 @@ fn scope_for_offset( | |||
430 | .filter_map(|(id, scope)| { | 420 | .filter_map(|(id, scope)| { |
431 | let source = source_map.expr_syntax(*id)?; | 421 | let source = source_map.expr_syntax(*id)?; |
432 | // FIXME: correctly handle macro expansion | 422 | // FIXME: correctly handle macro expansion |
433 | if source.file_id != file_id { | 423 | if source.file_id != offset.file_id { |
434 | return None; | 424 | return None; |
435 | } | 425 | } |
436 | let syntax_node_ptr = | 426 | let syntax_node_ptr = |
@@ -439,9 +429,14 @@ fn scope_for_offset( | |||
439 | }) | 429 | }) |
440 | // find containing scope | 430 | // find containing scope |
441 | .min_by_key(|(ptr, _scope)| { | 431 | .min_by_key(|(ptr, _scope)| { |
442 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | 432 | ( |
433 | !(ptr.range().start() <= offset.ast && offset.ast <= ptr.range().end()), | ||
434 | ptr.range().len(), | ||
435 | ) | ||
436 | }) | ||
437 | .map(|(ptr, scope)| { | ||
438 | adjust(scopes, source_map, ptr, offset.file_id, offset.ast).unwrap_or(*scope) | ||
443 | }) | 439 | }) |
444 | .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope)) | ||
445 | } | 440 | } |
446 | 441 | ||
447 | // XXX: during completion, cursor might be outside of any particular | 442 | // XXX: during completion, cursor might be outside of any particular |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index eb5ca6769..9aad2d3fe 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -5,16 +5,14 @@ | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::CrateModuleId; | ||
9 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
10 | 9 | ||
11 | use crate::{ | 10 | use crate::{ |
12 | db::HirDatabase, | 11 | db::HirDatabase, |
13 | impl_block::{ImplBlock, ImplId}, | ||
14 | resolve::Resolver, | 12 | resolve::Resolver, |
15 | ty::primitive::{FloatBitness, Uncertain}, | 13 | ty::primitive::{FloatBitness, Uncertain}, |
16 | ty::{Ty, TypeCtor}, | 14 | ty::{Ty, TypeCtor}, |
17 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, | 15 | AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, |
18 | }; | 16 | }; |
19 | 17 | ||
20 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 18 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
@@ -39,65 +37,46 @@ impl TyFingerprint { | |||
39 | 37 | ||
40 | #[derive(Debug, PartialEq, Eq)] | 38 | #[derive(Debug, PartialEq, Eq)] |
41 | pub struct CrateImplBlocks { | 39 | pub struct CrateImplBlocks { |
42 | /// To make sense of the CrateModuleIds, we need the source root. | 40 | impls: FxHashMap<TyFingerprint, Vec<ImplBlock>>, |
43 | krate: Crate, | 41 | impls_by_trait: FxHashMap<Trait, Vec<ImplBlock>>, |
44 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, | ||
45 | impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>, | ||
46 | } | 42 | } |
47 | 43 | ||
48 | impl CrateImplBlocks { | 44 | impl CrateImplBlocks { |
49 | pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a { | 45 | pub(crate) fn impls_in_crate_query( |
46 | db: &impl HirDatabase, | ||
47 | krate: Crate, | ||
48 | ) -> Arc<CrateImplBlocks> { | ||
49 | let mut crate_impl_blocks = | ||
50 | CrateImplBlocks { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | ||
51 | if let Some(module) = krate.root_module(db) { | ||
52 | crate_impl_blocks.collect_recursive(db, module); | ||
53 | } | ||
54 | Arc::new(crate_impl_blocks) | ||
55 | } | ||
56 | pub fn lookup_impl_blocks(&self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + '_ { | ||
50 | let fingerprint = TyFingerprint::for_impl(ty); | 57 | let fingerprint = TyFingerprint::for_impl(ty); |
51 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map( | 58 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() |
52 | move |(module_id, impl_id)| { | ||
53 | let module = Module::new(self.krate, *module_id); | ||
54 | ImplBlock::from_id(module, *impl_id) | ||
55 | }, | ||
56 | ) | ||
57 | } | 59 | } |
58 | 60 | ||
59 | pub fn lookup_impl_blocks_for_trait<'a>( | 61 | pub fn lookup_impl_blocks_for_trait(&self, tr: Trait) -> impl Iterator<Item = ImplBlock> + '_ { |
60 | &'a self, | 62 | self.impls_by_trait.get(&tr).into_iter().flatten().copied() |
61 | tr: Trait, | ||
62 | ) -> impl Iterator<Item = ImplBlock> + 'a { | ||
63 | self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( | ||
64 | move |(module_id, impl_id)| { | ||
65 | let module = Module::new(self.krate, *module_id); | ||
66 | ImplBlock::from_id(module, *impl_id) | ||
67 | }, | ||
68 | ) | ||
69 | } | 63 | } |
70 | 64 | ||
71 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { | 65 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { |
72 | self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map( | 66 | self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() |
73 | move |(module_id, impl_id)| { | ||
74 | let module = Module::new(self.krate, *module_id); | ||
75 | ImplBlock::from_id(module, *impl_id) | ||
76 | }, | ||
77 | ) | ||
78 | } | 67 | } |
79 | 68 | ||
80 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { | 69 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { |
81 | let module_impl_blocks = db.impls_in_module(module); | 70 | for impl_block in module.impl_blocks(db) { |
82 | |||
83 | for (impl_id, _) in module_impl_blocks.impls.iter() { | ||
84 | let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id); | ||
85 | |||
86 | let target_ty = impl_block.target_ty(db); | 71 | let target_ty = impl_block.target_ty(db); |
87 | 72 | ||
88 | if impl_block.target_trait(db).is_some() { | 73 | if impl_block.target_trait(db).is_some() { |
89 | if let Some(tr) = impl_block.target_trait_ref(db) { | 74 | if let Some(tr) = impl_block.target_trait_ref(db) { |
90 | self.impls_by_trait | 75 | self.impls_by_trait.entry(tr.trait_).or_default().push(impl_block); |
91 | .entry(tr.trait_) | ||
92 | .or_insert_with(Vec::new) | ||
93 | .push((module.id.module_id, impl_id)); | ||
94 | } | 76 | } |
95 | } else { | 77 | } else { |
96 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 78 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
97 | self.impls | 79 | self.impls.entry(target_ty_fp).or_default().push(impl_block); |
98 | .entry(target_ty_fp) | ||
99 | .or_insert_with(Vec::new) | ||
100 | .push((module.id.module_id, impl_id)); | ||
101 | } | 80 | } |
102 | } | 81 | } |
103 | } | 82 | } |
@@ -106,21 +85,6 @@ impl CrateImplBlocks { | |||
106 | self.collect_recursive(db, child); | 85 | self.collect_recursive(db, child); |
107 | } | 86 | } |
108 | } | 87 | } |
109 | |||
110 | pub(crate) fn impls_in_crate_query( | ||
111 | db: &impl HirDatabase, | ||
112 | krate: Crate, | ||
113 | ) -> Arc<CrateImplBlocks> { | ||
114 | let mut crate_impl_blocks = CrateImplBlocks { | ||
115 | krate, | ||
116 | impls: FxHashMap::default(), | ||
117 | impls_by_trait: FxHashMap::default(), | ||
118 | }; | ||
119 | if let Some(module) = krate.root_module(db) { | ||
120 | crate_impl_blocks.collect_recursive(db, module); | ||
121 | } | ||
122 | Arc::new(crate_impl_blocks) | ||
123 | } | ||
124 | } | 88 | } |
125 | 89 | ||
126 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { | 90 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fe9346c78..9a26e02fa 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | mod never_type; | ||
2 | mod coercion; | ||
3 | |||
1 | use std::fmt::Write; | 4 | use std::fmt::Write; |
2 | use std::sync::Arc; | 5 | use std::sync::Arc; |
3 | 6 | ||
@@ -11,7 +14,7 @@ use ra_syntax::{ | |||
11 | use test_utils::covers; | 14 | use test_utils::covers; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
14 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, | 17 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, Source, |
15 | SourceAnalyzer, | 18 | SourceAnalyzer, |
16 | }; | 19 | }; |
17 | 20 | ||
@@ -19,9 +22,6 @@ use crate::{ | |||
19 | // against snapshots of the expected results using insta. Use cargo-insta to | 22 | // against snapshots of the expected results using insta. Use cargo-insta to |
20 | // update the snapshots. | 23 | // update the snapshots. |
21 | 24 | ||
22 | mod never_type; | ||
23 | mod coercion; | ||
24 | |||
25 | #[test] | 25 | #[test] |
26 | fn cfg_impl_block() { | 26 | fn cfg_impl_block() { |
27 | let (db, pos) = TestDB::with_position( | 27 | let (db, pos) = TestDB::with_position( |
@@ -4609,7 +4609,8 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
4609 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 4609 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { |
4610 | let file = db.parse(pos.file_id).ok().unwrap(); | 4610 | let file = db.parse(pos.file_id).ok().unwrap(); |
4611 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 4611 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
4612 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); | 4612 | let analyzer = |
4613 | SourceAnalyzer::new(db, Source::new(pos.file_id.into(), expr.syntax()), Some(pos.offset)); | ||
4613 | let ty = analyzer.type_of(db, &expr).unwrap(); | 4614 | let ty = analyzer.type_of(db, &expr).unwrap(); |
4614 | ty.display(db).to_string() | 4615 | ty.display(db).to_string() |
4615 | } | 4616 | } |
@@ -4674,7 +4675,7 @@ fn infer(content: &str) -> String { | |||
4674 | 4675 | ||
4675 | for node in source_file.syntax().descendants() { | 4676 | for node in source_file.syntax().descendants() { |
4676 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { | 4677 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { |
4677 | let analyzer = SourceAnalyzer::new(&db, file_id, &node, None); | 4678 | let analyzer = SourceAnalyzer::new(&db, Source::new(file_id.into(), &node), None); |
4678 | infer_def(analyzer.inference_result(), analyzer.body_source_map()); | 4679 | infer_def(analyzer.inference_result(), analyzer.body_source_map()); |
4679 | } | 4680 | } |
4680 | } | 4681 | } |
@@ -4715,7 +4716,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
4715 | let file = db.parse(pos.file_id).ok().unwrap(); | 4716 | let file = db.parse(pos.file_id).ok().unwrap(); |
4716 | let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); | 4717 | let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); |
4717 | let events = db.log_executed(|| { | 4718 | let events = db.log_executed(|| { |
4718 | SourceAnalyzer::new(&db, pos.file_id, &node, None); | 4719 | SourceAnalyzer::new(&db, Source::new(pos.file_id.into(), &node), None); |
4719 | }); | 4720 | }); |
4720 | assert!(format!("{:?}", events).contains("infer")) | 4721 | assert!(format!("{:?}", events).contains("infer")) |
4721 | } | 4722 | } |
@@ -4735,7 +4736,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
4735 | let file = db.parse(pos.file_id).ok().unwrap(); | 4736 | let file = db.parse(pos.file_id).ok().unwrap(); |
4736 | let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); | 4737 | let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); |
4737 | let events = db.log_executed(|| { | 4738 | let events = db.log_executed(|| { |
4738 | SourceAnalyzer::new(&db, pos.file_id, &node, None); | 4739 | SourceAnalyzer::new(&db, Source::new(pos.file_id.into(), &node), None); |
4739 | }); | 4740 | }); |
4740 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | 4741 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) |
4741 | } | 4742 | } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 75351c17d..68304b950 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -191,11 +191,11 @@ impl ToChalk for Impl { | |||
191 | type Chalk = chalk_ir::ImplId; | 191 | type Chalk = chalk_ir::ImplId; |
192 | 192 | ||
193 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { | 193 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { |
194 | db.intern_impl(self).into() | 194 | db.intern_chalk_impl(self).into() |
195 | } | 195 | } |
196 | 196 | ||
197 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { | 197 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { |
198 | db.lookup_intern_impl(impl_id.into()) | 198 | db.lookup_intern_chalk_impl(impl_id.into()) |
199 | } | 199 | } |
200 | } | 200 | } |
201 | 201 | ||
@@ -630,7 +630,7 @@ fn impl_block_datum( | |||
630 | .target_trait_ref(db) | 630 | .target_trait_ref(db) |
631 | .expect("FIXME handle unresolved impl block trait ref") | 631 | .expect("FIXME handle unresolved impl block trait ref") |
632 | .subst(&bound_vars); | 632 | .subst(&bound_vars); |
633 | let impl_type = if impl_block.module().krate() == krate { | 633 | let impl_type = if impl_block.krate(db) == krate { |
634 | chalk_rust_ir::ImplType::Local | 634 | chalk_rust_ir::ImplType::Local |
635 | } else { | 635 | } else { |
636 | chalk_rust_ir::ImplType::External | 636 | chalk_rust_ir::ImplType::External |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 40b5920d9..348aca07f 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -8,30 +8,32 @@ use ra_syntax::ast; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | adt::{EnumData, StructData}, | 9 | adt::{EnumData, StructData}, |
10 | body::{scope::ExprScopes, Body, BodySourceMap}, | 10 | body::{scope::ExprScopes, Body, BodySourceMap}, |
11 | imp::ImplData, | ||
11 | nameres::{ | 12 | nameres::{ |
12 | raw::{ImportSourceMap, RawItems}, | 13 | raw::{ImportSourceMap, RawItems}, |
13 | CrateDefMap, | 14 | CrateDefMap, |
14 | }, | 15 | }, |
15 | DefWithBodyId, EnumId, StructOrUnionId, | 16 | DefWithBodyId, EnumId, ImplId, ItemLoc, StructOrUnionId, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[salsa::query_group(InternDatabaseStorage)] | 19 | #[salsa::query_group(InternDatabaseStorage)] |
19 | pub trait InternDatabase: SourceDatabase { | 20 | pub trait InternDatabase: SourceDatabase { |
20 | #[salsa::interned] | 21 | #[salsa::interned] |
21 | fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; | 22 | fn intern_function(&self, loc: ItemLoc<ast::FnDef>) -> crate::FunctionId; |
22 | #[salsa::interned] | 23 | #[salsa::interned] |
23 | fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>) | 24 | fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId; |
24 | -> crate::StructOrUnionId; | ||
25 | #[salsa::interned] | 25 | #[salsa::interned] |
26 | fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; | 26 | fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId; |
27 | #[salsa::interned] | 27 | #[salsa::interned] |
28 | fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; | 28 | fn intern_const(&self, loc: ItemLoc<ast::ConstDef>) -> crate::ConstId; |
29 | #[salsa::interned] | 29 | #[salsa::interned] |
30 | fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId; | 30 | fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId; |
31 | #[salsa::interned] | 31 | #[salsa::interned] |
32 | fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId; | 32 | fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId; |
33 | #[salsa::interned] | 33 | #[salsa::interned] |
34 | fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; | 34 | fn intern_type_alias(&self, loc: ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; |
35 | #[salsa::interned] | ||
36 | fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId; | ||
35 | } | 37 | } |
36 | 38 | ||
37 | #[salsa::query_group(DefDatabase2Storage)] | 39 | #[salsa::query_group(DefDatabase2Storage)] |
@@ -54,6 +56,9 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { | |||
54 | #[salsa::invoke(EnumData::enum_data_query)] | 56 | #[salsa::invoke(EnumData::enum_data_query)] |
55 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | 57 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; |
56 | 58 | ||
59 | #[salsa::invoke(ImplData::impl_data_query)] | ||
60 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
61 | |||
57 | #[salsa::invoke(Body::body_with_source_map_query)] | 62 | #[salsa::invoke(Body::body_with_source_map_query)] |
58 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | 63 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); |
59 | 64 | ||
diff --git a/crates/ra_hir_def/src/imp.rs b/crates/ra_hir_def/src/imp.rs new file mode 100644 index 000000000..717991c40 --- /dev/null +++ b/crates/ra_hir_def/src/imp.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Defines hir-level representation of impls. | ||
2 | //! | ||
3 | //! The handling is similar, but is not quite the same as for other items, | ||
4 | //! because `impl`s don't have names. | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use ra_syntax::ast; | ||
9 | |||
10 | use crate::{ | ||
11 | db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId, | ||
12 | LocationCtx, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub struct ImplData { | ||
17 | target_trait: Option<TypeRef>, | ||
18 | target_type: TypeRef, | ||
19 | items: Vec<AssocItemId>, | ||
20 | negative: bool, | ||
21 | } | ||
22 | |||
23 | impl ImplData { | ||
24 | pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> { | ||
25 | let src = id.source(db); | ||
26 | let items = db.ast_id_map(src.file_id); | ||
27 | |||
28 | let target_trait = src.ast.target_trait().map(TypeRef::from_ast); | ||
29 | let target_type = TypeRef::from_ast_opt(src.ast.target_type()); | ||
30 | let negative = src.ast.is_negative(); | ||
31 | |||
32 | let items = if let Some(item_list) = src.ast.item_list() { | ||
33 | let ctx = LocationCtx::new(db, id.module(db), src.file_id); | ||
34 | item_list | ||
35 | .impl_items() | ||
36 | .map(|item_node| match item_node { | ||
37 | ast::ImplItem::FnDef(it) => { | ||
38 | FunctionId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
39 | } | ||
40 | ast::ImplItem::ConstDef(it) => { | ||
41 | ConstId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
42 | } | ||
43 | ast::ImplItem::TypeAliasDef(it) => { | ||
44 | TypeAliasId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
45 | } | ||
46 | }) | ||
47 | .collect() | ||
48 | } else { | ||
49 | Vec::new() | ||
50 | }; | ||
51 | |||
52 | let res = ImplData { target_trait, target_type, items, negative }; | ||
53 | Arc::new(res) | ||
54 | } | ||
55 | |||
56 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
57 | self.target_trait.as_ref() | ||
58 | } | ||
59 | |||
60 | pub fn target_type(&self) -> &TypeRef { | ||
61 | &self.target_type | ||
62 | } | ||
63 | |||
64 | pub fn items(&self) -> &[AssocItemId] { | ||
65 | &self.items | ||
66 | } | ||
67 | |||
68 | pub fn is_negative(&self) -> bool { | ||
69 | self.negative | ||
70 | } | ||
71 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 3fab7965c..a240a10b8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -13,6 +13,7 @@ pub mod path; | |||
13 | pub mod type_ref; | 13 | pub mod type_ref; |
14 | pub mod builtin_type; | 14 | pub mod builtin_type; |
15 | pub mod adt; | 15 | pub mod adt; |
16 | pub mod imp; | ||
16 | pub mod diagnostics; | 17 | pub mod diagnostics; |
17 | pub mod expr; | 18 | pub mod expr; |
18 | pub mod body; | 19 | pub mod body; |
@@ -77,14 +78,13 @@ impl ModuleSource { | |||
77 | } | 78 | } |
78 | } | 79 | } |
79 | 80 | ||
80 | pub fn from_child_node( | 81 | pub fn from_child_node(db: &impl db::DefDatabase2, child: Source<&SyntaxNode>) -> ModuleSource { |
81 | db: &impl db::DefDatabase2, | 82 | if let Some(m) = |
82 | file_id: FileId, | 83 | child.ast.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) |
83 | child: &SyntaxNode, | 84 | { |
84 | ) -> ModuleSource { | ||
85 | if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) { | ||
86 | ModuleSource::Module(m) | 85 | ModuleSource::Module(m) |
87 | } else { | 86 | } else { |
87 | let file_id = child.file_id.original_file(db); | ||
88 | let source_file = db.parse(file_id).tree(); | 88 | let source_file = db.parse(file_id).tree(); |
89 | ModuleSource::SourceFile(source_file) | 89 | ModuleSource::SourceFile(source_file) |
90 | } | 90 | } |
@@ -321,6 +321,18 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | |||
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
325 | pub struct ImplId(salsa::InternId); | ||
326 | impl_intern_key!(ImplId); | ||
327 | impl AstItemDef<ast::ImplBlock> for ImplId { | ||
328 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self { | ||
329 | db.intern_impl(loc) | ||
330 | } | ||
331 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> { | ||
332 | db.lookup_intern_impl(self) | ||
333 | } | ||
334 | } | ||
335 | |||
324 | macro_rules! impl_froms { | 336 | macro_rules! impl_froms { |
325 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 337 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
326 | $( | 338 | $( |
@@ -384,3 +396,15 @@ pub enum DefWithBodyId { | |||
384 | } | 396 | } |
385 | 397 | ||
386 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); | 398 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); |
399 | |||
400 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
401 | pub enum AssocItemId { | ||
402 | FunctionId(FunctionId), | ||
403 | ConstId(ConstId), | ||
404 | TypeAliasId(TypeAliasId), | ||
405 | } | ||
406 | // FIXME: not every function, ... is actually an assoc item. maybe we should make | ||
407 | // sure that you can only turn actual assoc items into AssocItemIds. This would | ||
408 | // require not implementing From, and instead having some checked way of | ||
409 | // casting them, and somehow making the constructors private, which would be annoying. | ||
410 | impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); | ||
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index dfcec6443..e5b073a0f 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -73,7 +73,7 @@ use crate::{ | |||
73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, | 73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, |
74 | }, | 74 | }, |
75 | path::Path, | 75 | path::Path, |
76 | AstId, CrateModuleId, FunctionId, ModuleDefId, ModuleId, TraitId, | 76 | AstId, CrateModuleId, FunctionId, ImplId, ModuleDefId, ModuleId, TraitId, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /// Contains all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
@@ -122,14 +122,15 @@ pub struct ModuleData { | |||
122 | /// | 122 | /// |
123 | /// Note that non-inline modules, by definition, live inside non-macro file. | 123 | /// Note that non-inline modules, by definition, live inside non-macro file. |
124 | pub definition: Option<FileId>, | 124 | pub definition: Option<FileId>, |
125 | pub impls: Vec<ImplId>, | ||
125 | } | 126 | } |
126 | 127 | ||
127 | #[derive(Default, Debug, PartialEq, Eq, Clone)] | 128 | #[derive(Default, Debug, PartialEq, Eq)] |
128 | pub(crate) struct Declarations { | 129 | pub(crate) struct Declarations { |
129 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, | 130 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, |
130 | } | 131 | } |
131 | 132 | ||
132 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 133 | #[derive(Debug, Default, PartialEq, Eq)] |
133 | pub struct ModuleScope { | 134 | pub struct ModuleScope { |
134 | items: FxHashMap<Name, Resolution>, | 135 | items: FxHashMap<Name, Resolution>, |
135 | /// Macros visable in current module in legacy textual scope | 136 | /// Macros visable in current module in legacy textual scope |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 5c899aff3..c9ccb9023 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, | 19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, |
20 | }, | 20 | }, |
21 | path::{Path, PathKind}, | 21 | path::{Path, PathKind}, |
22 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, | 22 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, ImplId, |
23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, | 23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, |
24 | UnionId, | 24 | UnionId, |
25 | }; | 25 | }; |
@@ -571,6 +571,15 @@ where | |||
571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), |
573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
574 | raw::RawItemKind::Impl(imp) => { | ||
575 | let module = ModuleId { | ||
576 | krate: self.def_collector.def_map.krate, | ||
577 | module_id: self.module_id, | ||
578 | }; | ||
579 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | ||
580 | let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); | ||
581 | self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) | ||
582 | } | ||
574 | } | 583 | } |
575 | } | 584 | } |
576 | } | 585 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f52002bc0..a0a2c7273 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -28,6 +28,7 @@ pub struct RawItems { | |||
28 | imports: Arena<ImportId, ImportData>, | 28 | imports: Arena<ImportId, ImportData>, |
29 | defs: Arena<Def, DefData>, | 29 | defs: Arena<Def, DefData>, |
30 | macros: Arena<Macro, MacroData>, | 30 | macros: Arena<Macro, MacroData>, |
31 | impls: Arena<Impl, ImplData>, | ||
31 | /// items for top-level module | 32 | /// items for top-level module |
32 | items: Vec<RawItem>, | 33 | items: Vec<RawItem>, |
33 | } | 34 | } |
@@ -121,6 +122,13 @@ impl Index<Macro> for RawItems { | |||
121 | } | 122 | } |
122 | } | 123 | } |
123 | 124 | ||
125 | impl Index<Impl> for RawItems { | ||
126 | type Output = ImplData; | ||
127 | fn index(&self, idx: Impl) -> &ImplData { | ||
128 | &self.impls[idx] | ||
129 | } | ||
130 | } | ||
131 | |||
124 | // Avoid heap allocation on items without attributes. | 132 | // Avoid heap allocation on items without attributes. |
125 | type Attrs = Option<Arc<[Attr]>>; | 133 | type Attrs = Option<Arc<[Attr]>>; |
126 | 134 | ||
@@ -142,6 +150,7 @@ pub(super) enum RawItemKind { | |||
142 | Import(ImportId), | 150 | Import(ImportId), |
143 | Def(Def), | 151 | Def(Def), |
144 | Macro(Macro), | 152 | Macro(Macro), |
153 | Impl(Impl), | ||
145 | } | 154 | } |
146 | 155 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -203,6 +212,15 @@ pub(super) struct MacroData { | |||
203 | pub(super) builtin: bool, | 212 | pub(super) builtin: bool, |
204 | } | 213 | } |
205 | 214 | ||
215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
216 | pub(super) struct Impl(RawId); | ||
217 | impl_arena_id!(Impl); | ||
218 | |||
219 | #[derive(Debug, PartialEq, Eq)] | ||
220 | pub(super) struct ImplData { | ||
221 | pub(super) ast_id: FileAstId<ast::ImplBlock>, | ||
222 | } | ||
223 | |||
206 | struct RawItemsCollector { | 224 | struct RawItemsCollector { |
207 | raw_items: RawItems, | 225 | raw_items: RawItems, |
208 | source_ast_id_map: Arc<AstIdMap>, | 226 | source_ast_id_map: Arc<AstIdMap>, |
@@ -236,8 +254,8 @@ impl RawItemsCollector { | |||
236 | self.add_extern_crate_item(current_module, extern_crate); | 254 | self.add_extern_crate_item(current_module, extern_crate); |
237 | return; | 255 | return; |
238 | } | 256 | } |
239 | ast::ModuleItem::ImplBlock(_) => { | 257 | ast::ModuleItem::ImplBlock(it) => { |
240 | // impls don't participate in name resolution | 258 | self.add_impl(current_module, it); |
241 | return; | 259 | return; |
242 | } | 260 | } |
243 | ast::ModuleItem::StructDef(it) => { | 261 | ast::ModuleItem::StructDef(it) => { |
@@ -376,6 +394,13 @@ impl RawItemsCollector { | |||
376 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | 394 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
377 | } | 395 | } |
378 | 396 | ||
397 | fn add_impl(&mut self, current_module: Option<Module>, imp: ast::ImplBlock) { | ||
398 | let attrs = self.parse_attrs(&imp); | ||
399 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
400 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
401 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
402 | } | ||
403 | |||
379 | fn push_import( | 404 | fn push_import( |
380 | &mut self, | 405 | &mut self, |
381 | current_module: Option<Module>, | 406 | current_module: Option<Module>, |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 930789b0f..26531cb05 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -223,18 +223,30 @@ impl<N: AstNode> AstId<N> { | |||
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | /// FIXME: https://github.com/matklad/with ? | ||
226 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] | 227 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
227 | pub struct Source<T> { | 228 | pub struct Source<T> { |
228 | pub file_id: HirFileId, | 229 | pub file_id: HirFileId, |
230 | // FIXME: this stores all kind of things, not only `ast`. | ||
231 | // There should be a better name... | ||
229 | pub ast: T, | 232 | pub ast: T, |
230 | } | 233 | } |
231 | 234 | ||
232 | impl<T> Source<T> { | 235 | impl<T> Source<T> { |
236 | pub fn new(file_id: HirFileId, ast: T) -> Source<T> { | ||
237 | Source { file_id, ast } | ||
238 | } | ||
239 | |||
240 | // Similarly, naming here is stupid... | ||
241 | pub fn with_ast<U>(&self, ast: U) -> Source<U> { | ||
242 | Source::new(self.file_id, ast) | ||
243 | } | ||
244 | |||
233 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | 245 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { |
234 | Source { file_id: self.file_id, ast: f(self.ast) } | 246 | Source::new(self.file_id, f(self.ast)) |
235 | } | 247 | } |
236 | pub fn as_ref(&self) -> Source<&T> { | 248 | pub fn as_ref(&self) -> Source<&T> { |
237 | Source { file_id: self.file_id, ast: &self.ast } | 249 | self.with_ast(&self.ast) |
238 | } | 250 | } |
239 | pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { | 251 | pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { |
240 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | 252 | db.parse_or_expand(self.file_id).expect("source created from invalid file") |
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 3572825b5..41ee81511 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs | |||
@@ -19,7 +19,11 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
19 | let calling_node = FnCallNode::with_node(&syntax, position.offset)?; | 19 | let calling_node = FnCallNode::with_node(&syntax, position.offset)?; |
20 | let name_ref = calling_node.name_ref()?; | 20 | let name_ref = calling_node.name_ref()?; |
21 | 21 | ||
22 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); | 22 | let analyzer = hir::SourceAnalyzer::new( |
23 | db, | ||
24 | hir::Source::new(position.file_id.into(), name_ref.syntax()), | ||
25 | None, | ||
26 | ); | ||
23 | let (mut call_info, has_self) = match &calling_node { | 27 | let (mut call_info, has_self) = match &calling_node { |
24 | FnCallNode::CallExpr(expr) => { | 28 | FnCallNode::CallExpr(expr) => { |
25 | //FIXME: apply subst | 29 | //FIXME: apply subst |
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 010b45141..5c9dec13e 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs | |||
@@ -271,7 +271,6 @@ impl RootDatabase { | |||
271 | self.query(hir::db::AstIdMapQuery).sweep(sweep); | 271 | self.query(hir::db::AstIdMapQuery).sweep(sweep); |
272 | 272 | ||
273 | self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); | 273 | self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); |
274 | self.query(hir::db::ImplsInModuleWithSourceMapQuery).sweep(sweep); | ||
275 | self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); | 274 | self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); |
276 | 275 | ||
277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); | 276 | self.query(hir::db::ExprScopesQuery).sweep(sweep); |
@@ -314,8 +313,6 @@ impl RootDatabase { | |||
314 | hir::db::RawItemsWithSourceMapQuery | 313 | hir::db::RawItemsWithSourceMapQuery |
315 | hir::db::RawItemsQuery | 314 | hir::db::RawItemsQuery |
316 | hir::db::CrateDefMapQuery | 315 | hir::db::CrateDefMapQuery |
317 | hir::db::ImplsInModuleWithSourceMapQuery | ||
318 | hir::db::ImplsInModuleQuery | ||
319 | hir::db::GenericParamsQuery | 316 | hir::db::GenericParamsQuery |
320 | hir::db::FnDataQuery | 317 | hir::db::FnDataQuery |
321 | hir::db::TypeAliasDataQuery | 318 | hir::db::TypeAliasDataQuery |
@@ -340,6 +337,7 @@ impl RootDatabase { | |||
340 | hir::db::TraitDatumQuery | 337 | hir::db::TraitDatumQuery |
341 | hir::db::StructDatumQuery | 338 | hir::db::StructDatumQuery |
342 | hir::db::ImplDatumQuery | 339 | hir::db::ImplDatumQuery |
340 | hir::db::ImplDataQuery | ||
343 | hir::db::TraitSolveQuery | 341 | hir::db::TraitSolveQuery |
344 | ]; | 342 | ]; |
345 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); | 343 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); |
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 64cbc0f98..0906a4e1b 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs | |||
@@ -58,8 +58,11 @@ impl<'a> CompletionContext<'a> { | |||
58 | ); | 58 | ); |
59 | let token = | 59 | let token = |
60 | original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; | 60 | original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; |
61 | let analyzer = | 61 | let analyzer = hir::SourceAnalyzer::new( |
62 | hir::SourceAnalyzer::new(db, position.file_id, &token.parent(), Some(position.offset)); | 62 | db, |
63 | hir::Source::new(position.file_id.into(), &token.parent()), | ||
64 | Some(position.offset), | ||
65 | ); | ||
63 | let mut ctx = CompletionContext { | 66 | let mut ctx = CompletionContext { |
64 | db, | 67 | db, |
65 | analyzer, | 68 | analyzer, |
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 71146591d..2327cb1e7 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs | |||
@@ -18,7 +18,8 @@ pub(crate) fn goto_type_definition( | |||
18 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some()) | 18 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some()) |
19 | })?; | 19 | })?; |
20 | 20 | ||
21 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, &node, None); | 21 | let analyzer = |
22 | hir::SourceAnalyzer::new(db, hir::Source::new(position.file_id.into(), &node), None); | ||
22 | 23 | ||
23 | let ty: hir::Ty = if let Some(ty) = | 24 | let ty: hir::Ty = if let Some(ty) = |
24 | ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) | 25 | ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 07d511fb3..92b4b1f79 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -230,7 +230,8 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { | |||
230 | .ancestors() | 230 | .ancestors() |
231 | .take_while(|it| it.text_range() == leaf_node.text_range()) | 231 | .take_while(|it| it.text_range() == leaf_node.text_range()) |
232 | .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; | 232 | .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; |
233 | let analyzer = hir::SourceAnalyzer::new(db, frange.file_id, &node, None); | 233 | let analyzer = |
234 | hir::SourceAnalyzer::new(db, hir::Source::new(frange.file_id.into(), &node), None); | ||
234 | let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) | 235 | let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) |
235 | { | 236 | { |
236 | ty | 237 | ty |
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs index 2ff10b89a..0cd959848 100644 --- a/crates/ra_ide_api/src/inlay_hints.rs +++ b/crates/ra_ide_api/src/inlay_hints.rs | |||
@@ -32,6 +32,7 @@ fn get_inlay_hints( | |||
32 | file_id: FileId, | 32 | file_id: FileId, |
33 | node: &SyntaxNode, | 33 | node: &SyntaxNode, |
34 | ) -> Option<Vec<InlayHint>> { | 34 | ) -> Option<Vec<InlayHint>> { |
35 | let analyzer = SourceAnalyzer::new(db, hir::Source::new(file_id.into(), node), None); | ||
35 | match_ast! { | 36 | match_ast! { |
36 | match node { | 37 | match node { |
37 | ast::LetStmt(it) => { | 38 | ast::LetStmt(it) => { |
@@ -39,11 +40,9 @@ fn get_inlay_hints( | |||
39 | return None; | 40 | return None; |
40 | } | 41 | } |
41 | let pat = it.pat()?; | 42 | let pat = it.pat()?; |
42 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
43 | Some(get_pat_type_hints(db, &analyzer, pat, false)) | 43 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
44 | }, | 44 | }, |
45 | ast::LambdaExpr(it) => { | 45 | ast::LambdaExpr(it) => { |
46 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
47 | it.param_list().map(|param_list| { | 46 | it.param_list().map(|param_list| { |
48 | param_list | 47 | param_list |
49 | .params() | 48 | .params() |
@@ -56,21 +55,17 @@ fn get_inlay_hints( | |||
56 | }, | 55 | }, |
57 | ast::ForExpr(it) => { | 56 | ast::ForExpr(it) => { |
58 | let pat = it.pat()?; | 57 | let pat = it.pat()?; |
59 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
60 | Some(get_pat_type_hints(db, &analyzer, pat, false)) | 58 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
61 | }, | 59 | }, |
62 | ast::IfExpr(it) => { | 60 | ast::IfExpr(it) => { |
63 | let pat = it.condition()?.pat()?; | 61 | let pat = it.condition()?.pat()?; |
64 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
65 | Some(get_pat_type_hints(db, &analyzer, pat, true)) | 62 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
66 | }, | 63 | }, |
67 | ast::WhileExpr(it) => { | 64 | ast::WhileExpr(it) => { |
68 | let pat = it.condition()?.pat()?; | 65 | let pat = it.condition()?.pat()?; |
69 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
70 | Some(get_pat_type_hints(db, &analyzer, pat, true)) | 66 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
71 | }, | 67 | }, |
72 | ast::MatchArmList(it) => { | 68 | ast::MatchArmList(it) => { |
73 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); | ||
74 | Some( | 69 | Some( |
75 | it | 70 | it |
76 | .arms() | 71 | .arms() |
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 9cb9433e7..faa88d988 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs | |||
@@ -369,6 +369,21 @@ mod tests { | |||
369 | assert_eq!(refs.len(), 2); | 369 | assert_eq!(refs.len(), 2); |
370 | } | 370 | } |
371 | 371 | ||
372 | #[test] | ||
373 | fn test_find_all_refs_macro_def() { | ||
374 | let code = r#" | ||
375 | #[macro_export] | ||
376 | macro_rules! m1<|> { () => (()) } | ||
377 | |||
378 | fn foo() { | ||
379 | m1(); | ||
380 | m1(); | ||
381 | }"#; | ||
382 | |||
383 | let refs = get_all_refs(code); | ||
384 | assert_eq!(refs.len(), 3); | ||
385 | } | ||
386 | |||
372 | fn get_all_refs(text: &str) -> ReferenceSearchResult { | 387 | fn get_all_refs(text: &str) -> ReferenceSearchResult { |
373 | let (analysis, position) = single_file_with_position(text); | 388 | let (analysis, position) = single_file_with_position(text); |
374 | analysis.find_all_refs(position, None).unwrap().unwrap() | 389 | analysis.find_all_refs(position, None).unwrap().unwrap() |
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 217f9951e..f12b58cb9 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs | |||
@@ -21,7 +21,6 @@ pub(crate) fn classify_name( | |||
21 | let parent = name.syntax().parent()?; | 21 | let parent = name.syntax().parent()?; |
22 | let file_id = file_id.into(); | 22 | let file_id = file_id.into(); |
23 | 23 | ||
24 | // FIXME: add ast::MacroCall(it) | ||
25 | match_ast! { | 24 | match_ast! { |
26 | match parent { | 25 | match parent { |
27 | ast::BindPat(it) => { | 26 | ast::BindPat(it) => { |
@@ -104,6 +103,19 @@ pub(crate) fn classify_name( | |||
104 | Some(from_module_def(db, def.into(), None)) | 103 | Some(from_module_def(db, def.into(), None)) |
105 | } | 104 | } |
106 | }, | 105 | }, |
106 | ast::MacroCall(it) => { | ||
107 | let src = hir::Source { file_id, ast: it}; | ||
108 | let def = hir::MacroDef::from_source(db, src.clone())?; | ||
109 | |||
110 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
111 | let module = Module::from_definition(db, Source::new(file_id, module_src))?; | ||
112 | |||
113 | Some(NameDefinition { | ||
114 | visibility: None, | ||
115 | container: module, | ||
116 | kind: NameKind::Macro(def), | ||
117 | }) | ||
118 | }, | ||
107 | _ => None, | 119 | _ => None, |
108 | } | 120 | } |
109 | } | 121 | } |
@@ -114,12 +126,11 @@ pub(crate) fn classify_name_ref( | |||
114 | file_id: FileId, | 126 | file_id: FileId, |
115 | name_ref: &ast::NameRef, | 127 | name_ref: &ast::NameRef, |
116 | ) -> Option<NameDefinition> { | 128 | ) -> Option<NameDefinition> { |
117 | use PathResolution::*; | ||
118 | |||
119 | let _p = profile("classify_name_ref"); | 129 | let _p = profile("classify_name_ref"); |
120 | 130 | ||
121 | let parent = name_ref.syntax().parent()?; | 131 | let parent = name_ref.syntax().parent()?; |
122 | let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); | 132 | let analyzer = |
133 | SourceAnalyzer::new(db, hir::Source::new(file_id.into(), name_ref.syntax()), None); | ||
123 | 134 | ||
124 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | 135 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
125 | tested_by!(goto_definition_works_for_methods); | 136 | tested_by!(goto_definition_works_for_methods); |
@@ -146,8 +157,8 @@ pub(crate) fn classify_name_ref( | |||
146 | } | 157 | } |
147 | } | 158 | } |
148 | 159 | ||
149 | let ast = ModuleSource::from_child_node(db, file_id, &parent); | ||
150 | let file_id = file_id.into(); | 160 | let file_id = file_id.into(); |
161 | let ast = ModuleSource::from_child_node(db, Source::new(file_id, &parent)); | ||
151 | // FIXME: find correct container and visibility for each case | 162 | // FIXME: find correct container and visibility for each case |
152 | let container = Module::from_definition(db, Source { file_id, ast })?; | 163 | let container = Module::from_definition(db, Source { file_id, ast })?; |
153 | let visibility = None; | 164 | let visibility = None; |
@@ -163,26 +174,26 @@ pub(crate) fn classify_name_ref( | |||
163 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | 174 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; |
164 | let resolved = analyzer.resolve_path(db, &path)?; | 175 | let resolved = analyzer.resolve_path(db, &path)?; |
165 | match resolved { | 176 | match resolved { |
166 | Def(def) => Some(from_module_def(db, def, Some(container))), | 177 | PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))), |
167 | AssocItem(item) => Some(from_assoc_item(db, item)), | 178 | PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)), |
168 | Local(local) => { | 179 | PathResolution::Local(local) => { |
169 | let container = local.module(db); | 180 | let container = local.module(db); |
170 | let kind = NameKind::Local(local); | 181 | let kind = NameKind::Local(local); |
171 | Some(NameDefinition { kind, container, visibility: None }) | 182 | Some(NameDefinition { kind, container, visibility: None }) |
172 | } | 183 | } |
173 | GenericParam(par) => { | 184 | PathResolution::GenericParam(par) => { |
174 | // FIXME: get generic param def | 185 | // FIXME: get generic param def |
175 | let kind = NameKind::GenericParam(par); | 186 | let kind = NameKind::GenericParam(par); |
176 | Some(NameDefinition { kind, container, visibility }) | 187 | Some(NameDefinition { kind, container, visibility }) |
177 | } | 188 | } |
178 | Macro(def) => { | 189 | PathResolution::Macro(def) => { |
179 | let kind = NameKind::Macro(def); | 190 | let kind = NameKind::Macro(def); |
180 | Some(NameDefinition { kind, container, visibility }) | 191 | Some(NameDefinition { kind, container, visibility }) |
181 | } | 192 | } |
182 | SelfType(impl_block) => { | 193 | PathResolution::SelfType(impl_block) => { |
183 | let ty = impl_block.target_ty(db); | 194 | let ty = impl_block.target_ty(db); |
184 | let kind = NameKind::SelfType(ty); | 195 | let kind = NameKind::SelfType(ty); |
185 | let container = impl_block.module(); | 196 | let container = impl_block.module(db); |
186 | Some(NameDefinition { kind, container, visibility }) | 197 | Some(NameDefinition { kind, container, visibility }) |
187 | } | 198 | } |
188 | } | 199 | } |
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs index 366ac8048..8039a5164 100644 --- a/crates/ra_ide_api/src/runnables.rs +++ b/crates/ra_ide_api/src/runnables.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::Source; | ||
3 | use itertools::Itertools; | 4 | use itertools::Itertools; |
4 | use ra_db::SourceDatabase; | 5 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -65,9 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti | |||
65 | return None; | 66 | return None; |
66 | } | 67 | } |
67 | let range = module.syntax().text_range(); | 68 | let range = module.syntax().text_range(); |
68 | let src = hir::ModuleSource::from_child_node(db, file_id, &module.syntax()); | 69 | let src = hir::ModuleSource::from_child_node(db, Source::new(file_id.into(), &module.syntax())); |
69 | let module = | 70 | let module = hir::Module::from_definition(db, Source::new(file_id.into(), src))?; |
70 | hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), ast: src })?; | ||
71 | 71 | ||
72 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); | 72 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); |
73 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) | 73 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 45f2e3de4..81d4f75f9 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -290,6 +290,22 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, | |||
290 | let m = lhs.precede(p); | 290 | let m = lhs.precede(p); |
291 | p.bump(op); | 291 | p.bump(op); |
292 | 292 | ||
293 | if is_range { | ||
294 | // test postfix_range | ||
295 | // fn foo() { | ||
296 | // let x = 1..; | ||
297 | // match 1.. { _ => () }; | ||
298 | // match a.b()..S { _ => () }; | ||
299 | // } | ||
300 | let has_trailing_expression = | ||
301 | p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])); | ||
302 | if !has_trailing_expression { | ||
303 | // no RHS | ||
304 | lhs = m.complete(p, RANGE_EXPR); | ||
305 | break; | ||
306 | } | ||
307 | } | ||
308 | |||
293 | expr_bp(p, r, op_bp + 1); | 309 | expr_bp(p, r, op_bp + 1); |
294 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 310 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
295 | } | 311 | } |
@@ -330,7 +346,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> | |||
330 | if p.at(op) { | 346 | if p.at(op) { |
331 | m = p.start(); | 347 | m = p.start(); |
332 | p.bump(op); | 348 | p.bump(op); |
333 | if p.at_ts(EXPR_FIRST) { | 349 | if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { |
334 | expr_bp(p, r, 2); | 350 | expr_bp(p, r, 2); |
335 | } | 351 | } |
336 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | 352 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); |
@@ -344,13 +360,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> | |||
344 | // } | 360 | // } |
345 | // | 361 | // |
346 | let (lhs, blocklike) = atom::atom_expr(p, r)?; | 362 | let (lhs, blocklike) = atom::atom_expr(p, r)?; |
347 | return Some(postfix_expr( | 363 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); |
348 | p, | ||
349 | lhs, | ||
350 | blocklike, | ||
351 | !(r.prefer_stmt && blocklike.is_block()), | ||
352 | r.forbid_structs, | ||
353 | )); | ||
354 | } | 364 | } |
355 | }; | 365 | }; |
356 | // parse the interior of the unary expression | 366 | // parse the interior of the unary expression |
@@ -366,7 +376,6 @@ fn postfix_expr( | |||
366 | // `while true {break}; ();` | 376 | // `while true {break}; ();` |
367 | mut block_like: BlockLike, | 377 | mut block_like: BlockLike, |
368 | mut allow_calls: bool, | 378 | mut allow_calls: bool, |
369 | forbid_structs: bool, | ||
370 | ) -> (CompletedMarker, BlockLike) { | 379 | ) -> (CompletedMarker, BlockLike) { |
371 | loop { | 380 | loop { |
372 | lhs = match p.current() { | 381 | lhs = match p.current() { |
@@ -380,7 +389,7 @@ fn postfix_expr( | |||
380 | // } | 389 | // } |
381 | T!['('] if allow_calls => call_expr(p, lhs), | 390 | T!['('] if allow_calls => call_expr(p, lhs), |
382 | T!['['] if allow_calls => index_expr(p, lhs), | 391 | T!['['] if allow_calls => index_expr(p, lhs), |
383 | T![.] => match postfix_dot_expr(p, lhs, forbid_structs) { | 392 | T![.] => match postfix_dot_expr(p, lhs) { |
384 | Ok(it) => it, | 393 | Ok(it) => it, |
385 | Err(it) => { | 394 | Err(it) => { |
386 | lhs = it; | 395 | lhs = it; |
@@ -398,7 +407,6 @@ fn postfix_expr( | |||
398 | fn postfix_dot_expr( | 407 | fn postfix_dot_expr( |
399 | p: &mut Parser, | 408 | p: &mut Parser, |
400 | lhs: CompletedMarker, | 409 | lhs: CompletedMarker, |
401 | forbid_structs: bool, | ||
402 | ) -> Result<CompletedMarker, CompletedMarker> { | 410 | ) -> Result<CompletedMarker, CompletedMarker> { |
403 | assert!(p.at(T![.])); | 411 | assert!(p.at(T![.])); |
404 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { | 412 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { |
@@ -418,25 +426,8 @@ fn postfix_expr( | |||
418 | return Ok(m.complete(p, AWAIT_EXPR)); | 426 | return Ok(m.complete(p, AWAIT_EXPR)); |
419 | } | 427 | } |
420 | 428 | ||
421 | // test postfix_range | 429 | if p.at(T![..=]) || p.at(T![..]) { |
422 | // fn foo() { | 430 | return Err(lhs); |
423 | // let x = 1..; | ||
424 | // match 1.. { _ => () }; | ||
425 | // match a.b()..S { _ => () }; | ||
426 | // } | ||
427 | for &(op, la) in &[(T![..=], 3), (T![..], 2)] { | ||
428 | if p.at(op) { | ||
429 | let next_token = p.nth(la); | ||
430 | let has_trailing_expression = | ||
431 | !(forbid_structs && next_token == T!['{']) && EXPR_FIRST.contains(next_token); | ||
432 | return if has_trailing_expression { | ||
433 | Err(lhs) | ||
434 | } else { | ||
435 | let m = lhs.precede(p); | ||
436 | p.bump(op); | ||
437 | Ok(m.complete(p, RANGE_EXPR)) | ||
438 | }; | ||
439 | } | ||
440 | } | 431 | } |
441 | 432 | ||
442 | Ok(field_expr(p, lhs)) | 433 | Ok(field_expr(p, lhs)) |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 1ec9881b9..277532a8c 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub use self::{ | 18 | pub use self::{ |
19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp}, | 19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, |
20 | extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind}, | 20 | extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind}, |
21 | generated::*, | 21 | generated::*, |
22 | tokens::*, | 22 | tokens::*, |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 25dbd0bed..7c53aa934 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -189,6 +189,52 @@ impl ast::BinExpr { | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
193 | pub enum RangeOp { | ||
194 | /// `..` | ||
195 | Exclusive, | ||
196 | /// `..=` | ||
197 | Inclusive, | ||
198 | } | ||
199 | |||
200 | impl ast::RangeExpr { | ||
201 | fn op_details(&self) -> Option<(usize, SyntaxToken, RangeOp)> { | ||
202 | self.syntax().children_with_tokens().enumerate().find_map(|(ix, child)| { | ||
203 | let token = child.into_token()?; | ||
204 | let bin_op = match token.kind() { | ||
205 | T![..] => RangeOp::Exclusive, | ||
206 | T![..=] => RangeOp::Inclusive, | ||
207 | _ => return None, | ||
208 | }; | ||
209 | Some((ix, token, bin_op)) | ||
210 | }) | ||
211 | } | ||
212 | |||
213 | pub fn op_kind(&self) -> Option<RangeOp> { | ||
214 | self.op_details().map(|t| t.2) | ||
215 | } | ||
216 | |||
217 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
218 | self.op_details().map(|t| t.1) | ||
219 | } | ||
220 | |||
221 | pub fn start(&self) -> Option<ast::Expr> { | ||
222 | let op_ix = self.op_details()?.0; | ||
223 | self.syntax() | ||
224 | .children_with_tokens() | ||
225 | .take(op_ix) | ||
226 | .find_map(|it| ast::Expr::cast(it.into_node()?)) | ||
227 | } | ||
228 | |||
229 | pub fn end(&self) -> Option<ast::Expr> { | ||
230 | let op_ix = self.op_details()?.0; | ||
231 | self.syntax() | ||
232 | .children_with_tokens() | ||
233 | .skip(op_ix + 1) | ||
234 | .find_map(|it| ast::Expr::cast(it.into_node()?)) | ||
235 | } | ||
236 | } | ||
237 | |||
192 | impl ast::IndexExpr { | 238 | impl ast::IndexExpr { |
193 | pub fn base(&self) -> Option<ast::Expr> { | 239 | pub fn base(&self) -> Option<ast::Expr> { |
194 | children(self).nth(0) | 240 | children(self).nth(0) |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 5dcb6a95a..9931fec84 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -176,9 +176,11 @@ impl SourceFile { | |||
176 | /// ``` | 176 | /// ``` |
177 | #[macro_export] | 177 | #[macro_export] |
178 | macro_rules! match_ast { | 178 | macro_rules! match_ast { |
179 | (match $node:ident { | 179 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; |
180 | |||
181 | (match ($node:expr) { | ||
180 | $( ast::$ast:ident($it:ident) => $res:block, )* | 182 | $( ast::$ast:ident($it:ident) => $res:block, )* |
181 | _ => $catch_all:expr, | 183 | _ => $catch_all:expr $(,)? |
182 | }) => {{ | 184 | }) => {{ |
183 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | 185 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* |
184 | { $catch_all } | 186 | { $catch_all } |
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs index 1f60a7aab..6c171df8d 100644 --- a/crates/ra_syntax/src/syntax_error.rs +++ b/crates/ra_syntax/src/syntax_error.rs | |||
@@ -83,6 +83,7 @@ pub enum SyntaxErrorKind { | |||
83 | InvalidMatchInnerAttr, | 83 | InvalidMatchInnerAttr, |
84 | InvalidTupleIndexFormat, | 84 | InvalidTupleIndexFormat, |
85 | VisibilityNotAllowed, | 85 | VisibilityNotAllowed, |
86 | InclusiveRangeMissingEnd, | ||
86 | } | 87 | } |
87 | 88 | ||
88 | impl fmt::Display for SyntaxErrorKind { | 89 | impl fmt::Display for SyntaxErrorKind { |
@@ -103,6 +104,9 @@ impl fmt::Display for SyntaxErrorKind { | |||
103 | VisibilityNotAllowed => { | 104 | VisibilityNotAllowed => { |
104 | write!(f, "unnecessary visibility qualifier") | 105 | write!(f, "unnecessary visibility qualifier") |
105 | } | 106 | } |
107 | InclusiveRangeMissingEnd => { | ||
108 | write!(f, "An inclusive range must have an end expression") | ||
109 | } | ||
106 | } | 110 | } |
107 | } | 111 | } |
108 | } | 112 | } |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 2d596763e..222ac15f8 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -103,6 +103,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
103 | ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, | 103 | ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
104 | ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, | 104 | ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
105 | ast::Visibility(it) => { validate_visibility(it, &mut errors) }, | 105 | ast::Visibility(it) => { validate_visibility(it, &mut errors) }, |
106 | ast::RangeExpr(it) => { validate_range_expr(it, &mut errors) }, | ||
106 | _ => (), | 107 | _ => (), |
107 | } | 108 | } |
108 | } | 109 | } |
@@ -227,3 +228,12 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) { | |||
227 | .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range())) | 228 | .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range())) |
228 | } | 229 | } |
229 | } | 230 | } |
231 | |||
232 | fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { | ||
233 | if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() { | ||
234 | errors.push(SyntaxError::new( | ||
235 | SyntaxErrorKind::InclusiveRangeMissingEnd, | ||
236 | expr.syntax().text_range(), | ||
237 | )); | ||
238 | } | ||
239 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs new file mode 100644 index 000000000..0b4ed7a2b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | 0..=; | ||
3 | ..=; | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt new file mode 100644 index 000000000..3810b9680 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | SOURCE_FILE@[0; 33) | ||
2 | FN_DEF@[0; 32) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 32) | ||
12 | BLOCK@[10; 32) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | EXPR_STMT@[16; 21) | ||
16 | RANGE_EXPR@[16; 20) | ||
17 | LITERAL@[16; 17) | ||
18 | INT_NUMBER@[16; 17) "0" | ||
19 | DOTDOTEQ@[17; 20) "..=" | ||
20 | SEMI@[20; 21) ";" | ||
21 | WHITESPACE@[21; 26) "\n " | ||
22 | EXPR_STMT@[26; 30) | ||
23 | RANGE_EXPR@[26; 29) | ||
24 | DOTDOTEQ@[26; 29) "..=" | ||
25 | SEMI@[29; 30) ";" | ||
26 | WHITESPACE@[30; 31) "\n" | ||
27 | R_CURLY@[31; 32) "}" | ||
28 | WHITESPACE@[32; 33) "\n" | ||
29 | error [16; 20): An inclusive range must have an end expression | ||
30 | error [26; 29): An inclusive range must have an end expression | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs new file mode 100644 index 000000000..f063ffadb --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | 0 as usize ..; | ||
3 | 1 + 2 as usize ..; | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt b/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt new file mode 100644 index 000000000..ad0c4a3fe --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt | |||
@@ -0,0 +1,56 @@ | |||
1 | SOURCE_FILE@[0; 56) | ||
2 | FN_DEF@[0; 55) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 55) | ||
12 | BLOCK@[10; 55) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | EXPR_STMT@[16; 30) | ||
16 | RANGE_EXPR@[16; 29) | ||
17 | CAST_EXPR@[16; 26) | ||
18 | LITERAL@[16; 17) | ||
19 | INT_NUMBER@[16; 17) "0" | ||
20 | WHITESPACE@[17; 18) " " | ||
21 | AS_KW@[18; 20) "as" | ||
22 | WHITESPACE@[20; 21) " " | ||
23 | PATH_TYPE@[21; 26) | ||
24 | PATH@[21; 26) | ||
25 | PATH_SEGMENT@[21; 26) | ||
26 | NAME_REF@[21; 26) | ||
27 | IDENT@[21; 26) "usize" | ||
28 | WHITESPACE@[26; 27) " " | ||
29 | DOTDOT@[27; 29) ".." | ||
30 | SEMI@[29; 30) ";" | ||
31 | WHITESPACE@[30; 35) "\n " | ||
32 | EXPR_STMT@[35; 53) | ||
33 | RANGE_EXPR@[35; 52) | ||
34 | BIN_EXPR@[35; 49) | ||
35 | LITERAL@[35; 36) | ||
36 | INT_NUMBER@[35; 36) "1" | ||
37 | WHITESPACE@[36; 37) " " | ||
38 | PLUS@[37; 38) "+" | ||
39 | WHITESPACE@[38; 39) " " | ||
40 | CAST_EXPR@[39; 49) | ||
41 | LITERAL@[39; 40) | ||
42 | INT_NUMBER@[39; 40) "2" | ||
43 | WHITESPACE@[40; 41) " " | ||
44 | AS_KW@[41; 43) "as" | ||
45 | WHITESPACE@[43; 44) " " | ||
46 | PATH_TYPE@[44; 49) | ||
47 | PATH@[44; 49) | ||
48 | PATH_SEGMENT@[44; 49) | ||
49 | NAME_REF@[44; 49) | ||
50 | IDENT@[44; 49) "usize" | ||
51 | WHITESPACE@[49; 50) " " | ||
52 | DOTDOT@[50; 52) ".." | ||
53 | SEMI@[52; 53) ";" | ||
54 | WHITESPACE@[53; 54) "\n" | ||
55 | R_CURLY@[54; 55) "}" | ||
56 | WHITESPACE@[55; 56) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs new file mode 100644 index 000000000..2c4ed11e1 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | match .. { | ||
3 | } | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt new file mode 100644 index 000000000..bdfac9b76 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | SOURCE_FILE@[0; 35) | ||
2 | FN_DEF@[0; 34) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 34) | ||
12 | BLOCK@[10; 34) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | MATCH_EXPR@[16; 32) | ||
16 | MATCH_KW@[16; 21) "match" | ||
17 | WHITESPACE@[21; 22) " " | ||
18 | RANGE_EXPR@[22; 24) | ||
19 | DOTDOT@[22; 24) ".." | ||
20 | WHITESPACE@[24; 25) " " | ||
21 | MATCH_ARM_LIST@[25; 32) | ||
22 | L_CURLY@[25; 26) "{" | ||
23 | WHITESPACE@[26; 31) "\n " | ||
24 | R_CURLY@[31; 32) "}" | ||
25 | WHITESPACE@[32; 33) "\n" | ||
26 | R_CURLY@[33; 34) "}" | ||
27 | WHITESPACE@[34; 35) "\n" | ||