diff options
author | Seivan Heidari <[email protected]> | 2019-11-18 01:27:53 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-18 01:27:53 +0000 |
commit | 166636ba77adcf5bf2c4ef935e9aa75e20f25e10 (patch) | |
tree | 168be1ca55c73b016e20586c08417c608450c92c /crates | |
parent | cb26df950699586b314731fb70786e0db8eaa049 (diff) | |
parent | 28c2d74b2150102a8756a5357a5a965d7610bd15 (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates')
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" | |||
3 | name = "ra_arena" | 3 | name = "ra_arena" |
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | |||
7 | [lib] | ||
8 | doctest = 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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | format-buf = "1.0.0" | 11 | format-buf = "1.0.0" |
9 | join_to_string = "0.1.3" | 12 | join_to_string = "0.1.3" |
10 | itertools = "0.8.0" | 13 | itertools = "0.8.0" |
11 | rustc_lexer = "0.1.0" | ||
12 | 14 | ||
13 | ra_syntax = { path = "../ra_syntax" } | 15 | ra_syntax = { path = "../ra_syntax" } |
14 | ra_text_edit = { path = "../ra_text_edit" } | 16 | ra_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 | 2 | use hir::{db::HirDatabase, SourceAnalyzer}; | |
3 | use hir::db::HirDatabase; | ||
4 | use ra_db::FileRange; | 3 | use ra_db::FileRange; |
5 | use ra_fmt::{leading_indent, reindent}; | 4 | use ra_fmt::{leading_indent, reindent}; |
6 | use ra_syntax::{ | 5 | use ra_syntax::{ |
@@ -113,6 +112,13 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
113 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 112 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
114 | find_covering_element(self.source_file.syntax(), self.frange.range) | 113 | find_covering_element(self.source_file.syntax(), self.frange.range) |
115 | } | 114 | } |
115 | pub(crate) fn source_analyzer( | ||
116 | &self, | ||
117 | node: &SyntaxNode, | ||
118 | offset: Option<TextUnit>, | ||
119 | ) -> SourceAnalyzer { | ||
120 | SourceAnalyzer::new(self.db, hir::Source::new(self.frange.file_id.into(), node), offset) | ||
121 | } | ||
116 | 122 | ||
117 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { | 123 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { |
118 | find_covering_element(self.source_file.syntax(), range) | 124 | find_covering_element(self.source_file.syntax(), range) |
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index ddda1a0f2..562a09685 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -40,7 +40,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
40 | } | 40 | } |
41 | // Infer type | 41 | // Infer type |
42 | let db = ctx.db; | 42 | let db = ctx.db; |
43 | let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None); | 43 | let analyzer = ctx.source_analyzer(stmt.syntax(), None); |
44 | let ty = analyzer.type_of(db, &expr)?; | 44 | let ty = analyzer.type_of(db, &expr)?; |
45 | // Assist not applicable if the type is unknown | 45 | // Assist not applicable if the type is unknown |
46 | if is_unknown(&ty) { | 46 | if is_unknown(&ty) { |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 41de23921..91af161ee 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -100,8 +100,7 @@ fn add_missing_impl_members_inner( | |||
100 | let impl_item_list = impl_node.item_list()?; | 100 | let impl_item_list = impl_node.item_list()?; |
101 | 101 | ||
102 | let trait_def = { | 102 | let trait_def = { |
103 | let file_id = ctx.frange.file_id; | 103 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); |
104 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, impl_node.syntax(), None); | ||
105 | 104 | ||
106 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? | 105 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? |
107 | }; | 106 | }; |
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs index a8839cfba..2038afdc6 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/assists/add_new.rs | |||
@@ -158,9 +158,12 @@ fn find_struct_impl( | |||
158 | let same_ty = blk.target_ty(db) == struct_ty; | 158 | let same_ty = blk.target_ty(db) == struct_ty; |
159 | let not_trait_impl = blk.target_trait(db).is_none(); | 159 | let not_trait_impl = blk.target_trait(db).is_none(); |
160 | 160 | ||
161 | found_new_fn = has_new_fn(impl_blk); | 161 | if !(same_ty && not_trait_impl) { |
162 | return false; | ||
163 | } | ||
162 | 164 | ||
163 | same_ty && not_trait_impl | 165 | found_new_fn = has_new_fn(impl_blk); |
166 | true | ||
164 | }); | 167 | }); |
165 | 168 | ||
166 | if found_new_fn { | 169 | if found_new_fn { |
@@ -186,9 +189,10 @@ fn has_new_fn(imp: &ast::ImplBlock) -> bool { | |||
186 | 189 | ||
187 | #[cfg(test)] | 190 | #[cfg(test)] |
188 | mod tests { | 191 | mod tests { |
189 | use super::*; | ||
190 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 192 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; |
191 | 193 | ||
194 | use super::*; | ||
195 | |||
192 | #[test] | 196 | #[test] |
193 | #[rustfmt::skip] | 197 | #[rustfmt::skip] |
194 | fn test_add_new() { | 198 | fn test_add_new() { |
@@ -345,7 +349,7 @@ struct Foo {<|>} | |||
345 | impl Foo { | 349 | impl Foo { |
346 | fn new() -> Self { | 350 | fn new() -> Self { |
347 | Self | 351 | Self |
348 | } | 352 | } |
349 | }", | 353 | }", |
350 | ); | 354 | ); |
351 | 355 | ||
@@ -357,7 +361,7 @@ struct Foo {<|>} | |||
357 | impl Foo { | 361 | impl Foo { |
358 | fn New() -> Self { | 362 | fn New() -> Self { |
359 | Self | 363 | Self |
360 | } | 364 | } |
361 | }", | 365 | }", |
362 | ); | 366 | ); |
363 | } | 367 | } |
@@ -376,4 +380,59 @@ struct EvenMoreIrrelevant; | |||
376 | struct Foo<'a, T: Foo<'a>> {}", | 380 | struct Foo<'a, T: Foo<'a>> {}", |
377 | ); | 381 | ); |
378 | } | 382 | } |
383 | |||
384 | #[test] | ||
385 | fn test_unrelated_new() { | ||
386 | check_assist( | ||
387 | add_new, | ||
388 | r##" | ||
389 | pub struct AstId<N: AstNode> { | ||
390 | file_id: HirFileId, | ||
391 | file_ast_id: FileAstId<N>, | ||
392 | } | ||
393 | |||
394 | impl<N: AstNode> AstId<N> { | ||
395 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
396 | AstId { file_id, file_ast_id } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | pub struct Source<T> { | ||
401 | pub file_id: HirFileId,<|> | ||
402 | pub ast: T, | ||
403 | } | ||
404 | |||
405 | impl<T> Source<T> { | ||
406 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
407 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
408 | } | ||
409 | } | ||
410 | "##, | ||
411 | r##" | ||
412 | pub struct AstId<N: AstNode> { | ||
413 | file_id: HirFileId, | ||
414 | file_ast_id: FileAstId<N>, | ||
415 | } | ||
416 | |||
417 | impl<N: AstNode> AstId<N> { | ||
418 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
419 | AstId { file_id, file_ast_id } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | pub struct Source<T> { | ||
424 | pub file_id: HirFileId, | ||
425 | pub ast: T, | ||
426 | } | ||
427 | |||
428 | impl<T> Source<T> { | ||
429 | pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> | ||
430 | |||
431 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
432 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
433 | } | ||
434 | } | ||
435 | "##, | ||
436 | ); | ||
437 | } | ||
379 | } | 438 | } |
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 2b74f355c..b851c2082 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -47,8 +47,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
47 | 47 | ||
48 | let expr = match_expr.expr()?; | 48 | let expr = match_expr.expr()?; |
49 | let enum_def = { | 49 | let enum_def = { |
50 | let file_id = ctx.frange.file_id; | 50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); |
51 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, expr.syntax(), None); | ||
52 | resolve_enum_def(ctx.db, &analyzer, &expr)? | 51 | resolve_enum_def(ctx.db, &analyzer, &expr)? |
53 | }; | 52 | }; |
54 | let variant_list = enum_def.variant_list()?; | 53 | let variant_list = enum_def.variant_list()?; |
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index a7fd9b6d2..18a34502c 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs | |||
@@ -45,7 +45,7 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
45 | } else { | 45 | } else { |
46 | let_stmt.syntax().text_range() | 46 | let_stmt.syntax().text_range() |
47 | }; | 47 | }; |
48 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None); | 48 | let analyzer = ctx.source_analyzer(bind_pat.syntax(), None); |
49 | let refs = analyzer.find_all_refs(&bind_pat); | 49 | let refs = analyzer.find_all_refs(&bind_pat); |
50 | 50 | ||
51 | let mut wrap_in_parens = vec![true; refs.len()]; | 51 | let mut wrap_in_parens = vec![true; refs.len()]; |
diff --git a/crates/ra_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 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast, AstToken, | ||
3 | SyntaxKind::{RAW_STRING, STRING}, | 4 | SyntaxKind::{RAW_STRING, STRING}, |
4 | TextRange, TextUnit, | 5 | TextUnit, |
5 | }; | 6 | }; |
6 | use rustc_lexer; | ||
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 9 | ||
@@ -23,32 +23,16 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(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 | // ``` |
70 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 54 | pub(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 | ||
157 | fn 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)] |
172 | mod test { | 139 | mod 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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | log = "0.4.5" | 11 | log = "0.4.5" |
9 | rustc-hash = "1.0" | 12 | rustc-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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | rustc-hash = "1.0.1" | 11 | rustc-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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | salsa = "0.13.0" | 11 | salsa = "0.13.0" |
9 | relative-path = "1.0.0" | 12 | relative-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" | |||
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [lib] | ||
9 | doctest = false | ||
10 | |||
8 | [dependencies] | 11 | [dependencies] |
9 | itertools = "0.8.0" | 12 | itertools = "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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | arrayvec = "0.5.1" | 11 | arrayvec = "0.5.1" |
9 | log = "0.4.5" | 12 | log = "0.4.5" |
@@ -23,9 +26,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } | |||
23 | test_utils = { path = "../test_utils" } | 26 | test_utils = { path = "../test_utils" } |
24 | ra_prof = { path = "../ra_prof" } | 27 | ra_prof = { path = "../ra_prof" } |
25 | 28 | ||
26 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } | 29 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" } |
27 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } | 30 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" } |
28 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } | 31 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" } |
29 | lalrpop-intern = "0.15.1" | 32 | lalrpop-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 | }; |
16 | use hir_expand::{ | 16 | use hir_expand::{ |
17 | diagnostics::DiagnosticSink, | 17 | diagnostics::DiagnosticSink, |
@@ -29,7 +29,6 @@ use crate::{ | |||
29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
30 | TypeAliasId, | 30 | TypeAliasId, |
31 | }, | 31 | }, |
32 | impl_block::ImplBlock, | ||
33 | resolve::{Resolver, Scope, TypeNs}, | 32 | resolve::{Resolver, Scope, TypeNs}, |
34 | traits::TraitData, | 33 | traits::TraitData, |
35 | ty::{InferenceResult, Namespace, TraitRef}, | 34 | ty::{InferenceResult, Namespace, TraitRef}, |
@@ -243,12 +242,8 @@ impl Module { | |||
243 | } | 242 | } |
244 | 243 | ||
245 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { | 244 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { |
246 | let module_impl_blocks = db.impls_in_module(self); | 245 | let def_map = db.crate_def_map(self.id.krate); |
247 | module_impl_blocks | 246 | def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() |
248 | .impls | ||
249 | .iter() | ||
250 | .map(|(impl_id, _)| ImplBlock::from_id(self, impl_id)) | ||
251 | .collect() | ||
252 | } | 247 | } |
253 | 248 | ||
254 | fn with_module_id(self, module_id: CrateModuleId) -> Module { | 249 | fn with_module_id(self, module_id: CrateModuleId) -> Module { |
@@ -693,8 +688,7 @@ impl Function { | |||
693 | 688 | ||
694 | /// The containing impl block, if this is a method. | 689 | /// The containing impl block, if this is a method. |
695 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 690 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
696 | let module_impls = db.impls_in_module(self.module(db)); | 691 | ImplBlock::containing(db, self.into()) |
697 | ImplBlock::containing(module_impls, self.into()) | ||
698 | } | 692 | } |
699 | 693 | ||
700 | /// The containing trait, if this is a trait method definition. | 694 | /// The containing trait, if this is a trait method definition. |
@@ -759,8 +753,7 @@ impl Const { | |||
759 | 753 | ||
760 | /// The containing impl block, if this is a method. | 754 | /// The containing impl block, if this is a method. |
761 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 755 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
762 | let module_impls = db.impls_in_module(self.module(db)); | 756 | ImplBlock::containing(db, self.into()) |
763 | ImplBlock::containing(module_impls, self.into()) | ||
764 | } | 757 | } |
765 | 758 | ||
766 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { | 759 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { |
@@ -973,8 +966,7 @@ impl TypeAlias { | |||
973 | 966 | ||
974 | /// The containing impl block, if this is a method. | 967 | /// The containing impl block, if this is a method. |
975 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 968 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
976 | let module_impls = db.impls_in_module(self.module(db)); | 969 | ImplBlock::containing(db, self.into()) |
977 | ImplBlock::containing(module_impls, self.into()) | ||
978 | } | 970 | } |
979 | 971 | ||
980 | /// The containing trait, if this is a trait method definition. | 972 | /// The containing trait, if this is a trait method definition. |
@@ -1137,3 +1129,8 @@ pub struct GenericParam { | |||
1137 | pub(crate) parent: GenericDef, | 1129 | pub(crate) parent: GenericDef, |
1138 | pub(crate) idx: u32, | 1130 | pub(crate) idx: u32, |
1139 | } | 1131 | } |
1132 | |||
1133 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1134 | pub struct ImplBlock { | ||
1135 | pub(crate) id: ImplId, | ||
1136 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index c60029c01..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 | ||
25 | pub use hir_def::db::{ | 26 | pub 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 | }; |
30 | pub use hir_expand::db::{ | 31 | pub 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 | ||
6 | use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; | 6 | use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId}; |
7 | 7 | ||
8 | use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; | 8 | use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef}; |
9 | 9 | ||
10 | macro_rules! from_id { | 10 | macro_rules! from_id { |
11 | ($(($id:path, $ty:path)),*) => {$( | 11 | ($(($id:path, $ty:path)),*) => {$( |
@@ -27,6 +27,7 @@ from_id![ | |||
27 | (hir_def::StaticId, crate::Static), | 27 | (hir_def::StaticId, crate::Static), |
28 | (hir_def::ConstId, crate::Const), | 28 | (hir_def::ConstId, crate::Const), |
29 | (hir_def::FunctionId, crate::Function), | 29 | (hir_def::FunctionId, crate::Function), |
30 | (hir_def::ImplId, crate::ImplBlock), | ||
30 | (hir_expand::MacroDefId, crate::MacroDef) | 31 | (hir_expand::MacroDefId, crate::MacroDef) |
31 | ]; | 32 | ]; |
32 | 33 | ||
@@ -71,3 +72,13 @@ impl From<DefWithBody> for DefWithBodyId { | |||
71 | } | 72 | } |
72 | } | 73 | } |
73 | } | 74 | } |
75 | |||
76 | impl From<AssocItemId> for AssocItem { | ||
77 | fn from(def: AssocItemId) -> Self { | ||
78 | match def { | ||
79 | AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), | ||
80 | AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), | ||
81 | AssocItemId::ConstId(it) => AssocItem::Const(it.into()), | ||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 7e5523c54..1c26756c9 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; | 3 | use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; |
4 | use hir_expand::name::AsName; | 4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 6 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, | 7 | match_ast, |
@@ -11,8 +11,8 @@ use crate::{ | |||
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, | 13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, |
14 | Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, | 14 | Local, MacroDef, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, |
15 | VariantDef, | 15 | Union, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -77,19 +77,28 @@ impl FromSource for TypeAlias { | |||
77 | Some(TypeAlias { id }) | 77 | Some(TypeAlias { id }) |
78 | } | 78 | } |
79 | } | 79 | } |
80 | // FIXME: add impl FromSource for MacroDef | 80 | |
81 | impl FromSource for MacroDef { | ||
82 | type Ast = ast::MacroCall; | ||
83 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
84 | let kind = MacroDefKind::Declarative; | ||
85 | |||
86 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
87 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | ||
88 | let krate = module.krate().crate_id(); | ||
89 | |||
90 | let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.ast)); | ||
91 | |||
92 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; | ||
93 | Some(MacroDef { id }) | ||
94 | } | ||
95 | } | ||
81 | 96 | ||
82 | impl FromSource for ImplBlock { | 97 | impl FromSource for ImplBlock { |
83 | type Ast = ast::ImplBlock; | 98 | type Ast = ast::ImplBlock; |
84 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 99 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
85 | let module_src = crate::ModuleSource::from_child_node( | 100 | let id = from_source(db, src)?; |
86 | db, | 101 | Some(ImplBlock { id }) |
87 | src.file_id.original_file(db), | ||
88 | &src.ast.syntax(), | ||
89 | ); | ||
90 | let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; | ||
91 | let impls = module.impl_blocks(db); | ||
92 | impls.into_iter().find(|b| b.source(db) == src) | ||
93 | } | 102 | } |
94 | } | 103 | } |
95 | 104 | ||
@@ -202,9 +211,8 @@ where | |||
202 | N: AstNode, | 211 | N: AstNode, |
203 | DEF: AstItemDef<N>, | 212 | DEF: AstItemDef<N>, |
204 | { | 213 | { |
205 | let module_src = | 214 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); |
206 | crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax()); | 215 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; |
207 | let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; | ||
208 | let ctx = LocationCtx::new(db, module.id, src.file_id); | 216 | let ctx = LocationCtx::new(db, module.id, src.file_id); |
209 | Some(DEF::from_ast(ctx, &src.ast)) | 217 | Some(DEF::from_ast(ctx, &src.ast)) |
210 | } | 218 | } |
diff --git a/crates/ra_hir/src/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)] |
38 | pub struct GlobalImplId(salsa::InternId); | 38 | pub struct GlobalImplId(salsa::InternId); |
39 | impl_intern_key!(GlobalImplId); | 39 | impl_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)] | ||
44 | pub struct AssocTyValueId(salsa::InternId); | ||
45 | impl_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 | ||
3 | use rustc_hash::FxHashMap; | 3 | use hir_def::{type_ref::TypeRef, AstItemDef}; |
4 | use std::sync::Arc; | 4 | use ra_syntax::ast::{self}; |
5 | |||
6 | use hir_def::{attr::Attr, type_ref::TypeRef}; | ||
7 | use hir_expand::hygiene::Hygiene; | ||
8 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | ||
9 | use ra_cfg::CfgOptions; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, AstNode}, | ||
12 | AstPtr, | ||
13 | }; | ||
14 | 5 | ||
15 | use crate::{ | 6 | use crate::{ |
16 | code_model::{Module, ModuleSource}, | ||
17 | db::{AstDatabase, DefDatabase, HirDatabase}, | 7 | db::{AstDatabase, DefDatabase, HirDatabase}, |
18 | generics::HasGenericParams, | 8 | generics::HasGenericParams, |
19 | ids::LocationCtx, | ||
20 | ids::MacroCallLoc, | ||
21 | resolve::Resolver, | 9 | resolve::Resolver, |
22 | ty::Ty, | 10 | ty::Ty, |
23 | AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, | 11 | AssocItem, Crate, HasSource, ImplBlock, Module, Source, TraitRef, |
24 | TypeAlias, | ||
25 | }; | 12 | }; |
26 | 13 | ||
27 | #[derive(Debug, Default, PartialEq, Eq)] | ||
28 | pub struct ImplSourceMap { | ||
29 | map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>, | ||
30 | } | ||
31 | |||
32 | impl ImplSourceMap { | ||
33 | fn insert(&mut self, impl_id: ImplId, file_id: HirFileId, impl_block: &ast::ImplBlock) { | ||
34 | let source = Source { file_id, ast: AstPtr::new(impl_block) }; | ||
35 | self.map.insert(impl_id, source) | ||
36 | } | ||
37 | |||
38 | pub fn get(&self, db: &impl AstDatabase, impl_id: ImplId) -> Source<ast::ImplBlock> { | ||
39 | let src = self.map[impl_id]; | ||
40 | let root = src.file_syntax(db); | ||
41 | src.map(|ptr| ptr.to_node(&root)) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
46 | pub struct ImplBlock { | ||
47 | module: Module, | ||
48 | impl_id: ImplId, | ||
49 | } | ||
50 | |||
51 | impl HasSource for ImplBlock { | 14 | impl HasSource for ImplBlock { |
52 | type Ast = ast::ImplBlock; | 15 | type Ast = ast::ImplBlock; |
53 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { | 16 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { |
54 | let source_map = db.impls_in_module_with_source_map(self.module).1; | 17 | self.id.source(db) |
55 | source_map.get(db, self.impl_id) | ||
56 | } | 18 | } |
57 | } | 19 | } |
58 | 20 | ||
59 | impl ImplBlock { | 21 | impl ImplBlock { |
60 | pub(crate) fn containing( | 22 | pub(crate) fn containing(db: &impl DefDatabase, item: AssocItem) -> Option<ImplBlock> { |
61 | module_impl_blocks: Arc<ModuleImplBlocks>, | 23 | let module = item.module(db); |
62 | item: AssocItem, | 24 | let crate_def_map = db.crate_def_map(module.id.krate); |
63 | ) -> Option<ImplBlock> { | 25 | crate_def_map[module.id.module_id].impls.iter().copied().map(ImplBlock::from).find(|it| { |
64 | let impl_id = *module_impl_blocks.impls_by_def.get(&item)?; | 26 | db.impl_data(it.id).items().iter().copied().map(AssocItem::from).any(|it| it == item) |
65 | Some(ImplBlock { module: module_impl_blocks.module, impl_id }) | 27 | }) |
66 | } | ||
67 | |||
68 | pub(crate) fn from_id(module: Module, impl_id: ImplId) -> ImplBlock { | ||
69 | ImplBlock { module, impl_id } | ||
70 | } | ||
71 | |||
72 | pub fn id(&self) -> ImplId { | ||
73 | self.impl_id | ||
74 | } | ||
75 | |||
76 | pub fn module(&self) -> Module { | ||
77 | self.module | ||
78 | } | 28 | } |
79 | 29 | ||
80 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { | 30 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { |
81 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() | 31 | db.impl_data(self.id).target_trait().cloned() |
82 | } | 32 | } |
83 | 33 | ||
84 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { | 34 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { |
85 | db.impls_in_module(self.module).impls[self.impl_id].target_type().clone() | 35 | db.impl_data(self.id).target_type().clone() |
86 | } | 36 | } |
87 | 37 | ||
88 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { | 38 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { |
@@ -95,15 +45,23 @@ impl ImplBlock { | |||
95 | } | 45 | } |
96 | 46 | ||
97 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { | 47 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { |
98 | db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() | 48 | db.impl_data(self.id).items().iter().map(|it| (*it).into()).collect() |
99 | } | 49 | } |
100 | 50 | ||
101 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { | 51 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { |
102 | db.impls_in_module(self.module).impls[self.impl_id].negative | 52 | db.impl_data(self.id).is_negative() |
53 | } | ||
54 | |||
55 | pub fn module(&self, db: &impl DefDatabase) -> Module { | ||
56 | self.id.module(db).into() | ||
57 | } | ||
58 | |||
59 | pub fn krate(&self, db: &impl DefDatabase) -> Crate { | ||
60 | Crate { crate_id: self.module(db).id.krate } | ||
103 | } | 61 | } |
104 | 62 | ||
105 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { | 63 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { |
106 | let r = self.module().resolver(db); | 64 | let r = self.module(db).resolver(db); |
107 | // add generic params, if present | 65 | // add generic params, if present |
108 | let p = self.generic_params(db); | 66 | let p = self.generic_params(db); |
109 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | 67 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; |
@@ -111,175 +69,3 @@ impl ImplBlock { | |||
111 | r | 69 | r |
112 | } | 70 | } |
113 | } | 71 | } |
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
116 | pub struct ImplData { | ||
117 | target_trait: Option<TypeRef>, | ||
118 | target_type: TypeRef, | ||
119 | items: Vec<AssocItem>, | ||
120 | negative: bool, | ||
121 | } | ||
122 | |||
123 | impl ImplData { | ||
124 | pub(crate) fn from_ast( | ||
125 | db: &(impl DefDatabase + AstDatabase), | ||
126 | file_id: HirFileId, | ||
127 | module: Module, | ||
128 | node: &ast::ImplBlock, | ||
129 | ) -> Self { | ||
130 | let target_trait = node.target_trait().map(TypeRef::from_ast); | ||
131 | let target_type = TypeRef::from_ast_opt(node.target_type()); | ||
132 | let ctx = LocationCtx::new(db, module.id, file_id); | ||
133 | let negative = node.is_negative(); | ||
134 | let items = if let Some(item_list) = node.item_list() { | ||
135 | item_list | ||
136 | .impl_items() | ||
137 | .map(|item_node| match item_node { | ||
138 | ast::ImplItem::FnDef(it) => Function { id: ctx.to_def(&it) }.into(), | ||
139 | ast::ImplItem::ConstDef(it) => Const { id: ctx.to_def(&it) }.into(), | ||
140 | ast::ImplItem::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(&it) }.into(), | ||
141 | }) | ||
142 | .collect() | ||
143 | } else { | ||
144 | Vec::new() | ||
145 | }; | ||
146 | ImplData { target_trait, target_type, items, negative } | ||
147 | } | ||
148 | |||
149 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
150 | self.target_trait.as_ref() | ||
151 | } | ||
152 | |||
153 | pub fn target_type(&self) -> &TypeRef { | ||
154 | &self.target_type | ||
155 | } | ||
156 | |||
157 | pub fn items(&self) -> &[AssocItem] { | ||
158 | &self.items | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
163 | pub struct ImplId(pub RawId); | ||
164 | impl_arena_id!(ImplId); | ||
165 | |||
166 | /// The collection of impl blocks is a two-step process: first we collect the | ||
167 | /// blocks per-module; then we build an index of all impl blocks in the crate. | ||
168 | /// This way, we avoid having to do this process for the whole crate whenever | ||
169 | /// a file is changed; as long as the impl blocks in the file don't change, | ||
170 | /// we don't need to do the second step again. | ||
171 | #[derive(Debug, PartialEq, Eq)] | ||
172 | pub struct ModuleImplBlocks { | ||
173 | pub(crate) module: Module, | ||
174 | pub(crate) impls: Arena<ImplId, ImplData>, | ||
175 | impls_by_def: FxHashMap<AssocItem, ImplId>, | ||
176 | } | ||
177 | |||
178 | impl ModuleImplBlocks { | ||
179 | pub(crate) fn impls_in_module_with_source_map_query( | ||
180 | db: &(impl DefDatabase + AstDatabase), | ||
181 | module: Module, | ||
182 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | ||
183 | let mut source_map = ImplSourceMap::default(); | ||
184 | let crate_graph = db.crate_graph(); | ||
185 | let cfg_options = crate_graph.cfg_options(module.id.krate); | ||
186 | |||
187 | let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); | ||
188 | (Arc::new(result), Arc::new(source_map)) | ||
189 | } | ||
190 | |||
191 | pub(crate) fn impls_in_module_query( | ||
192 | db: &impl DefDatabase, | ||
193 | module: Module, | ||
194 | ) -> Arc<ModuleImplBlocks> { | ||
195 | db.impls_in_module_with_source_map(module).0 | ||
196 | } | ||
197 | |||
198 | fn collect( | ||
199 | db: &(impl DefDatabase + AstDatabase), | ||
200 | cfg_options: &CfgOptions, | ||
201 | module: Module, | ||
202 | source_map: &mut ImplSourceMap, | ||
203 | ) -> Self { | ||
204 | let mut m = ModuleImplBlocks { | ||
205 | module, | ||
206 | impls: Arena::default(), | ||
207 | impls_by_def: FxHashMap::default(), | ||
208 | }; | ||
209 | |||
210 | let src = m.module.definition_source(db); | ||
211 | match &src.ast { | ||
212 | ModuleSource::SourceFile(node) => { | ||
213 | m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id) | ||
214 | } | ||
215 | ModuleSource::Module(node) => { | ||
216 | let item_list = node.item_list().expect("inline module should have item list"); | ||
217 | m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id) | ||
218 | } | ||
219 | }; | ||
220 | m | ||
221 | } | ||
222 | |||
223 | fn collect_from_item_owner( | ||
224 | &mut self, | ||
225 | db: &(impl DefDatabase + AstDatabase), | ||
226 | cfg_options: &CfgOptions, | ||
227 | source_map: &mut ImplSourceMap, | ||
228 | owner: &dyn ast::ModuleItemOwner, | ||
229 | file_id: HirFileId, | ||
230 | ) { | ||
231 | let hygiene = Hygiene::new(db, file_id); | ||
232 | for item in owner.items_with_macros() { | ||
233 | match item { | ||
234 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | ||
235 | let attrs = Attr::from_attrs_owner(&impl_block_ast, &hygiene); | ||
236 | if attrs.map_or(false, |attrs| { | ||
237 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
238 | }) { | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | ||
243 | let id = self.impls.alloc(impl_block); | ||
244 | for &impl_item in &self.impls[id].items { | ||
245 | self.impls_by_def.insert(impl_item, id); | ||
246 | } | ||
247 | |||
248 | source_map.insert(id, file_id, &impl_block_ast); | ||
249 | } | ||
250 | ast::ItemOrMacro::Item(_) => (), | ||
251 | ast::ItemOrMacro::Macro(macro_call) => { | ||
252 | let attrs = Attr::from_attrs_owner(¯o_call, &hygiene); | ||
253 | if attrs.map_or(false, |attrs| { | ||
254 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
255 | }) { | ||
256 | continue; | ||
257 | } | ||
258 | |||
259 | //FIXME: we should really cut down on the boilerplate required to process a macro | ||
260 | let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_call)); | ||
261 | if let Some(path) = | ||
262 | macro_call.path().and_then(|path| Path::from_src(path, &hygiene)) | ||
263 | { | ||
264 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | ||
265 | { | ||
266 | let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id }); | ||
267 | let file_id = call_id.as_file(MacroFileKind::Items); | ||
268 | if let Some(item_list) = | ||
269 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | ||
270 | { | ||
271 | self.collect_from_item_owner( | ||
272 | db, | ||
273 | cfg_options, | ||
274 | source_map, | ||
275 | &item_list, | ||
276 | file_id, | ||
277 | ) | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index e1780ed38..fa2ef8a17 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -25,7 +25,7 @@ impl LangItemTarget { | |||
25 | Some(match self { | 25 | Some(match self { |
26 | LangItemTarget::Enum(e) => e.module(db).krate(), | 26 | LangItemTarget::Enum(e) => e.module(db).krate(), |
27 | LangItemTarget::Function(f) => f.module(db).krate(), | 27 | LangItemTarget::Function(f) => f.module(db).krate(), |
28 | LangItemTarget::ImplBlock(i) => i.module().krate(), | 28 | LangItemTarget::ImplBlock(i) => i.krate(db), |
29 | LangItemTarget::Static(s) => s.module(db).krate(), | 29 | LangItemTarget::Static(s) => s.module(db).krate(), |
30 | LangItemTarget::Struct(s) => s.module(db).krate(), | 30 | LangItemTarget::Struct(s) => s.module(db).krate(), |
31 | LangItemTarget::Trait(t) => t.module(db).krate(), | 31 | LangItemTarget::Trait(t) => t.module(db).krate(), |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5ba847d35..da33c9591 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -54,12 +54,11 @@ mod test_db; | |||
54 | #[cfg(test)] | 54 | #[cfg(test)] |
55 | mod marks; | 55 | mod marks; |
56 | 56 | ||
57 | use hir_expand::AstId; | 57 | use crate::resolve::Resolver; |
58 | |||
59 | use crate::{ids::MacroFileKind, resolve::Resolver}; | ||
60 | 58 | ||
61 | pub use crate::{ | 59 | pub use crate::{ |
62 | adt::VariantDef, | 60 | adt::VariantDef, |
61 | code_model::ImplBlock, | ||
63 | code_model::{ | 62 | code_model::{ |
64 | attrs::{AttrDef, Attrs}, | 63 | attrs::{AttrDef, Attrs}, |
65 | docs::{DocDef, Docs, Documentation}, | 64 | docs::{DocDef, Docs, Documentation}, |
@@ -72,7 +71,6 @@ pub use crate::{ | |||
72 | from_source::FromSource, | 71 | from_source::FromSource, |
73 | generics::GenericDef, | 72 | generics::GenericDef, |
74 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, | 73 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, |
75 | impl_block::ImplBlock, | ||
76 | resolve::ScopeDef, | 74 | resolve::ScopeDef, |
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 75 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | ty::{ | 76 | ty::{ |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2fb913108..79b92180a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,9 +15,8 @@ use crate::{ | |||
15 | db::{DefDatabase, HirDatabase}, | 15 | db::{DefDatabase, HirDatabase}, |
16 | expr::{ExprScopes, PatId, ScopeId}, | 16 | expr::{ExprScopes, PatId, ScopeId}, |
17 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | impl_block::ImplBlock, | 18 | Adt, Const, DefWithBody, Enum, EnumVariant, Function, ImplBlock, Local, MacroDef, ModuleDef, |
19 | Adt, Const, DefWithBody, Enum, EnumVariant, Function, Local, MacroDef, ModuleDef, PerNs, | 19 | PerNs, Static, Struct, Trait, TypeAlias, |
20 | Static, Struct, Trait, TypeAlias, | ||
21 | }; | 20 | }; |
22 | 21 | ||
23 | #[derive(Debug, Clone, Default)] | 22 | #[derive(Debug, Clone, Default)] |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 662d3f880..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 | }; |
14 | use hir_expand::{name::AsName, Source}; | 14 | use hir_expand::{name::AsName, AstId, MacroCallId, MacroCallLoc, MacroFileKind, Source}; |
15 | use ra_db::FileId; | ||
16 | use ra_syntax::{ | 15 | use ra_syntax::{ |
17 | ast::{self, AstNode}, | 16 | ast::{self, AstNode}, |
18 | match_ast, AstPtr, | 17 | match_ast, AstPtr, |
19 | SyntaxKind::*, | 18 | SyntaxKind::*, |
20 | SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, | 19 | SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, |
21 | }; | 20 | }; |
22 | 21 | ||
23 | use crate::{ | 22 | use 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 | ||
33 | fn try_get_resolver_for_node( | 32 | fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { |
34 | db: &impl HirDatabase, | ||
35 | file_id: FileId, | ||
36 | node: &SyntaxNode, | ||
37 | ) -> Option<Resolver> { | ||
38 | match_ast! { | 33 | match_ast! { |
39 | match node { | 34 | match (node.ast) { |
40 | ast::Module(it) => { | 35 | ast::Module(it) => { |
41 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 36 | let src = node.with_ast(it); |
42 | Some(crate::Module::from_declaration(db, src)?.resolver(db)) | 37 | Some(crate::Module::from_declaration(db, src)?.resolver(db)) |
43 | }, | 38 | }, |
44 | ast::SourceFile(it) => { | 39 | ast::SourceFile(it) => { |
45 | let src = | 40 | let src = node.with_ast(crate::ModuleSource::SourceFile(it)); |
46 | crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(it) }; | ||
47 | Some(crate::Module::from_definition(db, src)?.resolver(db)) | 41 | Some(crate::Module::from_definition(db, src)?.resolver(db)) |
48 | }, | 42 | }, |
49 | ast::StructDef(it) => { | 43 | ast::StructDef(it) => { |
50 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 44 | let src = node.with_ast(it); |
51 | Some(Struct::from_source(db, src)?.resolver(db)) | 45 | Some(Struct::from_source(db, src)?.resolver(db)) |
52 | }, | 46 | }, |
53 | ast::EnumDef(it) => { | 47 | ast::EnumDef(it) => { |
54 | let src = crate::Source { file_id: file_id.into(), ast: it }; | 48 | let src = node.with_ast(it); |
55 | Some(Enum::from_source(db, src)?.resolver(db)) | 49 | Some(Enum::from_source(db, src)?.resolver(db)) |
56 | }, | 50 | }, |
57 | _ => { | 51 | _ => match node.ast.kind() { |
58 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { | 52 | FN_DEF | CONST_DEF | STATIC_DEF => { |
59 | Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) | 53 | Some(def_with_body_from_child_node(db, node)?.resolver(db)) |
60 | } else { | ||
61 | // FIXME add missing cases | ||
62 | None | ||
63 | } | 54 | } |
64 | }, | 55 | // FIXME add missing cases |
56 | _ => None | ||
57 | } | ||
65 | } | 58 | } |
66 | } | 59 | } |
67 | } | 60 | } |
68 | 61 | ||
69 | fn def_with_body_from_child_node( | 62 | fn def_with_body_from_child_node( |
70 | db: &impl HirDatabase, | 63 | db: &impl HirDatabase, |
71 | file_id: FileId, | 64 | child: Source<&SyntaxNode>, |
72 | node: &SyntaxNode, | ||
73 | ) -> Option<DefWithBody> { | 65 | ) -> Option<DefWithBody> { |
74 | let src = crate::ModuleSource::from_child_node(db, file_id, node); | 66 | let module_source = crate::ModuleSource::from_child_node(db, child); |
75 | let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?; | 67 | let module = Module::from_definition(db, Source::new(child.file_id, module_source))?; |
76 | let ctx = LocationCtx::new(db, module.id, file_id.into()); | 68 | let ctx = LocationCtx::new(db, module.id, child.file_id); |
77 | 69 | ||
78 | node.ancestors().find_map(|node| { | 70 | child.ast.ancestors().find_map(|node| { |
79 | match_ast! { | 71 | match_ast! { |
80 | match node { | 72 | match node { |
81 | ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, | 73 | ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, |
@@ -91,8 +83,7 @@ fn def_with_body_from_child_node( | |||
91 | /// original source files. It should not be used inside the HIR itself. | 83 | /// original source files. It should not be used inside the HIR itself. |
92 | #[derive(Debug)] | 84 | #[derive(Debug)] |
93 | pub struct SourceAnalyzer { | 85 | pub struct SourceAnalyzer { |
94 | // FIXME: this doesn't handle macros at all | 86 | file_id: HirFileId, |
95 | file_id: FileId, | ||
96 | resolver: Resolver, | 87 | resolver: Resolver, |
97 | body_owner: Option<DefWithBody>, | 88 | body_owner: Option<DefWithBody>, |
98 | body_source_map: Option<Arc<BodySourceMap>>, | 89 | body_source_map: Option<Arc<BodySourceMap>>, |
@@ -135,20 +126,38 @@ pub struct ReferenceDescriptor { | |||
135 | pub name: String, | 126 | pub name: String, |
136 | } | 127 | } |
137 | 128 | ||
129 | pub struct Expansion { | ||
130 | macro_call_id: MacroCallId, | ||
131 | } | ||
132 | |||
133 | impl 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 | |||
138 | impl SourceAnalyzer { | 148 | impl 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 { | |||
409 | fn scope_for( | 426 | fn 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 | ||
421 | fn scope_for_offset( | 438 | fn 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)] |
292 | pub struct Substs(Arc<[Ty]>); | 292 | pub struct Substs(Arc<[Ty]>); |
293 | 293 | ||
294 | impl 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 | |||
294 | impl Substs { | 308 | impl 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. |
672 | pub trait TypeWalk { | 676 | pub 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 | ||
136 | impl<T> Canonicalized<T> { | 136 | impl<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 @@ | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::CrateModuleId; | ||
9 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
10 | 9 | ||
11 | use crate::{ | 10 | use crate::{ |
12 | db::HirDatabase, | 11 | db::HirDatabase, |
13 | impl_block::{ImplBlock, ImplId}, | ||
14 | resolve::Resolver, | 12 | resolve::Resolver, |
15 | ty::primitive::{FloatBitness, Uncertain}, | 13 | ty::primitive::{FloatBitness, Uncertain}, |
16 | ty::{Ty, TypeCtor}, | 14 | ty::{Ty, TypeCtor}, |
17 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, | 15 | AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, |
18 | }; | 16 | }; |
19 | 17 | ||
20 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 18 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
@@ -39,65 +37,46 @@ impl TyFingerprint { | |||
39 | 37 | ||
40 | #[derive(Debug, PartialEq, Eq)] | 38 | #[derive(Debug, PartialEq, Eq)] |
41 | pub struct CrateImplBlocks { | 39 | pub struct CrateImplBlocks { |
42 | /// To make sense of the CrateModuleIds, we need the source root. | 40 | impls: FxHashMap<TyFingerprint, Vec<ImplBlock>>, |
43 | krate: Crate, | 41 | impls_by_trait: FxHashMap<Trait, Vec<ImplBlock>>, |
44 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, | ||
45 | impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>, | ||
46 | } | 42 | } |
47 | 43 | ||
48 | impl CrateImplBlocks { | 44 | impl CrateImplBlocks { |
49 | pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a { | 45 | pub(crate) fn impls_in_crate_query( |
46 | db: &impl HirDatabase, | ||
47 | krate: Crate, | ||
48 | ) -> Arc<CrateImplBlocks> { | ||
49 | let mut crate_impl_blocks = | ||
50 | CrateImplBlocks { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | ||
51 | if let Some(module) = krate.root_module(db) { | ||
52 | crate_impl_blocks.collect_recursive(db, module); | ||
53 | } | ||
54 | Arc::new(crate_impl_blocks) | ||
55 | } | ||
56 | pub fn lookup_impl_blocks(&self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + '_ { | ||
50 | let fingerprint = TyFingerprint::for_impl(ty); | 57 | let fingerprint = TyFingerprint::for_impl(ty); |
51 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map( | 58 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() |
52 | move |(module_id, impl_id)| { | ||
53 | let module = Module::new(self.krate, *module_id); | ||
54 | ImplBlock::from_id(module, *impl_id) | ||
55 | }, | ||
56 | ) | ||
57 | } | 59 | } |
58 | 60 | ||
59 | pub fn lookup_impl_blocks_for_trait<'a>( | 61 | pub fn lookup_impl_blocks_for_trait(&self, tr: Trait) -> impl Iterator<Item = ImplBlock> + '_ { |
60 | &'a self, | 62 | self.impls_by_trait.get(&tr).into_iter().flatten().copied() |
61 | tr: Trait, | ||
62 | ) -> impl Iterator<Item = ImplBlock> + 'a { | ||
63 | self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( | ||
64 | move |(module_id, impl_id)| { | ||
65 | let module = Module::new(self.krate, *module_id); | ||
66 | ImplBlock::from_id(module, *impl_id) | ||
67 | }, | ||
68 | ) | ||
69 | } | 63 | } |
70 | 64 | ||
71 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { | 65 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { |
72 | self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map( | 66 | self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() |
73 | move |(module_id, impl_id)| { | ||
74 | let module = Module::new(self.krate, *module_id); | ||
75 | ImplBlock::from_id(module, *impl_id) | ||
76 | }, | ||
77 | ) | ||
78 | } | 67 | } |
79 | 68 | ||
80 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { | 69 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { |
81 | let module_impl_blocks = db.impls_in_module(module); | 70 | for impl_block in module.impl_blocks(db) { |
82 | |||
83 | for (impl_id, _) in module_impl_blocks.impls.iter() { | ||
84 | let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id); | ||
85 | |||
86 | let target_ty = impl_block.target_ty(db); | 71 | let target_ty = impl_block.target_ty(db); |
87 | 72 | ||
88 | if impl_block.target_trait(db).is_some() { | 73 | if impl_block.target_trait(db).is_some() { |
89 | if let Some(tr) = impl_block.target_trait_ref(db) { | 74 | if let Some(tr) = impl_block.target_trait_ref(db) { |
90 | self.impls_by_trait | 75 | self.impls_by_trait.entry(tr.trait_).or_default().push(impl_block); |
91 | .entry(tr.trait_) | ||
92 | .or_insert_with(Vec::new) | ||
93 | .push((module.id.module_id, impl_id)); | ||
94 | } | 76 | } |
95 | } else { | 77 | } else { |
96 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 78 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
97 | self.impls | 79 | self.impls.entry(target_ty_fp).or_default().push(impl_block); |
98 | .entry(target_ty_fp) | ||
99 | .or_insert_with(Vec::new) | ||
100 | .push((module.id.module_id, impl_id)); | ||
101 | } | 80 | } |
102 | } | 81 | } |
103 | } | 82 | } |
@@ -106,21 +85,6 @@ impl CrateImplBlocks { | |||
106 | self.collect_recursive(db, child); | 85 | self.collect_recursive(db, child); |
107 | } | 86 | } |
108 | } | 87 | } |
109 | |||
110 | pub(crate) fn impls_in_crate_query( | ||
111 | db: &impl HirDatabase, | ||
112 | krate: Crate, | ||
113 | ) -> Arc<CrateImplBlocks> { | ||
114 | let mut crate_impl_blocks = CrateImplBlocks { | ||
115 | krate, | ||
116 | impls: FxHashMap::default(), | ||
117 | impls_by_trait: FxHashMap::default(), | ||
118 | }; | ||
119 | if let Some(module) = krate.root_module(db) { | ||
120 | crate_impl_blocks.collect_recursive(db, module); | ||
121 | } | ||
122 | Arc::new(crate_impl_blocks) | ||
123 | } | ||
124 | } | 88 | } |
125 | 89 | ||
126 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { | 90 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { |
@@ -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 @@ | |||
1 | mod never_type; | ||
2 | mod coercion; | ||
3 | |||
1 | use std::fmt::Write; | 4 | use std::fmt::Write; |
2 | use std::sync::Arc; | 5 | use std::sync::Arc; |
3 | 6 | ||
@@ -11,7 +14,7 @@ use ra_syntax::{ | |||
11 | use test_utils::covers; | 14 | use test_utils::covers; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
14 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, | 17 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, Source, |
15 | SourceAnalyzer, | 18 | SourceAnalyzer, |
16 | }; | 19 | }; |
17 | 20 | ||
@@ -19,9 +22,6 @@ use crate::{ | |||
19 | // against snapshots of the expected results using insta. Use cargo-insta to | 22 | // against snapshots of the expected results using insta. Use cargo-insta to |
20 | // update the snapshots. | 23 | // update the snapshots. |
21 | 24 | ||
22 | mod never_type; | ||
23 | mod coercion; | ||
24 | |||
25 | #[test] | 25 | #[test] |
26 | fn cfg_impl_block() { | 26 | fn cfg_impl_block() { |
27 | let (db, pos) = TestDB::with_position( | 27 | let (db, pos) = TestDB::with_position( |
@@ -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] |
4188 | fn impl_trait_assoc_binding_projection_bug() { | ||
4189 | let (db, pos) = TestDB::with_position( | ||
4190 | r#" | ||
4191 | //- /main.rs crate:main deps:std | ||
4192 | pub trait Language { | ||
4193 | type Kind; | ||
4194 | } | ||
4195 | pub enum RustLanguage {} | ||
4196 | impl Language for RustLanguage { | ||
4197 | type Kind = SyntaxKind; | ||
4198 | } | ||
4199 | struct SyntaxNode<L> {} | ||
4200 | fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {} | ||
4201 | |||
4202 | trait Clone { | ||
4203 | fn clone(&self) -> Self; | ||
4204 | } | ||
4205 | |||
4206 | fn api_walkthrough() { | ||
4207 | for node in foo() { | ||
4208 | node.clone()<|>; | ||
4209 | } | ||
4210 | } | ||
4211 | |||
4212 | //- /std.rs crate:std | ||
4213 | #[prelude_import] use iter::*; | ||
4214 | mod 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] | ||
4188 | fn projection_eq_within_chalk() { | 4231 | fn 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> { | |||
4609 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 4652 | fn 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; | |||
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 10 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
11 | use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait}; | 11 | use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait, TypeAlias}; |
12 | 12 | ||
13 | use self::chalk::{from_chalk, ToChalk}; | 13 | use self::chalk::{from_chalk, ToChalk}; |
14 | 14 | ||
@@ -17,7 +17,7 @@ pub(crate) mod chalk; | |||
17 | #[derive(Debug, Clone)] | 17 | #[derive(Debug, Clone)] |
18 | pub struct TraitSolver { | 18 | pub 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 | ||
198 | fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { | 199 | fn 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)] | ||
312 | pub 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 | }; |
10 | use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; | 10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; |
11 | 11 | ||
12 | use hir_expand::name; | 12 | use hir_expand::name; |
13 | 13 | ||
14 | use ra_db::salsa::{InternId, InternKey}; | 14 | use ra_db::salsa::{InternId, InternKey}; |
15 | 15 | ||
16 | use super::{Canonical, ChalkContext, Impl, Obligation}; | 16 | use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; |
17 | use crate::{ | 17 | use 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 | ||
218 | impl 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 | |||
214 | impl ToChalk for GenericPredicate { | 233 | impl 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 | ||
402 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | 421 | impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB> |
403 | where | 422 | where |
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 | |||
485 | pub(crate) fn associated_ty_data_query( | 502 | pub(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 | ||
621 | fn impl_block_datum( | 631 | fn 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 | ||
687 | fn invalid_impl_datum() -> Arc<ImplDatum> { | 687 | fn 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> { | |||
705 | fn closure_fn_trait_impl_datum( | 702 | fn 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 | ||
759 | pub(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 | |||
775 | fn 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 | |||
801 | fn 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 | |||
768 | fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { | 835 | fn 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 | |||
874 | impl 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 | |||
880 | impl 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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | log = "0.4.5" | 11 | log = "0.4.5" |
9 | once_cell = "1.0.1" | 12 | once_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; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | adt::{EnumData, StructData}, | 9 | adt::{EnumData, StructData}, |
10 | body::{scope::ExprScopes, Body, BodySourceMap}, | 10 | body::{scope::ExprScopes, Body, BodySourceMap}, |
11 | imp::ImplData, | ||
11 | nameres::{ | 12 | nameres::{ |
12 | raw::{ImportSourceMap, RawItems}, | 13 | raw::{ImportSourceMap, RawItems}, |
13 | CrateDefMap, | 14 | CrateDefMap, |
14 | }, | 15 | }, |
15 | DefWithBodyId, EnumId, StructOrUnionId, | 16 | DefWithBodyId, EnumId, ImplId, ItemLoc, StructOrUnionId, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[salsa::query_group(InternDatabaseStorage)] | 19 | #[salsa::query_group(InternDatabaseStorage)] |
19 | pub trait InternDatabase: SourceDatabase { | 20 | pub trait InternDatabase: SourceDatabase { |
20 | #[salsa::interned] | 21 | #[salsa::interned] |
21 | fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; | 22 | fn intern_function(&self, loc: ItemLoc<ast::FnDef>) -> crate::FunctionId; |
22 | #[salsa::interned] | 23 | #[salsa::interned] |
23 | fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>) | 24 | fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId; |
24 | -> crate::StructOrUnionId; | ||
25 | #[salsa::interned] | 25 | #[salsa::interned] |
26 | fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; | 26 | fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId; |
27 | #[salsa::interned] | 27 | #[salsa::interned] |
28 | fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; | 28 | fn intern_const(&self, loc: ItemLoc<ast::ConstDef>) -> crate::ConstId; |
29 | #[salsa::interned] | 29 | #[salsa::interned] |
30 | fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId; | 30 | fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId; |
31 | #[salsa::interned] | 31 | #[salsa::interned] |
32 | fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId; | 32 | fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId; |
33 | #[salsa::interned] | 33 | #[salsa::interned] |
34 | fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; | 34 | fn intern_type_alias(&self, loc: ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; |
35 | #[salsa::interned] | ||
36 | fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId; | ||
35 | } | 37 | } |
36 | 38 | ||
37 | #[salsa::query_group(DefDatabase2Storage)] | 39 | #[salsa::query_group(DefDatabase2Storage)] |
@@ -54,6 +56,9 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { | |||
54 | #[salsa::invoke(EnumData::enum_data_query)] | 56 | #[salsa::invoke(EnumData::enum_data_query)] |
55 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | 57 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; |
56 | 58 | ||
59 | #[salsa::invoke(ImplData::impl_data_query)] | ||
60 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
61 | |||
57 | #[salsa::invoke(Body::body_with_source_map_query)] | 62 | #[salsa::invoke(Body::body_with_source_map_query)] |
58 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | 63 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); |
59 | 64 | ||
diff --git a/crates/ra_hir_def/src/imp.rs b/crates/ra_hir_def/src/imp.rs new file mode 100644 index 000000000..717991c40 --- /dev/null +++ b/crates/ra_hir_def/src/imp.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Defines hir-level representation of impls. | ||
2 | //! | ||
3 | //! The handling is similar, but is not quite the same as for other items, | ||
4 | //! because `impl`s don't have names. | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use ra_syntax::ast; | ||
9 | |||
10 | use crate::{ | ||
11 | db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId, | ||
12 | LocationCtx, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub struct ImplData { | ||
17 | target_trait: Option<TypeRef>, | ||
18 | target_type: TypeRef, | ||
19 | items: Vec<AssocItemId>, | ||
20 | negative: bool, | ||
21 | } | ||
22 | |||
23 | impl ImplData { | ||
24 | pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> { | ||
25 | let src = id.source(db); | ||
26 | let items = db.ast_id_map(src.file_id); | ||
27 | |||
28 | let target_trait = src.ast.target_trait().map(TypeRef::from_ast); | ||
29 | let target_type = TypeRef::from_ast_opt(src.ast.target_type()); | ||
30 | let negative = src.ast.is_negative(); | ||
31 | |||
32 | let items = if let Some(item_list) = src.ast.item_list() { | ||
33 | let ctx = LocationCtx::new(db, id.module(db), src.file_id); | ||
34 | item_list | ||
35 | .impl_items() | ||
36 | .map(|item_node| match item_node { | ||
37 | ast::ImplItem::FnDef(it) => { | ||
38 | FunctionId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
39 | } | ||
40 | ast::ImplItem::ConstDef(it) => { | ||
41 | ConstId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
42 | } | ||
43 | ast::ImplItem::TypeAliasDef(it) => { | ||
44 | TypeAliasId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
45 | } | ||
46 | }) | ||
47 | .collect() | ||
48 | } else { | ||
49 | Vec::new() | ||
50 | }; | ||
51 | |||
52 | let res = ImplData { target_trait, target_type, items, negative }; | ||
53 | Arc::new(res) | ||
54 | } | ||
55 | |||
56 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
57 | self.target_trait.as_ref() | ||
58 | } | ||
59 | |||
60 | pub fn target_type(&self) -> &TypeRef { | ||
61 | &self.target_type | ||
62 | } | ||
63 | |||
64 | pub fn items(&self) -> &[AssocItemId] { | ||
65 | &self.items | ||
66 | } | ||
67 | |||
68 | pub fn is_negative(&self) -> bool { | ||
69 | self.negative | ||
70 | } | ||
71 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 3fab7965c..a240a10b8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -13,6 +13,7 @@ pub mod path; | |||
13 | pub mod type_ref; | 13 | pub mod type_ref; |
14 | pub mod builtin_type; | 14 | pub mod builtin_type; |
15 | pub mod adt; | 15 | pub mod adt; |
16 | pub mod imp; | ||
16 | pub mod diagnostics; | 17 | pub mod diagnostics; |
17 | pub mod expr; | 18 | pub mod expr; |
18 | pub mod body; | 19 | pub mod body; |
@@ -77,14 +78,13 @@ impl ModuleSource { | |||
77 | } | 78 | } |
78 | } | 79 | } |
79 | 80 | ||
80 | pub fn from_child_node( | 81 | pub fn from_child_node(db: &impl db::DefDatabase2, child: Source<&SyntaxNode>) -> ModuleSource { |
81 | db: &impl db::DefDatabase2, | 82 | if let Some(m) = |
82 | file_id: FileId, | 83 | child.ast.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) |
83 | child: &SyntaxNode, | 84 | { |
84 | ) -> ModuleSource { | ||
85 | if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) { | ||
86 | ModuleSource::Module(m) | 85 | ModuleSource::Module(m) |
87 | } else { | 86 | } else { |
87 | let file_id = child.file_id.original_file(db); | ||
88 | let source_file = db.parse(file_id).tree(); | 88 | let source_file = db.parse(file_id).tree(); |
89 | ModuleSource::SourceFile(source_file) | 89 | ModuleSource::SourceFile(source_file) |
90 | } | 90 | } |
@@ -321,6 +321,18 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | |||
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
325 | pub struct ImplId(salsa::InternId); | ||
326 | impl_intern_key!(ImplId); | ||
327 | impl AstItemDef<ast::ImplBlock> for ImplId { | ||
328 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self { | ||
329 | db.intern_impl(loc) | ||
330 | } | ||
331 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> { | ||
332 | db.lookup_intern_impl(self) | ||
333 | } | ||
334 | } | ||
335 | |||
324 | macro_rules! impl_froms { | 336 | macro_rules! impl_froms { |
325 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 337 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
326 | $( | 338 | $( |
@@ -384,3 +396,15 @@ pub enum DefWithBodyId { | |||
384 | } | 396 | } |
385 | 397 | ||
386 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); | 398 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); |
399 | |||
400 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
401 | pub enum AssocItemId { | ||
402 | FunctionId(FunctionId), | ||
403 | ConstId(ConstId), | ||
404 | TypeAliasId(TypeAliasId), | ||
405 | } | ||
406 | // FIXME: not every function, ... is actually an assoc item. maybe we should make | ||
407 | // sure that you can only turn actual assoc items into AssocItemIds. This would | ||
408 | // require not implementing From, and instead having some checked way of | ||
409 | // casting them, and somehow making the constructors private, which would be annoying. | ||
410 | impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); | ||
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 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)] |
128 | pub(crate) struct Declarations { | 129 | pub(crate) struct Declarations { |
129 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, | 130 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, |
130 | } | 131 | } |
131 | 132 | ||
132 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 133 | #[derive(Debug, Default, PartialEq, Eq)] |
133 | pub struct ModuleScope { | 134 | pub struct ModuleScope { |
134 | 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 | ||
125 | impl Index<Impl> for RawItems { | ||
126 | type Output = ImplData; | ||
127 | fn index(&self, idx: Impl) -> &ImplData { | ||
128 | &self.impls[idx] | ||
129 | } | ||
130 | } | ||
131 | |||
124 | // Avoid heap allocation on items without attributes. | 132 | // Avoid heap allocation on items without attributes. |
125 | type Attrs = Option<Arc<[Attr]>>; | 133 | type Attrs = Option<Arc<[Attr]>>; |
126 | 134 | ||
@@ -142,6 +150,7 @@ pub(super) enum RawItemKind { | |||
142 | Import(ImportId), | 150 | Import(ImportId), |
143 | Def(Def), | 151 | Def(Def), |
144 | Macro(Macro), | 152 | Macro(Macro), |
153 | Impl(Impl), | ||
145 | } | 154 | } |
146 | 155 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -203,6 +212,15 @@ pub(super) struct MacroData { | |||
203 | pub(super) builtin: bool, | 212 | pub(super) builtin: bool, |
204 | } | 213 | } |
205 | 214 | ||
215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
216 | pub(super) struct Impl(RawId); | ||
217 | impl_arena_id!(Impl); | ||
218 | |||
219 | #[derive(Debug, PartialEq, Eq)] | ||
220 | pub(super) struct ImplData { | ||
221 | pub(super) ast_id: FileAstId<ast::ImplBlock>, | ||
222 | } | ||
223 | |||
206 | struct RawItemsCollector { | 224 | struct RawItemsCollector { |
207 | raw_items: RawItems, | 225 | raw_items: RawItems, |
208 | source_ast_id_map: Arc<AstIdMap>, | 226 | source_ast_id_map: Arc<AstIdMap>, |
@@ -236,8 +254,8 @@ impl RawItemsCollector { | |||
236 | self.add_extern_crate_item(current_module, extern_crate); | 254 | self.add_extern_crate_item(current_module, extern_crate); |
237 | return; | 255 | return; |
238 | } | 256 | } |
239 | ast::ModuleItem::ImplBlock(_) => { | 257 | ast::ModuleItem::ImplBlock(it) => { |
240 | // impls don't participate in name resolution | 258 | self.add_impl(current_module, it); |
241 | return; | 259 | return; |
242 | } | 260 | } |
243 | ast::ModuleItem::StructDef(it) => { | 261 | ast::ModuleItem::StructDef(it) => { |
@@ -376,6 +394,13 @@ impl RawItemsCollector { | |||
376 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | 394 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
377 | } | 395 | } |
378 | 396 | ||
397 | fn add_impl(&mut self, current_module: Option<Module>, imp: ast::ImplBlock) { | ||
398 | let attrs = self.parse_attrs(&imp); | ||
399 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
400 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
401 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
402 | } | ||
403 | |||
379 | fn push_import( | 404 | fn push_import( |
380 | &mut self, | 405 | &mut self, |
381 | current_module: Option<Module>, | 406 | current_module: Option<Module>, |
diff --git a/crates/ra_hir_expand/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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | log = "0.4.5" | 11 | log = "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 | ||
19 | use ra_db::{salsa, CrateId, FileId}; | 19 | use ra_db::{salsa, CrateId, FileId}; |
20 | use ra_syntax::{ | 20 | use 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 | ||
25 | use crate::ast_id_map::FileAstId; | 26 | use 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)] | ||
152 | pub struct ExpansionInfo { | 160 | pub 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 | ||
162 | impl ExpansionInfo { | 170 | impl 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)] |
227 | pub struct Source<T> { | 252 | pub 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 | ||
232 | impl<T> Source<T> { | 259 | impl<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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [features] | 10 | [features] |
8 | wasm = [] | 11 | wasm = [] |
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 | ||
3 | use ra_db::{FileId, SourceDatabase}; | 3 | use std::iter::successors; |
4 | |||
5 | use hir::{db::AstDatabase, Source}; | ||
4 | use ra_syntax::{ | 6 | use 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 | ||
10 | use crate::{ | 11 | use 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 | |||
42 | fn 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, ¯o_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 | ||
50 | pub(crate) fn reference_definition( | 76 | pub(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 | ||
86 | pub(crate) fn name_definition( | 111 | pub(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 | ||
110 | fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { | 134 | fn 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 | ||
3 | use hir::{Adt, HasSource, HirDisplay}; | 3 | use hir::{Adt, HasSource, HirDisplay, Source}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 5 | use 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; | |||
14 | mod rename; | 14 | mod rename; |
15 | mod search_scope; | 15 | mod search_scope; |
16 | 16 | ||
17 | use hir::Source; | ||
17 | use once_cell::unsync::Lazy; | 18 | use once_cell::unsync::Lazy; |
18 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; |
19 | use ra_prof::profile; | 20 | use 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 | ||
112 | pub(crate) fn classify_name_ref( | 124 | pub(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 | ||
3 | use hir::Source; | ||
3 | use itertools::Itertools; | 4 | use itertools::Itertools; |
4 | use ra_db::SourceDatabase; | 5 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -65,9 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti | |||
65 | return None; | 66 | return None; |
66 | } | 67 | } |
67 | let range = module.syntax().text_range(); | 68 | let range = module.syntax().text_range(); |
68 | let src = hir::ModuleSource::from_child_node(db, file_id, &module.syntax()); | 69 | let src = hir::ModuleSource::from_child_node(db, Source::new(file_id.into(), &module.syntax())); |
69 | let module = | 70 | let module = hir::Module::from_definition(db, Source::new(file_id.into(), src))?; |
70 | hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), ast: src })?; | ||
71 | 71 | ||
72 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); | 72 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); |
73 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) | 73 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) |
diff --git a/crates/ra_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 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | 4 | ||
5 | use hir::{Mutability, Name}; | 5 | use hir::{Mutability, Name, Source}; |
6 | use ra_db::SourceDatabase; | 6 | use ra_db::SourceDatabase; |
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; | 8 | use 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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | threadpool = "1.7.1" | 11 | threadpool = "1.7.1" |
9 | relative-path = "1.0.0" | 12 | relative-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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | ra_syntax = { path = "../ra_syntax" } | 11 | ra_syntax = { path = "../ra_syntax" } |
9 | ra_parser = { path = "../ra_parser" } | 12 | ra_parser = { path = "../ra_parser" } |
@@ -14,4 +17,3 @@ log = "0.4.5" | |||
14 | 17 | ||
15 | [dev-dependencies] | 18 | [dev-dependencies] |
16 | test_utils = { path = "../test_utils" } | 19 | test_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)] |
42 | pub struct MacroRules { | 42 | pub 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)] |
49 | pub(crate) struct Rule { | 49 | struct 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)] |
55 | fn max_id(subtree: &tt::Subtree) -> Option<u32> { | 55 | struct Shift(u32); |
56 | subtree | 56 | |
57 | .token_trees | 57 | impl 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 { |
72 | fn 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 | ||
107 | pub enum Origin { | ||
108 | Def, | ||
109 | Call, | ||
110 | } | ||
111 | |||
86 | impl MacroRules { | 112 | impl 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 | ||
79 | impl TokenMap { | 79 | impl 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 | ||
92 | impl RevTokenMap { | 98 | impl 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" | |||
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [lib] | ||
9 | doctest = false | ||
10 | |||
8 | [dependencies] | 11 | [dependencies] |
9 | drop_bomb = "0.1.4" | 12 | drop_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" | |||
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [lib] | ||
9 | doctest = false | ||
10 | |||
8 | [dependencies] | 11 | [dependencies] |
9 | once_cell = "1.0.1" | 12 | once_cell = "1.0.1" |
10 | itertools = "0.8.0" | 13 | itertools = "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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | log = "0.4.5" | 11 | log = "0.4.5" |
9 | rustc-hash = "1.0" | 12 | rustc-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" | |||
7 | description = "Comment and whitespace preserving parser for the Rust langauge" | 7 | description = "Comment and whitespace preserving parser for the Rust langauge" |
8 | repository = "https://github.com/rust-analyzer/rust-analyzer" | 8 | repository = "https://github.com/rust-analyzer/rust-analyzer" |
9 | 9 | ||
10 | [lib] | ||
11 | doctest = false | ||
12 | |||
10 | [dependencies] | 13 | [dependencies] |
11 | itertools = "0.8.0" | 14 | itertools = "0.8.0" |
12 | rowan = "0.6.1" | 15 | rowan = "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 | ||
18 | pub use self::{ | 18 | pub use self::{ |
19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp}, | 19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, |
20 | extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind}, | 20 | extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind}, |
21 | generated::*, | 21 | generated::*, |
22 | tokens::*, | 22 | tokens::*, |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 25dbd0bed..7c53aa934 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -189,6 +189,52 @@ impl ast::BinExpr { | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
193 | pub enum RangeOp { | ||
194 | /// `..` | ||
195 | Exclusive, | ||
196 | /// `..=` | ||
197 | Inclusive, | ||
198 | } | ||
199 | |||
200 | impl ast::RangeExpr { | ||
201 | fn op_details(&self) -> Option<(usize, SyntaxToken, RangeOp)> { | ||
202 | self.syntax().children_with_tokens().enumerate().find_map(|(ix, child)| { | ||
203 | let token = child.into_token()?; | ||
204 | let bin_op = match token.kind() { | ||
205 | T![..] => RangeOp::Exclusive, | ||
206 | T![..=] => RangeOp::Inclusive, | ||
207 | _ => return None, | ||
208 | }; | ||
209 | Some((ix, token, bin_op)) | ||
210 | }) | ||
211 | } | ||
212 | |||
213 | pub fn op_kind(&self) -> Option<RangeOp> { | ||
214 | self.op_details().map(|t| t.2) | ||
215 | } | ||
216 | |||
217 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
218 | self.op_details().map(|t| t.1) | ||
219 | } | ||
220 | |||
221 | pub fn start(&self) -> Option<ast::Expr> { | ||
222 | let op_ix = self.op_details()?.0; | ||
223 | self.syntax() | ||
224 | .children_with_tokens() | ||
225 | .take(op_ix) | ||
226 | .find_map(|it| ast::Expr::cast(it.into_node()?)) | ||
227 | } | ||
228 | |||
229 | pub fn end(&self) -> Option<ast::Expr> { | ||
230 | let op_ix = self.op_details()?.0; | ||
231 | self.syntax() | ||
232 | .children_with_tokens() | ||
233 | .skip(op_ix + 1) | ||
234 | .find_map(|it| ast::Expr::cast(it.into_node()?)) | ||
235 | } | ||
236 | } | ||
237 | |||
192 | impl ast::IndexExpr { | 238 | impl ast::IndexExpr { |
193 | pub fn base(&self) -> Option<ast::Expr> { | 239 | pub fn base(&self) -> Option<ast::Expr> { |
194 | children(self).nth(0) | 240 | children(self).nth(0) |
diff --git a/crates/ra_syntax/src/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 | ||
3 | use crate::{ | 3 | use 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 | ||
12 | impl AstToken for Comment { | 12 | impl 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 | ||
95 | impl AstToken for Whitespace { | 94 | impl 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 | |||
113 | pub struct String(SyntaxToken); | ||
114 | |||
115 | impl 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 | |||
127 | impl 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 | |||
151 | pub struct RawString(SyntaxToken); | ||
152 | |||
153 | impl 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 | |||
165 | impl 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 | |||
176 | fn 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] |
178 | macro_rules! match_ast { | 178 | macro_rules! match_ast { |
179 | (match $node:ident { | 179 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; |
180 | |||
181 | (match ($node:expr) { | ||
180 | $( ast::$ast:ident($it:ident) => $res:block, )* | 182 | $( ast::$ast:ident($it:ident) => $res:block, )* |
181 | _ => $catch_all:expr, | 183 | _ => $catch_all:expr $(,)? |
182 | }) => {{ | 184 | }) => {{ |
183 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | 185 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* |
184 | { $catch_all } | 186 | { $catch_all } |
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs index 1f60a7aab..6c171df8d 100644 --- a/crates/ra_syntax/src/syntax_error.rs +++ b/crates/ra_syntax/src/syntax_error.rs | |||
@@ -83,6 +83,7 @@ pub enum SyntaxErrorKind { | |||
83 | InvalidMatchInnerAttr, | 83 | InvalidMatchInnerAttr, |
84 | InvalidTupleIndexFormat, | 84 | InvalidTupleIndexFormat, |
85 | VisibilityNotAllowed, | 85 | VisibilityNotAllowed, |
86 | InclusiveRangeMissingEnd, | ||
86 | } | 87 | } |
87 | 88 | ||
88 | impl fmt::Display for SyntaxErrorKind { | 89 | impl fmt::Display for SyntaxErrorKind { |
@@ -103,6 +104,9 @@ impl fmt::Display for SyntaxErrorKind { | |||
103 | VisibilityNotAllowed => { | 104 | VisibilityNotAllowed => { |
104 | write!(f, "unnecessary visibility qualifier") | 105 | write!(f, "unnecessary visibility qualifier") |
105 | } | 106 | } |
107 | InclusiveRangeMissingEnd => { | ||
108 | write!(f, "An inclusive range must have an end expression") | ||
109 | } | ||
106 | } | 110 | } |
107 | } | 111 | } |
108 | } | 112 | } |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 2d596763e..222ac15f8 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -103,6 +103,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
103 | ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, | 103 | ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
104 | ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, | 104 | ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
105 | ast::Visibility(it) => { validate_visibility(it, &mut errors) }, | 105 | ast::Visibility(it) => { validate_visibility(it, &mut errors) }, |
106 | ast::RangeExpr(it) => { validate_range_expr(it, &mut errors) }, | ||
106 | _ => (), | 107 | _ => (), |
107 | } | 108 | } |
108 | } | 109 | } |
@@ -227,3 +228,12 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) { | |||
227 | .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range())) | 228 | .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range())) |
228 | } | 229 | } |
229 | } | 230 | } |
231 | |||
232 | fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { | ||
233 | if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() { | ||
234 | errors.push(SyntaxError::new( | ||
235 | SyntaxErrorKind::InclusiveRangeMissingEnd, | ||
236 | expr.syntax().text_range(), | ||
237 | )); | ||
238 | } | ||
239 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs new file mode 100644 index 000000000..0b4ed7a2b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | 0..=; | ||
3 | ..=; | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt new file mode 100644 index 000000000..3810b9680 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | SOURCE_FILE@[0; 33) | ||
2 | FN_DEF@[0; 32) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 32) | ||
12 | BLOCK@[10; 32) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | EXPR_STMT@[16; 21) | ||
16 | RANGE_EXPR@[16; 20) | ||
17 | LITERAL@[16; 17) | ||
18 | INT_NUMBER@[16; 17) "0" | ||
19 | DOTDOTEQ@[17; 20) "..=" | ||
20 | SEMI@[20; 21) ";" | ||
21 | WHITESPACE@[21; 26) "\n " | ||
22 | EXPR_STMT@[26; 30) | ||
23 | RANGE_EXPR@[26; 29) | ||
24 | DOTDOTEQ@[26; 29) "..=" | ||
25 | SEMI@[29; 30) ";" | ||
26 | WHITESPACE@[30; 31) "\n" | ||
27 | R_CURLY@[31; 32) "}" | ||
28 | WHITESPACE@[32; 33) "\n" | ||
29 | error [16; 20): An inclusive range must have an end expression | ||
30 | error [26; 29): An inclusive range must have an end expression | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs new file mode 100644 index 000000000..f063ffadb --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | 0 as usize ..; | ||
3 | 1 + 2 as usize ..; | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt b/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt new file mode 100644 index 000000000..ad0c4a3fe --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0060_as_range.txt | |||
@@ -0,0 +1,56 @@ | |||
1 | SOURCE_FILE@[0; 56) | ||
2 | FN_DEF@[0; 55) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 55) | ||
12 | BLOCK@[10; 55) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | EXPR_STMT@[16; 30) | ||
16 | RANGE_EXPR@[16; 29) | ||
17 | CAST_EXPR@[16; 26) | ||
18 | LITERAL@[16; 17) | ||
19 | INT_NUMBER@[16; 17) "0" | ||
20 | WHITESPACE@[17; 18) " " | ||
21 | AS_KW@[18; 20) "as" | ||
22 | WHITESPACE@[20; 21) " " | ||
23 | PATH_TYPE@[21; 26) | ||
24 | PATH@[21; 26) | ||
25 | PATH_SEGMENT@[21; 26) | ||
26 | NAME_REF@[21; 26) | ||
27 | IDENT@[21; 26) "usize" | ||
28 | WHITESPACE@[26; 27) " " | ||
29 | DOTDOT@[27; 29) ".." | ||
30 | SEMI@[29; 30) ";" | ||
31 | WHITESPACE@[30; 35) "\n " | ||
32 | EXPR_STMT@[35; 53) | ||
33 | RANGE_EXPR@[35; 52) | ||
34 | BIN_EXPR@[35; 49) | ||
35 | LITERAL@[35; 36) | ||
36 | INT_NUMBER@[35; 36) "1" | ||
37 | WHITESPACE@[36; 37) " " | ||
38 | PLUS@[37; 38) "+" | ||
39 | WHITESPACE@[38; 39) " " | ||
40 | CAST_EXPR@[39; 49) | ||
41 | LITERAL@[39; 40) | ||
42 | INT_NUMBER@[39; 40) "2" | ||
43 | WHITESPACE@[40; 41) " " | ||
44 | AS_KW@[41; 43) "as" | ||
45 | WHITESPACE@[43; 44) " " | ||
46 | PATH_TYPE@[44; 49) | ||
47 | PATH@[44; 49) | ||
48 | PATH_SEGMENT@[44; 49) | ||
49 | NAME_REF@[44; 49) | ||
50 | IDENT@[44; 49) "usize" | ||
51 | WHITESPACE@[49; 50) " " | ||
52 | DOTDOT@[50; 52) ".." | ||
53 | SEMI@[52; 53) ";" | ||
54 | WHITESPACE@[53; 54) "\n" | ||
55 | R_CURLY@[54; 55) "}" | ||
56 | WHITESPACE@[55; 56) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs new file mode 100644 index 000000000..2c4ed11e1 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn main() { | ||
2 | match .. { | ||
3 | } | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt new file mode 100644 index 000000000..bdfac9b76 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | SOURCE_FILE@[0; 35) | ||
2 | FN_DEF@[0; 34) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 34) | ||
12 | BLOCK@[10; 34) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | MATCH_EXPR@[16; 32) | ||
16 | MATCH_KW@[16; 21) "match" | ||
17 | WHITESPACE@[21; 22) " " | ||
18 | RANGE_EXPR@[22; 24) | ||
19 | DOTDOT@[22; 24) ".." | ||
20 | WHITESPACE@[24; 25) " " | ||
21 | MATCH_ARM_LIST@[25; 32) | ||
22 | L_CURLY@[25; 26) "{" | ||
23 | WHITESPACE@[26; 31) "\n " | ||
24 | R_CURLY@[31; 32) "}" | ||
25 | WHITESPACE@[32; 33) "\n" | ||
26 | R_CURLY@[33; 34) "}" | ||
27 | WHITESPACE@[34; 35) "\n" | ||
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" | |||
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [lib] | ||
9 | doctest = false | ||
10 | |||
8 | [dependencies] | 11 | [dependencies] |
9 | text_unit = "0.1.6" | 12 | text_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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = 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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | ra_vfs = "0.5.0" | 11 | ra_vfs = "0.5.0" |
9 | globset = "0.4.4" | 12 | globset = "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" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | difference = "2.0.0" | 11 | difference = "2.0.0" |
9 | text_unit = "0.1.2" | 12 | text_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() { |