aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_import.rs43
-rw-r--r--crates/ra_hir/Cargo.toml7
-rw-r--r--crates/ra_hir/src/db.rs44
-rw-r--r--crates/ra_hir/src/debug.rs6
-rw-r--r--crates/ra_hir/src/expr/lower.rs13
-rw-r--r--crates/ra_hir/src/from_source.rs4
-rw-r--r--crates/ra_hir/src/ids.rs246
-rw-r--r--crates/ra_hir/src/impl_block.rs6
-rw-r--r--crates/ra_hir/src/lib.rs14
-rw-r--r--crates/ra_hir/src/nameres/collector.rs18
-rw-r--r--crates/ra_hir/src/path.rs9
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs15
-rw-r--r--crates/ra_hir_expand/Cargo.toml15
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs (renamed from crates/ra_hir/src/source_id.rs)115
-rw-r--r--crates/ra_hir_expand/src/db.rs104
-rw-r--r--crates/ra_hir_expand/src/lib.rs161
-rw-r--r--crates/ra_ide_api/Cargo.toml5
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt91
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt101
21 files changed, 589 insertions, 436 deletions
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index e87fae1af..c8b9809f4 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -124,9 +124,9 @@ fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) {
124 } 124 }
125} 125}
126 126
127// Returns the numeber of common segments. 127/// Returns the number of common segments.
128fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize { 128fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize {
129 left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count() 129 left.iter().zip(right).take_while(|(l, r)| compare_path_segment(l, r)).count()
130} 130}
131 131
132fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { 132fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool {
@@ -147,7 +147,7 @@ fn compare_path_segment_with_name(a: &SmolStr, b: &ast::Name) -> bool {
147 a == b.text() 147 a == b.text()
148} 148}
149 149
150#[derive(Clone)] 150#[derive(Clone, Debug)]
151enum ImportAction { 151enum ImportAction {
152 Nothing, 152 Nothing,
153 // Add a brand new use statement. 153 // Add a brand new use statement.
@@ -217,10 +217,18 @@ impl ImportAction {
217 ( 217 (
218 ImportAction::AddNestedImport { common_segments: n, .. }, 218 ImportAction::AddNestedImport { common_segments: n, .. },
219 ImportAction::AddInTreeList { common_segments: m, .. }, 219 ImportAction::AddInTreeList { common_segments: m, .. },
220 ) => n > m, 220 )
221 ( 221 | (
222 ImportAction::AddInTreeList { common_segments: n, .. }, 222 ImportAction::AddInTreeList { common_segments: n, .. },
223 ImportAction::AddNestedImport { common_segments: m, .. }, 223 ImportAction::AddNestedImport { common_segments: m, .. },
224 )
225 | (
226 ImportAction::AddInTreeList { common_segments: n, .. },
227 ImportAction::AddInTreeList { common_segments: m, .. },
228 )
229 | (
230 ImportAction::AddNestedImport { common_segments: n, .. },
231 ImportAction::AddNestedImport { common_segments: m, .. },
224 ) => n > m, 232 ) => n > m,
225 (ImportAction::AddInTreeList { .. }, _) => true, 233 (ImportAction::AddInTreeList { .. }, _) => true,
226 (ImportAction::AddNestedImport { .. }, ImportAction::Nothing) => false, 234 (ImportAction::AddNestedImport { .. }, ImportAction::Nothing) => false,
@@ -289,7 +297,7 @@ fn walk_use_tree_for_best_action(
289 common if common == left.len() && left.len() == right.len() => { 297 common if common == left.len() && left.len() == right.len() => {
290 // e.g: target is std::fmt and we can have 298 // e.g: target is std::fmt and we can have
291 // 1- use std::fmt; 299 // 1- use std::fmt;
292 // 2- use std::fmt:{ ... } 300 // 2- use std::fmt::{ ... }
293 if let Some(list) = tree_list { 301 if let Some(list) = tree_list {
294 // In case 2 we need to add self to the nested list 302 // In case 2 we need to add self to the nested list
295 // unless it's already there 303 // unless it's already there
@@ -868,6 +876,29 @@ impl Display<|> for Foo {
868 } 876 }
869 877
870 #[test] 878 #[test]
879 fn test_auto_import_use_nested_import() {
880 check_assist(
881 add_import,
882 "
883use crate::{
884 ty::{Substs, Ty},
885 AssocItem,
886};
887
888fn foo() { crate::ty::lower<|>::trait_env() }
889",
890 "
891use crate::{
892 ty::{Substs, Ty, lower},
893 AssocItem,
894};
895
896fn foo() { lower<|>::trait_env() }
897",
898 );
899 }
900
901 #[test]
871 fn test_auto_import_alias() { 902 fn test_auto_import_alias() {
872 check_assist( 903 check_assist(
873 add_import, 904 add_import,
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index f05ec0b8a..143dae6bd 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -19,12 +19,13 @@ ra_cfg = { path = "../ra_cfg" }
19ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
20mbe = { path = "../ra_mbe", package = "ra_mbe" } 20mbe = { path = "../ra_mbe", package = "ra_mbe" }
21tt = { path = "../ra_tt", package = "ra_tt" } 21tt = { path = "../ra_tt", package = "ra_tt" }
22hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
22test_utils = { path = "../test_utils" } 23test_utils = { path = "../test_utils" }
23ra_prof = { path = "../ra_prof" } 24ra_prof = { path = "../ra_prof" }
24 25
25chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } 26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
26chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } 27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
27chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } 28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
28lalrpop-intern = "0.15.1" 29lalrpop-intern = "0.15.1"
29 30
30[dev-dependencies] 31[dev-dependencies]
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 489a3b19c..6d34c671d 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use ra_db::{salsa, SourceDatabase}; 5use ra_db::{salsa, SourceDatabase};
6use ra_syntax::{ast, Parse, SmolStr, SyntaxNode}; 6use ra_syntax::{ast, SmolStr};
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
@@ -19,9 +19,13 @@ use crate::{
19 InferenceResult, Substs, Ty, TypableDef, TypeCtor, 19 InferenceResult, Substs, Ty, TypableDef, TypeCtor,
20 }, 20 },
21 type_alias::TypeAliasData, 21 type_alias::TypeAliasData,
22 AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData, 22 Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, HirFileId, Module,
23 Function, HirFileId, MacroCallLoc, MacroDefId, Module, Static, Struct, StructField, Trait, 23 Static, Struct, StructField, Trait, TypeAlias,
24 TypeAlias, 24};
25
26pub use hir_expand::db::{
27 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
28 ParseMacroQuery,
25}; 29};
26 30
27/// We store all interned things in the single QueryGroup. 31/// We store all interned things in the single QueryGroup.
@@ -32,8 +36,6 @@ use crate::{
32#[salsa::query_group(InternDatabaseStorage)] 36#[salsa::query_group(InternDatabaseStorage)]
33pub trait InternDatabase: SourceDatabase { 37pub trait InternDatabase: SourceDatabase {
34 #[salsa::interned] 38 #[salsa::interned]
35 fn intern_macro(&self, macro_call: MacroCallLoc) -> ids::MacroCallId;
36 #[salsa::interned]
37 fn intern_function(&self, loc: ids::ItemLoc<ast::FnDef>) -> ids::FunctionId; 39 fn intern_function(&self, loc: ids::ItemLoc<ast::FnDef>) -> ids::FunctionId;
38 #[salsa::interned] 40 #[salsa::interned]
39 fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId; 41 fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId;
@@ -55,38 +57,10 @@ pub trait InternDatabase: SourceDatabase {
55 fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; 57 fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId;
56} 58}
57 59
58/// This database has access to source code, so queries here are not really
59/// incremental.
60#[salsa::query_group(AstDatabaseStorage)]
61pub trait AstDatabase: InternDatabase {
62 #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)]
63 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
64
65 #[salsa::transparent]
66 #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)]
67 fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode;
68
69 #[salsa::transparent]
70 #[salsa::invoke(crate::ids::HirFileId::parse_or_expand_query)]
71 fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
72
73 #[salsa::invoke(crate::ids::HirFileId::parse_macro_query)]
74 fn parse_macro(&self, macro_file: ids::MacroFile) -> Option<Parse<SyntaxNode>>;
75
76 #[salsa::invoke(crate::ids::macro_def_query)]
77 fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>;
78
79 #[salsa::invoke(crate::ids::macro_arg_query)]
80 fn macro_arg(&self, macro_call: ids::MacroCallId) -> Option<Arc<tt::Subtree>>;
81
82 #[salsa::invoke(crate::ids::macro_expand_query)]
83 fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>;
84}
85
86// This database uses `AstDatabase` internally, 60// This database uses `AstDatabase` internally,
87#[salsa::query_group(DefDatabaseStorage)] 61#[salsa::query_group(DefDatabaseStorage)]
88#[salsa::requires(AstDatabase)] 62#[salsa::requires(AstDatabase)]
89pub trait DefDatabase: InternDatabase + HirDebugDatabase { 63pub trait DefDatabase: InternDatabase + HirDebugDatabase + AstDatabase {
90 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 64 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
91 fn struct_data(&self, s: Struct) -> Arc<StructData>; 65 fn struct_data(&self, s: Struct) -> Arc<StructData>;
92 66
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
index 48b69000b..4f3e922c3 100644
--- a/crates/ra_hir/src/debug.rs
+++ b/crates/ra_hir/src/debug.rs
@@ -36,12 +36,6 @@ impl Module {
36 } 36 }
37} 37}
38 38
39impl HirFileId {
40 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
41 debug_fn(move |fmt| db.debug_hir_file_id(self, fmt))
42 }
43}
44
45pub trait HirDebugHelper: HirDatabase { 39pub trait HirDebugHelper: HirDatabase {
46 fn crate_name(&self, _krate: CrateId) -> Option<String> { 40 fn crate_name(&self, _krate: CrateId) -> Option<String> {
47 None 41 None
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
index 50ea429ea..b3a9a2e6b 100644
--- a/crates/ra_hir/src/expr/lower.rs
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -16,7 +16,7 @@ use crate::{
16 path::GenericArgs, 16 path::GenericArgs,
17 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 17 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
18 type_ref::TypeRef, 18 type_ref::TypeRef,
19 DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, 19 AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver,
20 Source, 20 Source,
21}; 21};
22 22
@@ -458,15 +458,14 @@ where
458 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 458 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
459 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 459 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
460 ast::Expr::MacroCall(e) => { 460 ast::Expr::MacroCall(e) => {
461 let ast_id = self 461 let ast_id = AstId::new(
462 .db 462 self.current_file_id,
463 .ast_id_map(self.current_file_id) 463 self.db.ast_id_map(self.current_file_id).ast_id(&e),
464 .ast_id(&e) 464 );
465 .with_file_id(self.current_file_id);
466 465
467 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { 466 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
468 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { 467 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
469 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); 468 let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id });
470 let file_id = call_id.as_file(MacroFileKind::Expr); 469 let file_id = call_id.as_file(MacroFileKind::Expr);
471 if let Some(node) = self.db.parse_or_expand(file_id) { 470 if let Some(node) = self.db.parse_or_expand(file_id) {
472 if let Some(expr) = ast::Expr::cast(node) { 471 if let Some(expr) = ast::Expr::cast(node) {
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index f80d8eb5f..7954c04b2 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -11,7 +11,7 @@ use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 ids::{AstItemDef, LocationCtx}, 12 ids::{AstItemDef, LocationCtx},
13 name::AsName, 13 name::AsName,
14 Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, 14 AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
15 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, 15 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
16}; 16};
17 17
@@ -183,7 +183,7 @@ impl Module {
183 ModuleSource::Module(ref module) => { 183 ModuleSource::Module(ref module) => {
184 assert!(!module.has_semi()); 184 assert!(!module.has_semi());
185 let ast_id_map = db.ast_id_map(src.file_id); 185 let ast_id_map = db.ast_id_map(src.file_id);
186 let item_id = ast_id_map.ast_id(module).with_file_id(src.file_id); 186 let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module));
187 Some(item_id) 187 Some(item_id)
188 } 188 }
189 ModuleSource::SourceFile(_) => None, 189 ModuleSource::SourceFile(_) => None,
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 499dcafea..dea288eb7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,168 +1,21 @@
1//! FIXME: write short doc here 1//! hir makes heavy use of ids: integer (u32) handlers to various things. You
2//! can think of id as a pointer (but without a lifetime) or a file descriptor
3//! (but for hir objects).
4//!
5//! This module defines a bunch of ids we are using. The most important ones are
6//! probably `HirFileId` and `DefId`.
2 7
3use std::{ 8use std::hash::{Hash, Hasher};
4 hash::{Hash, Hasher},
5 sync::Arc,
6};
7 9
8use mbe::MacroRules; 10use ra_db::salsa;
9use ra_db::{salsa, FileId}; 11use ra_syntax::{ast, AstNode};
10use ra_prof::profile;
11use ra_syntax::{ast, AstNode, Parse, SyntaxNode};
12 12
13use crate::{ 13use crate::{
14 db::{AstDatabase, DefDatabase, InternDatabase}, 14 db::{AstDatabase, InternDatabase},
15 AstId, Crate, FileAstId, Module, Source, 15 AstId, FileAstId, Module, Source,
16}; 16};
17 17
18/// hir makes heavy use of ids: integer (u32) handlers to various things. You 18pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind};
19/// can think of id as a pointer (but without a lifetime) or a file descriptor
20/// (but for hir objects).
21///
22/// This module defines a bunch of ids we are using. The most important ones are
23/// probably `HirFileId` and `DefId`.
24
25/// Input to the analyzer is a set of files, where each file is identified by
26/// `FileId` and contains source code. However, another source of source code in
27/// Rust are macros: each macro can be thought of as producing a "temporary
28/// file". To assign an id to such a file, we use the id of the macro call that
29/// produced the file. So, a `HirFileId` is either a `FileId` (source code
30/// written by user), or a `MacroCallId` (source code produced by macro).
31///
32/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
33/// containing the call plus the offset of the macro call in the file. Note that
34/// this is a recursive definition! However, the size_of of `HirFileId` is
35/// finite (because everything bottoms out at the real `FileId`) and small
36/// (`MacroCallId` uses the location interner).
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct HirFileId(HirFileIdRepr);
39
40impl HirFileId {
41 /// For macro-expansion files, returns the file original source file the
42 /// expansion originated from.
43 pub fn original_file(self, db: &impl InternDatabase) -> FileId {
44 match self.0 {
45 HirFileIdRepr::File(file_id) => file_id,
46 HirFileIdRepr::Macro(macro_file) => {
47 let loc = macro_file.macro_call_id.loc(db);
48 loc.ast_id.file_id().original_file(db)
49 }
50 }
51 }
52
53 /// Get the crate which the macro lives in, if it is a macro file.
54 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
55 match self.0 {
56 HirFileIdRepr::File(_) => None,
57 HirFileIdRepr::Macro(macro_file) => {
58 let loc = macro_file.macro_call_id.loc(db);
59 Some(loc.def.krate)
60 }
61 }
62 }
63
64 pub(crate) fn parse_or_expand_query(
65 db: &impl AstDatabase,
66 file_id: HirFileId,
67 ) -> Option<SyntaxNode> {
68 match file_id.0 {
69 HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
70 HirFileIdRepr::Macro(macro_file) => {
71 db.parse_macro(macro_file).map(|it| it.syntax_node())
72 }
73 }
74 }
75
76 pub(crate) fn parse_macro_query(
77 db: &impl AstDatabase,
78 macro_file: MacroFile,
79 ) -> Option<Parse<SyntaxNode>> {
80 let _p = profile("parse_macro_query");
81 let macro_call_id = macro_file.macro_call_id;
82 let tt = db
83 .macro_expand(macro_call_id)
84 .map_err(|err| {
85 // Note:
86 // The final goal we would like to make all parse_macro success,
87 // such that the following log will not call anyway.
88 log::warn!("fail on macro_parse: (reason: {})", err,);
89 })
90 .ok()?;
91 match macro_file.macro_file_kind {
92 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
93 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99enum HirFileIdRepr {
100 File(FileId),
101 Macro(MacroFile),
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub struct MacroFile {
106 macro_call_id: MacroCallId,
107 macro_file_kind: MacroFileKind,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub(crate) enum MacroFileKind {
112 Items,
113 Expr,
114}
115
116impl From<FileId> for HirFileId {
117 fn from(file_id: FileId) -> HirFileId {
118 HirFileId(HirFileIdRepr::File(file_id))
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub struct MacroDefId {
124 pub(crate) ast_id: AstId<ast::MacroCall>,
125 pub(crate) krate: Crate,
126}
127
128pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
129 let macro_call = id.ast_id.to_node(db);
130 let arg = macro_call.token_tree()?;
131 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
132 log::warn!("fail on macro_def to token tree: {:#?}", arg);
133 None
134 })?;
135 let rules = MacroRules::parse(&tt).ok().or_else(|| {
136 log::warn!("fail on macro_def parse: {:#?}", tt);
137 None
138 })?;
139 Some(Arc::new(rules))
140}
141
142pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
143 let loc = id.loc(db);
144 let macro_call = loc.ast_id.to_node(db);
145 let arg = macro_call.token_tree()?;
146 let (tt, _) = mbe::ast_to_token_tree(&arg)?;
147 Some(Arc::new(tt))
148}
149
150pub(crate) fn macro_expand_query(
151 db: &impl AstDatabase,
152 id: MacroCallId,
153) -> Result<Arc<tt::Subtree>, String> {
154 let loc = id.loc(db);
155 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
156
157 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
158 let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
159 // Set a hard limit for the expanded tt
160 let count = tt.count();
161 if count > 65536 {
162 return Err(format!("Total tokens count exceed limit : count = {}", count));
163 }
164 Ok(Arc::new(tt))
165}
166 19
167macro_rules! impl_intern_key { 20macro_rules! impl_intern_key {
168 ($name:ident) => { 21 ($name:ident) => {
@@ -177,35 +30,6 @@ macro_rules! impl_intern_key {
177 }; 30 };
178} 31}
179 32
180/// `MacroCallId` identifies a particular macro invocation, like
181/// `println!("Hello, {}", world)`.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183pub struct MacroCallId(salsa::InternId);
184impl_intern_key!(MacroCallId);
185
186#[derive(Debug, Clone, PartialEq, Eq, Hash)]
187pub struct MacroCallLoc {
188 pub(crate) def: MacroDefId,
189 pub(crate) ast_id: AstId<ast::MacroCall>,
190}
191
192impl MacroCallId {
193 pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc {
194 db.lookup_intern_macro(self)
195 }
196
197 pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
198 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
199 HirFileId(HirFileIdRepr::Macro(macro_file))
200 }
201}
202
203impl MacroCallLoc {
204 pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId {
205 db.intern_macro(self)
206 }
207}
208
209#[derive(Debug)] 33#[derive(Debug)]
210pub struct ItemLoc<N: AstNode> { 34pub struct ItemLoc<N: AstNode> {
211 pub(crate) module: Module, 35 pub(crate) module: Module,
@@ -238,13 +62,13 @@ pub(crate) struct LocationCtx<DB> {
238 file_id: HirFileId, 62 file_id: HirFileId,
239} 63}
240 64
241impl<'a, DB: DefDatabase> LocationCtx<&'a DB> { 65impl<'a, DB> LocationCtx<&'a DB> {
242 pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { 66 pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
243 LocationCtx { db, module, file_id } 67 LocationCtx { db, module, file_id }
244 } 68 }
245} 69}
246 70
247impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> { 71impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
248 pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF 72 pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
249 where 73 where
250 N: AstNode, 74 N: AstNode,
@@ -255,24 +79,24 @@ impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> {
255} 79}
256 80
257pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { 81pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
258 fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self; 82 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
259 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>; 83 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
260 84
261 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + DefDatabase)>, ast: &N) -> Self { 85 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
262 let items = ctx.db.ast_id_map(ctx.file_id); 86 let items = ctx.db.ast_id_map(ctx.file_id);
263 let item_id = items.ast_id(ast); 87 let item_id = items.ast_id(ast);
264 Self::from_ast_id(ctx, item_id) 88 Self::from_ast_id(ctx, item_id)
265 } 89 }
266 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self { 90 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
267 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; 91 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
268 Self::intern(ctx.db, loc) 92 Self::intern(ctx.db, loc)
269 } 93 }
270 fn source(self, db: &(impl AstDatabase + DefDatabase)) -> Source<N> { 94 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> {
271 let loc = self.lookup_intern(db); 95 let loc = self.lookup_intern(db);
272 let ast = loc.ast_id.to_node(db); 96 let ast = loc.ast_id.to_node(db);
273 Source { file_id: loc.ast_id.file_id(), ast } 97 Source { file_id: loc.ast_id.file_id(), ast }
274 } 98 }
275 fn module(self, db: &impl DefDatabase) -> Module { 99 fn module(self, db: &impl InternDatabase) -> Module {
276 let loc = self.lookup_intern(db); 100 let loc = self.lookup_intern(db);
277 loc.module 101 loc.module
278 } 102 }
@@ -283,10 +107,10 @@ pub struct FunctionId(salsa::InternId);
283impl_intern_key!(FunctionId); 107impl_intern_key!(FunctionId);
284 108
285impl AstItemDef<ast::FnDef> for FunctionId { 109impl AstItemDef<ast::FnDef> for FunctionId {
286 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self { 110 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
287 db.intern_function(loc) 111 db.intern_function(loc)
288 } 112 }
289 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> { 113 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
290 db.lookup_intern_function(self) 114 db.lookup_intern_function(self)
291 } 115 }
292} 116}
@@ -295,10 +119,10 @@ impl AstItemDef<ast::FnDef> for FunctionId {
295pub struct StructId(salsa::InternId); 119pub struct StructId(salsa::InternId);
296impl_intern_key!(StructId); 120impl_intern_key!(StructId);
297impl AstItemDef<ast::StructDef> for StructId { 121impl AstItemDef<ast::StructDef> for StructId {
298 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 122 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
299 db.intern_struct(loc) 123 db.intern_struct(loc)
300 } 124 }
301 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> { 125 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
302 db.lookup_intern_struct(self) 126 db.lookup_intern_struct(self)
303 } 127 }
304} 128}
@@ -307,10 +131,10 @@ impl AstItemDef<ast::StructDef> for StructId {
307pub struct EnumId(salsa::InternId); 131pub struct EnumId(salsa::InternId);
308impl_intern_key!(EnumId); 132impl_intern_key!(EnumId);
309impl AstItemDef<ast::EnumDef> for EnumId { 133impl AstItemDef<ast::EnumDef> for EnumId {
310 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { 134 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
311 db.intern_enum(loc) 135 db.intern_enum(loc)
312 } 136 }
313 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> { 137 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
314 db.lookup_intern_enum(self) 138 db.lookup_intern_enum(self)
315 } 139 }
316} 140}
@@ -319,10 +143,10 @@ impl AstItemDef<ast::EnumDef> for EnumId {
319pub struct ConstId(salsa::InternId); 143pub struct ConstId(salsa::InternId);
320impl_intern_key!(ConstId); 144impl_intern_key!(ConstId);
321impl AstItemDef<ast::ConstDef> for ConstId { 145impl AstItemDef<ast::ConstDef> for ConstId {
322 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self { 146 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
323 db.intern_const(loc) 147 db.intern_const(loc)
324 } 148 }
325 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> { 149 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
326 db.lookup_intern_const(self) 150 db.lookup_intern_const(self)
327 } 151 }
328} 152}
@@ -331,10 +155,10 @@ impl AstItemDef<ast::ConstDef> for ConstId {
331pub struct StaticId(salsa::InternId); 155pub struct StaticId(salsa::InternId);
332impl_intern_key!(StaticId); 156impl_intern_key!(StaticId);
333impl AstItemDef<ast::StaticDef> for StaticId { 157impl AstItemDef<ast::StaticDef> for StaticId {
334 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self { 158 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
335 db.intern_static(loc) 159 db.intern_static(loc)
336 } 160 }
337 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> { 161 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
338 db.lookup_intern_static(self) 162 db.lookup_intern_static(self)
339 } 163 }
340} 164}
@@ -343,10 +167,10 @@ impl AstItemDef<ast::StaticDef> for StaticId {
343pub struct TraitId(salsa::InternId); 167pub struct TraitId(salsa::InternId);
344impl_intern_key!(TraitId); 168impl_intern_key!(TraitId);
345impl AstItemDef<ast::TraitDef> for TraitId { 169impl AstItemDef<ast::TraitDef> for TraitId {
346 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { 170 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
347 db.intern_trait(loc) 171 db.intern_trait(loc)
348 } 172 }
349 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> { 173 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
350 db.lookup_intern_trait(self) 174 db.lookup_intern_trait(self)
351 } 175 }
352} 176}
@@ -355,10 +179,10 @@ impl AstItemDef<ast::TraitDef> for TraitId {
355pub struct TypeAliasId(salsa::InternId); 179pub struct TypeAliasId(salsa::InternId);
356impl_intern_key!(TypeAliasId); 180impl_intern_key!(TypeAliasId);
357impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { 181impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
358 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self { 182 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
359 db.intern_type_alias(loc) 183 db.intern_type_alias(loc)
360 } 184 }
361 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> { 185 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
362 db.lookup_intern_type_alias(self) 186 db.lookup_intern_type_alias(self)
363 } 187 }
364} 188}
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 33ef87563..1a5223680 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -20,7 +20,7 @@ use crate::{
20 resolve::Resolver, 20 resolve::Resolver,
21 ty::Ty, 21 ty::Ty,
22 type_ref::TypeRef, 22 type_ref::TypeRef,
23 AssocItem, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, 23 AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef,
24 TypeAlias, 24 TypeAlias,
25}; 25};
26 26
@@ -256,14 +256,14 @@ impl ModuleImplBlocks {
256 } 256 }
257 257
258 //FIXME: we should really cut down on the boilerplate required to process a macro 258 //FIXME: we should really cut down on the boilerplate required to process a macro
259 let ast_id = db.ast_id_map(file_id).ast_id(&macro_call).with_file_id(file_id); 259 let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(&macro_call));
260 if let Some(path) = macro_call 260 if let Some(path) = macro_call
261 .path() 261 .path()
262 .and_then(|path| Path::from_src(Source { ast: path, file_id }, db)) 262 .and_then(|path| Path::from_src(Source { ast: path, file_id }, db))
263 { 263 {
264 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) 264 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path)
265 { 265 {
266 let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); 266 let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id });
267 let file_id = call_id.as_file(MacroFileKind::Items); 267 let file_id = call_id.as_file(MacroFileKind::Items);
268 if let Some(item_list) = 268 if let Some(item_list) =
269 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) 269 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast)
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ca261e8f5..0f2d233bb 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -35,7 +35,6 @@ pub mod mock;
35mod path; 35mod path;
36pub mod source_binder; 36pub mod source_binder;
37 37
38mod source_id;
39mod ids; 38mod ids;
40mod name; 39mod name;
41mod nameres; 40mod nameres;
@@ -60,14 +59,14 @@ pub mod from_source;
60#[cfg(test)] 59#[cfg(test)]
61mod marks; 60mod marks;
62 61
63use crate::{ 62use hir_expand::{
64 ids::MacroFileKind, 63 ast_id_map::{AstIdMap, FileAstId},
65 name::AsName, 64 AstId,
66 resolve::Resolver,
67 source_id::{AstId, FileAstId},
68}; 65};
69 66
70pub use self::{ 67use crate::{ids::MacroFileKind, name::AsName, resolve::Resolver};
68
69pub use crate::{
71 adt::VariantDef, 70 adt::VariantDef,
72 either::Either, 71 either::Either,
73 expr::ExprScopes, 72 expr::ExprScopes,
@@ -80,7 +79,6 @@ pub use self::{
80 path::{Path, PathKind}, 79 path::{Path, PathKind},
81 resolve::ScopeDef, 80 resolve::ScopeDef,
82 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 81 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
83 source_id::{AstIdMap, ErasedFileAstId},
84 ty::{ 82 ty::{
85 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 83 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
86 }, 84 },
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index b5fe16bfa..dc591e8d3 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -448,7 +448,7 @@ where
448 ); 448 );
449 449
450 if let Some(def) = resolved_res.resolved_def.get_macros() { 450 if let Some(def) = resolved_res.resolved_def.get_macros() {
451 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); 451 let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id });
452 resolved.push((*module_id, call_id, def.id)); 452 resolved.push((*module_id, call_id, def.id));
453 res = ReachedFixedPoint::No; 453 res = ReachedFixedPoint::No;
454 return false; 454 return false;
@@ -567,7 +567,7 @@ where
567 // inline module, just recurse 567 // inline module, just recurse
568 raw::ModuleData::Definition { name, items, ast_id } => { 568 raw::ModuleData::Definition { name, items, ast_id } => {
569 let module_id = 569 let module_id =
570 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 570 self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None);
571 571
572 ModCollector { 572 ModCollector {
573 def_collector: &mut *self.def_collector, 573 def_collector: &mut *self.def_collector,
@@ -583,7 +583,7 @@ where
583 } 583 }
584 // out of line module, resolve, parse and recurse 584 // out of line module, resolve, parse and recurse
585 raw::ModuleData::Declaration { name, ast_id } => { 585 raw::ModuleData::Declaration { name, ast_id } => {
586 let ast_id = ast_id.with_file_id(self.file_id); 586 let ast_id = AstId::new(self.file_id, *ast_id);
587 match self.mod_dir.resolve_declaration( 587 match self.mod_dir.resolve_declaration(
588 self.def_collector.db, 588 self.def_collector.db,
589 self.file_id, 589 self.file_id,
@@ -671,28 +671,26 @@ where
671 } 671 }
672 672
673 fn collect_macro(&mut self, mac: &raw::MacroData) { 673 fn collect_macro(&mut self, mac: &raw::MacroData) {
674 let ast_id = AstId::new(self.file_id, mac.ast_id);
675
674 // Case 1: macro rules, define a macro in crate-global mutable scope 676 // Case 1: macro rules, define a macro in crate-global mutable scope
675 if is_macro_rules(&mac.path) { 677 if is_macro_rules(&mac.path) {
676 if let Some(name) = &mac.name { 678 if let Some(name) = &mac.name {
677 let macro_id = MacroDefId { 679 let macro_id =
678 ast_id: mac.ast_id.with_file_id(self.file_id), 680 MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id };
679 krate: self.def_collector.def_map.krate,
680 };
681 let macro_ = MacroDef { id: macro_id }; 681 let macro_ = MacroDef { id: macro_id };
682 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); 682 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
683 } 683 }
684 return; 684 return;
685 } 685 }
686 686
687 let ast_id = mac.ast_id.with_file_id(self.file_id);
688
689 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 687 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering
690 // recursive item collection. 688 // recursive item collection.
691 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 689 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
692 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 690 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
693 }) { 691 }) {
694 let def = macro_def.id; 692 let def = macro_def.id;
695 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); 693 let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id });
696 694
697 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); 695 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
698 return; 696 return;
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 394617e1a..bbe536bcb 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -66,7 +66,12 @@ impl Path {
66 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), 66 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
67 ) { 67 ) {
68 if let Some(tree) = item_src.ast.use_tree() { 68 if let Some(tree) = item_src.ast.use_tree() {
69 expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); 69 expand_use_tree(
70 None,
71 tree,
72 &|| item_src.file_id.macro_crate(db).map(|crate_id| Crate { crate_id }),
73 &mut cb,
74 );
70 } 75 }
71 } 76 }
72 77
@@ -90,7 +95,7 @@ impl Path {
90 /// It correctly handles `$crate` based path from macro call. 95 /// It correctly handles `$crate` based path from macro call.
91 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> { 96 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> {
92 let file_id = source.file_id; 97 let file_id = source.file_id;
93 Path::parse(source.ast, &|| file_id.macro_crate(db)) 98 Path::parse(source.ast, &|| file_id.macro_crate(db).map(|crate_id| Crate { crate_id }))
94 } 99 }
95 100
96 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> { 101 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> {
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index ad7c11a5a..e18c28cf6 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -66,13 +66,11 @@ impl ToChalk for Ty {
66 } 66 }
67 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 67 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
68 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 68 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
69 // FIXME this is clearly incorrect, but probably not too incorrect
70 // and I'm not sure what to actually do with Ty::Unknown
71 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
72 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed 69 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed
73 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { 70 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
74 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() } 71 let parameters = Vec::new();
75 .to_ty::<ChalkIr>() 72 let name = TypeName::Error;
73 chalk_ir::ApplicationTy { name, parameters }.cast()
76 } 74 }
77 } 75 }
78 } 76 }
@@ -92,6 +90,7 @@ impl ToChalk for Ty {
92 let parameters = from_chalk(db, apply_ty.parameters); 90 let parameters = from_chalk(db, apply_ty.parameters);
93 Ty::Apply(ApplicationTy { ctor, parameters }) 91 Ty::Apply(ApplicationTy { ctor, parameters })
94 } 92 }
93 TypeName::Error => Ty::Unknown,
95 // FIXME handle TypeKindId::Trait/Type here 94 // FIXME handle TypeKindId::Trait/Type here
96 TypeName::TypeKindId(_) => unimplemented!(), 95 TypeName::TypeKindId(_) => unimplemented!(),
97 TypeName::Placeholder(idx) => { 96 TypeName::Placeholder(idx) => {
@@ -323,9 +322,9 @@ where
323} 322}
324 323
325impl ToChalk for Arc<super::TraitEnvironment> { 324impl ToChalk for Arc<super::TraitEnvironment> {
326 type Chalk = Arc<chalk_ir::Environment<ChalkIr>>; 325 type Chalk = chalk_ir::Environment<ChalkIr>;
327 326
328 fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment<ChalkIr>> { 327 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<ChalkIr> {
329 let mut clauses = Vec::new(); 328 let mut clauses = Vec::new();
330 for pred in &self.predicates { 329 for pred in &self.predicates {
331 if pred.is_error() { 330 if pred.is_error() {
@@ -340,7 +339,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
340 339
341 fn from_chalk( 340 fn from_chalk(
342 _db: &impl HirDatabase, 341 _db: &impl HirDatabase,
343 _env: Arc<chalk_ir::Environment<ChalkIr>>, 342 _env: chalk_ir::Environment<ChalkIr>,
344 ) -> Arc<super::TraitEnvironment> { 343 ) -> Arc<super::TraitEnvironment> {
345 unimplemented!() 344 unimplemented!()
346 } 345 }
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
new file mode 100644
index 000000000..9bf5b7918
--- /dev/null
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -0,0 +1,15 @@
1[package]
2edition = "2018"
3name = "ra_hir_expand"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6
7[dependencies]
8log = "0.4.5"
9
10ra_arena = { path = "../ra_arena" }
11ra_db = { path = "../ra_db" }
12ra_syntax = { path = "../ra_syntax" }
13ra_prof = { path = "../ra_prof" }
14tt = { path = "../ra_tt", package = "ra_tt" }
15mbe = { path = "../ra_mbe", package = "ra_mbe" }
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index a4dd99598..cb464c3ff 100644
--- a/crates/ra_hir/src/source_id.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -1,58 +1,21 @@
1//! FIXME: write short doc here 1//! `AstIdMap` allows to create stable IDs for "large" syntax nodes like items
2//! and macro calls.
3//!
4//! Specifically, it enumerates all items in a file and uses position of a an
5//! item as an ID. That way, id's don't change unless the set of items itself
6//! changes.
2 7
3use std::{ 8use std::{
4 hash::{Hash, Hasher}, 9 hash::{Hash, Hasher},
5 marker::PhantomData, 10 marker::PhantomData,
6 sync::Arc,
7}; 11};
8 12
9use ra_arena::{impl_arena_id, Arena, RawId}; 13use ra_arena::{impl_arena_id, Arena, RawId};
10use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; 14use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
11
12use crate::{db::AstDatabase, HirFileId};
13
14/// `AstId` points to an AST node in any file.
15///
16/// It is stable across reparses, and can be used as salsa key/value.
17#[derive(Debug)]
18pub(crate) struct AstId<N: AstNode> {
19 file_id: HirFileId,
20 file_ast_id: FileAstId<N>,
21}
22
23impl<N: AstNode> Clone for AstId<N> {
24 fn clone(&self) -> AstId<N> {
25 *self
26 }
27}
28impl<N: AstNode> Copy for AstId<N> {}
29
30impl<N: AstNode> PartialEq for AstId<N> {
31 fn eq(&self, other: &Self) -> bool {
32 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
33 }
34}
35impl<N: AstNode> Eq for AstId<N> {}
36impl<N: AstNode> Hash for AstId<N> {
37 fn hash<H: Hasher>(&self, hasher: &mut H) {
38 (self.file_id, self.file_ast_id).hash(hasher);
39 }
40}
41
42impl<N: AstNode> AstId<N> {
43 pub(crate) fn file_id(&self) -> HirFileId {
44 self.file_id
45 }
46
47 pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N {
48 let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw);
49 N::cast(syntax_node).unwrap()
50 }
51}
52 15
53/// `AstId` points to an AST node in a specific file. 16/// `AstId` points to an AST node in a specific file.
54#[derive(Debug)] 17#[derive(Debug)]
55pub(crate) struct FileAstId<N: AstNode> { 18pub struct FileAstId<N: AstNode> {
56 raw: ErasedFileAstId, 19 raw: ErasedFileAstId,
57 _ty: PhantomData<fn() -> N>, 20 _ty: PhantomData<fn() -> N>,
58} 21}
@@ -76,14 +39,8 @@ impl<N: AstNode> Hash for FileAstId<N> {
76 } 39 }
77} 40}
78 41
79impl<N: AstNode> FileAstId<N> {
80 pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId<N> {
81 AstId { file_id, file_ast_id: self }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
86pub struct ErasedFileAstId(RawId); 43struct ErasedFileAstId(RawId);
87impl_arena_id!(ErasedFileAstId); 44impl_arena_id!(ErasedFileAstId);
88 45
89/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. 46/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
@@ -93,39 +50,7 @@ pub struct AstIdMap {
93} 50}
94 51
95impl AstIdMap { 52impl AstIdMap {
96 pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { 53 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
97 let map = if let Some(node) = db.parse_or_expand(file_id) {
98 AstIdMap::from_source(&node)
99 } else {
100 AstIdMap::default()
101 };
102 Arc::new(map)
103 }
104
105 pub(crate) fn file_item_query(
106 db: &impl AstDatabase,
107 file_id: HirFileId,
108 ast_id: ErasedFileAstId,
109 ) -> SyntaxNode {
110 let node = db.parse_or_expand(file_id).unwrap();
111 db.ast_id_map(file_id).arena[ast_id].to_node(&node)
112 }
113
114 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
115 let ptr = SyntaxNodePtr::new(item.syntax());
116 let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) {
117 Some((it, _)) => it,
118 None => panic!(
119 "Can't find {:?} in AstIdMap:\n{:?}",
120 item.syntax(),
121 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
122 ),
123 };
124
125 FileAstId { raw, _ty: PhantomData }
126 }
127
128 fn from_source(node: &SyntaxNode) -> AstIdMap {
129 assert!(node.parent().is_none()); 54 assert!(node.parent().is_none());
130 let mut res = AstIdMap { arena: Arena::default() }; 55 let mut res = AstIdMap { arena: Arena::default() };
131 // By walking the tree in bread-first order we make sure that parents 56 // By walking the tree in bread-first order we make sure that parents
@@ -142,6 +67,26 @@ impl AstIdMap {
142 res 67 res
143 } 68 }
144 69
70 pub fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
71 let raw = self.erased_ast_id(item.syntax());
72 FileAstId { raw, _ty: PhantomData }
73 }
74 fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
75 let ptr = SyntaxNodePtr::new(item);
76 match self.arena.iter().find(|(_id, i)| **i == ptr) {
77 Some((it, _)) => it,
78 None => panic!(
79 "Can't find {:?} in AstIdMap:\n{:?}",
80 item,
81 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
82 ),
83 }
84 }
85
86 pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
87 self.arena[id.raw].cast::<N>().unwrap()
88 }
89
145 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { 90 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
146 self.arena.alloc(SyntaxNodePtr::new(item)) 91 self.arena.alloc(SyntaxNodePtr::new(item))
147 } 92 }
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
new file mode 100644
index 000000000..a4ee9a529
--- /dev/null
+++ b/crates/ra_hir_expand/src/db.rs
@@ -0,0 +1,104 @@
1//! Defines database & queries for macro expansion.
2
3use std::sync::Arc;
4
5use mbe::MacroRules;
6use ra_db::{salsa, SourceDatabase};
7use ra_prof::profile;
8use ra_syntax::{AstNode, Parse, SyntaxNode};
9
10use crate::{
11 ast_id_map::AstIdMap, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId,
12 MacroFile, MacroFileKind,
13};
14
15// FIXME: rename to ExpandDatabase
16#[salsa::query_group(AstDatabaseStorage)]
17pub trait AstDatabase: SourceDatabase {
18 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
19
20 #[salsa::transparent]
21 fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
22
23 #[salsa::interned]
24 fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
25 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<tt::Subtree>>;
26 fn macro_def(&self, id: MacroDefId) -> Option<Arc<mbe::MacroRules>>;
27 fn parse_macro(&self, macro_file: MacroFile) -> Option<Parse<SyntaxNode>>;
28 fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>;
29}
30
31pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
32 let map =
33 db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
34 Arc::new(map)
35}
36
37pub(crate) fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
38 let macro_call = id.ast_id.to_node(db);
39 let arg = macro_call.token_tree()?;
40 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
41 log::warn!("fail on macro_def to token tree: {:#?}", arg);
42 None
43 })?;
44 let rules = MacroRules::parse(&tt).ok().or_else(|| {
45 log::warn!("fail on macro_def parse: {:#?}", tt);
46 None
47 })?;
48 Some(Arc::new(rules))
49}
50
51pub(crate) fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
52 let loc = db.lookup_intern_macro(id);
53 let macro_call = loc.ast_id.to_node(db);
54 let arg = macro_call.token_tree()?;
55 let (tt, _) = mbe::ast_to_token_tree(&arg)?;
56 Some(Arc::new(tt))
57}
58
59pub(crate) fn macro_expand(
60 db: &dyn AstDatabase,
61 id: MacroCallId,
62) -> Result<Arc<tt::Subtree>, String> {
63 let loc = db.lookup_intern_macro(id);
64 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
65
66 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
67 let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
68 // Set a hard limit for the expanded tt
69 let count = tt.count();
70 if count > 65536 {
71 return Err(format!("Total tokens count exceed limit : count = {}", count));
72 }
73 Ok(Arc::new(tt))
74}
75
76pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
77 match file_id.0 {
78 HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
79 HirFileIdRepr::MacroFile(macro_file) => {
80 db.parse_macro(macro_file).map(|it| it.syntax_node())
81 }
82 }
83}
84
85pub(crate) fn parse_macro(
86 db: &dyn AstDatabase,
87 macro_file: MacroFile,
88) -> Option<Parse<SyntaxNode>> {
89 let _p = profile("parse_macro_query");
90 let macro_call_id = macro_file.macro_call_id;
91 let tt = db
92 .macro_expand(macro_call_id)
93 .map_err(|err| {
94 // Note:
95 // The final goal we would like to make all parse_macro success,
96 // such that the following log will not call anyway.
97 log::warn!("fail on macro_parse: (reason: {})", err,);
98 })
99 .ok()?;
100 match macro_file.macro_file_kind {
101 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
102 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
103 }
104}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
new file mode 100644
index 000000000..6b3538673
--- /dev/null
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -0,0 +1,161 @@
1//! `ra_hir_expand` deals with macro expansion.
2//!
3//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
4//! tree originates not from the text of some `FileId`, but from some macro
5//! expansion.
6
7pub mod db;
8pub mod ast_id_map;
9
10use std::hash::{Hash, Hasher};
11
12use ra_db::{salsa, CrateId, FileId};
13use ra_syntax::ast::{self, AstNode};
14
15use crate::{ast_id_map::FileAstId, db::AstDatabase};
16
17/// Input to the analyzer is a set of files, where each file is identified by
18/// `FileId` and contains source code. However, another source of source code in
19/// Rust are macros: each macro can be thought of as producing a "temporary
20/// file". To assign an id to such a file, we use the id of the macro call that
21/// produced the file. So, a `HirFileId` is either a `FileId` (source code
22/// written by user), or a `MacroCallId` (source code produced by macro).
23///
24/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
25/// containing the call plus the offset of the macro call in the file. Note that
26/// this is a recursive definition! However, the size_of of `HirFileId` is
27/// finite (because everything bottoms out at the real `FileId`) and small
28/// (`MacroCallId` uses the location interner).
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub struct HirFileId(HirFileIdRepr);
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33enum HirFileIdRepr {
34 FileId(FileId),
35 MacroFile(MacroFile),
36}
37
38impl From<FileId> for HirFileId {
39 fn from(id: FileId) -> Self {
40 HirFileId(HirFileIdRepr::FileId(id))
41 }
42}
43
44impl From<MacroFile> for HirFileId {
45 fn from(id: MacroFile) -> Self {
46 HirFileId(HirFileIdRepr::MacroFile(id))
47 }
48}
49
50impl HirFileId {
51 /// For macro-expansion files, returns the file original source file the
52 /// expansion originated from.
53 pub fn original_file(self, db: &dyn AstDatabase) -> FileId {
54 match self.0 {
55 HirFileIdRepr::FileId(file_id) => file_id,
56 HirFileIdRepr::MacroFile(macro_file) => {
57 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
58 loc.ast_id.file_id().original_file(db)
59 }
60 }
61 }
62
63 /// Get the crate which the macro lives in, if it is a macro file.
64 pub fn macro_crate(self, db: &dyn AstDatabase) -> Option<CrateId> {
65 match self.0 {
66 HirFileIdRepr::FileId(_) => None,
67 HirFileIdRepr::MacroFile(macro_file) => {
68 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
69 Some(loc.def.krate)
70 }
71 }
72 }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub struct MacroFile {
77 macro_call_id: MacroCallId,
78 macro_file_kind: MacroFileKind,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
82pub enum MacroFileKind {
83 Items,
84 Expr,
85}
86
87/// `MacroCallId` identifies a particular macro invocation, like
88/// `println!("Hello, {}", world)`.
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
90pub struct MacroCallId(salsa::InternId);
91impl salsa::InternKey for MacroCallId {
92 fn from_intern_id(v: salsa::InternId) -> Self {
93 MacroCallId(v)
94 }
95 fn as_intern_id(&self) -> salsa::InternId {
96 self.0
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
101pub struct MacroDefId {
102 pub krate: CrateId,
103 pub ast_id: AstId<ast::MacroCall>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
107pub struct MacroCallLoc {
108 pub def: MacroDefId,
109 pub ast_id: AstId<ast::MacroCall>,
110}
111
112impl MacroCallId {
113 pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
114 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
115 macro_file.into()
116 }
117}
118
119/// `AstId` points to an AST node in any file.
120///
121/// It is stable across reparses, and can be used as salsa key/value.
122// FIXME: isn't this just a `Source<FileAstId<N>>` ?
123#[derive(Debug)]
124pub struct AstId<N: AstNode> {
125 file_id: HirFileId,
126 file_ast_id: FileAstId<N>,
127}
128
129impl<N: AstNode> Clone for AstId<N> {
130 fn clone(&self) -> AstId<N> {
131 *self
132 }
133}
134impl<N: AstNode> Copy for AstId<N> {}
135
136impl<N: AstNode> PartialEq for AstId<N> {
137 fn eq(&self, other: &Self) -> bool {
138 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
139 }
140}
141impl<N: AstNode> Eq for AstId<N> {}
142impl<N: AstNode> Hash for AstId<N> {
143 fn hash<H: Hasher>(&self, hasher: &mut H) {
144 (self.file_id, self.file_ast_id).hash(hasher);
145 }
146}
147
148impl<N: AstNode> AstId<N> {
149 pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
150 AstId { file_id, file_ast_id }
151 }
152
153 pub fn file_id(&self) -> HirFileId {
154 self.file_id
155 }
156
157 pub fn to_node(&self, db: &dyn AstDatabase) -> N {
158 let root = db.parse_or_expand(self.file_id).unwrap();
159 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
160 }
161}
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index f66f0a6ba..bf6ef12f3 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -27,10 +27,13 @@ ra_db = { path = "../ra_db" }
27ra_cfg = { path = "../ra_cfg" } 27ra_cfg = { path = "../ra_cfg" }
28ra_fmt = { path = "../ra_fmt" } 28ra_fmt = { path = "../ra_fmt" }
29ra_prof = { path = "../ra_prof" } 29ra_prof = { path = "../ra_prof" }
30hir = { path = "../ra_hir", package = "ra_hir" }
31test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils" }
32ra_assists = { path = "../ra_assists" } 31ra_assists = { path = "../ra_assists" }
33 32
33# ra_ide_api should depend only on the top-level `hir` package. if you need
34# something from some `hir_xxx` subpackage, reexport the API via `hir`.
35hir = { path = "../ra_hir", package = "ra_hir" }
36
34[dev-dependencies] 37[dev-dependencies]
35insta = "0.12.0" 38insta = "0.12.0"
36 39
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 7454005c4..4952bd189 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -56,7 +56,8 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
56 LIFETIME, 56 LIFETIME,
57 ASYNC_KW, 57 ASYNC_KW,
58 TRY_KW, 58 TRY_KW,
59 LOOP_KW 59 LOOP_KW,
60 FOR_KW,
60 ]); 61 ]);
61 62
62const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; 63const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
index 198daf7b4..0a93e11a5 100644
--- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
+++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
@@ -179,50 +179,47 @@ SOURCE_FILE@[0; 240)
179 ERROR@[148; 149) 179 ERROR@[148; 149)
180 PLUS@[148; 149) "+" 180 PLUS@[148; 149) "+"
181 WHITESPACE@[149; 150) " " 181 WHITESPACE@[149; 150) " "
182 EXPR_STMT@[150; 151) 182 EXPR_STMT@[150; 180)
183 PAREN_EXPR@[150; 151) 183 TUPLE_EXPR@[150; 180)
184 L_PAREN@[150; 151) "(" 184 L_PAREN@[150; 151) "("
185 EXPR_STMT@[151; 157) 185 BIN_EXPR@[151; 180)
186 FOR_EXPR@[151; 157) 186 BIN_EXPR@[151; 178)
187 FOR_KW@[151; 154) "for" 187 BIN_EXPR@[151; 169)
188 ERROR@[154; 155) 188 BIN_EXPR@[151; 167)
189 L_ANGLE@[154; 155) "<" 189 BIN_EXPR@[151; 164)
190 ERROR@[155; 157) 190 FOR_EXPR@[151; 157)
191 LIFETIME@[155; 157) "\'a" 191 FOR_KW@[151; 154) "for"
192 EXPR_STMT@[157; 158) 192 ERROR@[154; 155)
193 ERROR@[157; 158) 193 L_ANGLE@[154; 155) "<"
194 R_ANGLE@[157; 158) ">" 194 ERROR@[155; 157)
195 WHITESPACE@[158; 159) " " 195 LIFETIME@[155; 157) "\'a"
196 EXPR_STMT@[159; 180) 196 R_ANGLE@[157; 158) ">"
197 BIN_EXPR@[159; 180) 197 WHITESPACE@[158; 159) " "
198 BIN_EXPR@[159; 178) 198 PATH_EXPR@[159; 164)
199 BIN_EXPR@[159; 169) 199 PATH@[159; 164)
200 BIN_EXPR@[159; 167) 200 PATH_SEGMENT@[159; 164)
201 PATH_EXPR@[159; 164) 201 NAME_REF@[159; 164)
202 PATH@[159; 164) 202 IDENT@[159; 164) "Trait"
203 PATH_SEGMENT@[159; 164) 203 L_ANGLE@[164; 165) "<"
204 NAME_REF@[159; 164) 204 ERROR@[165; 167)
205 IDENT@[159; 164) "Trait" 205 LIFETIME@[165; 167) "\'a"
206 L_ANGLE@[164; 165) "<" 206 R_ANGLE@[167; 168) ">"
207 ERROR@[165; 167) 207 ERROR@[168; 169)
208 LIFETIME@[165; 167) "\'a" 208 R_PAREN@[168; 169) ")"
209 R_ANGLE@[167; 168) ">" 209 WHITESPACE@[169; 170) " "
210 ERROR@[168; 169) 210 PLUS@[170; 171) "+"
211 R_PAREN@[168; 169) ")" 211 WHITESPACE@[171; 172) " "
212 WHITESPACE@[169; 170) " " 212 PAREN_EXPR@[172; 178)
213 PLUS@[170; 171) "+" 213 L_PAREN@[172; 173) "("
214 WHITESPACE@[171; 172) " " 214 PATH_EXPR@[173; 177)
215 PAREN_EXPR@[172; 178) 215 PATH@[173; 177)
216 L_PAREN@[172; 173) "(" 216 PATH_SEGMENT@[173; 177)
217 PATH_EXPR@[173; 177) 217 NAME_REF@[173; 177)
218 PATH@[173; 177) 218 IDENT@[173; 177) "Copy"
219 PATH_SEGMENT@[173; 177) 219 R_PAREN@[177; 178) ")"
220 NAME_REF@[173; 177) 220 R_ANGLE@[178; 179) ">"
221 IDENT@[173; 177) "Copy" 221 ERROR@[179; 180)
222 R_PAREN@[177; 178) ")" 222 SEMI@[179; 180) ";"
223 R_ANGLE@[178; 179) ">"
224 ERROR@[179; 180)
225 SEMI@[179; 180) ";"
226 WHITESPACE@[180; 185) "\n " 223 WHITESPACE@[180; 185) "\n "
227 LET_STMT@[185; 235) 224 LET_STMT@[185; 235)
228 LET_KW@[185; 188) "let" 225 LET_KW@[185; 188) "let"
@@ -307,18 +304,16 @@ error 146: expected expression
307error 147: expected SEMI 304error 147: expected SEMI
308error 148: expected expression 305error 148: expected expression
309error 149: expected SEMI 306error 149: expected SEMI
310error 151: expected expression
311error 151: expected R_PAREN
312error 151: expected SEMI
313error 154: expected pattern 307error 154: expected pattern
314error 155: expected IN_KW 308error 155: expected IN_KW
315error 155: expected expression 309error 155: expected expression
316error 157: expected a block 310error 157: expected a block
317error 157: expected expression
318error 158: expected SEMI
319error 165: expected expression 311error 165: expected expression
320error 168: expected expression 312error 168: expected expression
321error 179: expected expression 313error 179: expected expression
314error 180: expected COMMA
315error 180: expected expression
316error 180: expected R_PAREN
322error 180: expected SEMI 317error 180: expected SEMI
323error 215: expected COMMA 318error 215: expected COMMA
324error 215: expected R_ANGLE 319error 215: expected R_ANGLE
diff --git a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs
new file mode 100644
index 000000000..6e8b718aa
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs
@@ -0,0 +1,5 @@
1fn main() {
2 Some(for _ in [1].into_iter() {});
3 Some(loop { break; });
4 Some(while true {});
5}
diff --git a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt
new file mode 100644
index 000000000..c011187ea
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt
@@ -0,0 +1,101 @@
1SOURCE_FILE@[0; 105)
2 FN_DEF@[0; 104)
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; 104)
12 BLOCK@[10; 104)
13 L_CURLY@[10; 11) "{"
14 WHITESPACE@[11; 16) "\n "
15 EXPR_STMT@[16; 50)
16 CALL_EXPR@[16; 49)
17 PATH_EXPR@[16; 20)
18 PATH@[16; 20)
19 PATH_SEGMENT@[16; 20)
20 NAME_REF@[16; 20)
21 IDENT@[16; 20) "Some"
22 ARG_LIST@[20; 49)
23 L_PAREN@[20; 21) "("
24 FOR_EXPR@[21; 48)
25 FOR_KW@[21; 24) "for"
26 WHITESPACE@[24; 25) " "
27 PLACEHOLDER_PAT@[25; 26)
28 UNDERSCORE@[25; 26) "_"
29 WHITESPACE@[26; 27) " "
30 IN_KW@[27; 29) "in"
31 WHITESPACE@[29; 30) " "
32 METHOD_CALL_EXPR@[30; 45)
33 ARRAY_EXPR@[30; 33)
34 L_BRACK@[30; 31) "["
35 LITERAL@[31; 32)
36 INT_NUMBER@[31; 32) "1"
37 R_BRACK@[32; 33) "]"
38 DOT@[33; 34) "."
39 NAME_REF@[34; 43)
40 IDENT@[34; 43) "into_iter"
41 ARG_LIST@[43; 45)
42 L_PAREN@[43; 44) "("
43 R_PAREN@[44; 45) ")"
44 WHITESPACE@[45; 46) " "
45 BLOCK_EXPR@[46; 48)
46 BLOCK@[46; 48)
47 L_CURLY@[46; 47) "{"
48 R_CURLY@[47; 48) "}"
49 R_PAREN@[48; 49) ")"
50 SEMI@[49; 50) ";"
51 WHITESPACE@[50; 55) "\n "
52 EXPR_STMT@[55; 77)
53 CALL_EXPR@[55; 76)
54 PATH_EXPR@[55; 59)
55 PATH@[55; 59)
56 PATH_SEGMENT@[55; 59)
57 NAME_REF@[55; 59)
58 IDENT@[55; 59) "Some"
59 ARG_LIST@[59; 76)
60 L_PAREN@[59; 60) "("
61 LOOP_EXPR@[60; 75)
62 LOOP_KW@[60; 64) "loop"
63 WHITESPACE@[64; 65) " "
64 BLOCK_EXPR@[65; 75)
65 BLOCK@[65; 75)
66 L_CURLY@[65; 66) "{"
67 WHITESPACE@[66; 67) " "
68 EXPR_STMT@[67; 73)
69 BREAK_EXPR@[67; 72)
70 BREAK_KW@[67; 72) "break"
71 SEMI@[72; 73) ";"
72 WHITESPACE@[73; 74) " "
73 R_CURLY@[74; 75) "}"
74 R_PAREN@[75; 76) ")"
75 SEMI@[76; 77) ";"
76 WHITESPACE@[77; 82) "\n "
77 EXPR_STMT@[82; 102)
78 CALL_EXPR@[82; 101)
79 PATH_EXPR@[82; 86)
80 PATH@[82; 86)
81 PATH_SEGMENT@[82; 86)
82 NAME_REF@[82; 86)
83 IDENT@[82; 86) "Some"
84 ARG_LIST@[86; 101)
85 L_PAREN@[86; 87) "("
86 WHILE_EXPR@[87; 100)
87 WHILE_KW@[87; 92) "while"
88 WHITESPACE@[92; 93) " "
89 CONDITION@[93; 97)
90 LITERAL@[93; 97)
91 TRUE_KW@[93; 97) "true"
92 WHITESPACE@[97; 98) " "
93 BLOCK_EXPR@[98; 100)
94 BLOCK@[98; 100)
95 L_CURLY@[98; 99) "{"
96 R_CURLY@[99; 100) "}"
97 R_PAREN@[100; 101) ")"
98 SEMI@[101; 102) ";"
99 WHITESPACE@[102; 103) "\n"
100 R_CURLY@[103; 104) "}"
101 WHITESPACE@[104; 105) "\n"