aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-18 01:27:53 +0000
committerSeivan Heidari <[email protected]>2019-11-18 01:27:53 +0000
commit166636ba77adcf5bf2c4ef935e9aa75e20f25e10 (patch)
tree168be1ca55c73b016e20586c08417c608450c92c /crates
parentcb26df950699586b314731fb70786e0db8eaa049 (diff)
parent28c2d74b2150102a8756a5357a5a965d7610bd15 (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_arena/Cargo.toml3
-rw-r--r--crates/ra_assists/Cargo.toml4
-rw-r--r--crates/ra_assists/src/assist_ctx.rs10
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs2
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs3
-rw-r--r--crates/ra_assists/src/assists/add_new.rs69
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs3
-rw-r--r--crates/ra_assists/src/assists/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs59
-rw-r--r--crates/ra_batch/Cargo.toml3
-rw-r--r--crates/ra_cfg/Cargo.toml3
-rw-r--r--crates/ra_cli/src/analysis_stats.rs4
-rw-r--r--crates/ra_db/Cargo.toml3
-rw-r--r--crates/ra_fmt/Cargo.toml3
-rw-r--r--crates/ra_hir/Cargo.toml9
-rw-r--r--crates/ra_hir/src/code_model.rs25
-rw-r--r--crates/ra_hir/src/db.rs50
-rw-r--r--crates/ra_hir/src/from_id.rs15
-rw-r--r--crates/ra_hir/src/from_source.rs38
-rw-r--r--crates/ra_hir/src/ids.rs6
-rw-r--r--crates/ra_hir/src/impl_block.rs260
-rw-r--r--crates/ra_hir/src/lang_item.rs2
-rw-r--r--crates/ra_hir/src/lib.rs6
-rw-r--r--crates/ra_hir/src/resolve.rs5
-rw-r--r--crates/ra_hir/src/source_binder.rs119
-rw-r--r--crates/ra_hir/src/ty.rs93
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs22
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs86
-rw-r--r--crates/ra_hir/src/ty/tests.rs72
-rw-r--r--crates/ra_hir/src/ty/traits.rs29
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs325
-rw-r--r--crates/ra_hir_def/Cargo.toml3
-rw-r--r--crates/ra_hir_def/src/db.rs23
-rw-r--r--crates/ra_hir_def/src/imp.rs71
-rw-r--r--crates/ra_hir_def/src/lib.rs36
-rw-r--r--crates/ra_hir_def/src/nameres.rs9
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs13
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs29
-rw-r--r--crates/ra_hir_expand/Cargo.toml3
-rw-r--r--crates/ra_hir_expand/src/db.rs13
-rw-r--r--crates/ra_hir_expand/src/lib.rs70
-rw-r--r--crates/ra_ide_api/Cargo.toml3
-rw-r--r--crates/ra_ide_api/src/call_info.rs6
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs7
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs115
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs3
-rw-r--r--crates/ra_ide_api/src/hover.rs8
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs7
-rw-r--r--crates/ra_ide_api/src/references.rs20
-rw-r--r--crates/ra_ide_api/src/references/classify.rs46
-rw-r--r--crates/ra_ide_api/src/runnables.rs6
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs5
-rw-r--r--crates/ra_lsp_server/Cargo.toml3
-rw-r--r--crates/ra_mbe/Cargo.toml4
-rw-r--r--crates/ra_mbe/src/lib.rs106
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs15
-rw-r--r--crates/ra_parser/Cargo.toml3
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs51
-rw-r--r--crates/ra_prof/Cargo.toml3
-rw-r--r--crates/ra_project_model/Cargo.toml3
-rw-r--r--crates/ra_syntax/Cargo.toml3
-rw-r--r--crates/ra_syntax/src/ast.rs2
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs46
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs95
-rw-r--r--crates/ra_syntax/src/lib.rs6
-rw-r--r--crates/ra_syntax/src/syntax_error.rs4
-rw-r--r--crates/ra_syntax/src/validation.rs10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt30
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0060_as_range.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0060_as_range.txt56
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt27
-rw-r--r--crates/ra_text_edit/Cargo.toml3
-rw-r--r--crates/ra_tt/Cargo.toml3
-rw-r--r--crates/ra_vfs_glob/Cargo.toml3
-rw-r--r--crates/test_utils/Cargo.toml3
-rw-r--r--crates/test_utils/src/marks.rs4
79 files changed, 1459 insertions, 869 deletions
diff --git a/crates/ra_arena/Cargo.toml b/crates/ra_arena/Cargo.toml
index 9328c1f50..d287dbb73 100644
--- a/crates/ra_arena/Cargo.toml
+++ b/crates/ra_arena/Cargo.toml
@@ -3,3 +3,6 @@ edition = "2018"
3name = "ra_arena" 3name = "ra_arena"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6
7[lib]
8doctest = false
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index beebccbd9..434e6656c 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -4,11 +4,13 @@ name = "ra_assists"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8format-buf = "1.0.0" 11format-buf = "1.0.0"
9join_to_string = "0.1.3" 12join_to_string = "0.1.3"
10itertools = "0.8.0" 13itertools = "0.8.0"
11rustc_lexer = "0.1.0"
12 14
13ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
14ra_text_edit = { path = "../ra_text_edit" } 16ra_text_edit = { path = "../ra_text_edit" }
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 2use hir::{db::HirDatabase, SourceAnalyzer};
3use hir::db::HirDatabase;
4use ra_db::FileRange; 3use ra_db::FileRange;
5use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
6use ra_syntax::{ 5use 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)]
188mod tests { 191mod 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 {<|>}
345impl Foo { 349impl 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 {<|>}
357impl Foo { 361impl 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;
376struct Foo<'a, T: Foo<'a>> {}", 380struct 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##"
389pub struct AstId<N: AstNode> {
390 file_id: HirFileId,
391 file_ast_id: FileAstId<N>,
392}
393
394impl<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
400pub struct Source<T> {
401 pub file_id: HirFileId,<|>
402 pub ast: T,
403}
404
405impl<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##"
412pub struct AstId<N: AstNode> {
413 file_id: HirFileId,
414 file_ast_id: FileAstId<N>,
415}
416
417impl<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
423pub struct Source<T> {
424 pub file_id: HirFileId,
425 pub ast: T,
426}
427
428impl<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_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 58f7157ae..93912a470 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -1,9 +1,9 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast, AstToken,
3 SyntaxKind::{RAW_STRING, STRING}, 4 SyntaxKind::{RAW_STRING, STRING},
4 TextRange, TextUnit, 5 TextUnit,
5}; 6};
6use rustc_lexer;
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9 9
@@ -23,32 +23,16 @@ use crate::{Assist, AssistCtx, AssistId};
23// } 23// }
24// ``` 24// ```
25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let token = ctx.find_token_at_offset(STRING)?; 26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
27 let text = token.text().as_str(); 27 let value = token.value()?;
28 let usual_string_range = find_usual_string_range(text)?;
29 let start_of_inside = usual_string_range.start().to_usize() + 1;
30 let end_of_inside = usual_string_range.end().to_usize();
31 let inside_str = &text[start_of_inside..end_of_inside];
32 let mut unescaped = String::with_capacity(inside_str.len());
33 let mut error = Ok(());
34 rustc_lexer::unescape::unescape_str(
35 inside_str,
36 &mut |_, unescaped_char| match unescaped_char {
37 Ok(c) => unescaped.push(c),
38 Err(_) => error = Err(()),
39 },
40 );
41 if error.is_err() {
42 return None;
43 }
44 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { 28 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| {
45 edit.target(token.text_range()); 29 edit.target(token.syntax().text_range());
46 let max_hash_streak = count_hashes(&unescaped); 30 let max_hash_streak = count_hashes(&value);
47 let mut hashes = String::with_capacity(max_hash_streak + 1); 31 let mut hashes = String::with_capacity(max_hash_streak + 1);
48 for _ in 0..hashes.capacity() { 32 for _ in 0..hashes.capacity() {
49 hashes.push('#'); 33 hashes.push('#');
50 } 34 }
51 edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes)); 35 edit.replace(token.syntax().text_range(), format!("r{}\"{}\"{}", hashes, value, hashes));
52 }) 36 })
53} 37}
54 38
@@ -68,17 +52,13 @@ pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
68// } 52// }
69// ``` 53// ```
70pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 54pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
71 let token = ctx.find_token_at_offset(RAW_STRING)?; 55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
72 let text = token.text().as_str(); 56 let value = token.value()?;
73 let usual_string_range = find_usual_string_range(text)?;
74 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { 57 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| {
75 edit.target(token.text_range()); 58 edit.target(token.syntax().text_range());
76 // parse inside string to escape `"` 59 // parse inside string to escape `"`
77 let start_of_inside = usual_string_range.start().to_usize() + 1; 60 let escaped = value.escape_default().to_string();
78 let end_of_inside = usual_string_range.end().to_usize(); 61 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
79 let inside_str = &text[start_of_inside..end_of_inside];
80 let escaped = inside_str.escape_default().to_string();
81 edit.replace(token.text_range(), format!("\"{}\"", escaped));
82 }) 62 })
83} 63}
84 64
@@ -132,6 +112,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
132 edit.target(token.text_range()); 112 edit.target(token.text_range());
133 let result = &text[2..text.len() - 1]; 113 let result = &text[2..text.len() - 1];
134 let result = if result.starts_with('\"') { 114 let result = if result.starts_with('\"') {
115 // FIXME: this logic is wrong, not only the last has has to handled specially
135 // no more hash, escape 116 // no more hash, escape
136 let internal_str = &result[1..result.len() - 1]; 117 let internal_str = &result[1..result.len() - 1];
137 format!("\"{}\"", internal_str.escape_default().to_string()) 118 format!("\"{}\"", internal_str.escape_default().to_string())
@@ -154,20 +135,6 @@ fn count_hashes(s: &str) -> usize {
154 max_hash_streak 135 max_hash_streak
155} 136}
156 137
157fn find_usual_string_range(s: &str) -> Option<TextRange> {
158 let left_quote = s.find('"')?;
159 let right_quote = s.rfind('"')?;
160 if left_quote == right_quote {
161 // `s` only contains one quote
162 None
163 } else {
164 Some(TextRange::from_to(
165 TextUnit::from(left_quote as u32),
166 TextUnit::from(right_quote as u32),
167 ))
168 }
169}
170
171#[cfg(test)] 138#[cfg(test)]
172mod test { 139mod test {
173 use super::*; 140 use super::*;
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml
index d08c5ceac..35626d77d 100644
--- a/crates/ra_batch/Cargo.toml
+++ b/crates/ra_batch/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_batch"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8log = "0.4.5" 11log = "0.4.5"
9rustc-hash = "1.0" 12rustc-hash = "1.0"
diff --git a/crates/ra_cfg/Cargo.toml b/crates/ra_cfg/Cargo.toml
index b28affc3a..dd5ff88b0 100644
--- a/crates/ra_cfg/Cargo.toml
+++ b/crates/ra_cfg/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_cfg"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8rustc-hash = "1.0.1" 11rustc-hash = "1.0.1"
9 12
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 04aba3743..3429a3c49 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -169,12 +169,12 @@ pub fn run(
169 println!( 169 println!(
170 "Expressions of unknown type: {} ({}%)", 170 "Expressions of unknown type: {} ({}%)",
171 num_exprs_unknown, 171 num_exprs_unknown,
172 (num_exprs_unknown * 100 / num_exprs) 172 if num_exprs > 0 { (num_exprs_unknown * 100 / num_exprs) } else { 100 }
173 ); 173 );
174 println!( 174 println!(
175 "Expressions of partially unknown type: {} ({}%)", 175 "Expressions of partially unknown type: {} ({}%)",
176 num_exprs_partially_unknown, 176 num_exprs_partially_unknown,
177 (num_exprs_partially_unknown * 100 / num_exprs) 177 if num_exprs > 0 { (num_exprs_partially_unknown * 100 / num_exprs) } else { 100 }
178 ); 178 );
179 println!("Type mismatches: {}", num_type_mismatches); 179 println!("Type mismatches: {}", num_type_mismatches);
180 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage()); 180 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index bf1f7920c..4ec09b6d9 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_db"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8salsa = "0.13.0" 11salsa = "0.13.0"
9relative-path = "1.0.0" 12relative-path = "1.0.0"
diff --git a/crates/ra_fmt/Cargo.toml b/crates/ra_fmt/Cargo.toml
index ba7b3ceac..9969d4746 100644
--- a/crates/ra_fmt/Cargo.toml
+++ b/crates/ra_fmt/Cargo.toml
@@ -5,6 +5,9 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[lib]
9doctest = false
10
8[dependencies] 11[dependencies]
9itertools = "0.8.0" 12itertools = "0.8.0"
10 13
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 324961328..42ddfecc9 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_hir"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8arrayvec = "0.5.1" 11arrayvec = "0.5.1"
9log = "0.4.5" 12log = "0.4.5"
@@ -23,9 +26,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
23test_utils = { path = "../test_utils" } 26test_utils = { path = "../test_utils" }
24ra_prof = { path = "../ra_prof" } 27ra_prof = { path = "../ra_prof" }
25 28
26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 29chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 30chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 31chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
29lalrpop-intern = "0.15.1" 32lalrpop-intern = "0.15.1"
30 33
31[dev-dependencies] 34[dev-dependencies]
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};
16use hir_expand::{ 16use 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)]
1134pub 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..d75d71d66 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -10,22 +10,23 @@ 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::{
17 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, 16 method_resolution::CrateImplBlocks,
18 InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, 17 traits::{AssocTyValue, Impl},
18 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
19 TypeCtor,
19 }, 20 },
20 type_alias::TypeAliasData, 21 type_alias::TypeAliasData,
21 Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait, 22 Const, ConstData, Crate, DefWithBody, FnData, Function, ImplBlock, Module, Static, StructField,
22 TypeAlias, 23 Trait, TypeAlias,
23}; 24};
24 25
25pub use hir_def::db::{ 26pub use hir_def::db::{
26 BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, 27 BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage,
27 EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, 28 EnumDataQuery, ExprScopesQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
28 RawItemsWithSourceMapQuery, StructDataQuery, 29 RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
29}; 30};
30pub use hir_expand::db::{ 31pub use hir_expand::db::{
31 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 32 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@@ -42,15 +43,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
42 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] 43 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
43 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; 44 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
44 45
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)] 46 #[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
55 fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; 47 fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;
56 48
@@ -128,27 +120,43 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
128 #[salsa::interned] 120 #[salsa::interned]
129 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; 121 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
130 #[salsa::interned] 122 #[salsa::interned]
131 fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; 123 fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId;
124 #[salsa::interned]
125 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> ids::AssocTyValueId;
132 126
133 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] 127 #[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>; 128 fn associated_ty_data(
129 &self,
130 id: chalk_ir::TypeId,
131 ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;
135 132
136 #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)] 133 #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)]
137 fn trait_datum( 134 fn trait_datum(
138 &self, 135 &self,
139 krate: Crate, 136 krate: Crate,
140 trait_id: chalk_ir::TraitId, 137 trait_id: chalk_ir::TraitId,
141 ) -> Arc<chalk_rust_ir::TraitDatum>; 138 ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;
142 139
143 #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)] 140 #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)]
144 fn struct_datum( 141 fn struct_datum(
145 &self, 142 &self,
146 krate: Crate, 143 krate: Crate,
147 struct_id: chalk_ir::StructId, 144 struct_id: chalk_ir::StructId,
148 ) -> Arc<chalk_rust_ir::StructDatum>; 145 ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;
149 146
150 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)] 147 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
151 fn impl_datum(&self, krate: Crate, impl_id: chalk_ir::ImplId) -> Arc<chalk_rust_ir::ImplDatum>; 148 fn impl_datum(
149 &self,
150 krate: Crate,
151 impl_id: chalk_ir::ImplId,
152 ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;
153
154 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_value_query)]
155 fn associated_ty_value(
156 &self,
157 krate: Crate,
158 id: chalk_rust_ir::AssociatedTyValueId,
159 ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>;
152 160
153 #[salsa::invoke(crate::ty::traits::trait_solve_query)] 161 #[salsa::invoke(crate::ty::traits::trait_solve_query)]
154 fn trait_solve( 162 fn trait_solve(
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
6use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; 6use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId};
7 7
8use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; 8use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef};
9 9
10macro_rules! from_id { 10macro_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
76impl 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
3use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; 3use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId};
4use hir_expand::name::AsName; 4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
5use ra_syntax::{ 5use 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
18pub trait FromSource: Sized { 18pub 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
81impl 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
82impl FromSource for ImplBlock { 97impl 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/ids.rs b/crates/ra_hir/src/ids.rs
index fe083c0c6..2b59365fb 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -37,3 +37,9 @@ impl_intern_key!(TypeCtorId);
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct GlobalImplId(salsa::InternId); 38pub struct GlobalImplId(salsa::InternId);
39impl_intern_key!(GlobalImplId); 39impl_intern_key!(GlobalImplId);
40
41/// This exists just for Chalk, because it needs a unique ID for each associated
42/// type value in an impl (even synthetic ones).
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct AssocTyValueId(salsa::InternId);
45impl_intern_key!(AssocTyValueId);
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
3use rustc_hash::FxHashMap; 3use hir_def::{type_ref::TypeRef, AstItemDef};
4use std::sync::Arc; 4use ra_syntax::ast::{self};
5
6use hir_def::{attr::Attr, type_ref::TypeRef};
7use hir_expand::hygiene::Hygiene;
8use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
9use ra_cfg::CfgOptions;
10use ra_syntax::{
11 ast::{self, AstNode},
12 AstPtr,
13};
14 5
15use crate::{ 6use 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)]
28pub struct ImplSourceMap {
29 map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>,
30}
31
32impl 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)]
46pub struct ImplBlock {
47 module: Module,
48 impl_id: ImplId,
49}
50
51impl HasSource for ImplBlock { 14impl 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
59impl ImplBlock { 21impl 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)]
116pub struct ImplData {
117 target_trait: Option<TypeRef>,
118 target_type: TypeRef,
119 items: Vec<AssocItem>,
120 negative: bool,
121}
122
123impl 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)]
163pub struct ImplId(pub RawId);
164impl_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)]
172pub struct ModuleImplBlocks {
173 pub(crate) module: Module,
174 pub(crate) impls: Arena<ImplId, ImplData>,
175 impls_by_def: FxHashMap<AssocItem, ImplId>,
176}
177
178impl 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(&macro_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(&macro_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)]
55mod marks; 55mod marks;
56 56
57use hir_expand::AstId; 57use crate::resolve::Resolver;
58
59use crate::{ids::MacroFileKind, resolve::Resolver};
60 58
61pub use crate::{ 59pub 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..f0ed8e2b2 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -11,13 +11,12 @@ use hir_def::{
11 expr::{ExprId, PatId}, 11 expr::{ExprId, PatId},
12 path::known, 12 path::known,
13}; 13};
14use hir_expand::{name::AsName, Source}; 14use hir_expand::{name::AsName, AstId, MacroCallId, MacroCallLoc, MacroFileKind, Source};
15use ra_db::FileId;
16use ra_syntax::{ 15use ra_syntax::{
17 ast::{self, AstNode}, 16 ast::{self, AstNode},
18 match_ast, AstPtr, 17 match_ast, AstPtr,
19 SyntaxKind::*, 18 SyntaxKind::*,
20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 19 SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
21}; 20};
22 21
23use crate::{ 22use crate::{
@@ -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
33fn try_get_resolver_for_node( 32fn 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
69fn def_with_body_from_child_node( 62fn 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)]
93pub struct SourceAnalyzer { 85pub 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>>,
@@ -135,20 +126,38 @@ pub struct ReferenceDescriptor {
135 pub name: String, 126 pub name: String,
136} 127}
137 128
129pub struct Expansion {
130 macro_call_id: MacroCallId,
131}
132
133impl Expansion {
134 pub fn map_token_down(
135 &self,
136 db: &impl HirDatabase,
137 token: Source<&SyntaxToken>,
138 ) -> Option<Source<SyntaxToken>> {
139 let exp_info = self.file_id().expansion_info(db)?;
140 exp_info.map_token_down(token)
141 }
142
143 fn file_id(&self) -> HirFileId {
144 self.macro_call_id.as_file(MacroFileKind::Items)
145 }
146}
147
138impl SourceAnalyzer { 148impl SourceAnalyzer {
139 pub fn new( 149 pub fn new(
140 db: &impl HirDatabase, 150 db: &impl HirDatabase,
141 file_id: FileId, 151 node: Source<&SyntaxNode>,
142 node: &SyntaxNode,
143 offset: Option<TextUnit>, 152 offset: Option<TextUnit>,
144 ) -> SourceAnalyzer { 153 ) -> SourceAnalyzer {
145 let def_with_body = def_with_body_from_child_node(db, file_id, node); 154 let def_with_body = def_with_body_from_child_node(db, node);
146 if let Some(def) = def_with_body { 155 if let Some(def) = def_with_body {
147 let source_map = def.body_source_map(db); 156 let source_map = def.body_source_map(db);
148 let scopes = def.expr_scopes(db); 157 let scopes = def.expr_scopes(db);
149 let scope = match offset { 158 let scope = match offset {
150 None => scope_for(&scopes, &source_map, file_id.into(), &node), 159 None => scope_for(&scopes, &source_map, node),
151 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), 160 Some(offset) => scope_for_offset(&scopes, &source_map, node.with_ast(offset)),
152 }; 161 };
153 let resolver = expr::resolver_for_scope(db, def, scope); 162 let resolver = expr::resolver_for_scope(db, def, scope);
154 SourceAnalyzer { 163 SourceAnalyzer {
@@ -157,30 +166,31 @@ impl SourceAnalyzer {
157 body_source_map: Some(source_map), 166 body_source_map: Some(source_map),
158 infer: Some(def.infer(db)), 167 infer: Some(def.infer(db)),
159 scopes: Some(scopes), 168 scopes: Some(scopes),
160 file_id, 169 file_id: node.file_id,
161 } 170 }
162 } else { 171 } else {
163 SourceAnalyzer { 172 SourceAnalyzer {
164 resolver: node 173 resolver: node
174 .ast
165 .ancestors() 175 .ancestors()
166 .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) 176 .find_map(|it| try_get_resolver_for_node(db, node.with_ast(&it)))
167 .unwrap_or_default(), 177 .unwrap_or_default(),
168 body_owner: None, 178 body_owner: None,
169 body_source_map: None, 179 body_source_map: None,
170 infer: None, 180 infer: None,
171 scopes: None, 181 scopes: None,
172 file_id, 182 file_id: node.file_id,
173 } 183 }
174 } 184 }
175 } 185 }
176 186
177 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { 187 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
178 let src = Source { file_id: self.file_id.into(), ast: expr }; 188 let src = Source { file_id: self.file_id, ast: expr };
179 self.body_source_map.as_ref()?.node_expr(src) 189 self.body_source_map.as_ref()?.node_expr(src)
180 } 190 }
181 191
182 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 192 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
183 let src = Source { file_id: self.file_id.into(), ast: pat }; 193 let src = Source { file_id: self.file_id, ast: pat };
184 self.body_source_map.as_ref()?.node_pat(src) 194 self.body_source_map.as_ref()?.node_pat(src)
185 } 195 }
186 196
@@ -288,7 +298,7 @@ impl SourceAnalyzer {
288 let name = name_ref.as_name(); 298 let name = name_ref.as_name();
289 let source_map = self.body_source_map.as_ref()?; 299 let source_map = self.body_source_map.as_ref()?;
290 let scopes = self.scopes.as_ref()?; 300 let scopes = self.scopes.as_ref()?;
291 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; 301 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)?; 302 let entry = scopes.resolve_name_in_scope(scope, &name)?;
293 Some(ScopeEntryWithSyntax { 303 Some(ScopeEntryWithSyntax {
294 name: entry.name().clone(), 304 name: entry.name().clone(),
@@ -395,6 +405,13 @@ impl SourceAnalyzer {
395 implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) 405 implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait)
396 } 406 }
397 407
408 pub fn expand(&self, db: &impl HirDatabase, macro_call: &ast::MacroCall) -> Option<Expansion> {
409 let def = self.resolve_macro_call(db, macro_call)?.id;
410 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(macro_call));
411 let macro_call_loc = MacroCallLoc { def, ast_id };
412 Some(Expansion { macro_call_id: db.intern_macro(macro_call_loc) })
413 }
414
398 #[cfg(test)] 415 #[cfg(test)]
399 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { 416 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> {
400 self.body_source_map.clone().unwrap() 417 self.body_source_map.clone().unwrap()
@@ -409,20 +426,19 @@ impl SourceAnalyzer {
409fn scope_for( 426fn scope_for(
410 scopes: &ExprScopes, 427 scopes: &ExprScopes,
411 source_map: &BodySourceMap, 428 source_map: &BodySourceMap,
412 file_id: HirFileId, 429 node: Source<&SyntaxNode>,
413 node: &SyntaxNode,
414) -> Option<ScopeId> { 430) -> Option<ScopeId> {
415 node.ancestors() 431 node.ast
432 .ancestors()
416 .filter_map(ast::Expr::cast) 433 .filter_map(ast::Expr::cast)
417 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) 434 .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it)))
418 .find_map(|it| scopes.scope_for(it)) 435 .find_map(|it| scopes.scope_for(it))
419} 436}
420 437
421fn scope_for_offset( 438fn scope_for_offset(
422 scopes: &ExprScopes, 439 scopes: &ExprScopes,
423 source_map: &BodySourceMap, 440 source_map: &BodySourceMap,
424 file_id: HirFileId, 441 offset: Source<TextUnit>,
425 offset: TextUnit,
426) -> Option<ScopeId> { 442) -> Option<ScopeId> {
427 scopes 443 scopes
428 .scope_by_expr() 444 .scope_by_expr()
@@ -430,7 +446,7 @@ fn scope_for_offset(
430 .filter_map(|(id, scope)| { 446 .filter_map(|(id, scope)| {
431 let source = source_map.expr_syntax(*id)?; 447 let source = source_map.expr_syntax(*id)?;
432 // FIXME: correctly handle macro expansion 448 // FIXME: correctly handle macro expansion
433 if source.file_id != file_id { 449 if source.file_id != offset.file_id {
434 return None; 450 return None;
435 } 451 }
436 let syntax_node_ptr = 452 let syntax_node_ptr =
@@ -439,9 +455,14 @@ fn scope_for_offset(
439 }) 455 })
440 // find containing scope 456 // find containing scope
441 .min_by_key(|(ptr, _scope)| { 457 .min_by_key(|(ptr, _scope)| {
442 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 458 (
459 !(ptr.range().start() <= offset.ast && offset.ast <= ptr.range().end()),
460 ptr.range().len(),
461 )
462 })
463 .map(|(ptr, scope)| {
464 adjust(scopes, source_map, ptr, offset.file_id, offset.ast).unwrap_or(*scope)
443 }) 465 })
444 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
445} 466}
446 467
447// XXX: during completion, cursor might be outside of any particular 468// XXX: during completion, cursor might be outside of any particular
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index ff6030ac4..b7f50b714 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -79,7 +79,7 @@ pub enum TypeCtor {
79 /// 79 ///
80 /// For example the type of `bar` here: 80 /// For example the type of `bar` here:
81 /// 81 ///
82 /// ```rust 82 /// ```
83 /// fn foo() -> i32 { 1 } 83 /// fn foo() -> i32 { 1 }
84 /// let bar = foo; // bar: fn() -> i32 {foo} 84 /// let bar = foo; // bar: fn() -> i32 {foo}
85 /// ``` 85 /// ```
@@ -89,7 +89,7 @@ pub enum TypeCtor {
89 /// 89 ///
90 /// For example the type of `bar` here: 90 /// For example the type of `bar` here:
91 /// 91 ///
92 /// ```rust 92 /// ```
93 /// fn foo() -> i32 { 1 } 93 /// fn foo() -> i32 { 1 }
94 /// let bar: fn() -> i32 = foo; 94 /// let bar: fn() -> i32 = foo;
95 /// ``` 95 /// ```
@@ -224,8 +224,8 @@ impl TypeWalk for ProjectionTy {
224 self.parameters.walk(f); 224 self.parameters.walk(f);
225 } 225 }
226 226
227 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 227 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
228 self.parameters.walk_mut(f); 228 self.parameters.walk_mut_binders(f, binders);
229 } 229 }
230} 230}
231 231
@@ -291,6 +291,20 @@ pub enum Ty {
291#[derive(Clone, PartialEq, Eq, Debug, Hash)] 291#[derive(Clone, PartialEq, Eq, Debug, Hash)]
292pub struct Substs(Arc<[Ty]>); 292pub struct Substs(Arc<[Ty]>);
293 293
294impl TypeWalk for Substs {
295 fn walk(&self, f: &mut impl FnMut(&Ty)) {
296 for t in self.0.iter() {
297 t.walk(f);
298 }
299 }
300
301 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
302 for t in make_mut_slice(&mut self.0) {
303 t.walk_mut_binders(f, binders);
304 }
305 }
306}
307
294impl Substs { 308impl Substs {
295 pub fn empty() -> Substs { 309 pub fn empty() -> Substs {
296 Substs(Arc::new([])) 310 Substs(Arc::new([]))
@@ -304,18 +318,6 @@ impl Substs {
304 Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) 318 Substs(self.0[..std::cmp::min(self.0.len(), n)].into())
305 } 319 }
306 320
307 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
308 for t in self.0.iter() {
309 t.walk(f);
310 }
311 }
312
313 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
314 for t in make_mut_slice(&mut self.0) {
315 t.walk_mut(f);
316 }
317 }
318
319 pub fn as_single(&self) -> &Ty { 321 pub fn as_single(&self) -> &Ty {
320 if self.0.len() != 1 { 322 if self.0.len() != 1 {
321 panic!("expected substs of len 1, got {:?}", self); 323 panic!("expected substs of len 1, got {:?}", self);
@@ -440,8 +442,8 @@ impl TypeWalk for TraitRef {
440 self.substs.walk(f); 442 self.substs.walk(f);
441 } 443 }
442 444
443 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 445 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
444 self.substs.walk_mut(f); 446 self.substs.walk_mut_binders(f, binders);
445 } 447 }
446} 448}
447 449
@@ -491,10 +493,12 @@ impl TypeWalk for GenericPredicate {
491 } 493 }
492 } 494 }
493 495
494 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 496 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
495 match self { 497 match self {
496 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 498 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
497 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), 499 GenericPredicate::Projection(projection_pred) => {
500 projection_pred.walk_mut_binders(f, binders)
501 }
498 GenericPredicate::Error => {} 502 GenericPredicate::Error => {}
499 } 503 }
500 } 504 }
@@ -544,9 +548,9 @@ impl TypeWalk for FnSig {
544 } 548 }
545 } 549 }
546 550
547 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 551 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
548 for t in make_mut_slice(&mut self.params_and_return) { 552 for t in make_mut_slice(&mut self.params_and_return) {
549 t.walk_mut(f); 553 t.walk_mut_binders(f, binders);
550 } 554 }
551 } 555 }
552} 556}
@@ -671,7 +675,20 @@ impl Ty {
671/// types, similar to Chalk's `Fold` trait. 675/// types, similar to Chalk's `Fold` trait.
672pub trait TypeWalk { 676pub trait TypeWalk {
673 fn walk(&self, f: &mut impl FnMut(&Ty)); 677 fn walk(&self, f: &mut impl FnMut(&Ty));
674 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); 678 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
679 self.walk_mut_binders(&mut |ty, _binders| f(ty), 0);
680 }
681 /// Walk the type, counting entered binders.
682 ///
683 /// `Ty::Bound` variables use DeBruijn indexing, which means that 0 refers
684 /// to the innermost binder, 1 to the next, etc.. So when we want to
685 /// substitute a certain bound variable, we can't just walk the whole type
686 /// and blindly replace each instance of a certain index; when we 'enter'
687 /// things that introduce new bound variables, we have to keep track of
688 /// that. Currently, the only thing that introduces bound variables on our
689 /// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound
690 /// variable for the self type.
691 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize);
675 692
676 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self 693 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
677 where 694 where
@@ -700,14 +717,22 @@ pub trait TypeWalk {
700 } 717 }
701 718
702 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 719 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
703 fn subst_bound_vars(self, substs: &Substs) -> Self 720 fn subst_bound_vars(mut self, substs: &Substs) -> Self
704 where 721 where
705 Self: Sized, 722 Self: Sized,
706 { 723 {
707 self.fold(&mut |ty| match ty { 724 self.walk_mut_binders(
708 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 725 &mut |ty, binders| match ty {
709 ty => ty, 726 &mut Ty::Bound(idx) => {
710 }) 727 if idx as usize >= binders && (idx as usize - binders) < substs.len() {
728 *ty = substs.0[idx as usize - binders].clone();
729 }
730 }
731 _ => {}
732 },
733 0,
734 );
735 self
711 } 736 }
712 737
713 /// Shifts up `Ty::Bound` vars by `n`. 738 /// Shifts up `Ty::Bound` vars by `n`.
@@ -748,22 +773,22 @@ impl TypeWalk for Ty {
748 f(self); 773 f(self);
749 } 774 }
750 775
751 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 776 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
752 match self { 777 match self {
753 Ty::Apply(a_ty) => { 778 Ty::Apply(a_ty) => {
754 a_ty.parameters.walk_mut(f); 779 a_ty.parameters.walk_mut_binders(f, binders);
755 } 780 }
756 Ty::Projection(p_ty) => { 781 Ty::Projection(p_ty) => {
757 p_ty.parameters.walk_mut(f); 782 p_ty.parameters.walk_mut_binders(f, binders);
758 } 783 }
759 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 784 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
760 for p in make_mut_slice(predicates) { 785 for p in make_mut_slice(predicates) {
761 p.walk_mut(f); 786 p.walk_mut_binders(f, binders + 1);
762 } 787 }
763 } 788 }
764 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 789 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
765 } 790 }
766 f(self); 791 f(self, binders);
767 } 792 }
768} 793}
769 794
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index ca33cc7f8..64d9394cf 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -134,17 +134,19 @@ where
134} 134}
135 135
136impl<T> Canonicalized<T> { 136impl<T> Canonicalized<T> {
137 pub fn decanonicalize_ty(&self, ty: Ty) -> Ty { 137 pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty {
138 ty.fold(&mut |ty| match ty { 138 ty.walk_mut_binders(
139 Ty::Bound(idx) => { 139 &mut |ty, binders| match ty {
140 if (idx as usize) < self.free_vars.len() { 140 &mut Ty::Bound(idx) => {
141 Ty::Infer(self.free_vars[idx as usize]) 141 if idx as usize >= binders && (idx as usize - binders) < self.free_vars.len() {
142 } else { 142 *ty = Ty::Infer(self.free_vars[idx as usize - binders]);
143 Ty::Bound(idx) 143 }
144 } 144 }
145 } 145 _ => {}
146 ty => ty, 146 },
147 }) 147 0,
148 );
149 ty
148 } 150 }
149 151
150 pub fn apply_solution( 152 pub fn apply_solution(
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index eb5ca6769..d20aeaacf 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -5,16 +5,14 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::CrateModuleId;
9use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
10 9
11use crate::{ 10use 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
20use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; 18use 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)]
41pub struct CrateImplBlocks { 39pub 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
48impl CrateImplBlocks { 44impl 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
126fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { 90fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
@@ -264,14 +228,10 @@ fn iterate_trait_method_candidates<T>(
264 'traits: for t in traits { 228 'traits: for t in traits {
265 let data = t.trait_data(db); 229 let data = t.trait_data(db);
266 230
267 // FIXME this is a bit of a hack, since Chalk should say the same thing
268 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
269 let inherently_implemented = ty.value.inherent_trait() == Some(t);
270
271 // we'll be lazy about checking whether the type implements the 231 // we'll be lazy about checking whether the type implements the
272 // trait, but if we find out it doesn't, we'll skip the rest of the 232 // trait, but if we find out it doesn't, we'll skip the rest of the
273 // iteration 233 // iteration
274 let mut known_implemented = inherently_implemented; 234 let mut known_implemented = false;
275 for &item in data.items() { 235 for &item in data.items() {
276 if !is_valid_candidate(db, name, mode, item) { 236 if !is_valid_candidate(db, name, mode, item) {
277 continue; 237 continue;
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index fe9346c78..ca1693679 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,3 +1,6 @@
1mod never_type;
2mod coercion;
3
1use std::fmt::Write; 4use std::fmt::Write;
2use std::sync::Arc; 5use std::sync::Arc;
3 6
@@ -11,7 +14,7 @@ use ra_syntax::{
11use test_utils::covers; 14use test_utils::covers;
12 15
13use crate::{ 16use 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
22mod never_type;
23mod coercion;
24
25#[test] 25#[test]
26fn cfg_impl_block() { 26fn cfg_impl_block() {
27 let (db, pos) = TestDB::with_position( 27 let (db, pos) = TestDB::with_position(
@@ -3983,11 +3983,11 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
3983 [180; 183) 'bar': fn bar() -> impl Trait<u64> 3983 [180; 183) 'bar': fn bar() -> impl Trait<u64>
3984 [180; 185) 'bar()': impl Trait<u64> 3984 [180; 185) 'bar()': impl Trait<u64>
3985 [191; 192) 'x': impl Trait<u64> 3985 [191; 192) 'x': impl Trait<u64>
3986 [191; 198) 'x.foo()': {unknown} 3986 [191; 198) 'x.foo()': u64
3987 [204; 205) 'y': &impl Trait<u64> 3987 [204; 205) 'y': &impl Trait<u64>
3988 [204; 211) 'y.foo()': {unknown} 3988 [204; 211) 'y.foo()': u64
3989 [217; 218) 'z': impl Trait<u64> 3989 [217; 218) 'z': impl Trait<u64>
3990 [217; 224) 'z.foo()': {unknown} 3990 [217; 224) 'z.foo()': u64
3991 [230; 231) 'x': impl Trait<u64> 3991 [230; 231) 'x': impl Trait<u64>
3992 [230; 238) 'x.foo2()': i64 3992 [230; 238) 'x.foo2()': i64
3993 [244; 245) 'y': &impl Trait<u64> 3993 [244; 245) 'y': &impl Trait<u64>
@@ -4033,11 +4033,11 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
4033 [177; 180) 'bar': fn bar() -> dyn Trait<u64> 4033 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
4034 [177; 182) 'bar()': dyn Trait<u64> 4034 [177; 182) 'bar()': dyn Trait<u64>
4035 [188; 189) 'x': dyn Trait<u64> 4035 [188; 189) 'x': dyn Trait<u64>
4036 [188; 195) 'x.foo()': {unknown} 4036 [188; 195) 'x.foo()': u64
4037 [201; 202) 'y': &dyn Trait<u64> 4037 [201; 202) 'y': &dyn Trait<u64>
4038 [201; 208) 'y.foo()': {unknown} 4038 [201; 208) 'y.foo()': u64
4039 [214; 215) 'z': dyn Trait<u64> 4039 [214; 215) 'z': dyn Trait<u64>
4040 [214; 221) 'z.foo()': {unknown} 4040 [214; 221) 'z.foo()': u64
4041 [227; 228) 'x': dyn Trait<u64> 4041 [227; 228) 'x': dyn Trait<u64>
4042 [227; 235) 'x.foo2()': i64 4042 [227; 235) 'x.foo2()': i64
4043 [241; 242) 'y': &dyn Trait<u64> 4043 [241; 242) 'y': &dyn Trait<u64>
@@ -4185,6 +4185,49 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
4185} 4185}
4186 4186
4187#[test] 4187#[test]
4188fn impl_trait_assoc_binding_projection_bug() {
4189 let (db, pos) = TestDB::with_position(
4190 r#"
4191//- /main.rs crate:main deps:std
4192pub trait Language {
4193 type Kind;
4194}
4195pub enum RustLanguage {}
4196impl Language for RustLanguage {
4197 type Kind = SyntaxKind;
4198}
4199struct SyntaxNode<L> {}
4200fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
4201
4202trait Clone {
4203 fn clone(&self) -> Self;
4204}
4205
4206fn api_walkthrough() {
4207 for node in foo() {
4208 node.clone()<|>;
4209 }
4210}
4211
4212//- /std.rs crate:std
4213#[prelude_import] use iter::*;
4214mod iter {
4215 trait IntoIterator {
4216 type Item;
4217 }
4218 trait Iterator {
4219 type Item;
4220 }
4221 impl<T: Iterator> IntoIterator for T {
4222 type Item = <T as Iterator>::Item;
4223 }
4224}
4225"#,
4226 );
4227 assert_eq!("{unknown}", type_at_pos(&db, pos));
4228}
4229
4230#[test]
4188fn projection_eq_within_chalk() { 4231fn projection_eq_within_chalk() {
4189 // std::env::set_var("CHALK_DEBUG", "1"); 4232 // std::env::set_var("CHALK_DEBUG", "1");
4190 assert_snapshot!( 4233 assert_snapshot!(
@@ -4609,7 +4652,8 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
4609fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 4652fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
4610 let file = db.parse(pos.file_id).ok().unwrap(); 4653 let file = db.parse(pos.file_id).ok().unwrap();
4611 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 4654 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)); 4655 let analyzer =
4656 SourceAnalyzer::new(db, Source::new(pos.file_id.into(), expr.syntax()), Some(pos.offset));
4613 let ty = analyzer.type_of(db, &expr).unwrap(); 4657 let ty = analyzer.type_of(db, &expr).unwrap();
4614 ty.display(db).to_string() 4658 ty.display(db).to_string()
4615} 4659}
@@ -4674,7 +4718,7 @@ fn infer(content: &str) -> String {
4674 4718
4675 for node in source_file.syntax().descendants() { 4719 for node in source_file.syntax().descendants() {
4676 if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { 4720 if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF {
4677 let analyzer = SourceAnalyzer::new(&db, file_id, &node, None); 4721 let analyzer = SourceAnalyzer::new(&db, Source::new(file_id.into(), &node), None);
4678 infer_def(analyzer.inference_result(), analyzer.body_source_map()); 4722 infer_def(analyzer.inference_result(), analyzer.body_source_map());
4679 } 4723 }
4680 } 4724 }
@@ -4715,7 +4759,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
4715 let file = db.parse(pos.file_id).ok().unwrap(); 4759 let file = db.parse(pos.file_id).ok().unwrap();
4716 let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); 4760 let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent();
4717 let events = db.log_executed(|| { 4761 let events = db.log_executed(|| {
4718 SourceAnalyzer::new(&db, pos.file_id, &node, None); 4762 SourceAnalyzer::new(&db, Source::new(pos.file_id.into(), &node), None);
4719 }); 4763 });
4720 assert!(format!("{:?}", events).contains("infer")) 4764 assert!(format!("{:?}", events).contains("infer"))
4721 } 4765 }
@@ -4735,7 +4779,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
4735 let file = db.parse(pos.file_id).ok().unwrap(); 4779 let file = db.parse(pos.file_id).ok().unwrap();
4736 let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent(); 4780 let node = file.syntax().token_at_offset(pos.offset).right_biased().unwrap().parent();
4737 let events = db.log_executed(|| { 4781 let events = db.log_executed(|| {
4738 SourceAnalyzer::new(&db, pos.file_id, &node, None); 4782 SourceAnalyzer::new(&db, Source::new(pos.file_id.into(), &node), None);
4739 }); 4783 });
4740 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) 4784 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
4741 } 4785 }
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 4f1eab150..45f725438 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -8,7 +8,7 @@ use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 10use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
11use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait}; 11use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait, TypeAlias};
12 12
13use self::chalk::{from_chalk, ToChalk}; 13use self::chalk::{from_chalk, ToChalk};
14 14
@@ -17,7 +17,7 @@ pub(crate) mod chalk;
17#[derive(Debug, Clone)] 17#[derive(Debug, Clone)]
18pub struct TraitSolver { 18pub struct TraitSolver {
19 krate: Crate, 19 krate: Crate,
20 inner: Arc<Mutex<chalk_solve::Solver>>, 20 inner: Arc<Mutex<chalk_solve::Solver<ChalkIr>>>,
21} 21}
22 22
23/// We need eq for salsa 23/// We need eq for salsa
@@ -34,7 +34,7 @@ impl TraitSolver {
34 &self, 34 &self,
35 db: &impl HirDatabase, 35 db: &impl HirDatabase,
36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>, 36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>,
37 ) -> Option<chalk_solve::Solution> { 37 ) -> Option<chalk_solve::Solution<ChalkIr>> {
38 let context = ChalkContext { db, krate: self.krate }; 38 let context = ChalkContext { db, krate: self.krate };
39 debug!("solve goal: {:?}", goal); 39 debug!("solve goal: {:?}", goal);
40 let mut solver = match self.inner.lock() { 40 let mut solver = match self.inner.lock() {
@@ -165,9 +165,9 @@ impl TypeWalk for ProjectionPredicate {
165 self.ty.walk(f); 165 self.ty.walk(f);
166 } 166 }
167 167
168 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 168 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
169 self.projection_ty.walk_mut(f); 169 self.projection_ty.walk_mut_binders(f, binders);
170 self.ty.walk_mut(f); 170 self.ty.walk_mut_binders(f, binders);
171 } 171 }
172} 172}
173 173
@@ -188,6 +188,7 @@ pub(crate) fn trait_solve_query(
188 } 188 }
189 189
190 let canonical = goal.to_chalk(db).cast(); 190 let canonical = goal.to_chalk(db).cast();
191
191 // We currently don't deal with universes (I think / hope they're not yet 192 // We currently don't deal with universes (I think / hope they're not yet
192 // relevant for our use cases?) 193 // relevant for our use cases?)
193 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 194 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
@@ -195,7 +196,10 @@ pub(crate) fn trait_solve_query(
195 solution.map(|solution| solution_from_chalk(db, solution)) 196 solution.map(|solution| solution_from_chalk(db, solution))
196} 197}
197 198
198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { 199fn solution_from_chalk(
200 db: &impl HirDatabase,
201 solution: chalk_solve::Solution<ChalkIr>,
202) -> Solution {
199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| { 203 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| {
200 let value = subst 204 let value = subst
201 .value 205 .value
@@ -300,3 +304,14 @@ pub enum Impl {
300 /// Closure types implement the Fn traits synthetically. 304 /// Closure types implement the Fn traits synthetically.
301 ClosureFnTraitImpl(ClosureFnTraitImplData), 305 ClosureFnTraitImpl(ClosureFnTraitImplData),
302} 306}
307
308/// An associated type value. Usually this comes from a `type` declaration
309/// inside an impl block, but for built-in impls we have to synthesize it.
310/// (We only need this because Chalk wants a unique ID for each of these.)
311#[derive(Debug, Clone, PartialEq, Eq, Hash)]
312pub enum AssocTyValue {
313 /// A normal assoc type value from an impl block.
314 TypeAlias(TypeAlias),
315 /// The output type of the Fn trait implementation.
316 ClosureFnTraitImplOutput(ClosureFnTraitImplData),
317}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 75351c17d..9bf93981a 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -7,22 +7,19 @@ use chalk_ir::{
7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, 7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId,
8 TypeKindId, TypeName, UniverseIndex, 8 TypeKindId, TypeName, UniverseIndex,
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_expand::name; 12use hir_expand::name;
13 13
14use ra_db::salsa::{InternId, InternKey}; 14use ra_db::salsa::{InternId, InternKey};
15 15
16use super::{Canonical, ChalkContext, Impl, Obligation}; 16use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 generics::{GenericDef, HasGenericParams}, 19 generics::{GenericDef, HasGenericParams},
20 ty::display::HirDisplay, 20 ty::display::HirDisplay,
21 ty::{ 21 ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk},
22 ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 22 Crate, HasBody, ImplBlock, Trait, TypeAlias,
23 TypeWalk,
24 },
25 AssocItem, Crate, HasBody, ImplBlock, Trait, TypeAlias,
26}; 23};
27 24
28/// This represents a trait whose name we could not resolve. 25/// This represents a trait whose name we could not resolve.
@@ -59,29 +56,36 @@ impl ToChalk for Ty {
59 } 56 }
60 }; 57 };
61 let parameters = apply_ty.parameters.to_chalk(db); 58 let parameters = apply_ty.parameters.to_chalk(db);
62 chalk_ir::ApplicationTy { name, parameters }.cast() 59 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
63 } 60 }
64 Ty::Projection(proj_ty) => { 61 Ty::Projection(proj_ty) => {
65 let associated_ty_id = proj_ty.associated_ty.to_chalk(db); 62 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
66 let parameters = proj_ty.parameters.to_chalk(db); 63 let parameters = proj_ty.parameters.to_chalk(db);
67 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() 64 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern()
68 } 65 }
69 Ty::Param { idx, .. } => { 66 Ty::Param { idx, .. } => {
70 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>() 67 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>()
71 } 68 }
72 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 69 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(),
73 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 70 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
74 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed 71 Ty::Dyn(predicates) => {
75 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { 72 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect();
73 chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern()
74 }
75 Ty::Opaque(predicates) => {
76 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect();
77 chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern()
78 }
79 Ty::Unknown => {
76 let parameters = Vec::new(); 80 let parameters = Vec::new();
77 let name = TypeName::Error; 81 let name = TypeName::Error;
78 chalk_ir::ApplicationTy { name, parameters }.cast() 82 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
79 } 83 }
80 } 84 }
81 } 85 }
82 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self { 86 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self {
83 match chalk { 87 match chalk.data().clone() {
84 chalk_ir::Ty::Apply(apply_ty) => { 88 chalk_ir::TyData::Apply(apply_ty) => {
85 // FIXME this is kind of hacky due to the fact that 89 // FIXME this is kind of hacky due to the fact that
86 // TypeName::Placeholder is a Ty::Param on our side 90 // TypeName::Placeholder is a Ty::Param on our side
87 match apply_ty.name { 91 match apply_ty.name {
@@ -104,21 +108,21 @@ impl ToChalk for Ty {
104 } 108 }
105 } 109 }
106 } 110 }
107 chalk_ir::Ty::Projection(proj) => { 111 chalk_ir::TyData::Projection(proj) => {
108 let associated_ty = from_chalk(db, proj.associated_ty_id); 112 let associated_ty = from_chalk(db, proj.associated_ty_id);
109 let parameters = from_chalk(db, proj.parameters); 113 let parameters = from_chalk(db, proj.parameters);
110 Ty::Projection(ProjectionTy { associated_ty, parameters }) 114 Ty::Projection(ProjectionTy { associated_ty, parameters })
111 } 115 }
112 chalk_ir::Ty::ForAll(_) => unimplemented!(), 116 chalk_ir::TyData::ForAll(_) => unimplemented!(),
113 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 117 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32),
114 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, 118 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
115 chalk_ir::Ty::Dyn(where_clauses) => { 119 chalk_ir::TyData::Dyn(where_clauses) => {
116 assert_eq!(where_clauses.binders.len(), 1); 120 assert_eq!(where_clauses.binders.len(), 1);
117 let predicates = 121 let predicates =
118 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 122 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
119 Ty::Dyn(predicates) 123 Ty::Dyn(predicates)
120 } 124 }
121 chalk_ir::Ty::Opaque(where_clauses) => { 125 chalk_ir::TyData::Opaque(where_clauses) => {
122 assert_eq!(where_clauses.binders.len(), 1); 126 assert_eq!(where_clauses.binders.len(), 1);
123 let predicates = 127 let predicates =
124 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 128 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
@@ -191,11 +195,11 @@ impl ToChalk for Impl {
191 type Chalk = chalk_ir::ImplId; 195 type Chalk = chalk_ir::ImplId;
192 196
193 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { 197 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
194 db.intern_impl(self).into() 198 db.intern_chalk_impl(self).into()
195 } 199 }
196 200
197 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { 201 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl {
198 db.lookup_intern_impl(impl_id.into()) 202 db.lookup_intern_chalk_impl(impl_id.into())
199 } 203 }
200} 204}
201 205
@@ -211,6 +215,21 @@ impl ToChalk for TypeAlias {
211 } 215 }
212} 216}
213 217
218impl ToChalk for AssocTyValue {
219 type Chalk = chalk_rust_ir::AssociatedTyValueId;
220
221 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId {
222 db.intern_assoc_ty_value(self).into()
223 }
224
225 fn from_chalk(
226 db: &impl HirDatabase,
227 assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId,
228 ) -> AssocTyValue {
229 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
230 }
231}
232
214impl ToChalk for GenericPredicate { 233impl ToChalk for GenericPredicate {
215 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>; 234 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>;
216 235
@@ -399,20 +418,20 @@ fn convert_where_clauses(
399 result 418 result
400} 419}
401 420
402impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 421impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB>
403where 422where
404 DB: HirDatabase, 423 DB: HirDatabase,
405{ 424{
406 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum> { 425 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum<ChalkIr>> {
407 self.db.associated_ty_data(id) 426 self.db.associated_ty_data(id)
408 } 427 }
409 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { 428 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum<ChalkIr>> {
410 self.db.trait_datum(self.krate, trait_id) 429 self.db.trait_datum(self.krate, trait_id)
411 } 430 }
412 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { 431 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum<ChalkIr>> {
413 self.db.struct_datum(self.krate, struct_id) 432 self.db.struct_datum(self.krate, struct_id)
414 } 433 }
415 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { 434 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum<ChalkIr>> {
416 self.db.impl_datum(self.krate, impl_id) 435 self.db.impl_datum(self.krate, impl_id)
417 } 436 }
418 fn impls_for_trait( 437 fn impls_for_trait(
@@ -462,13 +481,11 @@ where
462 fn type_name(&self, _id: TypeKindId) -> Identifier { 481 fn type_name(&self, _id: TypeKindId) -> Identifier {
463 unimplemented!() 482 unimplemented!()
464 } 483 }
465 fn split_projection<'p>( 484 fn associated_ty_value(
466 &self, 485 &self,
467 projection: &'p chalk_ir::ProjectionTy<ChalkIr>, 486 id: chalk_rust_ir::AssociatedTyValueId,
468 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter<ChalkIr>], &'p [Parameter<ChalkIr>]) { 487 ) -> Arc<AssociatedTyValue<ChalkIr>> {
469 debug!("split_projection {:?}", projection); 488 self.db.associated_ty_value(self.krate, id)
470 // we don't support GATs, so I think this should always be correct currently
471 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[])
472 } 489 }
473 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> { 490 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> {
474 vec![] 491 vec![]
@@ -485,7 +502,7 @@ where
485pub(crate) fn associated_ty_data_query( 502pub(crate) fn associated_ty_data_query(
486 db: &impl HirDatabase, 503 db: &impl HirDatabase,
487 id: TypeId, 504 id: TypeId,
488) -> Arc<AssociatedTyDatum> { 505) -> Arc<AssociatedTyDatum<ChalkIr>> {
489 debug!("associated_ty_data {:?}", id); 506 debug!("associated_ty_data {:?}", id);
490 let type_alias: TypeAlias = from_chalk(db, id); 507 let type_alias: TypeAlias = from_chalk(db, id);
491 let trait_ = match type_alias.container(db) { 508 let trait_ = match type_alias.container(db) {
@@ -493,19 +510,16 @@ pub(crate) fn associated_ty_data_query(
493 _ => panic!("associated type not in trait"), 510 _ => panic!("associated type not in trait"),
494 }; 511 };
495 let generic_params = type_alias.generic_params(db); 512 let generic_params = type_alias.generic_params(db);
496 let parameter_kinds = generic_params 513 let bound_data = chalk_rust_ir::AssociatedTyDatumBound {
497 .params_including_parent() 514 // FIXME add bounds and where clauses
498 .into_iter() 515 bounds: vec![],
499 .map(|p| chalk_ir::ParameterKind::Ty(lalrpop_intern::intern(&p.name.to_string()))) 516 where_clauses: vec![],
500 .collect(); 517 };
501 let datum = AssociatedTyDatum { 518 let datum = AssociatedTyDatum {
502 trait_id: trait_.to_chalk(db), 519 trait_id: trait_.to_chalk(db),
503 id, 520 id,
504 name: lalrpop_intern::intern(&type_alias.name(db).to_string()), 521 name: lalrpop_intern::intern(&type_alias.name(db).to_string()),
505 parameter_kinds, 522 binders: make_binders(bound_data, generic_params.count_params_including_parent()),
506 // FIXME add bounds and where clauses
507 bounds: vec![],
508 where_clauses: vec![],
509 }; 523 };
510 Arc::new(datum) 524 Arc::new(datum)
511} 525}
@@ -514,17 +528,10 @@ pub(crate) fn trait_datum_query(
514 db: &impl HirDatabase, 528 db: &impl HirDatabase,
515 krate: Crate, 529 krate: Crate,
516 trait_id: chalk_ir::TraitId, 530 trait_id: chalk_ir::TraitId,
517) -> Arc<TraitDatum> { 531) -> Arc<TraitDatum<ChalkIr>> {
518 debug!("trait_datum {:?}", trait_id); 532 debug!("trait_datum {:?}", trait_id);
519 if trait_id == UNKNOWN_TRAIT { 533 if trait_id == UNKNOWN_TRAIT {
520 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { 534 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() };
521 trait_ref: chalk_ir::TraitRef {
522 trait_id: UNKNOWN_TRAIT,
523 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
524 },
525 associated_ty_ids: Vec::new(),
526 where_clauses: Vec::new(),
527 };
528 535
529 let flags = chalk_rust_ir::TraitFlags { 536 let flags = chalk_rust_ir::TraitFlags {
530 auto: false, 537 auto: false,
@@ -532,18 +539,24 @@ pub(crate) fn trait_datum_query(
532 upstream: true, 539 upstream: true,
533 fundamental: false, 540 fundamental: false,
534 non_enumerable: true, 541 non_enumerable: true,
542 coinductive: false,
535 }; 543 };
536 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1), flags }); 544 return Arc::new(TraitDatum {
545 id: trait_id,
546 binders: make_binders(trait_datum_bound, 1),
547 flags,
548 associated_ty_ids: vec![],
549 });
537 } 550 }
538 let trait_: Trait = from_chalk(db, trait_id); 551 let trait_: Trait = from_chalk(db, trait_id);
539 debug!("trait {:?} = {:?}", trait_id, trait_.name(db)); 552 debug!("trait {:?} = {:?}", trait_id, trait_.name(db));
540 let generic_params = trait_.generic_params(db); 553 let generic_params = trait_.generic_params(db);
541 let bound_vars = Substs::bound_vars(&generic_params); 554 let bound_vars = Substs::bound_vars(&generic_params);
542 let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db);
543 let flags = chalk_rust_ir::TraitFlags { 555 let flags = chalk_rust_ir::TraitFlags {
544 auto: trait_.is_auto(db), 556 auto: trait_.is_auto(db),
545 upstream: trait_.module(db).krate() != krate, 557 upstream: trait_.module(db).krate() != krate,
546 non_enumerable: true, 558 non_enumerable: true,
559 coinductive: false, // only relevant for Chalk testing
547 // FIXME set these flags correctly 560 // FIXME set these flags correctly
548 marker: false, 561 marker: false,
549 fundamental: false, 562 fundamental: false,
@@ -558,10 +571,13 @@ pub(crate) fn trait_datum_query(
558 }) 571 })
559 .map(|type_alias| type_alias.to_chalk(db)) 572 .map(|type_alias| type_alias.to_chalk(db))
560 .collect(); 573 .collect();
561 let trait_datum_bound = 574 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses };
562 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, associated_ty_ids }; 575 let trait_datum = TraitDatum {
563 let trait_datum = 576 id: trait_id,
564 TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()), flags }; 577 binders: make_binders(trait_datum_bound, bound_vars.len()),
578 flags,
579 associated_ty_ids,
580 };
565 Arc::new(trait_datum) 581 Arc::new(trait_datum)
566} 582}
567 583
@@ -569,7 +585,7 @@ pub(crate) fn struct_datum_query(
569 db: &impl HirDatabase, 585 db: &impl HirDatabase,
570 krate: Crate, 586 krate: Crate,
571 struct_id: chalk_ir::StructId, 587 struct_id: chalk_ir::StructId,
572) -> Arc<StructDatum> { 588) -> Arc<StructDatum<ChalkIr>> {
573 debug!("struct_datum {:?}", struct_id); 589 debug!("struct_datum {:?}", struct_id);
574 let type_ctor: TypeCtor = from_chalk(db, struct_id); 590 let type_ctor: TypeCtor = from_chalk(db, struct_id);
575 debug!("struct {:?} = {:?}", struct_id, type_ctor); 591 debug!("struct {:?} = {:?}", struct_id, type_ctor);
@@ -588,17 +604,12 @@ pub(crate) fn struct_datum_query(
588 // FIXME set fundamental flag correctly 604 // FIXME set fundamental flag correctly
589 fundamental: false, 605 fundamental: false,
590 }; 606 };
591 let self_ty = chalk_ir::ApplicationTy {
592 name: TypeName::TypeKindId(type_ctor.to_chalk(db).into()),
593 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
594 };
595 let struct_datum_bound = chalk_rust_ir::StructDatumBound { 607 let struct_datum_bound = chalk_rust_ir::StructDatumBound {
596 self_ty,
597 fields: Vec::new(), // FIXME add fields (only relevant for auto traits) 608 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
598 where_clauses, 609 where_clauses,
599 flags,
600 }; 610 };
601 let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) }; 611 let struct_datum =
612 StructDatum { id: struct_id, binders: make_binders(struct_datum_bound, num_params), flags };
602 Arc::new(struct_datum) 613 Arc::new(struct_datum)
603} 614}
604 615
@@ -606,16 +617,15 @@ pub(crate) fn impl_datum_query(
606 db: &impl HirDatabase, 617 db: &impl HirDatabase,
607 krate: Crate, 618 krate: Crate,
608 impl_id: ImplId, 619 impl_id: ImplId,
609) -> Arc<ImplDatum> { 620) -> Arc<ImplDatum<ChalkIr>> {
610 let _p = ra_prof::profile("impl_datum"); 621 let _p = ra_prof::profile("impl_datum");
611 debug!("impl_datum {:?}", impl_id); 622 debug!("impl_datum {:?}", impl_id);
612 let impl_: Impl = from_chalk(db, impl_id); 623 let impl_: Impl = from_chalk(db, impl_id);
613 match impl_ { 624 match impl_ {
614 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 625 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
615 Impl::ClosureFnTraitImpl(data) => { 626 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
616 closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum)
617 }
618 } 627 }
628 .unwrap_or_else(invalid_impl_datum)
619} 629}
620 630
621fn impl_block_datum( 631fn impl_block_datum(
@@ -623,14 +633,12 @@ fn impl_block_datum(
623 krate: Crate, 633 krate: Crate,
624 impl_id: ImplId, 634 impl_id: ImplId,
625 impl_block: ImplBlock, 635 impl_block: ImplBlock,
626) -> Arc<ImplDatum> { 636) -> Option<Arc<ImplDatum<ChalkIr>>> {
627 let generic_params = impl_block.generic_params(db); 637 let generic_params = impl_block.generic_params(db);
628 let bound_vars = Substs::bound_vars(&generic_params); 638 let bound_vars = Substs::bound_vars(&generic_params);
629 let trait_ref = impl_block 639 let trait_ref = impl_block.target_trait_ref(db)?.subst(&bound_vars);
630 .target_trait_ref(db) 640 let trait_ = trait_ref.trait_;
631 .expect("FIXME handle unresolved impl block trait ref") 641 let impl_type = if impl_block.krate(db) == krate {
632 .subst(&bound_vars);
633 let impl_type = if impl_block.module().krate() == krate {
634 chalk_rust_ir::ImplType::Local 642 chalk_rust_ir::ImplType::Local
635 } else { 643 } else {
636 chalk_rust_ir::ImplType::External 644 chalk_rust_ir::ImplType::External
@@ -644,28 +652,7 @@ fn impl_block_datum(
644 trait_ref.display(db), 652 trait_ref.display(db),
645 where_clauses 653 where_clauses
646 ); 654 );
647 let trait_ = trait_ref.trait_;
648 let trait_ref = trait_ref.to_chalk(db); 655 let trait_ref = trait_ref.to_chalk(db);
649 let associated_ty_values = impl_block
650 .items(db)
651 .into_iter()
652 .filter_map(|item| match item {
653 AssocItem::TypeAlias(t) => Some(t),
654 _ => None,
655 })
656 .filter_map(|t| {
657 let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?;
658 let ty = db.type_for_def(t.into(), Namespace::Types).subst(&bound_vars);
659 Some(chalk_rust_ir::AssociatedTyValue {
660 impl_id,
661 associated_ty_id: assoc_ty.to_chalk(db),
662 value: chalk_ir::Binders {
663 value: chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) },
664 binders: vec![], // we don't support GATs yet
665 },
666 })
667 })
668 .collect();
669 656
670 let polarity = if negative { 657 let polarity = if negative {
671 chalk_rust_ir::Polarity::Negative 658 chalk_rust_ir::Polarity::Negative
@@ -673,31 +660,41 @@ fn impl_block_datum(
673 chalk_rust_ir::Polarity::Positive 660 chalk_rust_ir::Polarity::Positive
674 }; 661 };
675 662
676 let impl_datum_bound = 663 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses };
677 chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses, associated_ty_values }; 664 let associated_ty_value_ids = impl_block
665 .items(db)
666 .into_iter()
667 .filter_map(|item| match item {
668 crate::AssocItem::TypeAlias(type_alias) => Some(type_alias),
669 _ => None,
670 })
671 .filter(|type_alias| {
672 // don't include associated types that don't exist in the trait
673 trait_.associated_type_by_name(db, &type_alias.name(db)).is_some()
674 })
675 .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db))
676 .collect();
678 debug!("impl_datum: {:?}", impl_datum_bound); 677 debug!("impl_datum: {:?}", impl_datum_bound);
679 let impl_datum = ImplDatum { 678 let impl_datum = ImplDatum {
680 binders: make_binders(impl_datum_bound, bound_vars.len()), 679 binders: make_binders(impl_datum_bound, bound_vars.len()),
681 impl_type, 680 impl_type,
682 polarity, 681 polarity,
682 associated_ty_value_ids,
683 }; 683 };
684 Arc::new(impl_datum) 684 Some(Arc::new(impl_datum))
685} 685}
686 686
687fn invalid_impl_datum() -> Arc<ImplDatum> { 687fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> {
688 let trait_ref = chalk_ir::TraitRef { 688 let trait_ref = chalk_ir::TraitRef {
689 trait_id: UNKNOWN_TRAIT, 689 trait_id: UNKNOWN_TRAIT,
690 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], 690 parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()],
691 };
692 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
693 trait_ref,
694 where_clauses: Vec::new(),
695 associated_ty_values: Vec::new(),
696 }; 691 };
692 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() };
697 let impl_datum = ImplDatum { 693 let impl_datum = ImplDatum {
698 binders: make_binders(impl_datum_bound, 1), 694 binders: make_binders(impl_datum_bound, 1),
699 impl_type: chalk_rust_ir::ImplType::External, 695 impl_type: chalk_rust_ir::ImplType::External,
700 polarity: chalk_rust_ir::Polarity::Positive, 696 polarity: chalk_rust_ir::Polarity::Positive,
697 associated_ty_value_ids: Vec::new(),
701 }; 698 };
702 Arc::new(impl_datum) 699 Arc::new(impl_datum)
703} 700}
@@ -705,15 +702,19 @@ fn invalid_impl_datum() -> Arc<ImplDatum> {
705fn closure_fn_trait_impl_datum( 702fn closure_fn_trait_impl_datum(
706 db: &impl HirDatabase, 703 db: &impl HirDatabase,
707 krate: Crate, 704 krate: Crate,
708 impl_id: ImplId,
709 data: super::ClosureFnTraitImplData, 705 data: super::ClosureFnTraitImplData,
710) -> Option<Arc<ImplDatum>> { 706) -> Option<Arc<ImplDatum<ChalkIr>>> {
711 // for some closure |X, Y| -> Z: 707 // for some closure |X, Y| -> Z:
712 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } 708 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
713 709
714 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
715 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait 710 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
716 711
712 // validate FnOnce trait, since we need it in the assoc ty value definition
713 // and don't want to return a valid value only to find out later that FnOnce
714 // is broken
715 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
716 fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?;
717
717 let num_args: u16 = match &data.def.body(db)[data.expr] { 718 let num_args: u16 = match &data.def.body(db)[data.expr] {
718 crate::expr::Expr::Lambda { args, .. } => args.len() as u16, 719 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
719 _ => { 720 _ => {
@@ -726,7 +727,6 @@ fn closure_fn_trait_impl_datum(
726 TypeCtor::Tuple { cardinality: num_args }, 727 TypeCtor::Tuple { cardinality: num_args },
727 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), 728 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
728 ); 729 );
729 let output_ty = Ty::Bound(num_args.into());
730 let sig_ty = Ty::apply( 730 let sig_ty = Ty::apply(
731 TypeCtor::FnPtr { num_args }, 731 TypeCtor::FnPtr { num_args },
732 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), 732 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
@@ -739,32 +739,99 @@ fn closure_fn_trait_impl_datum(
739 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), 739 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
740 }; 740 };
741 741
742 let output_ty_id = fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?; 742 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
743
744 let output_ty_value = chalk_rust_ir::AssociatedTyValue {
745 associated_ty_id: output_ty_id.to_chalk(db),
746 impl_id,
747 value: make_binders(
748 chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) },
749 0,
750 ),
751 };
752 743
753 let impl_type = chalk_rust_ir::ImplType::External; 744 let impl_type = chalk_rust_ir::ImplType::External;
754 745
755 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 746 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
756 trait_ref: trait_ref.to_chalk(db), 747 trait_ref: trait_ref.to_chalk(db),
757 where_clauses: Vec::new(), 748 where_clauses: Vec::new(),
758 associated_ty_values: vec![output_ty_value],
759 }; 749 };
760 let impl_datum = ImplDatum { 750 let impl_datum = ImplDatum {
761 binders: make_binders(impl_datum_bound, num_args as usize + 1), 751 binders: make_binders(impl_datum_bound, num_args as usize + 1),
762 impl_type, 752 impl_type,
763 polarity: chalk_rust_ir::Polarity::Positive, 753 polarity: chalk_rust_ir::Polarity::Positive,
754 associated_ty_value_ids: vec![output_ty_id],
764 }; 755 };
765 Some(Arc::new(impl_datum)) 756 Some(Arc::new(impl_datum))
766} 757}
767 758
759pub(crate) fn associated_ty_value_query(
760 db: &impl HirDatabase,
761 krate: Crate,
762 id: chalk_rust_ir::AssociatedTyValueId,
763) -> Arc<chalk_rust_ir::AssociatedTyValue<ChalkIr>> {
764 let data: AssocTyValue = from_chalk(db, id);
765 match data {
766 AssocTyValue::TypeAlias(type_alias) => {
767 type_alias_associated_ty_value(db, krate, type_alias)
768 }
769 AssocTyValue::ClosureFnTraitImplOutput(data) => {
770 closure_fn_trait_output_assoc_ty_value(db, krate, data)
771 }
772 }
773}
774
775fn type_alias_associated_ty_value(
776 db: &impl HirDatabase,
777 _krate: Crate,
778 type_alias: TypeAlias,
779) -> Arc<AssociatedTyValue<ChalkIr>> {
780 let impl_block = type_alias.impl_block(db).expect("assoc ty value should be in impl");
781 let impl_id = Impl::ImplBlock(impl_block).to_chalk(db);
782 let trait_ = impl_block
783 .target_trait_ref(db)
784 .expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved
785 .trait_;
786 let assoc_ty = trait_
787 .associated_type_by_name(db, &type_alias.name(db))
788 .expect("assoc ty value should not exist"); // validated when building the impl data as well
789 let generic_params = impl_block.generic_params(db);
790 let bound_vars = Substs::bound_vars(&generic_params);
791 let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars);
792 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
793 let value = chalk_rust_ir::AssociatedTyValue {
794 impl_id,
795 associated_ty_id: assoc_ty.to_chalk(db),
796 value: make_binders(value_bound, bound_vars.len()),
797 };
798 Arc::new(value)
799}
800
801fn closure_fn_trait_output_assoc_ty_value(
802 db: &impl HirDatabase,
803 krate: Crate,
804 data: super::ClosureFnTraitImplData,
805) -> Arc<AssociatedTyValue<ChalkIr>> {
806 let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db);
807
808 let num_args: u16 = match &data.def.body(db)[data.expr] {
809 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
810 _ => {
811 log::warn!("closure for closure type {:?} not found", data);
812 0
813 }
814 };
815
816 let output_ty = Ty::Bound(num_args.into());
817
818 let fn_once_trait =
819 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
820
821 let output_ty_id = fn_once_trait
822 .associated_type_by_name(db, &name::OUTPUT_TYPE)
823 .expect("assoc ty value should not exist");
824
825 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
826
827 let value = chalk_rust_ir::AssociatedTyValue {
828 associated_ty_id: output_ty_id.to_chalk(db),
829 impl_id,
830 value: make_binders(value_bound, num_args as usize + 1),
831 };
832 Arc::new(value)
833}
834
768fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { 835fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
769 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; 836 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
770 match target { 837 match target {
@@ -803,3 +870,15 @@ impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
803 chalk_ir::ImplId(id_to_chalk(impl_id)) 870 chalk_ir::ImplId(id_to_chalk(impl_id))
804 } 871 }
805} 872}
873
874impl From<chalk_rust_ir::AssociatedTyValueId> for crate::ids::AssocTyValueId {
875 fn from(id: chalk_rust_ir::AssociatedTyValueId) -> Self {
876 id_from_chalk(id.0)
877 }
878}
879
880impl From<crate::ids::AssocTyValueId> for chalk_rust_ir::AssociatedTyValueId {
881 fn from(assoc_ty_value_id: crate::ids::AssocTyValueId) -> Self {
882 chalk_rust_ir::AssociatedTyValueId(id_to_chalk(assoc_ty_value_id))
883 }
884}
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 21262be79..7e65f4c1d 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_hir_def"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8log = "0.4.5" 11log = "0.4.5"
9once_cell = "1.0.1" 12once_cell = "1.0.1"
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;
8use crate::{ 8use 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)]
19pub trait InternDatabase: SourceDatabase { 20pub 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
6use std::sync::Arc;
7
8use ra_syntax::ast;
9
10use crate::{
11 db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId,
12 LocationCtx, TypeAliasId,
13};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ImplData {
17 target_trait: Option<TypeRef>,
18 target_type: TypeRef,
19 items: Vec<AssocItemId>,
20 negative: bool,
21}
22
23impl 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;
13pub mod type_ref; 13pub mod type_ref;
14pub mod builtin_type; 14pub mod builtin_type;
15pub mod adt; 15pub mod adt;
16pub mod imp;
16pub mod diagnostics; 17pub mod diagnostics;
17pub mod expr; 18pub mod expr;
18pub mod body; 19pub 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)]
325pub struct ImplId(salsa::InternId);
326impl_intern_key!(ImplId);
327impl 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
324macro_rules! impl_froms { 336macro_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
386impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); 398impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId);
399
400#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
401pub 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.
410impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 21d5f62e0..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,16 +122,17 @@ 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)]
128pub(crate) struct Declarations { 129pub(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)]
133pub struct ModuleScope { 134pub struct ModuleScope {
134 pub 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
136 /// 137 ///
137 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. 138 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 5c899aff3..8f426b097 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};
@@ -165,7 +165,7 @@ where
165 /// crate::foo!(); 165 /// crate::foo!();
166 /// ``` 166 /// ```
167 /// 167 ///
168 /// Well, this code compiles, bacause the plain path `foo` in `use` is searched 168 /// Well, this code compiles, because the plain path `foo` in `use` is searched
169 /// in the legacy textual scope only. 169 /// in the legacy textual scope only.
170 /// ```rust 170 /// ```rust
171 /// macro_rules! foo { () => {} } 171 /// macro_rules! foo { () => {} }
@@ -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
125impl 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.
125type Attrs = Option<Arc<[Attr]>>; 133type 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)]
216pub(super) struct Impl(RawId);
217impl_arena_id!(Impl);
218
219#[derive(Debug, PartialEq, Eq)]
220pub(super) struct ImplData {
221 pub(super) ast_id: FileAstId<ast::ImplBlock>,
222}
223
206struct RawItemsCollector { 224struct 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/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index 8f29bf7d9..c60152a79 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_hir_expand"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8log = "0.4.5" 11log = "0.4.5"
9 12
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 5eadee9c2..9de7c1ea8 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -32,10 +32,17 @@ impl TokenExpander {
32 } 32 }
33 } 33 }
34 34
35 pub fn shift(&self) -> u32 { 35 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
36 match self { 36 match self {
37 TokenExpander::MacroRules(it) => it.shift(), 37 TokenExpander::MacroRules(it) => it.map_id_down(id),
38 TokenExpander::Builtin(_) => 0, 38 TokenExpander::Builtin(..) => id,
39 }
40 }
41
42 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
43 match self {
44 TokenExpander::MacroRules(it) => it.map_id_up(id),
45 TokenExpander::Builtin(..) => (id, mbe::Origin::Def),
39 } 46 }
40 } 47 }
41} 48}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 930789b0f..57e2e6cb1 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -18,8 +18,9 @@ use std::sync::Arc;
18 18
19use ra_db::{salsa, CrateId, FileId}; 19use ra_db::{salsa, CrateId, FileId};
20use ra_syntax::{ 20use ra_syntax::{
21 algo,
21 ast::{self, AstNode}, 22 ast::{self, AstNode},
22 SyntaxNode, TextRange, TextUnit, 23 SyntaxNode, SyntaxToken, TextRange, TextUnit,
23}; 24};
24 25
25use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
@@ -83,14 +84,21 @@ impl HirFileId {
83 loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); 84 loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
84 85
85 let macro_def = db.macro_def(loc.def)?; 86 let macro_def = db.macro_def(loc.def)?;
86 let shift = macro_def.0.shift(); 87 let (parse, exp_map) = db.parse_macro(macro_file)?;
87 let exp_map = db.parse_macro(macro_file)?.1; 88 let expanded = Source::new(self, parse.syntax_node());
88 let macro_arg = db.macro_arg(macro_file.macro_call_id)?; 89 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
89 90
90 let arg_start = (loc.ast_id.file_id, arg_start); 91 let arg_start = (loc.ast_id.file_id, arg_start);
91 let def_start = (loc.def.ast_id.file_id, def_start); 92 let def_start = (loc.def.ast_id.file_id, def_start);
92 93
93 Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift }) 94 Some(ExpansionInfo {
95 expanded,
96 arg_start,
97 def_start,
98 macro_arg,
99 macro_def,
100 exp_map,
101 })
94 } 102 }
95 } 103 }
96 } 104 }
@@ -147,26 +155,42 @@ impl MacroCallId {
147 } 155 }
148} 156}
149 157
150#[derive(Debug, Clone, PartialEq, Eq)]
151/// ExpansionInfo mainly describes how to map text range between src and expanded macro 158/// ExpansionInfo mainly describes how to map text range between src and expanded macro
159#[derive(Debug, Clone, PartialEq, Eq)]
152pub struct ExpansionInfo { 160pub struct ExpansionInfo {
153 pub(crate) arg_start: (HirFileId, TextUnit), 161 expanded: Source<SyntaxNode>,
154 pub(crate) def_start: (HirFileId, TextUnit), 162 arg_start: (HirFileId, TextUnit),
155 pub(crate) shift: u32, 163 def_start: (HirFileId, TextUnit),
156 164
157 pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 165 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
158 pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 166 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
159 pub(crate) exp_map: Arc<mbe::RevTokenMap>, 167 exp_map: Arc<mbe::RevTokenMap>,
160} 168}
161 169
162impl ExpansionInfo { 170impl ExpansionInfo {
171 pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> {
172 assert_eq!(token.file_id, self.arg_start.0);
173 let range = token.ast.text_range().checked_sub(self.arg_start.1)?;
174 let token_id = self.macro_arg.1.token_by_range(range)?;
175 let token_id = self.macro_def.0.map_id_down(token_id);
176
177 let range = self.exp_map.range_by_token(token_id)?;
178
179 let token = algo::find_covering_element(&self.expanded.ast, range).into_token()?;
180
181 Some(self.expanded.with_ast(token))
182 }
183
184 // FIXME: a more correct signature would be
185 // `pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>>`
163 pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { 186 pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
164 let token_id = look_in_rev_map(&self.exp_map, from)?; 187 let token_id = look_in_rev_map(&self.exp_map, from)?;
165 188
166 let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= self.shift { 189 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
167 (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into()) 190
168 } else { 191 let (token_map, (file_id, start_offset)) = match origin {
169 (&self.macro_def.1, self.def_start, token_id) 192 mbe::Origin::Call => (&self.macro_arg.1, self.arg_start),
193 mbe::Origin::Def => (&self.macro_def.1, self.def_start),
170 }; 194 };
171 195
172 let range = token_map.relative_range_of(token_id)?; 196 let range = token_map.relative_range_of(token_id)?;
@@ -223,18 +247,30 @@ impl<N: AstNode> AstId<N> {
223 } 247 }
224} 248}
225 249
250/// FIXME: https://github.com/matklad/with ?
226#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 251#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
227pub struct Source<T> { 252pub struct Source<T> {
228 pub file_id: HirFileId, 253 pub file_id: HirFileId,
254 // FIXME: this stores all kind of things, not only `ast`.
255 // There should be a better name...
229 pub ast: T, 256 pub ast: T,
230} 257}
231 258
232impl<T> Source<T> { 259impl<T> Source<T> {
260 pub fn new(file_id: HirFileId, ast: T) -> Source<T> {
261 Source { file_id, ast }
262 }
263
264 // Similarly, naming here is stupid...
265 pub fn with_ast<U>(&self, ast: U) -> Source<U> {
266 Source::new(self.file_id, ast)
267 }
268
233 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 269 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
234 Source { file_id: self.file_id, ast: f(self.ast) } 270 Source::new(self.file_id, f(self.ast))
235 } 271 }
236 pub fn as_ref(&self) -> Source<&T> { 272 pub fn as_ref(&self) -> Source<&T> {
237 Source { file_id: self.file_id, ast: &self.ast } 273 self.with_ast(&self.ast)
238 } 274 }
239 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { 275 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
240 db.parse_or_expand(self.file_id).expect("source created from invalid file") 276 db.parse_or_expand(self.file_id).expect("source created from invalid file")
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index fa353b5dd..15346f388 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_ide_api"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[features] 10[features]
8wasm = [] 11wasm = []
9 12
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_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 6c8387f6c..b693a4c31 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,10 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::{FileId, SourceDatabase}; 3use std::iter::successors;
4
5use hir::{db::AstDatabase, Source};
4use ra_syntax::{ 6use ra_syntax::{
5 algo::find_node_at_offset,
6 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
7 match_ast, AstNode, SyntaxNode, 8 match_ast, AstNode, SyntaxNode, SyntaxToken,
8}; 9};
9 10
10use crate::{ 11use crate::{
@@ -18,17 +19,42 @@ pub(crate) fn goto_definition(
18 db: &RootDatabase, 19 db: &RootDatabase,
19 position: FilePosition, 20 position: FilePosition,
20) -> Option<RangeInfo<Vec<NavigationTarget>>> { 21) -> Option<RangeInfo<Vec<NavigationTarget>>> {
21 let parse = db.parse(position.file_id); 22 let token = descend_into_macros(db, position)?;
22 let syntax = parse.tree().syntax().clone(); 23
23 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&syntax, position.offset) { 24 let res = match_ast! {
24 let navs = reference_definition(db, position.file_id, &name_ref).to_vec(); 25 match (token.ast.parent()) {
25 return Some(RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())); 26 ast::NameRef(name_ref) => {
26 } 27 let navs = reference_definition(db, token.with_ast(&name_ref)).to_vec();
27 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { 28 RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())
28 let navs = name_definition(db, position.file_id, &name)?; 29 },
29 return Some(RangeInfo::new(name.syntax().text_range(), navs)); 30 ast::Name(name) => {
30 } 31 let navs = name_definition(db, token.with_ast(&name))?;
31 None 32 RangeInfo::new(name.syntax().text_range(), navs)
33
34 },
35 _ => return None,
36 }
37 };
38
39 Some(res)
40}
41
42fn descend_into_macros(db: &RootDatabase, position: FilePosition) -> Option<Source<SyntaxToken>> {
43 let file = db.parse_or_expand(position.file_id.into())?;
44 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?;
45
46 successors(Some(Source::new(position.file_id.into(), token)), |token| {
47 let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?;
48 let tt = macro_call.token_tree()?;
49 if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) {
50 return None;
51 }
52 let source_analyzer =
53 hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None);
54 let exp = source_analyzer.expand(db, &macro_call)?;
55 exp.map_token_down(db, token.as_ref())
56 })
57 .last()
32} 58}
33 59
34#[derive(Debug)] 60#[derive(Debug)]
@@ -49,12 +75,11 @@ impl ReferenceResult {
49 75
50pub(crate) fn reference_definition( 76pub(crate) fn reference_definition(
51 db: &RootDatabase, 77 db: &RootDatabase,
52 file_id: FileId, 78 name_ref: Source<&ast::NameRef>,
53 name_ref: &ast::NameRef,
54) -> ReferenceResult { 79) -> ReferenceResult {
55 use self::ReferenceResult::*; 80 use self::ReferenceResult::*;
56 81
57 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); 82 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind);
58 match name_kind { 83 match name_kind {
59 Some(Macro(mac)) => return Exact(mac.to_nav(db)), 84 Some(Macro(mac)) => return Exact(mac.to_nav(db)),
60 Some(Field(field)) => return Exact(field.to_nav(db)), 85 Some(Field(field)) => return Exact(field.to_nav(db)),
@@ -76,7 +101,7 @@ pub(crate) fn reference_definition(
76 }; 101 };
77 102
78 // Fallback index based approach: 103 // Fallback index based approach:
79 let navs = crate::symbol_index::index_resolve(db, name_ref) 104 let navs = crate::symbol_index::index_resolve(db, name_ref.ast)
80 .into_iter() 105 .into_iter()
81 .map(|s| s.to_nav(db)) 106 .map(|s| s.to_nav(db))
82 .collect(); 107 .collect();
@@ -85,14 +110,13 @@ pub(crate) fn reference_definition(
85 110
86pub(crate) fn name_definition( 111pub(crate) fn name_definition(
87 db: &RootDatabase, 112 db: &RootDatabase,
88 file_id: FileId, 113 name: Source<&ast::Name>,
89 name: &ast::Name,
90) -> Option<Vec<NavigationTarget>> { 114) -> Option<Vec<NavigationTarget>> {
91 let parent = name.syntax().parent()?; 115 let parent = name.ast.syntax().parent()?;
92 116
93 if let Some(module) = ast::Module::cast(parent.clone()) { 117 if let Some(module) = ast::Module::cast(parent.clone()) {
94 if module.has_semi() { 118 if module.has_semi() {
95 let src = hir::Source { file_id: file_id.into(), ast: module }; 119 let src = name.with_ast(module);
96 if let Some(child_module) = hir::Module::from_declaration(db, src) { 120 if let Some(child_module) = hir::Module::from_declaration(db, src) {
97 let nav = child_module.to_nav(db); 121 let nav = child_module.to_nav(db);
98 return Some(vec![nav]); 122 return Some(vec![nav]);
@@ -100,20 +124,20 @@ pub(crate) fn name_definition(
100 } 124 }
101 } 125 }
102 126
103 if let Some(nav) = named_target(db, file_id, &parent) { 127 if let Some(nav) = named_target(db, name.with_ast(&parent)) {
104 return Some(vec![nav]); 128 return Some(vec![nav]);
105 } 129 }
106 130
107 None 131 None
108} 132}
109 133
110fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { 134fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<NavigationTarget> {
111 match_ast! { 135 match_ast! {
112 match node { 136 match (node.ast) {
113 ast::StructDef(it) => { 137 ast::StructDef(it) => {
114 Some(NavigationTarget::from_named( 138 Some(NavigationTarget::from_named(
115 db, 139 db,
116 file_id.into(), 140 node.file_id,
117 &it, 141 &it,
118 it.doc_comment_text(), 142 it.doc_comment_text(),
119 it.short_label(), 143 it.short_label(),
@@ -122,7 +146,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
122 ast::EnumDef(it) => { 146 ast::EnumDef(it) => {
123 Some(NavigationTarget::from_named( 147 Some(NavigationTarget::from_named(
124 db, 148 db,
125 file_id.into(), 149 node.file_id,
126 &it, 150 &it,
127 it.doc_comment_text(), 151 it.doc_comment_text(),
128 it.short_label(), 152 it.short_label(),
@@ -131,7 +155,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
131 ast::EnumVariant(it) => { 155 ast::EnumVariant(it) => {
132 Some(NavigationTarget::from_named( 156 Some(NavigationTarget::from_named(
133 db, 157 db,
134 file_id.into(), 158 node.file_id,
135 &it, 159 &it,
136 it.doc_comment_text(), 160 it.doc_comment_text(),
137 it.short_label(), 161 it.short_label(),
@@ -140,7 +164,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
140 ast::FnDef(it) => { 164 ast::FnDef(it) => {
141 Some(NavigationTarget::from_named( 165 Some(NavigationTarget::from_named(
142 db, 166 db,
143 file_id.into(), 167 node.file_id,
144 &it, 168 &it,
145 it.doc_comment_text(), 169 it.doc_comment_text(),
146 it.short_label(), 170 it.short_label(),
@@ -149,7 +173,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
149 ast::TypeAliasDef(it) => { 173 ast::TypeAliasDef(it) => {
150 Some(NavigationTarget::from_named( 174 Some(NavigationTarget::from_named(
151 db, 175 db,
152 file_id.into(), 176 node.file_id,
153 &it, 177 &it,
154 it.doc_comment_text(), 178 it.doc_comment_text(),
155 it.short_label(), 179 it.short_label(),
@@ -158,7 +182,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
158 ast::ConstDef(it) => { 182 ast::ConstDef(it) => {
159 Some(NavigationTarget::from_named( 183 Some(NavigationTarget::from_named(
160 db, 184 db,
161 file_id.into(), 185 node.file_id,
162 &it, 186 &it,
163 it.doc_comment_text(), 187 it.doc_comment_text(),
164 it.short_label(), 188 it.short_label(),
@@ -167,7 +191,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
167 ast::StaticDef(it) => { 191 ast::StaticDef(it) => {
168 Some(NavigationTarget::from_named( 192 Some(NavigationTarget::from_named(
169 db, 193 db,
170 file_id.into(), 194 node.file_id,
171 &it, 195 &it,
172 it.doc_comment_text(), 196 it.doc_comment_text(),
173 it.short_label(), 197 it.short_label(),
@@ -176,7 +200,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
176 ast::TraitDef(it) => { 200 ast::TraitDef(it) => {
177 Some(NavigationTarget::from_named( 201 Some(NavigationTarget::from_named(
178 db, 202 db,
179 file_id.into(), 203 node.file_id,
180 &it, 204 &it,
181 it.doc_comment_text(), 205 it.doc_comment_text(),
182 it.short_label(), 206 it.short_label(),
@@ -185,7 +209,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
185 ast::RecordFieldDef(it) => { 209 ast::RecordFieldDef(it) => {
186 Some(NavigationTarget::from_named( 210 Some(NavigationTarget::from_named(
187 db, 211 db,
188 file_id.into(), 212 node.file_id,
189 &it, 213 &it,
190 it.doc_comment_text(), 214 it.doc_comment_text(),
191 it.short_label(), 215 it.short_label(),
@@ -194,7 +218,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
194 ast::Module(it) => { 218 ast::Module(it) => {
195 Some(NavigationTarget::from_named( 219 Some(NavigationTarget::from_named(
196 db, 220 db,
197 file_id.into(), 221 node.file_id,
198 &it, 222 &it,
199 it.doc_comment_text(), 223 it.doc_comment_text(),
200 it.short_label(), 224 it.short_label(),
@@ -203,7 +227,7 @@ fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option
203 ast::MacroCall(it) => { 227 ast::MacroCall(it) => {
204 Some(NavigationTarget::from_named( 228 Some(NavigationTarget::from_named(
205 db, 229 db,
206 file_id.into(), 230 node.file_id,
207 &it, 231 &it,
208 it.doc_comment_text(), 232 it.doc_comment_text(),
209 None, 233 None,
@@ -677,4 +701,23 @@ mod tests {
677 "bar MODULE FileId(1) [0; 11) [4; 7)", 701 "bar MODULE FileId(1) [0; 11) [4; 7)",
678 ); 702 );
679 } 703 }
704
705 #[test]
706 fn goto_from_macro() {
707 check_goto(
708 "
709 //- /lib.rs
710 macro_rules! id {
711 ($($tt:tt)*) => { $($tt)* }
712 }
713 fn foo() {}
714 id! {
715 fn bar() {
716 fo<|>o();
717 }
718 }
719 ",
720 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
721 );
722 }
680} 723}
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..cc25f4c37 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, HasSource, HirDisplay}; 3use hir::{Adt, HasSource, HirDisplay, Source};
4use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
5use ra_syntax::{ 5use ra_syntax::{
6 algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, 6 algo::{ancestors_at_offset, find_covering_element, find_node_at_offset},
@@ -171,7 +171,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
171 find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) 171 find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)
172 { 172 {
173 let mut no_fallback = false; 173 let mut no_fallback = false;
174 if let Some(name_kind) = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind) 174 if let Some(name_kind) =
175 classify_name_ref(db, Source::new(position.file_id.into(), &name_ref)).map(|d| d.kind)
175 { 176 {
176 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback)) 177 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
177 } 178 }
@@ -230,7 +231,8 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
230 .ancestors() 231 .ancestors()
231 .take_while(|it| it.text_range() == leaf_node.text_range()) 232 .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())?; 233 .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); 234 let analyzer =
235 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)) 236 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e))
235 { 237 {
236 ty 238 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..1af7e8a9f 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -14,6 +14,7 @@ mod name_definition;
14mod rename; 14mod rename;
15mod search_scope; 15mod search_scope;
16 16
17use hir::Source;
17use once_cell::unsync::Lazy; 18use once_cell::unsync::Lazy;
18use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
19use ra_prof::profile; 20use ra_prof::profile;
@@ -114,7 +115,7 @@ fn find_name<'a>(
114 return Some(RangeInfo::new(range, (name.text().to_string(), def))); 115 return Some(RangeInfo::new(range, (name.text().to_string(), def)));
115 } 116 }
116 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; 117 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
117 let def = classify_name_ref(db, position.file_id, &name_ref)?; 118 let def = classify_name_ref(db, Source::new(position.file_id.into(), &name_ref))?;
118 let range = name_ref.syntax().text_range(); 119 let range = name_ref.syntax().text_range();
119 Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) 120 Some(RangeInfo::new(range, (name_ref.text().to_string(), def)))
120} 121}
@@ -146,7 +147,7 @@ fn process_definition(
146 continue; 147 continue;
147 } 148 }
148 } 149 }
149 if let Some(d) = classify_name_ref(db, file_id, &name_ref) { 150 if let Some(d) = classify_name_ref(db, Source::new(file_id.into(), &name_ref)) {
150 if d == def { 151 if d == def {
151 refs.push(FileRange { file_id, range }); 152 refs.push(FileRange { file_id, range });
152 } 153 }
@@ -369,6 +370,21 @@ mod tests {
369 assert_eq!(refs.len(), 2); 370 assert_eq!(refs.len(), 2);
370 } 371 }
371 372
373 #[test]
374 fn test_find_all_refs_macro_def() {
375 let code = r#"
376 #[macro_export]
377 macro_rules! m1<|> { () => (()) }
378
379 fn foo() {
380 m1();
381 m1();
382 }"#;
383
384 let refs = get_all_refs(code);
385 assert_eq!(refs.len(), 3);
386 }
387
372 fn get_all_refs(text: &str) -> ReferenceSearchResult { 388 fn get_all_refs(text: &str) -> ReferenceSearchResult {
373 let (analysis, position) = single_file_with_position(text); 389 let (analysis, position) = single_file_with_position(text);
374 analysis.find_all_refs(position, None).unwrap().unwrap() 390 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..5ca9da15e 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 }
@@ -111,15 +123,12 @@ pub(crate) fn classify_name(
111 123
112pub(crate) fn classify_name_ref( 124pub(crate) fn classify_name_ref(
113 db: &RootDatabase, 125 db: &RootDatabase,
114 file_id: FileId, 126 name_ref: Source<&ast::NameRef>,
115 name_ref: &ast::NameRef,
116) -> Option<NameDefinition> { 127) -> Option<NameDefinition> {
117 use PathResolution::*;
118
119 let _p = profile("classify_name_ref"); 128 let _p = profile("classify_name_ref");
120 129
121 let parent = name_ref.syntax().parent()?; 130 let parent = name_ref.ast.syntax().parent()?;
122 let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 131 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
123 132
124 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { 133 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
125 tested_by!(goto_definition_works_for_methods); 134 tested_by!(goto_definition_works_for_methods);
@@ -139,17 +148,16 @@ pub(crate) fn classify_name_ref(
139 tested_by!(goto_definition_works_for_record_fields); 148 tested_by!(goto_definition_works_for_record_fields);
140 if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) { 149 if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) {
141 let variant_def = analyzer.resolve_record_literal(&record_lit)?; 150 let variant_def = analyzer.resolve_record_literal(&record_lit)?;
142 let hir_path = Path::from_name_ref(name_ref); 151 let hir_path = Path::from_name_ref(name_ref.ast);
143 let hir_name = hir_path.as_ident()?; 152 let hir_name = hir_path.as_ident()?;
144 let field = variant_def.field(db, hir_name)?; 153 let field = variant_def.field(db, hir_name)?;
145 return Some(from_struct_field(db, field)); 154 return Some(from_struct_field(db, field));
146 } 155 }
147 } 156 }
148 157
149 let ast = ModuleSource::from_child_node(db, file_id, &parent); 158 let ast = ModuleSource::from_child_node(db, name_ref.with_ast(&parent));
150 let file_id = file_id.into();
151 // FIXME: find correct container and visibility for each case 159 // FIXME: find correct container and visibility for each case
152 let container = Module::from_definition(db, Source { file_id, ast })?; 160 let container = Module::from_definition(db, name_ref.with_ast(ast))?;
153 let visibility = None; 161 let visibility = None;
154 162
155 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 163 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
@@ -160,29 +168,29 @@ pub(crate) fn classify_name_ref(
160 } 168 }
161 } 169 }
162 170
163 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; 171 let path = name_ref.ast.syntax().ancestors().find_map(ast::Path::cast)?;
164 let resolved = analyzer.resolve_path(db, &path)?; 172 let resolved = analyzer.resolve_path(db, &path)?;
165 match resolved { 173 match resolved {
166 Def(def) => Some(from_module_def(db, def, Some(container))), 174 PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))),
167 AssocItem(item) => Some(from_assoc_item(db, item)), 175 PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)),
168 Local(local) => { 176 PathResolution::Local(local) => {
169 let container = local.module(db); 177 let container = local.module(db);
170 let kind = NameKind::Local(local); 178 let kind = NameKind::Local(local);
171 Some(NameDefinition { kind, container, visibility: None }) 179 Some(NameDefinition { kind, container, visibility: None })
172 } 180 }
173 GenericParam(par) => { 181 PathResolution::GenericParam(par) => {
174 // FIXME: get generic param def 182 // FIXME: get generic param def
175 let kind = NameKind::GenericParam(par); 183 let kind = NameKind::GenericParam(par);
176 Some(NameDefinition { kind, container, visibility }) 184 Some(NameDefinition { kind, container, visibility })
177 } 185 }
178 Macro(def) => { 186 PathResolution::Macro(def) => {
179 let kind = NameKind::Macro(def); 187 let kind = NameKind::Macro(def);
180 Some(NameDefinition { kind, container, visibility }) 188 Some(NameDefinition { kind, container, visibility })
181 } 189 }
182 SelfType(impl_block) => { 190 PathResolution::SelfType(impl_block) => {
183 let ty = impl_block.target_ty(db); 191 let ty = impl_block.target_ty(db);
184 let kind = NameKind::SelfType(ty); 192 let kind = NameKind::SelfType(ty);
185 let container = impl_block.module(); 193 let container = impl_block.module(db);
186 Some(NameDefinition { kind, container, visibility }) 194 Some(NameDefinition { kind, container, visibility })
187 } 195 }
188 } 196 }
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
3use hir::Source;
3use itertools::Itertools; 4use itertools::Itertools;
4use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
5use ra_syntax::{ 6use 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_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index d53a759ee..584657ca2 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Mutability, Name}; 5use hir::{Mutability, Name, Source};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@@ -80,7 +80,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
80 } 80 }
81 81
82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
83 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); 83 let name_kind =
84 classify_name_ref(db, Source::new(file_id.into(), &name_ref)).map(|d| d.kind);
84 85
85 if let Some(Local(local)) = &name_kind { 86 if let Some(Local(local)) = &name_kind {
86 if let Some(name) = local.name(db) { 87 if let Some(name) = local.name(db) {
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 743f6a60a..72dbe06dc 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_lsp_server"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8threadpool = "1.7.1" 11threadpool = "1.7.1"
9relative-path = "1.0.0" 12relative-path = "1.0.0"
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index b02e45ee3..a3fc01f63 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_mbe"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8ra_syntax = { path = "../ra_syntax" } 11ra_syntax = { path = "../ra_syntax" }
9ra_parser = { path = "../ra_parser" } 12ra_parser = { path = "../ra_parser" }
@@ -14,4 +17,3 @@ log = "0.4.5"
14 17
15[dev-dependencies] 18[dev-dependencies]
16test_utils = { path = "../test_utils" } 19test_utils = { path = "../test_utils" }
17
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 8a31d1c36..58ca95368 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -40,49 +40,75 @@ pub use crate::syntax_bridge::{
40/// and `$()*` have special meaning (see `Var` and `Repeat` data structures) 40/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
41#[derive(Clone, Debug, PartialEq, Eq)] 41#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct MacroRules { 42pub struct MacroRules {
43 pub(crate) rules: Vec<Rule>, 43 rules: Vec<Rule>,
44 /// Highest id of the token we have in TokenMap 44 /// Highest id of the token we have in TokenMap
45 pub(crate) shift: u32, 45 shift: Shift,
46} 46}
47 47
48#[derive(Clone, Debug, PartialEq, Eq)] 48#[derive(Clone, Debug, PartialEq, Eq)]
49pub(crate) struct Rule { 49struct Rule {
50 pub(crate) lhs: tt::Subtree, 50 lhs: tt::Subtree,
51 pub(crate) rhs: tt::Subtree, 51 rhs: tt::Subtree,
52} 52}
53 53
54// Find the max token id inside a subtree 54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55fn max_id(subtree: &tt::Subtree) -> Option<u32> { 55struct Shift(u32);
56 subtree 56
57 .token_trees 57impl Shift {
58 .iter() 58 fn new(tt: &tt::Subtree) -> Shift {
59 .filter_map(|tt| match tt { 59 // Note that TokenId is started from zero,
60 tt::TokenTree::Subtree(subtree) => max_id(subtree), 60 // We have to add 1 to prevent duplication.
61 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) 61 let value = max_id(tt).map_or(0, |it| it + 1);
62 if ident.id != tt::TokenId::unspecified() => 62 return Shift(value);
63 { 63
64 Some(ident.id.0) 64 // Find the max token id inside a subtree
65 fn max_id(subtree: &tt::Subtree) -> Option<u32> {
66 subtree
67 .token_trees
68 .iter()
69 .filter_map(|tt| match tt {
70 tt::TokenTree::Subtree(subtree) => max_id(subtree),
71 tt::TokenTree::Leaf(tt::Leaf::Ident(ident))
72 if ident.id != tt::TokenId::unspecified() =>
73 {
74 Some(ident.id.0)
75 }
76 _ => None,
77 })
78 .max()
79 }
80 }
81
82 /// Shift given TokenTree token id
83 fn shift_all(self, tt: &mut tt::Subtree) {
84 for t in tt.token_trees.iter_mut() {
85 match t {
86 tt::TokenTree::Leaf(leaf) => match leaf {
87 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id),
88 _ => (),
89 },
90 tt::TokenTree::Subtree(tt) => self.shift_all(tt),
65 } 91 }
66 _ => None, 92 }
67 }) 93 }
68 .max()
69}
70 94
71/// Shift given TokenTree token id 95 fn shift(self, id: tt::TokenId) -> tt::TokenId {
72fn shift_subtree(tt: &mut tt::Subtree, shift: u32) { 96 if id == tt::TokenId::unspecified() {
73 for t in tt.token_trees.iter_mut() { 97 return id;
74 match t {
75 tt::TokenTree::Leaf(leaf) => match leaf {
76 tt::Leaf::Ident(ident) if ident.id != tt::TokenId::unspecified() => {
77 ident.id.0 += shift;
78 }
79 _ => (),
80 },
81 tt::TokenTree::Subtree(tt) => shift_subtree(tt, shift),
82 } 98 }
99 tt::TokenId(id.0 + self.0)
100 }
101
102 fn unshift(self, id: tt::TokenId) -> Option<tt::TokenId> {
103 id.0.checked_sub(self.0).map(tt::TokenId)
83 } 104 }
84} 105}
85 106
107pub enum Origin {
108 Def,
109 Call,
110}
111
86impl MacroRules { 112impl MacroRules {
87 pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> { 113 pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> {
88 // Note: this parsing can be implemented using mbe machinery itself, by 114 // Note: this parsing can be implemented using mbe machinery itself, by
@@ -105,21 +131,25 @@ impl MacroRules {
105 validate(&rule.lhs)?; 131 validate(&rule.lhs)?;
106 } 132 }
107 133
108 // Note that TokenId is started from zero, 134 Ok(MacroRules { rules, shift: Shift::new(tt) })
109 // We have to add 1 to prevent duplication.
110 let shift = max_id(tt).map_or(0, |it| it + 1);
111 Ok(MacroRules { rules, shift })
112 } 135 }
113 136
114 pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { 137 pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> {
115 // apply shift 138 // apply shift
116 let mut tt = tt.clone(); 139 let mut tt = tt.clone();
117 shift_subtree(&mut tt, self.shift); 140 self.shift.shift_all(&mut tt);
118 mbe_expander::expand(self, &tt) 141 mbe_expander::expand(self, &tt)
119 } 142 }
120 143
121 pub fn shift(&self) -> u32 { 144 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
122 self.shift 145 self.shift.shift(id)
146 }
147
148 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, Origin) {
149 match self.shift.unshift(id) {
150 Some(id) => (id, Origin::Call),
151 None => (id, Origin::Def),
152 }
123 } 153 }
124} 154}
125 155
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 3f57ce3b5..8398c9ac7 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -77,8 +77,14 @@ pub fn token_tree_to_syntax_node(
77} 77}
78 78
79impl TokenMap { 79impl TokenMap {
80 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { 80 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> {
81 let idx = tt.0 as usize; 81 let (idx, _) =
82 self.tokens.iter().enumerate().find(|(_, range)| **range == relative_range)?;
83 Some(tt::TokenId(idx as u32))
84 }
85
86 pub fn relative_range_of(&self, token_id: tt::TokenId) -> Option<TextRange> {
87 let idx = token_id.0 as usize;
82 self.tokens.get(idx).copied() 88 self.tokens.get(idx).copied()
83 } 89 }
84 90
@@ -90,6 +96,11 @@ impl TokenMap {
90} 96}
91 97
92impl RevTokenMap { 98impl RevTokenMap {
99 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> {
100 let &(r, _) = self.ranges.iter().find(|(_, tid)| *tid == token_id)?;
101 Some(r)
102 }
103
93 fn add(&mut self, relative_range: TextRange, token_id: tt::TokenId) { 104 fn add(&mut self, relative_range: TextRange, token_id: tt::TokenId) {
94 self.ranges.push((relative_range, token_id.clone())) 105 self.ranges.push((relative_range, token_id.clone()))
95 } 106 }
diff --git a/crates/ra_parser/Cargo.toml b/crates/ra_parser/Cargo.toml
index b110e2bc6..0da581fd5 100644
--- a/crates/ra_parser/Cargo.toml
+++ b/crates/ra_parser/Cargo.toml
@@ -5,5 +5,8 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[lib]
9doctest = false
10
8[dependencies] 11[dependencies]
9drop_bomb = "0.1.4" 12drop_bomb = "0.1.4"
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_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index 751bcdeb8..382e6219a 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -5,6 +5,9 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[lib]
9doctest = false
10
8[dependencies] 11[dependencies]
9once_cell = "1.0.1" 12once_cell = "1.0.1"
10itertools = "0.8.0" 13itertools = "0.8.0"
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index b31c95903..69edc3c66 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_project_model"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8log = "0.4.5" 11log = "0.4.5"
9rustc-hash = "1.0" 12rustc-hash = "1.0"
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 9c0e856e8..45a18a73f 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -7,6 +7,9 @@ license = "MIT OR Apache-2.0"
7description = "Comment and whitespace preserving parser for the Rust langauge" 7description = "Comment and whitespace preserving parser for the Rust langauge"
8repository = "https://github.com/rust-analyzer/rust-analyzer" 8repository = "https://github.com/rust-analyzer/rust-analyzer"
9 9
10[lib]
11doctest = false
12
10[dependencies] 13[dependencies]
11itertools = "0.8.0" 14itertools = "0.8.0"
12rowan = "0.6.1" 15rowan = "0.6.1"
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
18pub use self::{ 18pub 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)]
193pub enum RangeOp {
194 /// `..`
195 Exclusive,
196 /// `..=`
197 Inclusive,
198}
199
200impl 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
192impl ast::IndexExpr { 238impl 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/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 87cca325d..ed8661faf 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -2,8 +2,8 @@
2 2
3use crate::{ 3use crate::{
4 ast::AstToken, 4 ast::AstToken,
5 SyntaxKind::{COMMENT, WHITESPACE}, 5 SyntaxKind::{COMMENT, RAW_STRING, STRING, WHITESPACE},
6 SyntaxToken, 6 SyntaxToken, TextRange, TextUnit,
7}; 7};
8 8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)] 9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -11,10 +11,9 @@ pub struct Comment(SyntaxToken);
11 11
12impl AstToken for Comment { 12impl AstToken for Comment {
13 fn cast(token: SyntaxToken) -> Option<Self> { 13 fn cast(token: SyntaxToken) -> Option<Self> {
14 if token.kind() == COMMENT { 14 match token.kind() {
15 Some(Comment(token)) 15 COMMENT => Some(Comment(token)),
16 } else { 16 _ => None,
17 None
18 } 17 }
19 } 18 }
20 fn syntax(&self) -> &SyntaxToken { 19 fn syntax(&self) -> &SyntaxToken {
@@ -94,10 +93,9 @@ pub struct Whitespace(SyntaxToken);
94 93
95impl AstToken for Whitespace { 94impl AstToken for Whitespace {
96 fn cast(token: SyntaxToken) -> Option<Self> { 95 fn cast(token: SyntaxToken) -> Option<Self> {
97 if token.kind() == WHITESPACE { 96 match token.kind() {
98 Some(Whitespace(token)) 97 WHITESPACE => Some(Whitespace(token)),
99 } else { 98 _ => None,
100 None
101 } 99 }
102 } 100 }
103 fn syntax(&self) -> &SyntaxToken { 101 fn syntax(&self) -> &SyntaxToken {
@@ -111,3 +109,80 @@ impl Whitespace {
111 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) 109 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
112 } 110 }
113} 111}
112
113pub struct String(SyntaxToken);
114
115impl AstToken for String {
116 fn cast(token: SyntaxToken) -> Option<Self> {
117 match token.kind() {
118 STRING => Some(String(token)),
119 _ => None,
120 }
121 }
122 fn syntax(&self) -> &SyntaxToken {
123 &self.0
124 }
125}
126
127impl String {
128 pub fn value(&self) -> Option<std::string::String> {
129 let text = self.text().as_str();
130 let usual_string_range = find_usual_string_range(text)?;
131 let start_of_inside = usual_string_range.start().to_usize() + 1;
132 let end_of_inside = usual_string_range.end().to_usize();
133 let inside_str = &text[start_of_inside..end_of_inside];
134
135 let mut buf = std::string::String::with_capacity(inside_str.len());
136 let mut has_error = false;
137 rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| {
138 match unescaped_char {
139 Ok(c) => buf.push(c),
140 Err(_) => has_error = true,
141 }
142 });
143
144 if has_error {
145 return None;
146 }
147 Some(buf)
148 }
149}
150
151pub struct RawString(SyntaxToken);
152
153impl AstToken for RawString {
154 fn cast(token: SyntaxToken) -> Option<Self> {
155 match token.kind() {
156 RAW_STRING => Some(RawString(token)),
157 _ => None,
158 }
159 }
160 fn syntax(&self) -> &SyntaxToken {
161 &self.0
162 }
163}
164
165impl RawString {
166 pub fn value(&self) -> Option<std::string::String> {
167 let text = self.text().as_str();
168 let usual_string_range = find_usual_string_range(text)?;
169 let start_of_inside = usual_string_range.start().to_usize() + 1;
170 let end_of_inside = usual_string_range.end().to_usize();
171 let inside_str = &text[start_of_inside..end_of_inside];
172 Some(inside_str.to_string())
173 }
174}
175
176fn find_usual_string_range(s: &str) -> Option<TextRange> {
177 let left_quote = s.find('"')?;
178 let right_quote = s.rfind('"')?;
179 if left_quote == right_quote {
180 // `s` only contains one quote
181 None
182 } else {
183 Some(TextRange::from_to(
184 TextUnit::from(left_quote as u32),
185 TextUnit::from(right_quote as u32),
186 ))
187 }
188}
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]
178macro_rules! match_ast { 178macro_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
88impl fmt::Display for SyntaxErrorKind { 89impl 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
232fn 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 @@
1fn 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 @@
1SOURCE_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"
29error [16; 20): An inclusive range must have an end expression
30error [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 @@
1fn 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 @@
1SOURCE_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 @@
1fn 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 @@
1SOURCE_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"
diff --git a/crates/ra_text_edit/Cargo.toml b/crates/ra_text_edit/Cargo.toml
index b40026004..8573c521a 100644
--- a/crates/ra_text_edit/Cargo.toml
+++ b/crates/ra_text_edit/Cargo.toml
@@ -5,6 +5,9 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[lib]
9doctest = false
10
8[dependencies] 11[dependencies]
9text_unit = "0.1.6" 12text_unit = "0.1.6"
10 13
diff --git a/crates/ra_tt/Cargo.toml b/crates/ra_tt/Cargo.toml
index 3fcc7f085..b8dceb92a 100644
--- a/crates/ra_tt/Cargo.toml
+++ b/crates/ra_tt/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_tt"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 11# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
9# to reduce number of compilations 12# to reduce number of compilations
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml
index 83749675f..094d6d6f4 100644
--- a/crates/ra_vfs_glob/Cargo.toml
+++ b/crates/ra_vfs_glob/Cargo.toml
@@ -4,6 +4,9 @@ name = "ra_vfs_glob"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8ra_vfs = "0.5.0" 11ra_vfs = "0.5.0"
9globset = "0.4.4" 12globset = "0.4.4"
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 0be9c3665..a71366cc4 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -4,6 +4,9 @@ name = "test_utils"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[lib]
8doctest = false
9
7[dependencies] 10[dependencies]
8difference = "2.0.0" 11difference = "2.0.0"
9text_unit = "0.1.2" 12text_unit = "0.1.2"
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
index 1c268b49c..fe1813947 100644
--- a/crates/test_utils/src/marks.rs
+++ b/crates/test_utils/src/marks.rs
@@ -4,7 +4,7 @@
4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html> 4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
5//! for details, but the TL;DR is that you write your test as 5//! for details, but the TL;DR is that you write your test as
6//! 6//!
7//! ```rust,no_run 7//! ```
8//! #[test] 8//! #[test]
9//! fn test_foo() { 9//! fn test_foo() {
10//! covers!(test_foo); 10//! covers!(test_foo);
@@ -13,7 +13,7 @@
13//! 13//!
14//! and in the code under test you write 14//! and in the code under test you write
15//! 15//!
16//! ```rust,no_run 16//! ```
17//! # use test_utils::tested_by; 17//! # use test_utils::tested_by;
18//! # fn some_condition() -> bool { true } 18//! # fn some_condition() -> bool { true }
19//! fn foo() { 19//! fn foo() {