aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs4
-rw-r--r--crates/ra_assists/src/assists/add_custom_impl.rs206
-rw-r--r--crates/ra_assists/src/assists/add_import.rs18
-rw-r--r--crates/ra_assists/src/assists/add_new.rs86
-rw-r--r--crates/ra_assists/src/assists/early_return.rs10
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs19
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/test_db.rs2
-rw-r--r--crates/ra_batch/src/lib.rs2
-rw-r--r--crates/ra_cli/Cargo.toml6
-rw-r--r--crates/ra_cli/src/analysis_stats.rs15
-rw-r--r--crates/ra_cli/src/main.rs3
-rw-r--r--crates/ra_db/src/input.rs9
-rw-r--r--crates/ra_hir/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model.rs409
-rw-r--r--crates/ra_hir/src/code_model/src.rs128
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/debug.rs94
-rw-r--r--crates/ra_hir/src/from_id.rs14
-rw-r--r--crates/ra_hir/src/from_source.rs362
-rw-r--r--crates/ra_hir/src/has_source.rs127
-rw-r--r--crates/ra_hir/src/lib.rs26
-rw-r--r--crates/ra_hir/src/source_binder.rs213
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir_def/Cargo.toml3
-rw-r--r--crates/ra_hir_def/src/adt.rs30
-rw-r--r--crates/ra_hir_def/src/attr.rs31
-rw-r--r--crates/ra_hir_def/src/body.rs108
-rw-r--r--crates/ra_hir_def/src/body/lower.rs108
-rw-r--r--crates/ra_hir_def/src/body/scope.rs10
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs42
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs177
-rw-r--r--crates/ra_hir_def/src/data.rs154
-rw-r--r--crates/ra_hir_def/src/db.rs29
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs6
-rw-r--r--crates/ra_hir_def/src/docs.rs22
-rw-r--r--crates/ra_hir_def/src/dyn_map.rs108
-rw-r--r--crates/ra_hir_def/src/expr.rs15
-rw-r--r--crates/ra_hir_def/src/generics.rs174
-rw-r--r--crates/ra_hir_def/src/item_scope.rs172
-rw-r--r--crates/ra_hir_def/src/keys.rs56
-rw-r--r--crates/ra_hir_def/src/lang_item.rs2
-rw-r--r--crates/ra_hir_def/src/lib.rs346
-rw-r--r--crates/ra_hir_def/src/marks.rs1
-rw-r--r--crates/ra_hir_def/src/nameres.rs224
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs637
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs53
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs21
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs24
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs4
-rw-r--r--crates/ra_hir_def/src/path.rs527
-rw-r--r--crates/ra_hir_def/src/path/lower.rs178
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs118
-rw-r--r--crates/ra_hir_def/src/per_ns.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs296
-rw-r--r--crates/ra_hir_def/src/src.rs36
-rw-r--r--crates/ra_hir_def/src/trace.rs8
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs321
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs244
-rw-r--r--crates/ra_hir_expand/src/db.rs66
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs4
-rw-r--r--crates/ra_hir_expand/src/either.rs54
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs9
-rw-r--r--crates/ra_hir_expand/src/lib.rs217
-rw-r--r--crates/ra_hir_expand/src/name.rs158
-rw-r--r--crates/ra_hir_expand/src/quote.rs40
-rw-r--r--crates/ra_hir_ty/Cargo.toml7
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs18
-rw-r--r--crates/ra_hir_ty/src/db.rs47
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs14
-rw-r--r--crates/ra_hir_ty/src/display.rs12
-rw-r--r--crates/ra_hir_ty/src/expr.rs8
-rw-r--r--crates/ra_hir_ty/src/infer.rs361
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs27
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs247
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs86
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs276
-rw-r--r--crates/ra_hir_ty/src/lib.rs96
-rw-r--r--crates/ra_hir_ty/src/lower.rs174
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs238
-rw-r--r--crates/ra_hir_ty/src/test_db.rs4
-rw-r--r--crates/ra_hir_ty/src/tests.rs4767
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs159
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs390
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs1005
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs238
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs333
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs1663
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs1598
-rw-r--r--crates/ra_hir_ty/src/traits.rs25
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs178
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs667
-rw-r--r--crates/ra_hir_ty/src/utils.rs90
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/call_info.rs43
-rw-r--r--crates/ra_ide/src/change.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs35
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs17
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs37
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs32
-rw-r--r--crates/ra_ide/src/db.rs14
-rw-r--r--crates/ra_ide/src/diagnostics.rs2
-rw-r--r--crates/ra_ide/src/display.rs2
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs84
-rw-r--r--crates/ra_ide/src/expand.rs89
-rw-r--r--crates/ra_ide/src/expand_macro.rs21
-rw-r--r--crates/ra_ide/src/extend_selection.rs80
-rw-r--r--crates/ra_ide/src/goto_definition.rs393
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs43
-rw-r--r--crates/ra_ide/src/hover.rs126
-rw-r--r--crates/ra_ide/src/impls.rs10
-rw-r--r--crates/ra_ide/src/inlay_hints.rs68
-rw-r--r--crates/ra_ide/src/lib.rs5
-rw-r--r--crates/ra_ide/src/marks.rs9
-rw-r--r--crates/ra_ide/src/parent_module.rs11
-rw-r--r--crates/ra_ide/src/references.rs10
-rw-r--r--crates/ra_ide/src/references/classify.rs29
-rw-r--r--crates/ra_ide/src/references/name_definition.rs6
-rw-r--r--crates/ra_ide/src/references/rename.rs54
-rw-r--r--crates/ra_ide/src/references/search_scope.rs16
-rw-r--r--crates/ra_ide/src/runnables.rs6
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html31
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html6
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs129
-rw-r--r--crates/ra_lsp_server/Cargo.toml4
-rw-r--r--crates/ra_lsp_server/build.rs15
-rw-r--r--crates/ra_lsp_server/src/caps.rs20
-rw-r--r--crates/ra_lsp_server/src/config.rs5
-rw-r--r--crates/ra_lsp_server/src/conv.rs7
-rw-r--r--crates/ra_lsp_server/src/main.rs25
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs19
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs18
-rw-r--r--crates/ra_lsp_server/src/main_loop/pending_requests.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs2
-rw-r--r--crates/ra_lsp_server/src/markdown.rs2
-rw-r--r--crates/ra_lsp_server/src/req.rs29
-rw-r--r--crates/ra_lsp_server/src/world.rs75
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs118
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs3
-rw-r--r--crates/ra_mbe/src/lib.rs25
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs8
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs17
-rw-r--r--crates/ra_mbe/src/subtree_source.rs14
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs242
-rw-r--r--crates/ra_mbe/src/tests.rs684
-rw-r--r--crates/ra_parser/src/grammar.rs2
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs10
-rw-r--r--crates/ra_parser/src/grammar/items.rs30
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs11
-rw-r--r--crates/ra_parser/src/lib.rs1
-rw-r--r--crates/ra_parser/src/parser.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs9
-rw-r--r--crates/ra_parser/src/token_set.rs8
-rw-r--r--crates/ra_prof/src/lib.rs8
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs37
-rw-r--r--crates/ra_project_model/src/lib.rs14
-rw-r--r--crates/ra_syntax/Cargo.toml9
-rw-r--r--crates/ra_syntax/src/algo.rs12
-rw-r--r--crates/ra_syntax/src/ast/edit.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs34
-rw-r--r--crates/ra_syntax/src/ast/make.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron16
-rw-r--r--crates/ra_syntax/src/ptr.rs14
-rw-r--r--crates/ra_syntax/src/syntax_node.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt328
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt83
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt23
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt45
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt21
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs (renamed from crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt176
-rw-r--r--crates/ra_tt/src/lib.rs43
-rw-r--r--crates/test_utils/src/lib.rs15
187 files changed, 13463 insertions, 9824 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 0ea84d548..993aebc47 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +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.
2use hir::{db::HirDatabase, SourceAnalyzer}; 2use hir::{db::HirDatabase, InFile, SourceAnalyzer};
3use ra_db::FileRange; 3use ra_db::FileRange;
4use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
5use ra_syntax::{ 5use ra_syntax::{
@@ -117,7 +117,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
117 node: &SyntaxNode, 117 node: &SyntaxNode,
118 offset: Option<TextUnit>, 118 offset: Option<TextUnit>,
119 ) -> SourceAnalyzer { 119 ) -> SourceAnalyzer {
120 SourceAnalyzer::new(self.db, hir::Source::new(self.frange.file_id.into(), node), offset) 120 SourceAnalyzer::new(self.db, InFile::new(self.frange.file_id.into(), node), offset)
121 } 121 }
122 122
123 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { 123 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement {
diff --git a/crates/ra_assists/src/assists/add_custom_impl.rs b/crates/ra_assists/src/assists/add_custom_impl.rs
new file mode 100644
index 000000000..037306fd6
--- /dev/null
+++ b/crates/ra_assists/src/assists/add_custom_impl.rs
@@ -0,0 +1,206 @@
1//! FIXME: write short doc here
2
3use crate::{Assist, AssistCtx, AssistId};
4use hir::db::HirDatabase;
5use join_to_string::join;
6use ra_syntax::{
7 ast::{self, AstNode},
8 Direction, SmolStr,
9 SyntaxKind::{IDENT, WHITESPACE},
10 TextRange, TextUnit,
11};
12
13const DERIVE_TRAIT: &'static str = "derive";
14
15// Assist: add_custom_impl
16//
17// Adds impl block for derived trait.
18//
19// ```
20// #[derive(Deb<|>ug, Display)]
21// struct S;
22// ```
23// ->
24// ```
25// #[derive(Display)]
26// struct S;
27//
28// impl Debug for S {
29//
30// }
31// ```
32pub(crate) fn add_custom_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
33 let input = ctx.find_node_at_offset::<ast::AttrInput>()?;
34 let attr = input.syntax().parent().and_then(ast::Attr::cast)?;
35
36 let attr_name = attr
37 .syntax()
38 .descendants_with_tokens()
39 .filter(|t| t.kind() == IDENT)
40 .find_map(|i| i.into_token())
41 .filter(|t| *t.text() == DERIVE_TRAIT)?
42 .text()
43 .clone();
44
45 let trait_token =
46 ctx.token_at_offset().filter(|t| t.kind() == IDENT && *t.text() != attr_name).next()?;
47
48 let annotated = attr.syntax().siblings(Direction::Next).find_map(|s| ast::Name::cast(s))?;
49 let annotated_name = annotated.syntax().text().to_string();
50 let start_offset = annotated.syntax().parent()?.text_range().end();
51
52 ctx.add_assist(AssistId("add_custom_impl"), "add custom impl", |edit| {
53 edit.target(attr.syntax().text_range());
54
55 let new_attr_input = input
56 .syntax()
57 .descendants_with_tokens()
58 .filter(|t| t.kind() == IDENT)
59 .filter_map(|t| t.into_token().map(|t| t.text().clone()))
60 .filter(|t| t != trait_token.text())
61 .collect::<Vec<SmolStr>>();
62 let has_more_derives = new_attr_input.len() > 0;
63 let new_attr_input =
64 join(new_attr_input.iter()).separator(", ").surround_with("(", ")").to_string();
65 let new_attr_input_len = new_attr_input.len();
66
67 let mut buf = String::new();
68 buf.push_str("\n\nimpl ");
69 buf.push_str(trait_token.text().as_str());
70 buf.push_str(" for ");
71 buf.push_str(annotated_name.as_str());
72 buf.push_str(" {\n");
73
74 let cursor_delta = if has_more_derives {
75 edit.replace(input.syntax().text_range(), new_attr_input);
76 input.syntax().text_range().len() - TextUnit::from_usize(new_attr_input_len)
77 } else {
78 let attr_range = attr.syntax().text_range();
79 edit.delete(attr_range);
80
81 let line_break_range = attr
82 .syntax()
83 .next_sibling_or_token()
84 .filter(|t| t.kind() == WHITESPACE)
85 .map(|t| t.text_range())
86 .unwrap_or(TextRange::from_to(TextUnit::from(0), TextUnit::from(0)));
87 edit.delete(line_break_range);
88
89 attr_range.len() + line_break_range.len()
90 };
91
92 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - cursor_delta);
93 buf.push_str("\n}");
94 edit.insert(start_offset, buf);
95 })
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::helpers::{check_assist, check_assist_not_applicable};
102
103 #[test]
104 fn add_custom_impl_for_unique_input() {
105 check_assist(
106 add_custom_impl,
107 "
108#[derive(Debu<|>g)]
109struct Foo {
110 bar: String,
111}
112 ",
113 "
114struct Foo {
115 bar: String,
116}
117
118impl Debug for Foo {
119<|>
120}
121 ",
122 )
123 }
124
125 #[test]
126 fn add_custom_impl_for_with_visibility_modifier() {
127 check_assist(
128 add_custom_impl,
129 "
130#[derive(Debug<|>)]
131pub struct Foo {
132 bar: String,
133}
134 ",
135 "
136pub struct Foo {
137 bar: String,
138}
139
140impl Debug for Foo {
141<|>
142}
143 ",
144 )
145 }
146
147 #[test]
148 fn add_custom_impl_when_multiple_inputs() {
149 check_assist(
150 add_custom_impl,
151 "
152#[derive(Display, Debug<|>, Serialize)]
153struct Foo {}
154 ",
155 "
156#[derive(Display, Serialize)]
157struct Foo {}
158
159impl Debug for Foo {
160<|>
161}
162 ",
163 )
164 }
165
166 #[test]
167 fn test_ignore_derive_macro_without_input() {
168 check_assist_not_applicable(
169 add_custom_impl,
170 "
171#[derive(<|>)]
172struct Foo {}
173 ",
174 )
175 }
176
177 #[test]
178 fn test_ignore_if_cursor_on_param() {
179 check_assist_not_applicable(
180 add_custom_impl,
181 "
182#[derive<|>(Debug)]
183struct Foo {}
184 ",
185 );
186
187 check_assist_not_applicable(
188 add_custom_impl,
189 "
190#[derive(Debug)<|>]
191struct Foo {}
192 ",
193 )
194 }
195
196 #[test]
197 fn test_ignore_if_not_derive() {
198 check_assist_not_applicable(
199 add_custom_impl,
200 "
201#[allow(non_camel_<|>case_types)]
202struct Foo {}
203 ",
204 )
205 }
206}
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index 363ade016..b8752cbad 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -578,17 +578,21 @@ fn apply_auto_import(
578 578
579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { 579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
580 let mut ps = Vec::<SmolStr>::with_capacity(10); 580 let mut ps = Vec::<SmolStr>::with_capacity(10);
581 match path.kind { 581 match path.kind() {
582 hir::PathKind::Abs => ps.push("".into()), 582 hir::PathKind::Abs => ps.push("".into()),
583 hir::PathKind::Crate => ps.push("crate".into()), 583 hir::PathKind::Crate => ps.push("crate".into()),
584 hir::PathKind::Plain => {} 584 hir::PathKind::Plain => {}
585 hir::PathKind::Self_ => ps.push("self".into()), 585 hir::PathKind::Super(0) => ps.push("self".into()),
586 hir::PathKind::Super => ps.push("super".into()), 586 hir::PathKind::Super(lvl) => {
587 hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, 587 let mut chain = "super".to_string();
588 } 588 for _ in 0..*lvl {
589 for s in path.segments.iter() { 589 chain += "::super";
590 ps.push(s.name.to_string().into()); 590 }
591 ps.push(chain.into());
592 }
593 hir::PathKind::DollarCrate(_) => return None,
591 } 594 }
595 ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
592 Some(ps) 596 Some(ps)
593} 597}
594 598
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index 8f68bd5fb..b2f946fac 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -1,5 +1,5 @@
1use format_buf::format; 1use format_buf::format;
2use hir::{db::HirDatabase, FromSource}; 2use hir::{db::HirDatabase, FromSource, InFile};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{ 5 ast::{
@@ -56,42 +56,39 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
56 let vis = vis.as_ref().map(String::as_str).unwrap_or(""); 56 let vis = vis.as_ref().map(String::as_str).unwrap_or("");
57 write!(&mut buf, " {}fn new(", vis).unwrap(); 57 write!(&mut buf, " {}fn new(", vis).unwrap();
58 58
59 join(field_list.fields().map(|f| { 59 join(field_list.fields().filter_map(|f| {
60 format!( 60 Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
61 "{}: {}",
62 f.name().unwrap().syntax().text(),
63 f.ascribed_type().unwrap().syntax().text()
64 )
65 })) 61 }))
66 .separator(", ") 62 .separator(", ")
67 .to_buf(&mut buf); 63 .to_buf(&mut buf);
68 64
69 buf.push_str(") -> Self { Self {"); 65 buf.push_str(") -> Self { Self {");
70 66
71 join(field_list.fields().map(|f| f.name().unwrap().syntax().text())) 67 join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
72 .separator(", ") 68 .separator(", ")
73 .surround_with(" ", " ") 69 .surround_with(" ", " ")
74 .to_buf(&mut buf); 70 .to_buf(&mut buf);
75 71
76 buf.push_str("} }"); 72 buf.push_str("} }");
77 73
78 let (start_offset, end_offset) = if let Some(impl_block) = impl_block { 74 let (start_offset, end_offset) = impl_block
79 buf.push('\n'); 75 .and_then(|impl_block| {
80 let start = impl_block 76 buf.push('\n');
81 .syntax() 77 let start = impl_block
82 .descendants_with_tokens() 78 .syntax()
83 .find(|t| t.kind() == T!['{']) 79 .descendants_with_tokens()
84 .unwrap() 80 .find(|t| t.kind() == T!['{'])?
85 .text_range() 81 .text_range()
86 .end(); 82 .end();
87 83
88 (start, TextUnit::from_usize(1)) 84 Some((start, TextUnit::from_usize(1)))
89 } else { 85 })
90 buf = generate_impl_text(&strukt, &buf); 86 .unwrap_or_else(|| {
91 let start = strukt.syntax().text_range().end(); 87 buf = generate_impl_text(&strukt, &buf);
92 88 let start = strukt.syntax().text_range().end();
93 (start, TextUnit::from_usize(3)) 89
94 }; 90 (start, TextUnit::from_usize(3))
91 });
95 92
96 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset); 93 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
97 edit.insert(start_offset, buf); 94 edit.insert(start_offset, buf);
@@ -141,44 +138,41 @@ fn find_struct_impl(
141 })?; 138 })?;
142 139
143 let struct_ty = { 140 let struct_ty = {
144 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: strukt.clone() }; 141 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
145 hir::Struct::from_source(db, src).unwrap().ty(db) 142 hir::Struct::from_source(db, src)?.ty(db)
146 }; 143 };
147 144
148 let mut found_new_fn = false; 145 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
149 146 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
150 let block = module.descendants().filter_map(ast::ImplBlock::cast).find(|impl_blk| { 147 let blk = hir::ImplBlock::from_source(db, src)?;
151 if found_new_fn {
152 return false;
153 }
154
155 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
156 let blk = hir::ImplBlock::from_source(db, src).unwrap();
157 148
158 let same_ty = blk.target_ty(db) == struct_ty; 149 let same_ty = blk.target_ty(db) == struct_ty;
159 let not_trait_impl = blk.target_trait(db).is_none(); 150 let not_trait_impl = blk.target_trait(db).is_none();
160 151
161 if !(same_ty && not_trait_impl) { 152 if !(same_ty && not_trait_impl) {
162 return false; 153 None
154 } else {
155 Some(impl_blk)
163 } 156 }
164
165 found_new_fn = has_new_fn(impl_blk);
166 true
167 }); 157 });
168 158
169 if found_new_fn { 159 if let Some(ref impl_blk) = block {
170 None 160 if has_new_fn(impl_blk) {
171 } else { 161 return None;
172 Some(block) 162 }
173 } 163 }
164
165 Some(block)
174} 166}
175 167
176fn has_new_fn(imp: &ast::ImplBlock) -> bool { 168fn has_new_fn(imp: &ast::ImplBlock) -> bool {
177 if let Some(il) = imp.item_list() { 169 if let Some(il) = imp.item_list() {
178 for item in il.impl_items() { 170 for item in il.impl_items() {
179 if let ast::ImplItem::FnDef(f) = item { 171 if let ast::ImplItem::FnDef(f) = item {
180 if f.name().unwrap().text().eq_ignore_ascii_case("new") { 172 if let Some(name) = f.name() {
181 return true; 173 if name.text().eq_ignore_ascii_case("new") {
174 return true;
175 }
182 } 176 }
183 } 177 }
184 } 178 }
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index 264412526..023917aca 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -83,8 +83,8 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
83 let parent_container = parent_block.syntax().parent()?.parent()?; 83 let parent_container = parent_block.syntax().parent()?.parent()?;
84 84
85 let early_expression: ast::Expr = match parent_container.kind() { 85 let early_expression: ast::Expr = match parent_container.kind() {
86 WHILE_EXPR | LOOP_EXPR => make::expr_continue().into(), 86 WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
87 FN_DEF => make::expr_return().into(), 87 FN_DEF => make::expr_return(),
88 _ => return None, 88 _ => return None,
89 }; 89 };
90 90
@@ -116,13 +116,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
116 ) 116 )
117 .into(), 117 .into(),
118 ), 118 ),
119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(), 119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))),
120 ); 120 );
121 121
122 let sad_arm = make::match_arm( 122 let sad_arm = make::match_arm(
123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate 123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
124 once(make::placeholder_pat().into()), 124 once(make::placeholder_pat().into()),
125 early_expression.into(), 125 early_expression,
126 ); 126 );
127 127
128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) 128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
@@ -130,7 +130,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
130 130
131 let let_stmt = make::let_stmt( 131 let let_stmt = make::let_stmt(
132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
133 Some(match_expr.into()), 133 Some(match_expr),
134 ); 134 );
135 let let_stmt = if_indent_level.increase_indent(let_stmt); 135 let let_stmt = if_indent_level.increase_indent(let_stmt);
136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) 136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 3c716c2d1..4586eeb59 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -3,6 +3,25 @@
3use super::check; 3use super::check;
4 4
5#[test] 5#[test]
6fn doctest_add_custom_impl() {
7 check(
8 "add_custom_impl",
9 r#####"
10#[derive(Deb<|>ug, Display)]
11struct S;
12"#####,
13 r#####"
14#[derive(Display)]
15struct S;
16
17impl Debug for S {
18
19}
20"#####,
21 )
22}
23
24#[test]
6fn doctest_add_derive() { 25fn doctest_add_derive() {
7 check( 26 check(
8 "add_derive", 27 "add_derive",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index a372bd8b9..98fb20b22 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -95,6 +95,7 @@ mod assists {
95 mod add_derive; 95 mod add_derive;
96 mod add_explicit_type; 96 mod add_explicit_type;
97 mod add_impl; 97 mod add_impl;
98 mod add_custom_impl;
98 mod add_new; 99 mod add_new;
99 mod apply_demorgan; 100 mod apply_demorgan;
100 mod invert_if; 101 mod invert_if;
@@ -121,6 +122,7 @@ mod assists {
121 add_derive::add_derive, 122 add_derive::add_derive,
122 add_explicit_type::add_explicit_type, 123 add_explicit_type::add_explicit_type,
123 add_impl::add_impl, 124 add_impl::add_impl,
125 add_custom_impl::add_custom_impl,
124 add_new::add_new, 126 add_new::add_new,
125 apply_demorgan::apply_demorgan, 127 apply_demorgan::apply_demorgan,
126 invert_if::invert_if, 128 invert_if::invert_if,
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs
index 523259fd4..d5249f308 100644
--- a/crates/ra_assists/src/test_db.rs
+++ b/crates/ra_assists/src/test_db.rs
@@ -43,5 +43,3 @@ impl FileLoader for TestDB {
43 FileLoaderDelegate(self).relevant_crates(file_id) 43 FileLoaderDelegate(self).relevant_crates(file_id)
44 } 44 }
45} 45}
46
47impl hir::debug::HirDebugHelper for TestDB {}
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index 2c9645c00..7744ba85a 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -22,7 +22,7 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
22 22
23pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { 23pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
24 let root = std::env::current_dir()?.join(root); 24 let root = std::env::current_dir()?.join(root);
25 let ws = ProjectWorkspace::discover(root.as_ref())?; 25 let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?;
26 let project_roots = ws.to_roots(); 26 let project_roots = ws.to_roots();
27 let (sender, receiver) = unbounded(); 27 let (sender, receiver) = unbounded();
28 let sender = Box::new(move |t| sender.send(t).unwrap()); 28 let sender = Box::new(move |t| sender.send(t).unwrap());
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index c7e0d0f0f..12af075f7 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -7,12 +7,14 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9pico-args = "0.3.0" 9pico-args = "0.3.0"
10flexi_logger = "0.14.0" 10env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] }
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_ide = { path = "../ra_ide" } 13ra_ide = { path = "../ra_ide" }
14ra_batch = { path = "../ra_batch" } 14ra_batch = { path = "../ra_batch" }
15ra_hir = { path = "../ra_hir" } 15hir = { path = "../ra_hir", package = "ra_hir" }
16hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
17hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
16ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
17 19
18[dependencies.ra_prof] 20[dependencies.ra_prof]
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 9b1802a5f..ac65415a5 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,8 +2,13 @@
2 2
3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
4 4
5use hir::{
6 db::{DefDatabase, HirDatabase},
7 AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
8};
9use hir_def::FunctionId;
10use hir_ty::{Ty, TypeWalk};
5use ra_db::SourceDatabaseExt; 11use ra_db::SourceDatabaseExt;
6use ra_hir::{AssocItem, Crate, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
7use ra_syntax::AstNode; 12use ra_syntax::AstNode;
8 13
9use crate::{progress_report::ProgressReport, Result, Verbosity}; 14use crate::{progress_report::ProgressReport, Result, Verbosity};
@@ -101,8 +106,9 @@ pub fn run(
101 continue; 106 continue;
102 } 107 }
103 } 108 }
104 let body = f.body(db); 109 let f_id = FunctionId::from(f);
105 let inference_result = f.infer(db); 110 let body = db.body(f_id.into());
111 let inference_result = db.infer(f_id.into());
106 for (expr_id, _) in body.exprs.iter() { 112 for (expr_id, _) in body.exprs.iter() {
107 let ty = &inference_result[expr_id]; 113 let ty = &inference_result[expr_id];
108 num_exprs += 1; 114 num_exprs += 1;
@@ -122,7 +128,8 @@ pub fn run(
122 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
123 num_type_mismatches += 1; 129 num_type_mismatches += 1;
124 if verbosity.is_verbose() { 130 if verbosity.is_verbose() {
125 let src = f.body_source_map(db).expr_syntax(expr_id); 131 let (_, sm) = db.body_with_source_map(f_id.into());
132 let src = sm.expr_syntax(expr_id);
126 if let Some(src) = src { 133 if let Some(src) = src {
127 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly 134 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
128 let original_file = src.file_id.original_file(db); 135 let original_file = src.file_id.original_file(db);
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index fe847e611..3808590ab 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -7,7 +7,6 @@ mod progress_report;
7 7
8use std::{error::Error, fmt::Write, io::Read}; 8use std::{error::Error, fmt::Write, io::Read};
9 9
10use flexi_logger::Logger;
11use pico_args::Arguments; 10use pico_args::Arguments;
12use ra_ide::{file_structure, Analysis}; 11use ra_ide::{file_structure, Analysis};
13use ra_prof::profile; 12use ra_prof::profile;
@@ -32,7 +31,7 @@ impl Verbosity {
32} 31}
33 32
34fn main() -> Result<()> { 33fn main() -> Result<()> {
35 Logger::with_env_or_str("error").start()?; 34 env_logger::try_init()?;
36 35
37 let subcommand = match std::env::args_os().nth(1) { 36 let subcommand = match std::env::args_os().nth(1) {
38 None => { 37 None => {
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index b6d851776..2a7ed20d1 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -235,6 +235,15 @@ impl FromStr for Edition {
235 } 235 }
236} 236}
237 237
238impl fmt::Display for Edition {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 f.write_str(match self {
241 Edition::Edition2015 => "2015",
242 Edition::Edition2018 => "2018",
243 })
244 }
245}
246
238impl Dependency { 247impl Dependency {
239 pub fn crate_id(&self) -> CrateId { 248 pub fn crate_id(&self) -> CrateId {
240 self.crate_id 249 self.crate_id
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index e79361e7c..7dc31ad3c 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -10,9 +10,11 @@ doctest = false
10[dependencies] 10[dependencies]
11log = "0.4.5" 11log = "0.4.5"
12rustc-hash = "1.0" 12rustc-hash = "1.0"
13either = "1.5"
13 14
14ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
15ra_db = { path = "../ra_db" } 16ra_db = { path = "../ra_db" }
17ra_prof = { path = "../ra_prof" }
16hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } 18hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
17hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 19hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
18hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } 20hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 38d66c2a7..bcfc0d03e 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,36 +1,35 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3pub(crate) mod src;
4
5use std::sync::Arc; 2use std::sync::Arc;
6 3
4use either::Either;
7use hir_def::{ 5use hir_def::{
8 adt::VariantData, 6 adt::VariantData,
9 body::{Body, BodySourceMap},
10 builtin_type::BuiltinType, 7 builtin_type::BuiltinType,
11 docs::Documentation, 8 docs::Documentation,
12 expr::{BindingAnnotation, Pat, PatId}, 9 expr::{BindingAnnotation, Pat, PatId},
10 nameres::ModuleSource,
13 per_ns::PerNs, 11 per_ns::PerNs,
14 resolver::HasResolver, 12 resolver::HasResolver,
15 type_ref::{Mutability, TypeRef}, 13 type_ref::{Mutability, TypeRef},
16 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, 14 AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId,
17 HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, 15 LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
18 Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, 16 TypeParamId, UnionId,
19}; 17};
20use hir_expand::{ 18use hir_expand::{
21 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
22 name::{self, AsName}, 20 name::{name, AsName},
23 AstId, MacroDefId, 21 MacroDefId,
22};
23use hir_ty::{
24 autoderef, display::HirFormatter, expr::ExprValidator, ApplicationTy, Canonical, InEnvironment,
25 TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
24}; 26};
25use hir_ty::expr::ExprValidator; 27use ra_db::{CrateId, Edition, FileId};
26use ra_db::{CrateId, Edition, FileId, FilePosition}; 28use ra_syntax::ast;
27use ra_syntax::{ast, AstNode, SyntaxNode};
28 29
29use crate::{ 30use crate::{
30 db::{DefDatabase, HirDatabase}, 31 db::{DefDatabase, HirDatabase},
31 ty::display::HirFormatter, 32 CallableDef, HirDisplay, InFile, Name,
32 ty::{self, InEnvironment, InferenceResult, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk},
33 CallableDef, Either, HirDisplay, Name, Source,
34}; 33};
35 34
36/// hir::Crate describes a single crate. It's the main interface with which 35/// hir::Crate describes a single crate. It's the main interface with which
@@ -38,7 +37,7 @@ use crate::{
38/// root module. 37/// root module.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub struct Crate { 39pub struct Crate {
41 pub(crate) crate_id: CrateId, 40 pub(crate) id: CrateId,
42} 41}
43 42
44#[derive(Debug)] 43#[derive(Debug)]
@@ -48,91 +47,43 @@ pub struct CrateDependency {
48} 47}
49 48
50impl Crate { 49impl Crate {
51 pub fn crate_id(self) -> CrateId {
52 self.crate_id
53 }
54
55 pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> { 50 pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> {
56 db.crate_graph() 51 db.crate_graph()
57 .dependencies(self.crate_id) 52 .dependencies(self.id)
58 .map(|dep| { 53 .map(|dep| {
59 let krate = Crate { crate_id: dep.crate_id() }; 54 let krate = Crate { id: dep.crate_id() };
60 let name = dep.as_name(); 55 let name = dep.as_name();
61 CrateDependency { krate, name } 56 CrateDependency { krate, name }
62 }) 57 })
63 .collect() 58 .collect()
64 } 59 }
65 60
66 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { 61 // FIXME: add `transitive_reverse_dependencies`.
67 let module_id = db.crate_def_map(self.crate_id).root; 62 pub fn reverse_dependencies(self, db: &impl DefDatabase) -> Vec<Crate> {
68 Some(Module::new(self, module_id))
69 }
70
71 pub fn edition(self, db: &impl DefDatabase) -> Edition {
72 let crate_graph = db.crate_graph(); 63 let crate_graph = db.crate_graph();
73 crate_graph.edition(self.crate_id) 64 crate_graph
74 } 65 .iter()
75 66 .filter(|&krate| crate_graph.dependencies(krate).any(|it| it.crate_id == self.id))
76 pub fn all(db: &impl DefDatabase) -> Vec<Crate> { 67 .map(|id| Crate { id })
77 db.crate_graph().iter().map(|crate_id| Crate { crate_id }).collect() 68 .collect()
78 } 69 }
79}
80
81pub enum ModuleSource {
82 SourceFile(ast::SourceFile),
83 Module(ast::Module),
84}
85 70
86impl ModuleSource { 71 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
87 pub fn new( 72 let module_id = db.crate_def_map(self.id).root;
88 db: &impl DefDatabase, 73 Some(Module::new(self, module_id))
89 file_id: Option<FileId>,
90 decl_id: Option<AstId<ast::Module>>,
91 ) -> ModuleSource {
92 match (file_id, decl_id) {
93 (Some(file_id), _) => {
94 let source_file = db.parse(file_id).tree();
95 ModuleSource::SourceFile(source_file)
96 }
97 (None, Some(item_id)) => {
98 let module = item_id.to_node(db);
99 assert!(module.item_list().is_some(), "expected inline module");
100 ModuleSource::Module(module)
101 }
102 (None, None) => panic!(),
103 }
104 } 74 }
105 75
106 // FIXME: this methods do not belong here 76 pub fn root_file(self, db: &impl DefDatabase) -> FileId {
107 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource { 77 db.crate_graph().crate_root(self.id)
108 let parse = db.parse(position.file_id);
109 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
110 parse.tree().syntax(),
111 position.offset,
112 ) {
113 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
114 _ => {
115 let source_file = parse.tree();
116 ModuleSource::SourceFile(source_file)
117 }
118 }
119 } 78 }
120 79
121 pub fn from_child_node(db: &impl DefDatabase, child: Source<&SyntaxNode>) -> ModuleSource { 80 pub fn edition(self, db: &impl DefDatabase) -> Edition {
122 if let Some(m) = 81 let crate_graph = db.crate_graph();
123 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) 82 crate_graph.edition(self.id)
124 {
125 ModuleSource::Module(m)
126 } else {
127 let file_id = child.file_id.original_file(db);
128 let source_file = db.parse(file_id).tree();
129 ModuleSource::SourceFile(source_file)
130 }
131 } 83 }
132 84
133 pub fn from_file_id(db: &impl DefDatabase, file_id: FileId) -> ModuleSource { 85 pub fn all(db: &impl DefDatabase) -> Vec<Crate> {
134 let source_file = db.parse(file_id).tree(); 86 db.crate_graph().iter().map(|id| Crate { id }).collect()
135 ModuleSource::SourceFile(source_file)
136 } 87 }
137} 88}
138 89
@@ -171,7 +122,7 @@ pub use hir_def::attr::Attrs;
171 122
172impl Module { 123impl Module {
173 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { 124 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
174 Module { id: ModuleId { krate: krate.crate_id, local_id: crate_module_id } } 125 Module { id: ModuleId { krate: krate.id, local_id: crate_module_id } }
175 } 126 }
176 127
177 /// Name of this module. 128 /// Name of this module.
@@ -189,7 +140,7 @@ impl Module {
189 140
190 /// Returns the crate this module is part of. 141 /// Returns the crate this module is part of.
191 pub fn krate(self) -> Crate { 142 pub fn krate(self) -> Crate {
192 Crate { crate_id: self.id.krate } 143 Crate { id: self.id.krate }
193 } 144 }
194 145
195 /// Topmost parent of this module. Every module has a `crate_root`, but some 146 /// Topmost parent of this module. Every module has a `crate_root`, but some
@@ -200,13 +151,6 @@ impl Module {
200 self.with_module_id(def_map.root) 151 self.with_module_id(def_map.root)
201 } 152 }
202 153
203 /// Finds a child module with the specified name.
204 pub fn child(self, db: &impl DefDatabase, name: &Name) -> Option<Module> {
205 let def_map = db.crate_def_map(self.id.krate);
206 let child_id = def_map[self.id.local_id].children.get(name)?;
207 Some(self.with_module_id(*child_id))
208 }
209
210 /// Iterates over all child modules. 154 /// Iterates over all child modules.
211 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> { 155 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
212 let def_map = db.crate_def_map(self.id.krate); 156 let def_map = db.crate_def_map(self.id.krate);
@@ -236,13 +180,11 @@ impl Module {
236 } 180 }
237 181
238 /// Returns a `ModuleScope`: a set of items, visible in this module. 182 /// Returns a `ModuleScope`: a set of items, visible in this module.
239 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<Import>)> { 183 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef)> {
240 db.crate_def_map(self.id.krate)[self.id.local_id] 184 db.crate_def_map(self.id.krate)[self.id.local_id]
241 .scope 185 .scope
242 .entries() 186 .entries()
243 .map(|(name, res)| { 187 .map(|(name, def)| (name.clone(), def.into()))
244 (name.clone(), res.def.into(), res.import.map(|id| Import { parent: self, id }))
245 })
246 .collect() 188 .collect()
247 } 189 }
248 190
@@ -277,19 +219,14 @@ impl Module {
277 219
278 pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { 220 pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> {
279 let def_map = db.crate_def_map(self.id.krate); 221 let def_map = db.crate_def_map(self.id.krate);
280 def_map[self.id.local_id].impls.iter().copied().map(ImplBlock::from).collect() 222 def_map[self.id.local_id].scope.impls().map(ImplBlock::from).collect()
281 } 223 }
282 224
283 fn with_module_id(self, module_id: LocalModuleId) -> Module { 225 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
284 Module::new(self.krate(), module_id) 226 Module::new(self.krate(), module_id)
285 } 227 }
286} 228}
287 229
288pub struct Import {
289 pub(crate) parent: Module,
290 pub(crate) id: LocalImportId,
291}
292
293#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct StructField { 231pub struct StructField {
295 pub(crate) parent: VariantDef, 232 pub(crate) parent: VariantDef,
@@ -307,8 +244,10 @@ impl StructField {
307 self.parent.variant_data(db).fields()[self.id].name.clone() 244 self.parent.variant_data(db).fields()[self.id].name.clone()
308 } 245 }
309 246
310 pub fn ty(&self, db: &impl HirDatabase) -> Ty { 247 pub fn ty(&self, db: &impl HirDatabase) -> Type {
311 db.field_types(self.parent.into())[self.id].clone() 248 let var_id = self.parent.into();
249 let ty = db.field_types(var_id)[self.id].clone();
250 Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty)
312 } 251 }
313 252
314 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef { 253 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
@@ -323,7 +262,7 @@ pub struct Struct {
323 262
324impl Struct { 263impl Struct {
325 pub fn module(self, db: &impl DefDatabase) -> Module { 264 pub fn module(self, db: &impl DefDatabase) -> Module {
326 Module { id: self.id.module(db) } 265 Module { id: self.id.lookup(db).container.module(db) }
327 } 266 }
328 267
329 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 268 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -343,21 +282,8 @@ impl Struct {
343 .collect() 282 .collect()
344 } 283 }
345 284
346 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
347 db.struct_data(self.id.into())
348 .variant_data
349 .fields()
350 .iter()
351 .find(|(_id, data)| data.name == *name)
352 .map(|(id, _)| StructField { parent: self.into(), id })
353 }
354
355 pub fn ty(self, db: &impl HirDatabase) -> Type { 285 pub fn ty(self, db: &impl HirDatabase) -> Type {
356 Type::from_def(db, self.id.module(db).krate, self.id) 286 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
357 }
358
359 pub fn constructor_ty(self, db: &impl HirDatabase) -> Ty {
360 db.value_ty(self.id.into())
361 } 287 }
362 288
363 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 289 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
@@ -376,11 +302,11 @@ impl Union {
376 } 302 }
377 303
378 pub fn module(self, db: &impl DefDatabase) -> Module { 304 pub fn module(self, db: &impl DefDatabase) -> Module {
379 Module { id: self.id.module(db) } 305 Module { id: self.id.lookup(db).container.module(db) }
380 } 306 }
381 307
382 pub fn ty(self, db: &impl HirDatabase) -> Type { 308 pub fn ty(self, db: &impl HirDatabase) -> Type {
383 Type::from_def(db, self.id.module(db).krate, self.id) 309 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
384 } 310 }
385 311
386 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { 312 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
@@ -392,15 +318,6 @@ impl Union {
392 .collect() 318 .collect()
393 } 319 }
394 320
395 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
396 db.union_data(self.id)
397 .variant_data
398 .fields()
399 .iter()
400 .find(|(_id, data)| data.name == *name)
401 .map(|(id, _)| StructField { parent: self.into(), id })
402 }
403
404 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 321 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
405 db.union_data(self.id).variant_data.clone() 322 db.union_data(self.id).variant_data.clone()
406 } 323 }
@@ -413,7 +330,7 @@ pub struct Enum {
413 330
414impl Enum { 331impl Enum {
415 pub fn module(self, db: &impl DefDatabase) -> Module { 332 pub fn module(self, db: &impl DefDatabase) -> Module {
416 Module { id: self.id.module(db) } 333 Module { id: self.id.lookup(db).container.module(db) }
417 } 334 }
418 335
419 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 336 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -432,13 +349,8 @@ impl Enum {
432 .collect() 349 .collect()
433 } 350 }
434 351
435 pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option<EnumVariant> {
436 let id = db.enum_data(self.id).variant(name)?;
437 Some(EnumVariant { parent: self, id })
438 }
439
440 pub fn ty(self, db: &impl HirDatabase) -> Type { 352 pub fn ty(self, db: &impl HirDatabase) -> Type {
441 Type::from_def(db, self.id.module(db).krate, self.id) 353 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
442 } 354 }
443} 355}
444 356
@@ -468,14 +380,6 @@ impl EnumVariant {
468 .collect() 380 .collect()
469 } 381 }
470 382
471 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
472 self.variant_data(db)
473 .fields()
474 .iter()
475 .find(|(_id, data)| data.name == *name)
476 .map(|(id, _)| StructField { parent: self.into(), id })
477 }
478
479 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 383 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
480 db.enum_data(self.parent.id).variants[self.id].variant_data.clone() 384 db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
481 } 385 }
@@ -593,48 +497,8 @@ impl Function {
593 db.function_data(self.id).params.clone() 497 db.function_data(self.id).params.clone()
594 } 498 }
595 499
596 pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
597 db.body_with_source_map(self.id.into()).1
598 }
599
600 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> {
601 db.body(self.id.into())
602 }
603
604 pub fn ty(self, db: &impl HirDatabase) -> Ty {
605 db.value_ty(self.id.into())
606 }
607
608 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
609 db.infer(self.id.into())
610 }
611
612 /// The containing impl block, if this is a method.
613 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
614 match self.container(db) {
615 Some(Container::ImplBlock(it)) => Some(it),
616 _ => None,
617 }
618 }
619
620 /// The containing trait, if this is a trait method definition.
621 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
622 match self.container(db) {
623 Some(Container::Trait(it)) => Some(it),
624 _ => None,
625 }
626 }
627
628 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
629 match self.id.lookup(db).container {
630 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
631 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
632 ContainerId::ModuleId(_) => None,
633 }
634 }
635
636 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { 500 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
637 let infer = self.infer(db); 501 let infer = db.infer(self.id.into());
638 infer.add_diagnostics(db, self.id, sink); 502 infer.add_diagnostics(db, self.id, sink);
639 let mut validator = ExprValidator::new(self.id, infer, sink); 503 let mut validator = ExprValidator::new(self.id, infer, sink);
640 validator.validate_body(db); 504 validator.validate_body(db);
@@ -658,34 +522,6 @@ impl Const {
658 pub fn name(self, db: &impl HirDatabase) -> Option<Name> { 522 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
659 db.const_data(self.id).name.clone() 523 db.const_data(self.id).name.clone()
660 } 524 }
661
662 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
663 db.infer(self.id.into())
664 }
665
666 /// The containing impl block, if this is a type alias.
667 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
668 match self.container(db) {
669 Some(Container::ImplBlock(it)) => Some(it),
670 _ => None,
671 }
672 }
673
674 /// The containing trait, if this is a trait type alias definition.
675 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
676 match self.container(db) {
677 Some(Container::Trait(it)) => Some(it),
678 _ => None,
679 }
680 }
681
682 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
683 match self.id.lookup(db).container {
684 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
685 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
686 ContainerId::ModuleId(_) => None,
687 }
688 }
689} 525}
690 526
691#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 527#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -701,10 +537,6 @@ impl Static {
701 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 537 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
702 Some(self.module(db).krate()) 538 Some(self.module(db).krate())
703 } 539 }
704
705 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
706 db.infer(self.id.into())
707 }
708} 540}
709 541
710#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 542#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -714,7 +546,7 @@ pub struct Trait {
714 546
715impl Trait { 547impl Trait {
716 pub fn module(self, db: &impl DefDatabase) -> Module { 548 pub fn module(self, db: &impl DefDatabase) -> Module {
717 Module { id: self.id.module(db) } 549 Module { id: self.id.lookup(db).container.module(db) }
718 } 550 }
719 551
720 pub fn name(self, db: &impl DefDatabase) -> Name { 552 pub fn name(self, db: &impl DefDatabase) -> Name {
@@ -749,30 +581,6 @@ impl TypeAlias {
749 Some(self.module(db).krate()) 581 Some(self.module(db).krate())
750 } 582 }
751 583
752 /// The containing impl block, if this is a type alias.
753 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
754 match self.container(db) {
755 Some(Container::ImplBlock(it)) => Some(it),
756 _ => None,
757 }
758 }
759
760 /// The containing trait, if this is a trait type alias definition.
761 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
762 match self.container(db) {
763 Some(Container::Trait(it)) => Some(it),
764 _ => None,
765 }
766 }
767
768 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
769 match self.id.lookup(db).container {
770 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
771 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
772 ContainerId::ModuleId(_) => None,
773 }
774 }
775
776 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { 584 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> {
777 db.type_alias_data(self.id).type_ref.clone() 585 db.type_alias_data(self.id).type_ref.clone()
778 } 586 }
@@ -791,14 +599,6 @@ pub struct MacroDef {
791 pub(crate) id: MacroDefId, 599 pub(crate) id: MacroDefId,
792} 600}
793 601
794impl MacroDef {}
795
796pub enum Container {
797 Trait(Trait),
798 ImplBlock(ImplBlock),
799}
800impl_froms!(Container: Trait, ImplBlock);
801
802#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 602#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
803pub enum AssocItem { 603pub enum AssocItem {
804 Function(Function), 604 Function(Function),
@@ -819,15 +619,6 @@ impl AssocItem {
819 AssocItem::TypeAlias(t) => t.module(db), 619 AssocItem::TypeAlias(t) => t.module(db),
820 } 620 }
821 } 621 }
822
823 pub fn container(self, db: &impl DefDatabase) -> Container {
824 match self {
825 AssocItem::Function(f) => f.container(db),
826 AssocItem::Const(c) => c.container(db),
827 AssocItem::TypeAlias(t) => t.container(db),
828 }
829 .expect("AssocItem without container")
830 }
831} 622}
832 623
833#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 624#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
@@ -869,7 +660,7 @@ impl Local {
869 } 660 }
870 661
871 pub fn is_self(self, db: &impl HirDatabase) -> bool { 662 pub fn is_self(self, db: &impl HirDatabase) -> bool {
872 self.name(db) == Some(name::SELF_PARAM) 663 self.name(db) == Some(name![self])
873 } 664 }
874 665
875 pub fn is_mut(self, db: &impl HirDatabase) -> bool { 666 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
@@ -901,18 +692,30 @@ impl Local {
901 Type { krate, ty: InEnvironment { value: ty, environment } } 692 Type { krate, ty: InEnvironment { value: ty, environment } }
902 } 693 }
903 694
904 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { 695 pub fn source(self, db: &impl HirDatabase) -> InFile<Either<ast::BindPat, ast::SelfParam>> {
905 let (_body, source_map) = db.body_with_source_map(self.parent.into()); 696 let (_body, source_map) = db.body_with_source_map(self.parent.into());
906 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... 697 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
907 let root = src.file_syntax(db); 698 let root = src.file_syntax(db);
908 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) 699 src.map(|ast| {
700 ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root))
701 })
909 } 702 }
910} 703}
911 704
912#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 705#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
913pub struct GenericParam { 706pub struct TypeParam {
914 pub(crate) parent: GenericDefId, 707 pub(crate) id: TypeParamId,
915 pub(crate) idx: u32, 708}
709
710impl TypeParam {
711 pub fn name(self, db: &impl HirDatabase) -> Name {
712 let params = db.generic_params(self.id.parent);
713 params.types[self.id.local_id].name.clone()
714 }
715
716 pub fn module(self, db: &impl HirDatabase) -> Module {
717 self.id.parent.module(db).into()
718 }
916} 719}
917 720
918#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 721#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -922,11 +725,11 @@ pub struct ImplBlock {
922 725
923impl ImplBlock { 726impl ImplBlock {
924 pub fn all_in_crate(db: &impl HirDatabase, krate: Crate) -> Vec<ImplBlock> { 727 pub fn all_in_crate(db: &impl HirDatabase, krate: Crate) -> Vec<ImplBlock> {
925 let impls = db.impls_in_crate(krate.crate_id); 728 let impls = db.impls_in_crate(krate.id);
926 impls.all_impls().map(Self::from).collect() 729 impls.all_impls().map(Self::from).collect()
927 } 730 }
928 pub fn for_trait(db: &impl HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplBlock> { 731 pub fn for_trait(db: &impl HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplBlock> {
929 let impls = db.impls_in_crate(krate.crate_id); 732 let impls = db.impls_in_crate(krate.id);
930 impls.lookup_impl_blocks_for_trait(trait_.id).map(Self::from).collect() 733 impls.lookup_impl_blocks_for_trait(trait_.id).map(Self::from).collect()
931 } 734 }
932 735
@@ -943,7 +746,10 @@ impl ImplBlock {
943 let resolver = self.id.resolver(db); 746 let resolver = self.id.resolver(db);
944 let environment = TraitEnvironment::lower(db, &resolver); 747 let environment = TraitEnvironment::lower(db, &resolver);
945 let ty = Ty::from_hir(db, &resolver, &impl_data.target_type); 748 let ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
946 Type { krate: self.id.module(db).krate, ty: InEnvironment { value: ty, environment } } 749 Type {
750 krate: self.id.lookup(db).container.module(db).krate,
751 ty: InEnvironment { value: ty, environment },
752 }
947 } 753 }
948 754
949 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { 755 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
@@ -955,11 +761,11 @@ impl ImplBlock {
955 } 761 }
956 762
957 pub fn module(&self, db: &impl DefDatabase) -> Module { 763 pub fn module(&self, db: &impl DefDatabase) -> Module {
958 self.id.module(db).into() 764 self.id.lookup(db).container.module(db).into()
959 } 765 }
960 766
961 pub fn krate(&self, db: &impl DefDatabase) -> Crate { 767 pub fn krate(&self, db: &impl DefDatabase) -> Crate {
962 Crate { crate_id: self.module(db).id.krate } 768 Crate { id: self.module(db).id.krate }
963 } 769 }
964} 770}
965 771
@@ -970,15 +776,19 @@ pub struct Type {
970} 776}
971 777
972impl Type { 778impl Type {
779 fn new(db: &impl HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
780 let resolver = lexical_env.resolver(db);
781 let environment = TraitEnvironment::lower(db, &resolver);
782 Type { krate, ty: InEnvironment { value: ty, environment } }
783 }
784
973 fn from_def( 785 fn from_def(
974 db: &impl HirDatabase, 786 db: &impl HirDatabase,
975 krate: CrateId, 787 krate: CrateId,
976 def: impl HasResolver + Into<TyDefId>, 788 def: impl HasResolver + Into<TyDefId>,
977 ) -> Type { 789 ) -> Type {
978 let resolver = def.resolver(db);
979 let environment = TraitEnvironment::lower(db, &resolver);
980 let ty = db.ty(def.into()); 790 let ty = db.ty(def.into());
981 Type { krate, ty: InEnvironment { value: ty, environment } } 791 Type::new(db, krate, def, ty)
982 } 792 }
983 793
984 pub fn is_bool(&self) -> bool { 794 pub fn is_bool(&self) -> bool {
@@ -1028,7 +838,7 @@ impl Type {
1028 pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> { 838 pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> {
1029 if let Ty::Apply(a_ty) = &self.ty.value { 839 if let Ty::Apply(a_ty) = &self.ty.value {
1030 match a_ty.ctor { 840 match a_ty.ctor {
1031 ty::TypeCtor::Adt(AdtId::StructId(s)) => { 841 TypeCtor::Adt(AdtId::StructId(s)) => {
1032 let var_def = s.into(); 842 let var_def = s.into();
1033 return db 843 return db
1034 .field_types(var_def) 844 .field_types(var_def)
@@ -1050,7 +860,7 @@ impl Type {
1050 let mut res = Vec::new(); 860 let mut res = Vec::new();
1051 if let Ty::Apply(a_ty) = &self.ty.value { 861 if let Ty::Apply(a_ty) = &self.ty.value {
1052 match a_ty.ctor { 862 match a_ty.ctor {
1053 ty::TypeCtor::Tuple { .. } => { 863 TypeCtor::Tuple { .. } => {
1054 for ty in a_ty.parameters.iter() { 864 for ty in a_ty.parameters.iter() {
1055 let ty = ty.clone().subst(&a_ty.parameters); 865 let ty = ty.clone().subst(&a_ty.parameters);
1056 res.push(self.derived(ty)); 866 res.push(self.derived(ty));
@@ -1069,11 +879,16 @@ impl Type {
1069 ) -> Vec<(StructField, Type)> { 879 ) -> Vec<(StructField, Type)> {
1070 // FIXME: check that ty and def match 880 // FIXME: check that ty and def match
1071 match &self.ty.value { 881 match &self.ty.value {
1072 Ty::Apply(a_ty) => def 882 Ty::Apply(a_ty) => {
1073 .fields(db) 883 let field_types = db.field_types(def.into());
1074 .into_iter() 884 def.fields(db)
1075 .map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters)))) 885 .into_iter()
1076 .collect(), 886 .map(|it| {
887 let ty = field_types[it.id].clone().subst(&a_ty.parameters);
888 (it, self.derived(ty))
889 })
890 .collect()
891 }
1077 _ => Vec::new(), 892 _ => Vec::new(),
1078 } 893 }
1079 } 894 }
@@ -1081,10 +896,10 @@ impl Type {
1081 pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a { 896 pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a {
1082 // There should be no inference vars in types passed here 897 // There should be no inference vars in types passed here
1083 // FIXME check that? 898 // FIXME check that?
1084 let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 }; 899 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
1085 let environment = self.ty.environment.clone(); 900 let environment = self.ty.environment.clone();
1086 let ty = InEnvironment { value: canonical, environment: environment.clone() }; 901 let ty = InEnvironment { value: canonical, environment: environment.clone() };
1087 ty::autoderef(db, Some(self.krate), ty) 902 autoderef(db, Some(self.krate), ty)
1088 .map(|canonical| canonical.value) 903 .map(|canonical| canonical.value)
1089 .map(move |ty| self.derived(ty)) 904 .map(move |ty| self.derived(ty))
1090 } 905 }
@@ -1097,7 +912,7 @@ impl Type {
1097 krate: Crate, 912 krate: Crate,
1098 mut callback: impl FnMut(AssocItem) -> Option<T>, 913 mut callback: impl FnMut(AssocItem) -> Option<T>,
1099 ) -> Option<T> { 914 ) -> Option<T> {
1100 for krate in self.ty.value.def_crates(db, krate.crate_id)? { 915 for krate in self.ty.value.def_crates(db, krate.id)? {
1101 let impls = db.impls_in_crate(krate); 916 let impls = db.impls_in_crate(krate);
1102 917
1103 for impl_block in impls.lookup_impl_blocks(&self.ty.value) { 918 for impl_block in impls.lookup_impl_blocks(&self.ty.value) {
@@ -1111,11 +926,6 @@ impl Type {
1111 None 926 None
1112 } 927 }
1113 928
1114 // FIXME: remove
1115 pub fn into_ty(self) -> Ty {
1116 self.ty.value
1117 }
1118
1119 pub fn as_adt(&self) -> Option<Adt> { 929 pub fn as_adt(&self) -> Option<Adt> {
1120 let (adt, _subst) = self.ty.value.as_adt()?; 930 let (adt, _subst) = self.ty.value.as_adt()?;
1121 Some(adt.into()) 931 Some(adt.into())
@@ -1124,15 +934,14 @@ impl Type {
1124 // FIXME: provide required accessors such that it becomes implementable from outside. 934 // FIXME: provide required accessors such that it becomes implementable from outside.
1125 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { 935 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1126 match (&self.ty.value, &other.ty.value) { 936 match (&self.ty.value, &other.ty.value) {
1127 (Ty::Apply(a_original_ty), Ty::Apply(ty::ApplicationTy { ctor, parameters })) => { 937 (Ty::Apply(a_original_ty), Ty::Apply(ApplicationTy { ctor, parameters })) => match ctor
1128 match ctor { 938 {
1129 TypeCtor::Ref(..) => match parameters.as_single() { 939 TypeCtor::Ref(..) => match parameters.as_single() {
1130 Ty::Apply(a_ty) => a_original_ty.ctor == a_ty.ctor, 940 Ty::Apply(a_ty) => a_original_ty.ctor == a_ty.ctor,
1131 _ => false, 941 _ => false,
1132 }, 942 },
1133 _ => a_original_ty.ctor == *ctor, 943 _ => a_original_ty.ctor == *ctor,
1134 } 944 },
1135 }
1136 _ => false, 945 _ => false,
1137 } 946 }
1138 } 947 }
@@ -1155,7 +964,7 @@ impl HirDisplay for Type {
1155pub enum ScopeDef { 964pub enum ScopeDef {
1156 ModuleDef(ModuleDef), 965 ModuleDef(ModuleDef),
1157 MacroDef(MacroDef), 966 MacroDef(MacroDef),
1158 GenericParam(GenericParam), 967 GenericParam(TypeParam),
1159 ImplSelfType(ImplBlock), 968 ImplSelfType(ImplBlock),
1160 AdtSelfType(Adt), 969 AdtSelfType(Adt),
1161 Local(Local), 970 Local(Local),
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
deleted file mode 100644
index bf3ee0834..000000000
--- a/crates/ra_hir/src/code_model/src.rs
+++ /dev/null
@@ -1,128 +0,0 @@
1//! FIXME: write short doc here
2
3use hir_def::{AstItemDef, HasChildSource, HasSource as _, Lookup, VariantId};
4use hir_expand::either::Either;
5use ra_syntax::ast;
6
7use crate::{
8 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef,
9 Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
10};
11
12pub use hir_expand::Source;
13
14pub trait HasSource {
15 type Ast;
16 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast>;
17}
18
19/// NB: Module is !HasSource, because it has two source nodes at the same time:
20/// definition and declaration.
21impl Module {
22 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
23 pub fn definition_source(self, db: &impl DefDatabase) -> Source<ModuleSource> {
24 let def_map = db.crate_def_map(self.id.krate);
25 let src = def_map[self.id.local_id].definition_source(db);
26 src.map(|it| match it {
27 Either::A(it) => ModuleSource::SourceFile(it),
28 Either::B(it) => ModuleSource::Module(it),
29 })
30 }
31
32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
33 /// `None` for the crate root.
34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
35 let def_map = db.crate_def_map(self.id.krate);
36 def_map[self.id.local_id].declaration_source(db)
37 }
38}
39
40impl HasSource for StructField {
41 type Ast = FieldSource;
42 fn source(self, db: &impl DefDatabase) -> Source<FieldSource> {
43 let var = VariantId::from(self.parent);
44 let src = var.child_source(db);
45 src.map(|it| match it[self.id].clone() {
46 Either::A(it) => FieldSource::Pos(it),
47 Either::B(it) => FieldSource::Named(it),
48 })
49 }
50}
51impl HasSource for Struct {
52 type Ast = ast::StructDef;
53 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
54 self.id.source(db)
55 }
56}
57impl HasSource for Union {
58 type Ast = ast::UnionDef;
59 fn source(self, db: &impl DefDatabase) -> Source<ast::UnionDef> {
60 self.id.source(db)
61 }
62}
63impl HasSource for Enum {
64 type Ast = ast::EnumDef;
65 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumDef> {
66 self.id.source(db)
67 }
68}
69impl HasSource for EnumVariant {
70 type Ast = ast::EnumVariant;
71 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumVariant> {
72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
73 }
74}
75impl HasSource for Function {
76 type Ast = ast::FnDef;
77 fn source(self, db: &impl DefDatabase) -> Source<ast::FnDef> {
78 self.id.lookup(db).source(db)
79 }
80}
81impl HasSource for Const {
82 type Ast = ast::ConstDef;
83 fn source(self, db: &impl DefDatabase) -> Source<ast::ConstDef> {
84 self.id.lookup(db).source(db)
85 }
86}
87impl HasSource for Static {
88 type Ast = ast::StaticDef;
89 fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
90 self.id.lookup(db).source(db)
91 }
92}
93impl HasSource for Trait {
94 type Ast = ast::TraitDef;
95 fn source(self, db: &impl DefDatabase) -> Source<ast::TraitDef> {
96 self.id.source(db)
97 }
98}
99impl HasSource for TypeAlias {
100 type Ast = ast::TypeAliasDef;
101 fn source(self, db: &impl DefDatabase) -> Source<ast::TypeAliasDef> {
102 self.id.lookup(db).source(db)
103 }
104}
105impl HasSource for MacroDef {
106 type Ast = ast::MacroCall;
107 fn source(self, db: &impl DefDatabase) -> Source<ast::MacroCall> {
108 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) }
109 }
110}
111impl HasSource for ImplBlock {
112 type Ast = ast::ImplBlock;
113 fn source(self, db: &impl DefDatabase) -> Source<ast::ImplBlock> {
114 self.id.source(db)
115 }
116}
117impl HasSource for Import {
118 type Ast = Either<ast::UseTree, ast::ExternCrateItem>;
119
120 /// Returns the syntax of the last path segment corresponding to this import
121 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast> {
122 let src = self.parent.definition_source(db);
123 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
124 let root = db.parse_or_expand(src.file_id).unwrap();
125 let ptr = source_map.get(self.id);
126 src.with_value(ptr.map(|it| it.to_node(&root), |it| it.to_node(&root)))
127 }
128}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index bfae3660b..f5ffd64fa 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,8 +4,8 @@ pub use hir_def::db::{
4 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery, 4 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
5 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery, 5 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
6 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, 6 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
7 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery, 7 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery,
8 StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery, 8 TraitDataQuery, TypeAliasDataQuery,
9}; 9};
10pub use hir_expand::db::{ 10pub use hir_expand::db::{
11 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 11 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
deleted file mode 100644
index 7a2810f71..000000000
--- a/crates/ra_hir/src/debug.rs
+++ /dev/null
@@ -1,94 +0,0 @@
1//! XXX: This does not work at the moment.
2//!
3//! printf debugging infrastructure for rust-analyzer.
4//!
5//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`,
6//! you usually get back a numeric ID, which doesn't tell you much:
7//! `Module(92)`.
8//!
9//! This module adds convenience `debug` methods to various types, which resolve
10//! the id to a human-readable location info:
11//!
12//! ```not_rust
13//! eprintln!("{:?}", module.debug(db));
14//! =>
15//! Module { name: collections, path: "liballoc/collections/mod.rs" }
16//! ```
17//!
18//! Note that to get this info, we might need to execute queries! So
19//!
20//! * don't use the `debug` methods for logging
21//! * when debugging, be aware that interference is possible.
22
23use std::fmt;
24
25use hir_expand::HirFileId;
26use ra_db::{CrateId, FileId};
27
28use crate::{db::HirDatabase, Crate, Module, Name};
29
30impl Crate {
31 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
32 debug_fn(move |fmt| db.debug_crate(self, fmt))
33 }
34}
35
36impl Module {
37 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
38 debug_fn(move |fmt| db.debug_module(self, fmt))
39 }
40}
41
42pub trait HirDebugHelper: HirDatabase {
43 fn crate_name(&self, _krate: CrateId) -> Option<String> {
44 None
45 }
46 fn file_path(&self, _file_id: FileId) -> Option<String> {
47 None
48 }
49}
50
51pub trait HirDebugDatabase {
52 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
53 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
54 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
55}
56
57impl<DB: HirDebugHelper> HirDebugDatabase for DB {
58 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let mut builder = fmt.debug_tuple("Crate");
60 match self.crate_name(krate.crate_id) {
61 Some(name) => builder.field(&name),
62 None => builder.field(&krate.crate_id),
63 }
64 .finish()
65 }
66
67 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68 let file_id = module.definition_source(self).file_id.original_file(self);
69 let path = self.file_path(file_id).unwrap_or_else(|| "N/A".to_string());
70 fmt.debug_struct("Module")
71 .field("name", &module.name(self).unwrap_or_else(Name::missing))
72 .field("path", &path)
73 .finish()
74 }
75
76 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
77 let original = file_id.original_file(self);
78 let path = self.file_path(original).unwrap_or_else(|| "N/A".to_string());
79 let is_macro = file_id != original.into();
80 fmt.debug_struct("HirFileId").field("path", &path).field("macro", &is_macro).finish()
81 }
82}
83
84fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
85 struct DebugFn<F>(F);
86
87 impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
88 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
89 (&self.0)(fmt)
90 }
91 }
92
93 DebugFn(f)
94}
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index e96a18d12..75a1a7772 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -9,16 +9,10 @@ use hir_def::{
9}; 9};
10 10
11use crate::{ 11use crate::{
12 Adt, AssocItem, AttrDef, Crate, DefWithBody, EnumVariant, GenericDef, ModuleDef, StructField, 12 Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, ModuleDef, StructField,
13 VariantDef, 13 VariantDef,
14}; 14};
15 15
16impl From<ra_db::CrateId> for Crate {
17 fn from(crate_id: ra_db::CrateId) -> Self {
18 Crate { crate_id }
19 }
20}
21
22macro_rules! from_id { 16macro_rules! from_id {
23 ($(($id:path, $ty:path)),*) => {$( 17 ($(($id:path, $ty:path)),*) => {$(
24 impl From<$id> for $ty { 18 impl From<$id> for $ty {
@@ -26,10 +20,16 @@ macro_rules! from_id {
26 $ty { id } 20 $ty { id }
27 } 21 }
28 } 22 }
23 impl From<$ty> for $id {
24 fn from(ty: $ty) -> $id {
25 ty.id
26 }
27 }
29 )*} 28 )*}
30} 29}
31 30
32from_id![ 31from_id![
32 (ra_db::CrateId, crate::Crate),
33 (hir_def::ModuleId, crate::Module), 33 (hir_def::ModuleId, crate::Module),
34 (hir_def::StructId, crate::Struct), 34 (hir_def::StructId, crate::Struct),
35 (hir_def::UnionId, crate::Union), 35 (hir_def::UnionId, crate::Union),
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 9f7c22b21..6314be8d4 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,219 +1,140 @@
1//! FIXME: write short doc here 1//! Finds a corresponding hir data structure for a syntax node in a specific
2//! file.
2 3
3use hir_def::{AstItemDef, LocationCtx, ModuleId}; 4use hir_def::{
5 child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
6 ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
7 StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
8};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 9use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
10use ra_db::FileId;
11use ra_prof::profile;
5use ra_syntax::{ 12use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 13 ast::{self, AstNode, NameOwner},
7 match_ast, AstPtr, SyntaxNode, 14 match_ast, SyntaxNode,
8}; 15};
9 16
10use crate::{ 17use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 18 db::{DefDatabase, HirDatabase},
12 AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, 19 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
13 Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, 20 MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
14 TypeAlias, Union, VariantDef,
15}; 21};
16 22
17pub trait FromSource: Sized { 23pub trait FromSource: Sized {
18 type Ast; 24 type Ast;
19 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>; 25 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self>;
20} 26}
21 27
22impl FromSource for Struct { 28pub trait FromSourceByContainer: Sized {
23 type Ast = ast::StructDef; 29 type Ast: AstNode + 'static;
24 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 30 type Id: Copy + 'static;
25 let id = from_source(db, src)?; 31 const KEY: Key<Self::Ast, Self::Id>;
26 Some(Struct { id })
27 }
28}
29impl FromSource for Union {
30 type Ast = ast::UnionDef;
31 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
32 let id = from_source(db, src)?;
33 Some(Union { id })
34 }
35}
36impl FromSource for Enum {
37 type Ast = ast::EnumDef;
38 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
39 let id = from_source(db, src)?;
40 Some(Enum { id })
41 }
42}
43impl FromSource for Trait {
44 type Ast = ast::TraitDef;
45 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
46 let id = from_source(db, src)?;
47 Some(Trait { id })
48 }
49}
50impl FromSource for Function {
51 type Ast = ast::FnDef;
52 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
53 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
54 Container::Trait(it) => it.items(db),
55 Container::ImplBlock(it) => it.items(db),
56 Container::Module(m) => {
57 return m
58 .declarations(db)
59 .into_iter()
60 .filter_map(|it| match it {
61 ModuleDef::Function(it) => Some(it),
62 _ => None,
63 })
64 .find(|it| same_source(&it.source(db), &src))
65 }
66 };
67 items
68 .into_iter()
69 .filter_map(|it| match it {
70 AssocItem::Function(it) => Some(it),
71 _ => None,
72 })
73 .find(|it| same_source(&it.source(db), &src))
74 }
75} 32}
76 33
77impl FromSource for Const { 34impl<T: FromSourceByContainer> FromSource for T
78 type Ast = ast::ConstDef; 35where
79 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 36 T: From<<T as FromSourceByContainer>::Id>,
80 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 37{
81 Container::Trait(it) => it.items(db), 38 type Ast = <T as FromSourceByContainer>::Ast;
82 Container::ImplBlock(it) => it.items(db), 39 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
83 Container::Module(m) => { 40 analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY]
84 return m 41 .get(&src)
85 .declarations(db) 42 .copied()
86 .into_iter() 43 .map(Self::from)
87 .filter_map(|it| match it {
88 ModuleDef::Const(it) => Some(it),
89 _ => None,
90 })
91 .find(|it| same_source(&it.source(db), &src))
92 }
93 };
94 items
95 .into_iter()
96 .filter_map(|it| match it {
97 AssocItem::Const(it) => Some(it),
98 _ => None,
99 })
100 .find(|it| same_source(&it.source(db), &src))
101 }
102}
103impl FromSource for Static {
104 type Ast = ast::StaticDef;
105 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
106 let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
107 Container::Module(it) => it,
108 Container::Trait(_) | Container::ImplBlock(_) => return None,
109 };
110 module
111 .declarations(db)
112 .into_iter()
113 .filter_map(|it| match it {
114 ModuleDef::Static(it) => Some(it),
115 _ => None,
116 })
117 .find(|it| same_source(&it.source(db), &src))
118 } 44 }
119} 45}
120 46
121impl FromSource for TypeAlias { 47macro_rules! from_source_by_container_impls {
122 type Ast = ast::TypeAliasDef; 48 ($(($hir:ident, $id:ident, $ast:path, $key:path)),* ,) => {$(
123 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 49 impl FromSourceByContainer for $hir {
124 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 50 type Ast = $ast;
125 Container::Trait(it) => it.items(db), 51 type Id = $id;
126 Container::ImplBlock(it) => it.items(db), 52 const KEY: Key<Self::Ast, Self::Id> = $key;
127 Container::Module(m) => { 53 }
128 return m 54 )*}
129 .declarations(db)
130 .into_iter()
131 .filter_map(|it| match it {
132 ModuleDef::TypeAlias(it) => Some(it),
133 _ => None,
134 })
135 .find(|it| same_source(&it.source(db), &src))
136 }
137 };
138 items
139 .into_iter()
140 .filter_map(|it| match it {
141 AssocItem::TypeAlias(it) => Some(it),
142 _ => None,
143 })
144 .find(|it| same_source(&it.source(db), &src))
145 }
146} 55}
147 56
57from_source_by_container_impls![
58 (Struct, StructId, ast::StructDef, keys::STRUCT),
59 (Union, UnionId, ast::UnionDef, keys::UNION),
60 (Enum, EnumId, ast::EnumDef, keys::ENUM),
61 (Trait, TraitId, ast::TraitDef, keys::TRAIT),
62 (Function, FunctionId, ast::FnDef, keys::FUNCTION),
63 (Static, StaticId, ast::StaticDef, keys::STATIC),
64 (Const, ConstId, ast::ConstDef, keys::CONST),
65 (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
66 (ImplBlock, ImplId, ast::ImplBlock, keys::IMPL),
67];
68
148impl FromSource for MacroDef { 69impl FromSource for MacroDef {
149 type Ast = ast::MacroCall; 70 type Ast = ast::MacroCall;
150 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 71 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
151 let kind = MacroDefKind::Declarative; 72 let kind = MacroDefKind::Declarative;
152 73
153 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); 74 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
154 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; 75 let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?;
155 let krate = module.krate().crate_id(); 76 let krate = Some(module.krate().id);
156 77
157 let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)); 78 let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)));
158 79
159 let id: MacroDefId = MacroDefId { krate, ast_id, kind }; 80 let id: MacroDefId = MacroDefId { krate, ast_id, kind };
160 Some(MacroDef { id }) 81 Some(MacroDef { id })
161 } 82 }
162} 83}
163 84
164impl FromSource for ImplBlock {
165 type Ast = ast::ImplBlock;
166 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
167 let id = from_source(db, src)?;
168 Some(ImplBlock { id })
169 }
170}
171
172impl FromSource for EnumVariant { 85impl FromSource for EnumVariant {
173 type Ast = ast::EnumVariant; 86 type Ast = ast::EnumVariant;
174 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 87 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
175 let parent_enum = src.value.parent_enum(); 88 let parent_enum = src.value.parent_enum();
176 let src_enum = Source { file_id: src.file_id, value: parent_enum }; 89 let src_enum = InFile { file_id: src.file_id, value: parent_enum };
177 let variants = Enum::from_source(db, src_enum)?.variants(db); 90 let parent_enum = Enum::from_source(db, src_enum)?;
178 variants.into_iter().find(|v| same_source(&v.source(db), &src)) 91 parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT]
92 .get(&src)
93 .copied()
94 .map(EnumVariant::from)
179 } 95 }
180} 96}
181 97
182impl FromSource for StructField { 98impl FromSource for StructField {
183 type Ast = FieldSource; 99 type Ast = FieldSource;
184 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 100 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
185 let variant_def: VariantDef = match src.value { 101 let src = src.as_ref();
186 FieldSource::Named(ref field) => { 102
103 // FIXME this is buggy
104 let variant_id: VariantId = match src.value {
105 FieldSource::Named(field) => {
187 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; 106 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
188 let src = Source { file_id: src.file_id, value }; 107 let src = InFile { file_id: src.file_id, value };
189 let def = Struct::from_source(db, src)?; 108 let def = Struct::from_source(db, src)?;
190 VariantDef::from(def) 109 def.id.into()
191 } 110 }
192 FieldSource::Pos(ref field) => { 111 FieldSource::Pos(field) => {
193 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; 112 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
194 let src = Source { file_id: src.file_id, value }; 113 let src = InFile { file_id: src.file_id, value };
195 let def = EnumVariant::from_source(db, src)?; 114 let def = EnumVariant::from_source(db, src)?;
196 VariantDef::from(def) 115 EnumVariantId::from(def).into()
197 } 116 }
198 }; 117 };
199 variant_def 118
200 .variant_data(db) 119 let dyn_map = variant_id.child_by_source(db);
201 .fields() 120 match src.value {
202 .iter() 121 FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())),
203 .map(|(id, _)| StructField { parent: variant_def, id }) 122 FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())),
204 .find(|f| f.source(db) == src) 123 }
124 .copied()
125 .map(StructField::from)
205 } 126 }
206} 127}
207 128
208impl Local { 129impl Local {
209 pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { 130 pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> {
210 let file_id = src.file_id; 131 let file_id = src.file_id;
211 let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { 132 let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| {
212 let res = match_ast! { 133 let res = match_ast! {
213 match it { 134 match it {
214 ast::ConstDef(value) => { Const::from_source(db, Source { value, file_id})?.into() }, 135 ast::ConstDef(value) => { Const::from_source(db, InFile { value, file_id})?.into() },
215 ast::StaticDef(value) => { Static::from_source(db, Source { value, file_id})?.into() }, 136 ast::StaticDef(value) => { Static::from_source(db, InFile { value, file_id})?.into() },
216 ast::FnDef(value) => { Function::from_source(db, Source { value, file_id})?.into() }, 137 ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.into() },
217 _ => return None, 138 _ => return None,
218 } 139 }
219 }; 140 };
@@ -226,84 +147,111 @@ impl Local {
226 } 147 }
227} 148}
228 149
150impl TypeParam {
151 pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> {
152 let file_id = src.file_id;
153 let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
154 let res = match_ast! {
155 match it {
156 ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() },
157 ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() },
158 ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() },
159 ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() },
160 ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() },
161 ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() },
162 _ => return None,
163 }
164 };
165 Some(res)
166 })?;
167 let &id = parent.child_by_source(db)[keys::TYPE_PARAM].get(&src)?;
168 Some(TypeParam { id })
169 }
170}
171
229impl Module { 172impl Module {
230 pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { 173 pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> {
174 let _p = profile("Module::from_declaration");
231 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); 175 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast);
232 176
233 let parent_module = match parent_declaration { 177 let parent_module = match parent_declaration {
234 Some(parent_declaration) => { 178 Some(parent_declaration) => {
235 let src_parent = Source { file_id: src.file_id, value: parent_declaration }; 179 let src_parent = InFile { file_id: src.file_id, value: parent_declaration };
236 Module::from_declaration(db, src_parent) 180 Module::from_declaration(db, src_parent)
237 } 181 }
238 _ => { 182 None => {
239 let src_parent = Source { 183 let source_file = db.parse(src.file_id.original_file(db)).tree();
240 file_id: src.file_id, 184 let src_parent =
241 value: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), 185 InFile { file_id: src.file_id, value: ModuleSource::SourceFile(source_file) };
242 };
243 Module::from_definition(db, src_parent) 186 Module::from_definition(db, src_parent)
244 } 187 }
245 }?; 188 }?;
246 189
247 let child_name = src.value.name()?; 190 let child_name = src.value.name()?.as_name();
248 parent_module.child(db, &child_name.as_name()) 191 let def_map = db.crate_def_map(parent_module.id.krate);
192 let child_id = def_map[parent_module.id.local_id].children.get(&child_name)?;
193 Some(parent_module.with_module_id(*child_id))
249 } 194 }
250 195
251 pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { 196 pub fn from_definition(db: &impl DefDatabase, src: InFile<ModuleSource>) -> Option<Self> {
197 let _p = profile("Module::from_definition");
252 match src.value { 198 match src.value {
253 ModuleSource::Module(ref module) => { 199 ModuleSource::Module(ref module) => {
254 assert!(!module.has_semi()); 200 assert!(!module.has_semi());
255 return Module::from_declaration( 201 return Module::from_declaration(
256 db, 202 db,
257 Source { file_id: src.file_id, value: module.clone() }, 203 InFile { file_id: src.file_id, value: module.clone() },
258 ); 204 );
259 } 205 }
260 ModuleSource::SourceFile(_) => (), 206 ModuleSource::SourceFile(_) => (),
261 }; 207 };
262 208
263 let original_file = src.file_id.original_file(db); 209 let original_file = src.file_id.original_file(db);
210 Module::from_file(db, original_file)
211 }
264 212
265 let (krate, local_id) = db.relevant_crates(original_file).iter().find_map(|&crate_id| { 213 fn from_file(db: &impl DefDatabase, file: FileId) -> Option<Self> {
214 let _p = profile("Module::from_file");
215 let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| {
266 let crate_def_map = db.crate_def_map(crate_id); 216 let crate_def_map = db.crate_def_map(crate_id);
267 let local_id = crate_def_map.modules_for_file(original_file).next()?; 217 let local_id = crate_def_map.modules_for_file(file).next()?;
268 Some((crate_id, local_id)) 218 Some((crate_id, local_id))
269 })?; 219 })?;
270 Some(Module { id: ModuleId { krate, local_id } }) 220 Some(Module { id: ModuleId { krate, local_id } })
271 } 221 }
272} 222}
273 223
274fn from_source<N, DEF>(db: &(impl DefDatabase + AstDatabase), src: Source<N>) -> Option<DEF> 224fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap {
275where 225 let _p = profile("analyze_container");
276 N: AstNode, 226 return child_by_source(db, src).unwrap_or_default();
277 DEF: AstItemDef<N>,
278{
279 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
280 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?;
281 let ctx = LocationCtx::new(db, module.id, src.file_id);
282 let items = db.ast_id_map(src.file_id);
283 let item_id = items.ast_id(&src.value);
284 Some(DEF::from_ast_id(ctx, item_id))
285}
286
287enum Container {
288 Trait(Trait),
289 ImplBlock(ImplBlock),
290 Module(Module),
291}
292 227
293impl Container { 228 fn child_by_source(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<DynMap> {
294 fn find(db: &impl DefDatabase, src: Source<&SyntaxNode>) -> Option<Container> { 229 for container in src.value.ancestors().skip(1) {
295 // FIXME: this doesn't try to handle nested declarations
296 for container in src.value.ancestors() {
297 let res = match_ast! { 230 let res = match_ast! {
298 match container { 231 match container {
299 ast::TraitDef(it) => { 232 ast::TraitDef(it) => {
300 let c = Trait::from_source(db, src.with_value(it))?; 233 let def = Trait::from_source(db, src.with_value(it))?;
301 Container::Trait(c) 234 def.id.child_by_source(db)
302 }, 235 },
303 ast::ImplBlock(it) => { 236 ast::ImplBlock(it) => {
304 let c = ImplBlock::from_source(db, src.with_value(it))?; 237 let def = ImplBlock::from_source(db, src.with_value(it))?;
305 Container::ImplBlock(c) 238 def.id.child_by_source(db)
306 }, 239 },
240 ast::FnDef(it) => {
241 let def = Function::from_source(db, src.with_value(it))?;
242 DefWithBodyId::from(def.id)
243 .child_by_source(db)
244 },
245 ast::StaticDef(it) => {
246 let def = Static::from_source(db, src.with_value(it))?;
247 DefWithBodyId::from(def.id)
248 .child_by_source(db)
249 },
250 ast::ConstDef(it) => {
251 let def = Const::from_source(db, src.with_value(it))?;
252 DefWithBodyId::from(def.id)
253 .child_by_source(db)
254 },
307 _ => { continue }, 255 _ => { continue },
308 } 256 }
309 }; 257 };
@@ -312,16 +260,6 @@ impl Container {
312 260
313 let module_source = ModuleSource::from_child_node(db, src); 261 let module_source = ModuleSource::from_child_node(db, src);
314 let c = Module::from_definition(db, src.with_value(module_source))?; 262 let c = Module::from_definition(db, src.with_value(module_source))?;
315 Some(Container::Module(c)) 263 Some(c.id.child_by_source(db))
316 } 264 }
317} 265}
318
319/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
320/// equal if they point to exactly the same object.
321///
322/// In general, we do not guarantee that we have exactly one instance of a
323/// syntax tree for each file. We probably should add such guarantee, but, for
324/// the time being, we will use identity-less AstPtr comparison.
325fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool {
326 s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new)
327}
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
new file mode 100644
index 000000000..5541266e2
--- /dev/null
+++ b/crates/ra_hir/src/has_source.rs
@@ -0,0 +1,127 @@
1//! FIXME: write short doc here
2
3use either::Either;
4use hir_def::{
5 nameres::ModuleSource,
6 src::{HasChildSource, HasSource as _},
7 Lookup, VariantId,
8};
9use ra_syntax::ast;
10
11use crate::{
12 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, MacroDef, Module,
13 Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
14};
15
16pub use hir_expand::InFile;
17
18pub trait HasSource {
19 type Ast;
20 fn source(self, db: &impl DefDatabase) -> InFile<Self::Ast>;
21}
22
23/// NB: Module is !HasSource, because it has two source nodes at the same time:
24/// definition and declaration.
25impl Module {
26 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
27 pub fn definition_source(self, db: &impl DefDatabase) -> InFile<ModuleSource> {
28 let def_map = db.crate_def_map(self.id.krate);
29 def_map[self.id.local_id].definition_source(db)
30 }
31
32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
33 /// `None` for the crate root.
34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> {
35 let def_map = db.crate_def_map(self.id.krate);
36 def_map[self.id.local_id].declaration_source(db)
37 }
38}
39
40impl HasSource for StructField {
41 type Ast = FieldSource;
42 fn source(self, db: &impl DefDatabase) -> InFile<FieldSource> {
43 let var = VariantId::from(self.parent);
44 let src = var.child_source(db);
45 src.map(|it| match it[self.id].clone() {
46 Either::Left(it) => FieldSource::Pos(it),
47 Either::Right(it) => FieldSource::Named(it),
48 })
49 }
50}
51impl HasSource for Struct {
52 type Ast = ast::StructDef;
53 fn source(self, db: &impl DefDatabase) -> InFile<ast::StructDef> {
54 self.id.lookup(db).source(db)
55 }
56}
57impl HasSource for Union {
58 type Ast = ast::UnionDef;
59 fn source(self, db: &impl DefDatabase) -> InFile<ast::UnionDef> {
60 self.id.lookup(db).source(db)
61 }
62}
63impl HasSource for Enum {
64 type Ast = ast::EnumDef;
65 fn source(self, db: &impl DefDatabase) -> InFile<ast::EnumDef> {
66 self.id.lookup(db).source(db)
67 }
68}
69impl HasSource for EnumVariant {
70 type Ast = ast::EnumVariant;
71 fn source(self, db: &impl DefDatabase) -> InFile<ast::EnumVariant> {
72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
73 }
74}
75impl HasSource for Function {
76 type Ast = ast::FnDef;
77 fn source(self, db: &impl DefDatabase) -> InFile<ast::FnDef> {
78 self.id.lookup(db).source(db)
79 }
80}
81impl HasSource for Const {
82 type Ast = ast::ConstDef;
83 fn source(self, db: &impl DefDatabase) -> InFile<ast::ConstDef> {
84 self.id.lookup(db).source(db)
85 }
86}
87impl HasSource for Static {
88 type Ast = ast::StaticDef;
89 fn source(self, db: &impl DefDatabase) -> InFile<ast::StaticDef> {
90 self.id.lookup(db).source(db)
91 }
92}
93impl HasSource for Trait {
94 type Ast = ast::TraitDef;
95 fn source(self, db: &impl DefDatabase) -> InFile<ast::TraitDef> {
96 self.id.lookup(db).source(db)
97 }
98}
99impl HasSource for TypeAlias {
100 type Ast = ast::TypeAliasDef;
101 fn source(self, db: &impl DefDatabase) -> InFile<ast::TypeAliasDef> {
102 self.id.lookup(db).source(db)
103 }
104}
105impl HasSource for MacroDef {
106 type Ast = ast::MacroCall;
107 fn source(self, db: &impl DefDatabase) -> InFile<ast::MacroCall> {
108 InFile {
109 file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
110 value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db),
111 }
112 }
113}
114impl HasSource for ImplBlock {
115 type Ast = ast::ImplBlock;
116 fn source(self, db: &impl DefDatabase) -> InFile<ast::ImplBlock> {
117 self.id.lookup(db).source(db)
118 }
119}
120
121impl HasSource for TypeParam {
122 type Ast = Either<ast::TraitDef, ast::TypeParam>;
123 fn source(self, db: &impl DefDatabase) -> InFile<Self::Ast> {
124 let child_source = self.id.parent.child_source(db);
125 child_source.map(|it| it[self.id.local_id].clone())
126 }
127}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 3c12c61f0..0008a8858 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -26,42 +26,38 @@ macro_rules! impl_froms {
26 } 26 }
27} 27}
28 28
29pub mod debug;
30
31pub mod db; 29pub mod db;
32pub mod source_binder; 30pub mod source_binder;
33 31
34mod ty;
35pub mod diagnostics; 32pub mod diagnostics;
36 33
37mod from_id; 34mod from_id;
38mod code_model; 35mod code_model;
39 36
40pub mod from_source; 37mod has_source;
38mod from_source;
41 39
42pub use crate::{ 40pub use crate::{
43 code_model::{ 41 code_model::{
44 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, 42 Adt, AssocItem, AttrDef, Const, Crate, CrateDependency, DefWithBody, Docs, Enum,
45 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, 43 EnumVariant, FieldSource, Function, GenericDef, HasAttrs, ImplBlock, Local, MacroDef,
46 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, 44 Module, ModuleDef, ScopeDef, Static, Struct, StructField, Trait, Type, TypeAlias,
47 Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef, 45 TypeParam, Union, VariantDef,
48 }, 46 },
49 from_source::FromSource, 47 from_source::FromSource,
48 has_source::HasSource,
50 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 49 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
51 ty::{
52 display::HirDisplay,
53 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
54 ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
55 },
56}; 50};
57 51
58pub use hir_def::{ 52pub use hir_def::{
59 body::scope::ExprScopes, 53 body::scope::ExprScopes,
60 builtin_type::BuiltinType, 54 builtin_type::BuiltinType,
61 docs::Documentation, 55 docs::Documentation,
62 path::{Path, PathKind}, 56 nameres::ModuleSource,
57 path::{ModPath, Path, PathKind},
63 type_ref::Mutability, 58 type_ref::Mutability,
64}; 59};
65pub use hir_expand::{ 60pub use hir_expand::{
66 either::Either, name::Name, HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Source, 61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
67}; 62};
63pub use hir_ty::{display::HirDisplay, CallableDef};
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 76c493f1a..85b378483 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,19 +7,26 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use either::Either;
10use hir_def::{ 11use hir_def::{
11 body::{ 12 body::{
12 scope::{ExprScopes, ScopeId}, 13 scope::{ExprScopes, ScopeId},
13 BodySourceMap, 14 BodySourceMap,
14 }, 15 },
15 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
16 path::known, 17 nameres::ModuleSource,
18 path::path,
17 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, 19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
18 AssocItemId, DefWithBodyId, 20 AssocItemId, DefWithBodyId,
19}; 21};
20use hir_expand::{ 22use hir_expand::{
21 hygiene::Hygiene, name::AsName, AstId, HirFileId, MacroCallId, MacroFileKind, Source, 23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
22}; 24};
25use hir_ty::{
26 method_resolution::{self, implements_trait},
27 Canonical, InEnvironment, InferenceResult, TraitEnvironment, Ty,
28};
29use ra_prof::profile;
23use ra_syntax::{ 30use ra_syntax::{
24 ast::{self, AstNode}, 31 ast::{self, AstNode},
25 match_ast, AstPtr, 32 match_ast, AstPtr,
@@ -28,16 +35,12 @@ use ra_syntax::{
28}; 35};
29 36
30use crate::{ 37use crate::{
31 db::HirDatabase, 38 db::HirDatabase, Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function,
32 ty::{ 39 ImplBlock, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
33 method_resolution::{self, implements_trait}, 40 TypeParam,
34 InEnvironment, TraitEnvironment, Ty,
35 },
36 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
37 GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
38}; 41};
39 42
40fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { 43fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> {
41 match_ast! { 44 match_ast! {
42 match (node.value) { 45 match (node.value) {
43 ast::Module(it) => { 46 ast::Module(it) => {
@@ -45,7 +48,7 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
45 Some(crate::Module::from_declaration(db, src)?.id.resolver(db)) 48 Some(crate::Module::from_declaration(db, src)?.id.resolver(db))
46 }, 49 },
47 ast::SourceFile(it) => { 50 ast::SourceFile(it) => {
48 let src = node.with_value(crate::ModuleSource::SourceFile(it)); 51 let src = node.with_value(ModuleSource::SourceFile(it));
49 Some(crate::Module::from_definition(db, src)?.id.resolver(db)) 52 Some(crate::Module::from_definition(db, src)?.id.resolver(db))
50 }, 53 },
51 ast::StructDef(it) => { 54 ast::StructDef(it) => {
@@ -56,6 +59,14 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
56 let src = node.with_value(it); 59 let src = node.with_value(it);
57 Some(Enum::from_source(db, src)?.id.resolver(db)) 60 Some(Enum::from_source(db, src)?.id.resolver(db))
58 }, 61 },
62 ast::ImplBlock(it) => {
63 let src = node.with_value(it);
64 Some(ImplBlock::from_source(db, src)?.id.resolver(db))
65 },
66 ast::TraitDef(it) => {
67 let src = node.with_value(it);
68 Some(Trait::from_source(db, src)?.id.resolver(db))
69 },
59 _ => match node.value.kind() { 70 _ => match node.value.kind() {
60 FN_DEF | CONST_DEF | STATIC_DEF => { 71 FN_DEF | CONST_DEF | STATIC_DEF => {
61 let def = def_with_body_from_child_node(db, node)?; 72 let def = def_with_body_from_child_node(db, node)?;
@@ -71,14 +82,16 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
71 82
72fn def_with_body_from_child_node( 83fn def_with_body_from_child_node(
73 db: &impl HirDatabase, 84 db: &impl HirDatabase,
74 child: Source<&SyntaxNode>, 85 child: InFile<&SyntaxNode>,
75) -> Option<DefWithBody> { 86) -> Option<DefWithBody> {
76 child.value.ancestors().find_map(|node| { 87 let _p = profile("def_with_body_from_child_node");
88 child.cloned().ancestors_with_macros(db).find_map(|node| {
89 let n = &node.value;
77 match_ast! { 90 match_ast! {
78 match node { 91 match n {
79 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 92 ast::FnDef(def) => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
80 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 93 ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
81 ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 94 ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
82 _ => { None }, 95 _ => { None },
83 } 96 }
84 } 97 }
@@ -93,7 +106,7 @@ pub struct SourceAnalyzer {
93 resolver: Resolver, 106 resolver: Resolver,
94 body_owner: Option<DefWithBody>, 107 body_owner: Option<DefWithBody>,
95 body_source_map: Option<Arc<BodySourceMap>>, 108 body_source_map: Option<Arc<BodySourceMap>>,
96 infer: Option<Arc<crate::ty::InferenceResult>>, 109 infer: Option<Arc<InferenceResult>>,
97 scopes: Option<Arc<ExprScopes>>, 110 scopes: Option<Arc<ExprScopes>>,
98} 111}
99 112
@@ -104,7 +117,7 @@ pub enum PathResolution {
104 /// A local binding (only value namespace) 117 /// A local binding (only value namespace)
105 Local(Local), 118 Local(Local),
106 /// A generic parameter 119 /// A generic parameter
107 GenericParam(GenericParam), 120 TypeParam(TypeParam),
108 SelfType(crate::ImplBlock), 121 SelfType(crate::ImplBlock),
109 Macro(MacroDef), 122 Macro(MacroDef),
110 AssocItem(crate::AssocItem), 123 AssocItem(crate::AssocItem),
@@ -132,8 +145,8 @@ pub struct ReferenceDescriptor {
132 pub name: String, 145 pub name: String,
133} 146}
134 147
148#[derive(Debug)]
135pub struct Expansion { 149pub struct Expansion {
136 macro_file_kind: MacroFileKind,
137 macro_call_id: MacroCallId, 150 macro_call_id: MacroCallId,
138} 151}
139 152
@@ -141,23 +154,24 @@ impl Expansion {
141 pub fn map_token_down( 154 pub fn map_token_down(
142 &self, 155 &self,
143 db: &impl HirDatabase, 156 db: &impl HirDatabase,
144 token: Source<&SyntaxToken>, 157 token: InFile<&SyntaxToken>,
145 ) -> Option<Source<SyntaxToken>> { 158 ) -> Option<InFile<SyntaxToken>> {
146 let exp_info = self.file_id().expansion_info(db)?; 159 let exp_info = self.file_id().expansion_info(db)?;
147 exp_info.map_token_down(token) 160 exp_info.map_token_down(token)
148 } 161 }
149 162
150 pub fn file_id(&self) -> HirFileId { 163 pub fn file_id(&self) -> HirFileId {
151 self.macro_call_id.as_file(self.macro_file_kind) 164 self.macro_call_id.as_file()
152 } 165 }
153} 166}
154 167
155impl SourceAnalyzer { 168impl SourceAnalyzer {
156 pub fn new( 169 pub fn new(
157 db: &impl HirDatabase, 170 db: &impl HirDatabase,
158 node: Source<&SyntaxNode>, 171 node: InFile<&SyntaxNode>,
159 offset: Option<TextUnit>, 172 offset: Option<TextUnit>,
160 ) -> SourceAnalyzer { 173 ) -> SourceAnalyzer {
174 let _p = profile("SourceAnalyzer::new");
161 let def_with_body = def_with_body_from_child_node(db, node); 175 let def_with_body = def_with_body_from_child_node(db, node);
162 if let Some(def) = def_with_body { 176 if let Some(def) = def_with_body {
163 let (_body, source_map) = db.body_with_source_map(def.into()); 177 let (_body, source_map) = db.body_with_source_map(def.into());
@@ -192,12 +206,12 @@ impl SourceAnalyzer {
192 } 206 }
193 207
194 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { 208 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
195 let src = Source { file_id: self.file_id, value: expr }; 209 let src = InFile { file_id: self.file_id, value: expr };
196 self.body_source_map.as_ref()?.node_expr(src) 210 self.body_source_map.as_ref()?.node_expr(src)
197 } 211 }
198 212
199 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 213 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
200 let src = Source { file_id: self.file_id, value: pat }; 214 let src = InFile { file_id: self.file_id, value: pat };
201 self.body_source_map.as_ref()?.node_pat(src) 215 self.body_source_map.as_ref()?.node_pat(src)
202 } 216 }
203 217
@@ -226,7 +240,13 @@ impl SourceAnalyzer {
226 } 240 }
227 241
228 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> { 242 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
229 let expr_id = self.expr_id(&field.expr()?)?; 243 let expr_id = match field.expr() {
244 Some(it) => self.expr_id(&it)?,
245 None => {
246 let src = InFile { file_id: self.file_id, value: field };
247 self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?
248 }
249 };
230 self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) 250 self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into())
231 } 251 }
232 252
@@ -243,11 +263,11 @@ impl SourceAnalyzer {
243 pub fn resolve_macro_call( 263 pub fn resolve_macro_call(
244 &self, 264 &self,
245 db: &impl HirDatabase, 265 db: &impl HirDatabase,
246 macro_call: Source<&ast::MacroCall>, 266 macro_call: InFile<&ast::MacroCall>,
247 ) -> Option<MacroDef> { 267 ) -> Option<MacroDef> {
248 let hygiene = Hygiene::new(db, macro_call.file_id); 268 let hygiene = Hygiene::new(db, macro_call.file_id);
249 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; 269 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
250 self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into()) 270 self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into())
251 } 271 }
252 272
253 pub fn resolve_hir_path( 273 pub fn resolve_hir_path(
@@ -255,43 +275,42 @@ impl SourceAnalyzer {
255 db: &impl HirDatabase, 275 db: &impl HirDatabase,
256 path: &crate::Path, 276 path: &crate::Path,
257 ) -> Option<PathResolution> { 277 ) -> Option<PathResolution> {
258 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 278 let types =
259 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), 279 self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty {
260 TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { 280 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
261 parent: self.resolver.generic_def().unwrap(), 281 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
262 idx, 282 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
263 }), 283 PathResolution::Def(Adt::from(it).into())
264 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
265 PathResolution::Def(Adt::from(it).into())
266 }
267 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
268 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
269 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
270 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
271 });
272 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
273 let res = match val {
274 ValueNs::LocalBinding(pat_id) => {
275 let var = Local { parent: self.body_owner?, pat_id };
276 PathResolution::Local(var)
277 } 284 }
278 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), 285 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
279 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), 286 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
280 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), 287 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
281 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), 288 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
282 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), 289 });
283 }; 290 let values =
284 Some(res) 291 self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| {
285 }); 292 let res = match val {
293 ValueNs::LocalBinding(pat_id) => {
294 let var = Local { parent: self.body_owner?, pat_id };
295 PathResolution::Local(var)
296 }
297 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
298 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
299 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
300 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
301 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
302 };
303 Some(res)
304 });
286 305
287 let items = self 306 let items = self
288 .resolver 307 .resolver
289 .resolve_module_path(db, &path) 308 .resolve_module_path_in_items(db, path.mod_path())
290 .take_types() 309 .take_types()
291 .map(|it| PathResolution::Def(it.into())); 310 .map(|it| PathResolution::Def(it.into()));
292 types.or(values).or(items).or_else(|| { 311 types.or(values).or(items).or_else(|| {
293 self.resolver 312 self.resolver
294 .resolve_path_as_macro(db, &path) 313 .resolve_path_as_macro(db, path.mod_path())
295 .map(|def| PathResolution::Macro(def.into())) 314 .map(|def| PathResolution::Macro(def.into()))
296 }) 315 })
297 } 316 }
@@ -318,7 +337,7 @@ impl SourceAnalyzer {
318 let name = name_ref.as_name(); 337 let name = name_ref.as_name();
319 let source_map = self.body_source_map.as_ref()?; 338 let source_map = self.body_source_map.as_ref()?;
320 let scopes = self.scopes.as_ref()?; 339 let scopes = self.scopes.as_ref()?;
321 let scope = scope_for(scopes, source_map, Source::new(self.file_id, name_ref.syntax()))?; 340 let scope = scope_for(scopes, source_map, InFile::new(self.file_id, name_ref.syntax()))?;
322 let entry = scopes.resolve_name_in_scope(scope, &name)?; 341 let entry = scopes.resolve_name_in_scope(scope, &name)?;
323 Some(ScopeEntryWithSyntax { 342 Some(ScopeEntryWithSyntax {
324 name: entry.name().clone(), 343 name: entry.name().clone(),
@@ -332,10 +351,7 @@ impl SourceAnalyzer {
332 resolver::ScopeDef::PerNs(it) => it.into(), 351 resolver::ScopeDef::PerNs(it) => it.into(),
333 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), 352 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
334 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), 353 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
335 resolver::ScopeDef::GenericParam(idx) => { 354 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }),
336 let parent = self.resolver.generic_def().unwrap();
337 ScopeDef::GenericParam(GenericParam { parent, idx })
338 }
339 resolver::ScopeDef::Local(pat_id) => { 355 resolver::ScopeDef::Local(pat_id) => {
340 let parent = self.resolver.body_owner().unwrap().into(); 356 let parent = self.resolver.body_owner().unwrap().into();
341 ScopeDef::Local(Local { parent, pat_id }) 357 ScopeDef::Local(Local { parent, pat_id })
@@ -349,7 +365,7 @@ impl SourceAnalyzer {
349 // should switch to general reference search infra there. 365 // should switch to general reference search infra there.
350 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { 366 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
351 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 367 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
352 let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); 368 let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone())));
353 fn_def 369 fn_def
354 .syntax() 370 .syntax()
355 .descendants() 371 .descendants()
@@ -375,7 +391,7 @@ impl SourceAnalyzer {
375 // There should be no inference vars in types passed here 391 // There should be no inference vars in types passed here
376 // FIXME check that? 392 // FIXME check that?
377 // FIXME replace Unknown by bound vars here 393 // FIXME replace Unknown by bound vars here
378 let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; 394 let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
379 method_resolution::iterate_method_candidates( 395 method_resolution::iterate_method_candidates(
380 &canonical, 396 &canonical,
381 db, 397 db,
@@ -399,7 +415,7 @@ impl SourceAnalyzer {
399 // There should be no inference vars in types passed here 415 // There should be no inference vars in types passed here
400 // FIXME check that? 416 // FIXME check that?
401 // FIXME replace Unknown by bound vars here 417 // FIXME replace Unknown by bound vars here
402 let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; 418 let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
403 method_resolution::iterate_method_candidates( 419 method_resolution::iterate_method_candidates(
404 &canonical, 420 &canonical,
405 db, 421 db,
@@ -410,24 +426,10 @@ impl SourceAnalyzer {
410 ) 426 )
411 } 427 }
412 428
413 // pub fn autoderef<'a>(
414 // &'a self,
415 // db: &'a impl HirDatabase,
416 // ty: Ty,
417 // ) -> impl Iterator<Item = Ty> + 'a {
418 // // There should be no inference vars in types passed here
419 // // FIXME check that?
420 // let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
421 // let krate = self.resolver.krate();
422 // let environment = TraitEnvironment::lower(db, &self.resolver);
423 // let ty = crate::ty::InEnvironment { value: canonical, environment };
424 // crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value)
425 // }
426
427 /// Checks that particular type `ty` implements `std::future::Future`. 429 /// Checks that particular type `ty` implements `std::future::Future`.
428 /// This function is used in `.await` syntax completion. 430 /// This function is used in `.await` syntax completion.
429 pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { 431 pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool {
430 let std_future_path = known::std_future_future(); 432 let std_future_path = path![std::future::Future];
431 433
432 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { 434 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
433 Some(it) => it.into(), 435 Some(it) => it.into(),
@@ -439,43 +441,40 @@ impl SourceAnalyzer {
439 _ => return false, 441 _ => return false,
440 }; 442 };
441 443
442 let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; 444 let canonical_ty = Canonical { value: ty.ty.value, num_vars: 0 };
443 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait) 445 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait)
444 } 446 }
445 447
446 pub fn expand( 448 pub fn expand(
447 &self, 449 &self,
448 db: &impl HirDatabase, 450 db: &impl HirDatabase,
449 macro_call: Source<&ast::MacroCall>, 451 macro_call: InFile<&ast::MacroCall>,
450 ) -> Option<Expansion> { 452 ) -> Option<Expansion> {
451 let def = self.resolve_macro_call(db, macro_call)?.id; 453 let def = self.resolve_macro_call(db, macro_call)?.id;
452 let ast_id = AstId::new( 454 let ast_id = AstId::new(
453 macro_call.file_id, 455 macro_call.file_id,
454 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value), 456 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
455 ); 457 );
456 Some(Expansion { 458 Some(Expansion { macro_call_id: def.as_call_id(db, MacroCallKind::FnLike(ast_id)) })
457 macro_call_id: def.as_call_id(db, ast_id),
458 macro_file_kind: to_macro_file_kind(macro_call.value),
459 })
460 } 459 }
461} 460}
462 461
463fn scope_for( 462fn scope_for(
464 scopes: &ExprScopes, 463 scopes: &ExprScopes,
465 source_map: &BodySourceMap, 464 source_map: &BodySourceMap,
466 node: Source<&SyntaxNode>, 465 node: InFile<&SyntaxNode>,
467) -> Option<ScopeId> { 466) -> Option<ScopeId> {
468 node.value 467 node.value
469 .ancestors() 468 .ancestors()
470 .filter_map(ast::Expr::cast) 469 .filter_map(ast::Expr::cast)
471 .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it))) 470 .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
472 .find_map(|it| scopes.scope_for(it)) 471 .find_map(|it| scopes.scope_for(it))
473} 472}
474 473
475fn scope_for_offset( 474fn scope_for_offset(
476 scopes: &ExprScopes, 475 scopes: &ExprScopes,
477 source_map: &BodySourceMap, 476 source_map: &BodySourceMap,
478 offset: Source<TextUnit>, 477 offset: InFile<TextUnit>,
479) -> Option<ScopeId> { 478) -> Option<ScopeId> {
480 scopes 479 scopes
481 .scope_by_expr() 480 .scope_by_expr()
@@ -540,35 +539,3 @@ fn adjust(
540 }) 539 })
541 .map(|(_ptr, scope)| *scope) 540 .map(|(_ptr, scope)| *scope)
542} 541}
543
544/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to.
545/// FIXME: Not completed
546fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind {
547 let syn = macro_call.syntax();
548 let parent = match syn.parent() {
549 Some(it) => it,
550 None => {
551 // FIXME:
552 // If it is root, which means the parent HirFile
553 // MacroKindFile must be non-items
554 // return expr now.
555 return MacroFileKind::Expr;
556 }
557 };
558
559 match parent.kind() {
560 MACRO_ITEMS | SOURCE_FILE => MacroFileKind::Items,
561 LET_STMT => {
562 // FIXME: Handle Pattern
563 MacroFileKind::Expr
564 }
565 EXPR_STMT => MacroFileKind::Statements,
566 BLOCK => MacroFileKind::Statements,
567 ARG_LIST => MacroFileKind::Expr,
568 TRY_EXPR => MacroFileKind::Expr,
569 _ => {
570 // Unknown , Just guess it is `Items`
571 MacroFileKind::Items
572 }
573 }
574}
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
deleted file mode 100644
index 4ed69c00d..000000000
--- a/crates/ra_hir/src/ty.rs
+++ /dev/null
@@ -1,4 +0,0 @@
1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists.
3
4pub use hir_ty::*;
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 7e65f4c1d..2c368f690 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -11,6 +11,9 @@ doctest = false
11log = "0.4.5" 11log = "0.4.5"
12once_cell = "1.0.1" 12once_cell = "1.0.1"
13rustc-hash = "1.0" 13rustc-hash = "1.0"
14either = "1.5"
15anymap = "0.12"
16drop_bomb = "0.1.4"
14 17
15ra_arena = { path = "../ra_arena" } 18ra_arena = { path = "../ra_arena" }
16ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 3666529b0..d9ea693e3 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -2,17 +2,18 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use either::Either;
5use hir_expand::{ 6use hir_expand::{
6 either::Either,
7 name::{AsName, Name}, 7 name::{AsName, Name},
8 Source, 8 InFile,
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_prof::profile;
11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
12 13
13use crate::{ 14use crate::{
14 db::DefDatabase, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId, HasChildSource, 15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId,
15 LocalEnumVariantId, LocalStructFieldId, StructId, UnionId, VariantId, 16 LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId,
16}; 17};
17 18
18/// Note that we use `StructData` for unions as well! 19/// Note that we use `StructData` for unions as well!
@@ -50,14 +51,14 @@ pub struct StructFieldData {
50 51
51impl StructData { 52impl StructData {
52 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> { 53 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> {
53 let src = id.source(db); 54 let src = id.lookup(db).source(db);
54 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 55 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
55 let variant_data = VariantData::new(src.value.kind()); 56 let variant_data = VariantData::new(src.value.kind());
56 let variant_data = Arc::new(variant_data); 57 let variant_data = Arc::new(variant_data);
57 Arc::new(StructData { name, variant_data }) 58 Arc::new(StructData { name, variant_data })
58 } 59 }
59 pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> { 60 pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> {
60 let src = id.source(db); 61 let src = id.lookup(db).source(db);
61 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 62 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
62 let variant_data = VariantData::new( 63 let variant_data = VariantData::new(
63 src.value 64 src.value
@@ -72,7 +73,8 @@ impl StructData {
72 73
73impl EnumData { 74impl EnumData {
74 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> { 75 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> {
75 let src = e.source(db); 76 let _p = profile("enum_data_query");
77 let src = e.lookup(db).source(db);
76 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 78 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
77 let mut trace = Trace::new_for_arena(); 79 let mut trace = Trace::new_for_arena();
78 lower_enum(&mut trace, &src.value); 80 lower_enum(&mut trace, &src.value);
@@ -88,8 +90,8 @@ impl EnumData {
88impl HasChildSource for EnumId { 90impl HasChildSource for EnumId {
89 type ChildId = LocalEnumVariantId; 91 type ChildId = LocalEnumVariantId;
90 type Value = ast::EnumVariant; 92 type Value = ast::EnumVariant;
91 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { 93 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
92 let src = self.source(db); 94 let src = self.lookup(db).source(db);
93 let mut trace = Trace::new_for_map(); 95 let mut trace = Trace::new_for_map();
94 lower_enum(&mut trace, &src.value); 96 lower_enum(&mut trace, &src.value);
95 src.with_value(trace.into_map()) 97 src.with_value(trace.into_map())
@@ -145,7 +147,7 @@ impl HasChildSource for VariantId {
145 type ChildId = LocalStructFieldId; 147 type ChildId = LocalStructFieldId;
146 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; 148 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
147 149
148 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { 150 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
149 let src = match self { 151 let src = match self {
150 VariantId::EnumVariantId(it) => { 152 VariantId::EnumVariantId(it) => {
151 // I don't really like the fact that we call into parent source 153 // I don't really like the fact that we call into parent source
@@ -153,8 +155,8 @@ impl HasChildSource for VariantId {
153 let src = it.parent.child_source(db); 155 let src = it.parent.child_source(db);
154 src.map(|map| map[it.local_id].kind()) 156 src.map(|map| map[it.local_id].kind())
155 } 157 }
156 VariantId::StructId(it) => it.source(db).map(|it| it.kind()), 158 VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()),
157 VariantId::UnionId(it) => it.source(db).map(|it| { 159 VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| {
158 it.record_field_def_list() 160 it.record_field_def_list()
159 .map(ast::StructKind::Record) 161 .map(ast::StructKind::Record)
160 .unwrap_or(ast::StructKind::Unit) 162 .unwrap_or(ast::StructKind::Unit)
@@ -184,7 +186,7 @@ fn lower_struct(
184 ast::StructKind::Tuple(fl) => { 186 ast::StructKind::Tuple(fl) => {
185 for (i, fd) in fl.fields().enumerate() { 187 for (i, fd) in fl.fields().enumerate() {
186 trace.alloc( 188 trace.alloc(
187 || Either::A(fd.clone()), 189 || Either::Left(fd.clone()),
188 || StructFieldData { 190 || StructFieldData {
189 name: Name::new_tuple_field(i), 191 name: Name::new_tuple_field(i),
190 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 192 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
@@ -196,7 +198,7 @@ fn lower_struct(
196 ast::StructKind::Record(fl) => { 198 ast::StructKind::Record(fl) => {
197 for fd in fl.fields() { 199 for fd in fl.fields() {
198 trace.alloc( 200 trace.alloc(
199 || Either::B(fd.clone()), 201 || Either::Right(fd.clone()),
200 || StructFieldData { 202 || StructFieldData {
201 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 203 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
202 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), 204 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index fffb22201..9efa4970c 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,7 +2,8 @@
2 2
3use std::{ops, sync::Arc}; 3use std::{ops, sync::Arc};
4 4
5use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source}; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile};
6use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
7use ra_syntax::{ 8use ra_syntax::{
8 ast::{self, AstNode, AttrsOwner}, 9 ast::{self, AstNode, AttrsOwner},
@@ -11,7 +12,7 @@ use ra_syntax::{
11use tt::Subtree; 12use tt::Subtree;
12 13
13use crate::{ 14use crate::{
14 db::DefDatabase, path::Path, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup, 15 db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
15}; 16};
16 17
17#[derive(Default, Debug, Clone, PartialEq, Eq)] 18#[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -44,8 +45,8 @@ impl Attrs {
44 AttrDefId::StructFieldId(it) => { 45 AttrDefId::StructFieldId(it) => {
45 let src = it.parent.child_source(db); 46 let src = it.parent.child_source(db);
46 match &src.value[it.local_id] { 47 match &src.value[it.local_id] {
47 Either::A(_tuple) => Attrs::default(), 48 Either::Left(_tuple) => Attrs::default(),
48 Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)), 49 Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
49 } 50 }
50 } 51 }
51 AttrDefId::EnumVariantId(var_id) => { 52 AttrDefId::EnumVariantId(var_id) => {
@@ -54,13 +55,15 @@ impl Attrs {
54 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 55 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
55 } 56 }
56 AttrDefId::AdtId(it) => match it { 57 AttrDefId::AdtId(it) => match it {
57 AdtId::StructId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 58 AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db),
58 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 59 AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db),
59 AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 60 AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db),
60 }, 61 },
61 AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 62 AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db),
62 AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db), 63 AttrDefId::MacroDefId(it) => {
63 AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 64 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
65 }
66 AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db),
64 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 67 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
65 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), 68 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db),
66 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 69 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
@@ -68,7 +71,7 @@ impl Attrs {
68 } 71 }
69 } 72 }
70 73
71 fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs { 74 fn from_attrs_owner(db: &impl DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
72 let hygiene = Hygiene::new(db, owner.file_id); 75 let hygiene = Hygiene::new(db, owner.file_id);
73 Attrs::new(owner.value, &hygiene) 76 Attrs::new(owner.value, &hygiene)
74 } 77 }
@@ -91,7 +94,7 @@ impl Attrs {
91 94
92#[derive(Debug, Clone, PartialEq, Eq)] 95#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct Attr { 96pub struct Attr {
94 pub(crate) path: Path, 97 pub(crate) path: ModPath,
95 pub(crate) input: Option<AttrInput>, 98 pub(crate) input: Option<AttrInput>,
96} 99}
97 100
@@ -103,7 +106,7 @@ pub enum AttrInput {
103 106
104impl Attr { 107impl Attr {
105 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 108 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
106 let path = Path::from_src(ast.path()?, hygiene)?; 109 let path = ModPath::from_src(ast.path()?, hygiene)?;
107 let input = match ast.input() { 110 let input = match ast.input() {
108 None => None, 111 None => None,
109 Some(ast::AttrInput::Literal(lit)) => { 112 Some(ast::AttrInput::Literal(lit)) => {
@@ -157,7 +160,7 @@ where
157 N: ast::AttrsOwner, 160 N: ast::AttrsOwner,
158 D: DefDatabase, 161 D: DefDatabase,
159{ 162{
160 let src = Source::new(src.file_id(), src.to_node(db)); 163 let src = InFile::new(src.file_id, src.to_node(db));
161 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 164 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
162} 165}
163 166
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index a57a0176d..d3e4c50ae 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -3,58 +3,75 @@
3mod lower; 3mod lower;
4pub mod scope; 4pub mod scope;
5 5
6use std::{ops::Index, sync::Arc}; 6use std::{mem, ops::Index, sync::Arc};
7 7
8use drop_bomb::DropBomb;
9use either::Either;
8use hir_expand::{ 10use hir_expand::{
9 either::Either, hygiene::Hygiene, AstId, HirFileId, MacroDefId, MacroFileKind, Source, 11 ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId,
10}; 12};
11use ra_arena::{map::ArenaMap, Arena}; 13use ra_arena::{map::ArenaMap, Arena};
14use ra_prof::profile;
12use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
13use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
14 17
15use crate::{ 18use crate::{
16 db::DefDatabase, 19 db::DefDatabase,
17 expr::{Expr, ExprId, Pat, PatId}, 20 expr::{Expr, ExprId, Pat, PatId},
21 item_scope::BuiltinShadowMode,
22 item_scope::ItemScope,
18 nameres::CrateDefMap, 23 nameres::CrateDefMap,
19 path::Path, 24 path::{ModPath, Path},
20 DefWithBodyId, HasModule, HasSource, Lookup, ModuleId, 25 src::HasSource,
26 DefWithBodyId, HasModule, Lookup, ModuleId,
21}; 27};
22 28
23struct Expander { 29pub(crate) struct Expander {
24 crate_def_map: Arc<CrateDefMap>, 30 crate_def_map: Arc<CrateDefMap>,
25 current_file_id: HirFileId, 31 current_file_id: HirFileId,
26 hygiene: Hygiene, 32 hygiene: Hygiene,
33 ast_id_map: Arc<AstIdMap>,
27 module: ModuleId, 34 module: ModuleId,
28} 35}
29 36
30impl Expander { 37impl Expander {
31 fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { 38 pub(crate) fn new(
39 db: &impl DefDatabase,
40 current_file_id: HirFileId,
41 module: ModuleId,
42 ) -> Expander {
32 let crate_def_map = db.crate_def_map(module.krate); 43 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id); 44 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module } 45 let ast_id_map = db.ast_id_map(current_file_id);
46 Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
35 } 47 }
36 48
37 fn enter_expand( 49 pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
38 &mut self, 50 &mut self,
39 db: &impl DefDatabase, 51 db: &DB,
40 macro_call: ast::MacroCall, 52 macro_call: ast::MacroCall,
41 ) -> Option<(Mark, ast::Expr)> { 53 ) -> Option<(Mark, T)> {
42 let ast_id = AstId::new( 54 let ast_id = AstId::new(
43 self.current_file_id, 55 self.current_file_id,
44 db.ast_id_map(self.current_file_id).ast_id(&macro_call), 56 db.ast_id_map(self.current_file_id).ast_id(&macro_call),
45 ); 57 );
46 58
47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { 59 if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) {
48 if let Some(def) = self.resolve_path_as_macro(db, &path) { 60 if let Some(def) = self.resolve_path_as_macro(db, &path) {
49 let call_id = def.as_call_id(db, ast_id); 61 let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
50 let file_id = call_id.as_file(MacroFileKind::Expr); 62 let file_id = call_id.as_file();
51 if let Some(node) = db.parse_or_expand(file_id) { 63 if let Some(node) = db.parse_or_expand(file_id) {
52 if let Some(expr) = ast::Expr::cast(node) { 64 if let Some(expr) = T::cast(node) {
53 log::debug!("macro expansion {:#?}", expr.syntax()); 65 log::debug!("macro expansion {:#?}", expr.syntax());
54 66
55 let mark = Mark { file_id: self.current_file_id }; 67 let mark = Mark {
68 file_id: self.current_file_id,
69 ast_id_map: mem::take(&mut self.ast_id_map),
70 bomb: DropBomb::new("expansion mark dropped"),
71 };
56 self.hygiene = Hygiene::new(db, file_id); 72 self.hygiene = Hygiene::new(db, file_id);
57 self.current_file_id = file_id; 73 self.current_file_id = file_id;
74 self.ast_id_map = db.ast_id_map(file_id);
58 75
59 return Some((mark, expr)); 76 return Some((mark, expr));
60 } 77 }
@@ -67,37 +84,44 @@ impl Expander {
67 None 84 None
68 } 85 }
69 86
70 fn exit(&mut self, db: &impl DefDatabase, mark: Mark) { 87 pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id); 88 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id; 89 self.current_file_id = mark.file_id;
73 std::mem::forget(mark); 90 self.ast_id_map = mem::take(&mut mark.ast_id_map);
91 mark.bomb.defuse();
74 } 92 }
75 93
76 fn to_source<T>(&self, value: T) -> Source<T> { 94 pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
77 Source { file_id: self.current_file_id, value } 95 InFile { file_id: self.current_file_id, value }
78 } 96 }
79 97
80 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 98 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
81 Path::from_src(path, &self.hygiene) 99 Path::from_src(path, &self.hygiene)
82 } 100 }
83 101
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 102 fn parse_mod_path(&mut self, path: ast::Path) -> Option<ModPath> {
85 self.crate_def_map.resolve_path(db, self.module.local_id, path).0.take_macros() 103 ModPath::from_src(path, &self.hygiene)
86 } 104 }
87}
88 105
89struct Mark { 106 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option<MacroDefId> {
90 file_id: HirFileId, 107 self.crate_def_map
91} 108 .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
109 .0
110 .take_macros()
111 }
92 112
93impl Drop for Mark { 113 fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
94 fn drop(&mut self) { 114 let file_local_id = self.ast_id_map.ast_id(item);
95 if !std::thread::panicking() { 115 AstId::new(self.current_file_id, file_local_id)
96 panic!("dropped mark")
97 }
98 } 116 }
99} 117}
100 118
119pub(crate) struct Mark {
120 file_id: HirFileId,
121 ast_id_map: Arc<AstIdMap>,
122 bomb: DropBomb,
123}
124
101/// The body of an item (function, const etc.). 125/// The body of an item (function, const etc.).
102#[derive(Debug, Eq, PartialEq)] 126#[derive(Debug, Eq, PartialEq)]
103pub struct Body { 127pub struct Body {
@@ -112,13 +136,14 @@ pub struct Body {
112 pub params: Vec<PatId>, 136 pub params: Vec<PatId>,
113 /// The `ExprId` of the actual body expression. 137 /// The `ExprId` of the actual body expression.
114 pub body_expr: ExprId, 138 pub body_expr: ExprId,
139 pub item_scope: ItemScope,
115} 140}
116 141
117pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; 142pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
118pub type ExprSource = Source<ExprPtr>; 143pub type ExprSource = InFile<ExprPtr>;
119 144
120pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; 145pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
121pub type PatSource = Source<PatPtr>; 146pub type PatSource = InFile<PatPtr>;
122 147
123/// An item body together with the mapping from syntax nodes to HIR expression 148/// An item body together with the mapping from syntax nodes to HIR expression
124/// IDs. This is needed to go from e.g. a position in a file to the HIR 149/// IDs. This is needed to go from e.g. a position in a file to the HIR
@@ -145,6 +170,7 @@ impl Body {
145 db: &impl DefDatabase, 170 db: &impl DefDatabase,
146 def: DefWithBodyId, 171 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) { 172 ) -> (Arc<Body>, Arc<BodySourceMap>) {
173 let _p = profile("body_with_source_map_query");
148 let mut params = None; 174 let mut params = None;
149 175
150 let (file_id, module, body) = match def { 176 let (file_id, module, body) = match def {
@@ -166,7 +192,7 @@ impl Body {
166 } 192 }
167 }; 193 };
168 let expander = Expander::new(db, file_id, module); 194 let expander = Expander::new(db, file_id, module);
169 let (body, source_map) = Body::new(db, expander, params, body); 195 let (body, source_map) = Body::new(db, def, expander, params, body);
170 (Arc::new(body), Arc::new(source_map)) 196 (Arc::new(body), Arc::new(source_map))
171 } 197 }
172 198
@@ -176,11 +202,12 @@ impl Body {
176 202
177 fn new( 203 fn new(
178 db: &impl DefDatabase, 204 db: &impl DefDatabase,
205 def: DefWithBodyId,
179 expander: Expander, 206 expander: Expander,
180 params: Option<ast::ParamList>, 207 params: Option<ast::ParamList>,
181 body: Option<ast::Expr>, 208 body: Option<ast::Expr>,
182 ) -> (Body, BodySourceMap) { 209 ) -> (Body, BodySourceMap) {
183 lower::lower(db, expander, params, body) 210 lower::lower(db, def, expander, params, body)
184 } 211 }
185} 212}
186 213
@@ -205,8 +232,13 @@ impl BodySourceMap {
205 self.expr_map_back.get(expr).copied() 232 self.expr_map_back.get(expr).copied()
206 } 233 }
207 234
208 pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> { 235 pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
209 let src = node.map(|it| Either::A(AstPtr::new(it))); 236 let src = node.map(|it| Either::Left(AstPtr::new(it)));
237 self.expr_map.get(&src).cloned()
238 }
239
240 pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
241 let src = node.map(|it| Either::Right(AstPtr::new(it)));
210 self.expr_map.get(&src).cloned() 242 self.expr_map.get(&src).cloned()
211 } 243 }
212 244
@@ -214,8 +246,8 @@ impl BodySourceMap {
214 self.pat_map_back.get(pat).copied() 246 self.pat_map_back.get(pat).copied()
215 } 247 }
216 248
217 pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> { 249 pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
218 let src = node.map(|it| Either::A(AstPtr::new(it))); 250 let src = node.map(|it| Either::Left(AstPtr::new(it)));
219 self.pat_map.get(&src).cloned() 251 self.pat_map.get(&src).cloned()
220 } 252 }
221 253
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 331736cb2..5323af097 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -1,14 +1,13 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use hir_expand::{ 4use either::Either;
5 either::Either, 5
6 name::{self, AsName, Name}, 6use hir_expand::name::{name, AsName, Name};
7};
8use ra_arena::Arena; 7use ra_arena::Arena;
9use ra_syntax::{ 8use ra_syntax::{
10 ast::{ 9 ast::{
11 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, 10 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
12 TypeAscriptionOwner, 11 TypeAscriptionOwner,
13 }, 12 },
14 AstNode, AstPtr, 13 AstNode, AstPtr,
@@ -26,23 +25,28 @@ use crate::{
26 path::GenericArgs, 25 path::GenericArgs,
27 path::Path, 26 path::Path,
28 type_ref::{Mutability, TypeRef}, 27 type_ref::{Mutability, TypeRef},
28 ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc,
29 StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
29}; 30};
30 31
31pub(super) fn lower( 32pub(super) fn lower(
32 db: &impl DefDatabase, 33 db: &impl DefDatabase,
34 def: DefWithBodyId,
33 expander: Expander, 35 expander: Expander,
34 params: Option<ast::ParamList>, 36 params: Option<ast::ParamList>,
35 body: Option<ast::Expr>, 37 body: Option<ast::Expr>,
36) -> (Body, BodySourceMap) { 38) -> (Body, BodySourceMap) {
37 ExprCollector { 39 ExprCollector {
38 expander,
39 db, 40 db,
41 def,
42 expander,
40 source_map: BodySourceMap::default(), 43 source_map: BodySourceMap::default(),
41 body: Body { 44 body: Body {
42 exprs: Arena::default(), 45 exprs: Arena::default(),
43 pats: Arena::default(), 46 pats: Arena::default(),
44 params: Vec::new(), 47 params: Vec::new(),
45 body_expr: ExprId::dummy(), 48 body_expr: ExprId::dummy(),
49 item_scope: Default::default(),
46 }, 50 },
47 } 51 }
48 .collect(params, body) 52 .collect(params, body)
@@ -50,6 +54,7 @@ pub(super) fn lower(
50 54
51struct ExprCollector<DB> { 55struct ExprCollector<DB> {
52 db: DB, 56 db: DB,
57 def: DefWithBodyId,
53 expander: Expander, 58 expander: Expander,
54 59
55 body: Body, 60 body: Body,
@@ -70,11 +75,11 @@ where
70 let ptr = AstPtr::new(&self_param); 75 let ptr = AstPtr::new(&self_param);
71 let param_pat = self.alloc_pat( 76 let param_pat = self.alloc_pat(
72 Pat::Bind { 77 Pat::Bind {
73 name: name::SELF_PARAM, 78 name: name![self],
74 mode: BindingAnnotation::Unannotated, 79 mode: BindingAnnotation::Unannotated,
75 subpat: None, 80 subpat: None,
76 }, 81 },
77 Either::B(ptr), 82 Either::Right(ptr),
78 ); 83 );
79 self.body.params.push(param_pat); 84 self.body.params.push(param_pat);
80 } 85 }
@@ -94,7 +99,7 @@ where
94 } 99 }
95 100
96 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
97 let ptr = Either::A(ptr); 102 let ptr = Either::Left(ptr);
98 let id = self.body.exprs.alloc(expr); 103 let id = self.body.exprs.alloc(expr);
99 let src = self.expander.to_source(ptr); 104 let src = self.expander.to_source(ptr);
100 self.source_map.expr_map.insert(src, id); 105 self.source_map.expr_map.insert(src, id);
@@ -107,7 +112,7 @@ where
107 self.body.exprs.alloc(expr) 112 self.body.exprs.alloc(expr)
108 } 113 }
109 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { 114 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
110 let ptr = Either::B(ptr); 115 let ptr = Either::Right(ptr);
111 let id = self.body.exprs.alloc(expr); 116 let id = self.body.exprs.alloc(expr);
112 let src = self.expander.to_source(ptr); 117 let src = self.expander.to_source(ptr);
113 self.source_map.expr_map.insert(src, id); 118 self.source_map.expr_map.insert(src, id);
@@ -277,7 +282,7 @@ where
277 ast::Expr::ParenExpr(e) => { 282 ast::Expr::ParenExpr(e) => {
278 let inner = self.collect_expr_opt(e.expr()); 283 let inner = self.collect_expr_opt(e.expr());
279 // make the paren expr point to the inner expression as well 284 // make the paren expr point to the inner expression as well
280 let src = self.expander.to_source(Either::A(syntax_ptr)); 285 let src = self.expander.to_source(Either::Left(syntax_ptr));
281 self.source_map.expr_map.insert(src, inner); 286 self.source_map.expr_map.insert(src, inner);
282 inner 287 inner
283 } 288 }
@@ -367,8 +372,9 @@ where
367 arg_types.push(type_ref); 372 arg_types.push(type_ref);
368 } 373 }
369 } 374 }
375 let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast);
370 let body = self.collect_expr_opt(e.body()); 376 let body = self.collect_expr_opt(e.body());
371 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr) 377 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
372 } 378 }
373 ast::Expr::BinExpr(e) => { 379 ast::Expr::BinExpr(e) => {
374 let lhs = self.collect_expr_opt(e.lhs()); 380 let lhs = self.collect_expr_opt(e.lhs());
@@ -429,10 +435,17 @@ where
429 let index = self.collect_expr_opt(e.index()); 435 let index = self.collect_expr_opt(e.index());
430 self.alloc_expr(Expr::Index { base, index }, syntax_ptr) 436 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
431 } 437 }
432 438 ast::Expr::RangeExpr(e) => {
433 // FIXME implement HIR for these: 439 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
434 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 440 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
435 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 441 match e.op_kind() {
442 Some(range_type) => {
443 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
444 }
445 None => self.alloc_expr(Expr::Missing, syntax_ptr),
446 }
447 }
448 // FIXME expand to statements in statement position
436 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { 449 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) {
437 Some((mark, expansion)) => { 450 Some((mark, expansion)) => {
438 let id = self.collect_expr(expansion); 451 let id = self.collect_expr(expansion);
@@ -441,6 +454,9 @@ where
441 } 454 }
442 None => self.alloc_expr(Expr::Missing, syntax_ptr), 455 None => self.alloc_expr(Expr::Missing, syntax_ptr),
443 }, 456 },
457
458 // FIXME implement HIR for these:
459 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
444 } 460 }
445 } 461 }
446 462
@@ -458,6 +474,7 @@ where
458 Some(block) => block, 474 Some(block) => block,
459 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), 475 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
460 }; 476 };
477 self.collect_block_items(&block);
461 let statements = block 478 let statements = block
462 .statements() 479 .statements()
463 .map(|s| match s { 480 .map(|s| match s {
@@ -474,6 +491,63 @@ where
474 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) 491 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
475 } 492 }
476 493
494 fn collect_block_items(&mut self, block: &ast::Block) {
495 let container = ContainerId::DefWithBodyId(self.def);
496 for item in block.items() {
497 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
498 ast::ModuleItem::FnDef(def) => {
499 let ast_id = self.expander.ast_id(&def);
500 (
501 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(),
502 def.name(),
503 )
504 }
505 ast::ModuleItem::TypeAliasDef(def) => {
506 let ast_id = self.expander.ast_id(&def);
507 (
508 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(),
509 def.name(),
510 )
511 }
512 ast::ModuleItem::ConstDef(def) => {
513 let ast_id = self.expander.ast_id(&def);
514 (
515 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(),
516 def.name(),
517 )
518 }
519 ast::ModuleItem::StaticDef(def) => {
520 let ast_id = self.expander.ast_id(&def);
521 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name())
522 }
523 ast::ModuleItem::StructDef(def) => {
524 let ast_id = self.expander.ast_id(&def);
525 (StructLoc { container, ast_id }.intern(self.db).into(), def.name())
526 }
527 ast::ModuleItem::EnumDef(def) => {
528 let ast_id = self.expander.ast_id(&def);
529 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name())
530 }
531 ast::ModuleItem::UnionDef(def) => {
532 let ast_id = self.expander.ast_id(&def);
533 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name())
534 }
535 ast::ModuleItem::TraitDef(def) => {
536 let ast_id = self.expander.ast_id(&def);
537 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
538 }
539 ast::ModuleItem::ImplBlock(_)
540 | ast::ModuleItem::UseItem(_)
541 | ast::ModuleItem::ExternCrateItem(_)
542 | ast::ModuleItem::Module(_) => continue,
543 };
544 self.body.item_scope.define_def(def);
545 if let Some(name) = name {
546 self.body.item_scope.push_res(name.as_name(), def.into());
547 }
548 }
549 }
550
477 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { 551 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
478 if let Some(block) = expr { 552 if let Some(block) = expr {
479 self.collect_block(block) 553 self.collect_block(block)
@@ -541,7 +615,7 @@ where
541 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, 615 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
542 }; 616 };
543 let ptr = AstPtr::new(&pat); 617 let ptr = AstPtr::new(&pat);
544 self.alloc_pat(pattern, Either::A(ptr)) 618 self.alloc_pat(pattern, Either::Left(ptr))
545 } 619 }
546 620
547 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { 621 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 625aa39dd..a63552327 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -171,7 +171,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
171 171
172#[cfg(test)] 172#[cfg(test)]
173mod tests { 173mod tests {
174 use hir_expand::{name::AsName, Source}; 174 use hir_expand::{name::AsName, InFile};
175 use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; 175 use ra_db::{fixture::WithFixture, FileId, SourceDatabase};
176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
177 use test_utils::{assert_eq_text, covers, extract_offset}; 177 use test_utils::{assert_eq_text, covers, extract_offset};
@@ -183,8 +183,8 @@ mod tests {
183 let crate_def_map = db.crate_def_map(krate); 183 let crate_def_map = db.crate_def_map(krate);
184 184
185 let module = crate_def_map.modules_for_file(file_id).next().unwrap(); 185 let module = crate_def_map.modules_for_file(file_id).next().unwrap();
186 let (_, res) = crate_def_map[module].scope.entries().next().unwrap(); 186 let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
187 match res.def.take_values().unwrap() { 187 match def.take_values().unwrap() {
188 ModuleDefId::FunctionId(it) => it, 188 ModuleDefId::FunctionId(it) => it,
189 _ => panic!(), 189 _ => panic!(),
190 } 190 }
@@ -211,7 +211,7 @@ mod tests {
211 let (_body, source_map) = db.body_with_source_map(function.into()); 211 let (_body, source_map) = db.body_with_source_map(function.into());
212 212
213 let expr_id = source_map 213 let expr_id = source_map
214 .node_expr(Source { file_id: file_id.into(), value: &marker.into() }) 214 .node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
215 .unwrap(); 215 .unwrap();
216 let scope = scopes.scope_for(expr_id); 216 let scope = scopes.scope_for(expr_id);
217 217
@@ -318,7 +318,7 @@ mod tests {
318 let expr_scope = { 318 let expr_scope = {
319 let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); 319 let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
320 let expr_id = 320 let expr_id =
321 source_map.node_expr(Source { file_id: file_id.into(), value: &expr_ast }).unwrap(); 321 source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
322 scopes.scope_for(expr_id).unwrap() 322 scopes.scope_for(expr_id).unwrap()
323 }; 323 };
324 324
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index 5e8157144..d14901a9b 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -5,7 +5,7 @@
5 5
6use std::fmt; 6use std::fmt;
7 7
8use hir_expand::name::{self, Name}; 8use hir_expand::name::{name, Name};
9 9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Signedness { 11pub enum Signedness {
@@ -52,26 +52,26 @@ pub enum BuiltinType {
52impl BuiltinType { 52impl BuiltinType {
53 #[rustfmt::skip] 53 #[rustfmt::skip]
54 pub const ALL: &'static [(Name, BuiltinType)] = &[ 54 pub const ALL: &'static [(Name, BuiltinType)] = &[
55 (name::CHAR, BuiltinType::Char), 55 (name![char], BuiltinType::Char),
56 (name::BOOL, BuiltinType::Bool), 56 (name![bool], BuiltinType::Bool),
57 (name::STR, BuiltinType::Str ), 57 (name![str], BuiltinType::Str),
58 58
59 (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), 59 (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)),
60 (name::I8, BuiltinType::Int(BuiltinInt::I8)), 60 (name![i8], BuiltinType::Int(BuiltinInt::I8)),
61 (name::I16, BuiltinType::Int(BuiltinInt::I16)), 61 (name![i16], BuiltinType::Int(BuiltinInt::I16)),
62 (name::I32, BuiltinType::Int(BuiltinInt::I32)), 62 (name![i32], BuiltinType::Int(BuiltinInt::I32)),
63 (name::I64, BuiltinType::Int(BuiltinInt::I64)), 63 (name![i64], BuiltinType::Int(BuiltinInt::I64)),
64 (name::I128, BuiltinType::Int(BuiltinInt::I128)), 64 (name![i128], BuiltinType::Int(BuiltinInt::I128)),
65 65
66 (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), 66 (name![usize], BuiltinType::Int(BuiltinInt::USIZE)),
67 (name::U8, BuiltinType::Int(BuiltinInt::U8)), 67 (name![u8], BuiltinType::Int(BuiltinInt::U8)),
68 (name::U16, BuiltinType::Int(BuiltinInt::U16)), 68 (name![u16], BuiltinType::Int(BuiltinInt::U16)),
69 (name::U32, BuiltinType::Int(BuiltinInt::U32)), 69 (name![u32], BuiltinType::Int(BuiltinInt::U32)),
70 (name::U64, BuiltinType::Int(BuiltinInt::U64)), 70 (name![u64], BuiltinType::Int(BuiltinInt::U64)),
71 (name::U128, BuiltinType::Int(BuiltinInt::U128)), 71 (name![u128], BuiltinType::Int(BuiltinInt::U128)),
72 72
73 (name::F32, BuiltinType::Float(BuiltinFloat::F32)), 73 (name![f32], BuiltinType::Float(BuiltinFloat::F32)),
74 (name::F64, BuiltinType::Float(BuiltinFloat::F64)), 74 (name![f64], BuiltinType::Float(BuiltinFloat::F64)),
75 ]; 75 ];
76} 76}
77 77
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
new file mode 100644
index 000000000..8b6c773ee
--- /dev/null
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -0,0 +1,177 @@
1//! When *constructing* `hir`, we start at some parent syntax node and recursively
2//! lower the children.
3//!
4//! This modules allows one to go in the opposite direction: start with a syntax
5//! node for a *child*, and get its hir.
6
7use either::Either;
8
9use crate::{
10 db::DefDatabase,
11 dyn_map::DynMap,
12 item_scope::ItemScope,
13 keys,
14 src::{HasChildSource, HasSource},
15 AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId,
16 ModuleId, StructFieldId, TraitId, VariantId,
17};
18
19pub trait ChildBySource {
20 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap;
21}
22
23impl ChildBySource for TraitId {
24 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
25 let mut res = DynMap::default();
26
27 let data = db.trait_data(*self);
28 for (_name, item) in data.items.iter() {
29 match *item {
30 AssocItemId::FunctionId(func) => {
31 let src = func.lookup(db).source(db);
32 res[keys::FUNCTION].insert(src, func)
33 }
34 AssocItemId::ConstId(konst) => {
35 let src = konst.lookup(db).source(db);
36 res[keys::CONST].insert(src, konst)
37 }
38 AssocItemId::TypeAliasId(ty) => {
39 let src = ty.lookup(db).source(db);
40 res[keys::TYPE_ALIAS].insert(src, ty)
41 }
42 }
43 }
44
45 res
46 }
47}
48
49impl ChildBySource for ImplId {
50 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
51 let mut res = DynMap::default();
52
53 let data = db.impl_data(*self);
54 for &item in data.items.iter() {
55 match item {
56 AssocItemId::FunctionId(func) => {
57 let src = func.lookup(db).source(db);
58 res[keys::FUNCTION].insert(src, func)
59 }
60 AssocItemId::ConstId(konst) => {
61 let src = konst.lookup(db).source(db);
62 res[keys::CONST].insert(src, konst)
63 }
64 AssocItemId::TypeAliasId(ty) => {
65 let src = ty.lookup(db).source(db);
66 res[keys::TYPE_ALIAS].insert(src, ty)
67 }
68 }
69 }
70
71 res
72 }
73}
74
75impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
77 let crate_def_map = db.crate_def_map(self.krate);
78 let module_data = &crate_def_map[self.local_id];
79 module_data.scope.child_by_source(db)
80 }
81}
82
83impl ChildBySource for ItemScope {
84 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
85 let mut res = DynMap::default();
86 self.declarations().for_each(|item| add_module_def(db, &mut res, item));
87 self.impls().for_each(|imp| add_impl(db, &mut res, imp));
88 return res;
89
90 fn add_module_def(db: &impl DefDatabase, map: &mut DynMap, item: ModuleDefId) {
91 match item {
92 ModuleDefId::FunctionId(func) => {
93 let src = func.lookup(db).source(db);
94 map[keys::FUNCTION].insert(src, func)
95 }
96 ModuleDefId::ConstId(konst) => {
97 let src = konst.lookup(db).source(db);
98 map[keys::CONST].insert(src, konst)
99 }
100 ModuleDefId::StaticId(statik) => {
101 let src = statik.lookup(db).source(db);
102 map[keys::STATIC].insert(src, statik)
103 }
104 ModuleDefId::TypeAliasId(ty) => {
105 let src = ty.lookup(db).source(db);
106 map[keys::TYPE_ALIAS].insert(src, ty)
107 }
108 ModuleDefId::TraitId(trait_) => {
109 let src = trait_.lookup(db).source(db);
110 map[keys::TRAIT].insert(src, trait_)
111 }
112 ModuleDefId::AdtId(adt) => match adt {
113 AdtId::StructId(strukt) => {
114 let src = strukt.lookup(db).source(db);
115 map[keys::STRUCT].insert(src, strukt)
116 }
117 AdtId::UnionId(union_) => {
118 let src = union_.lookup(db).source(db);
119 map[keys::UNION].insert(src, union_)
120 }
121 AdtId::EnumId(enum_) => {
122 let src = enum_.lookup(db).source(db);
123 map[keys::ENUM].insert(src, enum_)
124 }
125 },
126 _ => (),
127 }
128 }
129 fn add_impl(db: &impl DefDatabase, map: &mut DynMap, imp: ImplId) {
130 let src = imp.lookup(db).source(db);
131 map[keys::IMPL].insert(src, imp)
132 }
133 }
134}
135
136impl ChildBySource for VariantId {
137 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
138 let mut res = DynMap::default();
139
140 let arena_map = self.child_source(db);
141 let arena_map = arena_map.as_ref();
142 for (local_id, source) in arena_map.value.iter() {
143 let id = StructFieldId { parent: *self, local_id };
144 match source {
145 Either::Left(source) => {
146 res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
147 }
148 Either::Right(source) => {
149 res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
150 }
151 }
152 }
153 res
154 }
155}
156
157impl ChildBySource for EnumId {
158 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
159 let mut res = DynMap::default();
160
161 let arena_map = self.child_source(db);
162 let arena_map = arena_map.as_ref();
163 for (local_id, source) in arena_map.value.iter() {
164 let id = EnumVariantId { parent: *self, local_id };
165 res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id)
166 }
167
168 res
169 }
170}
171
172impl ChildBySource for DefWithBodyId {
173 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
174 let body = db.body(*self);
175 body.item_scope.child_by_source(db)
176 }
177}
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index fee10b237..1aa9a9b7d 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -3,16 +3,17 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{
6 name::{self, AsName, Name}, 6 name::{name, AsName, Name},
7 AstId, 7 AstId, InFile,
8}; 8};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner};
10 10
11use crate::{ 11use crate::{
12 db::DefDatabase, 12 db::DefDatabase,
13 src::HasSource,
13 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
14 AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource, 15 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
15 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 16 ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
16}; 17};
17 18
18#[derive(Debug, Clone, PartialEq, Eq)] 19#[derive(Debug, Clone, PartialEq, Eq)]
@@ -36,7 +37,7 @@ impl FunctionData {
36 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 37 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
37 TypeRef::from_ast(type_ref) 38 TypeRef::from_ast(type_ref)
38 } else { 39 } else {
39 let self_type = TypeRef::Path(name::SELF_TYPE.into()); 40 let self_type = TypeRef::Path(name![Self].into());
40 match self_param.kind() { 41 match self_param.kind() {
41 ast::SelfParamKind::Owned => self_type, 42 ast::SelfParamKind::Owned => self_type,
42 ast::SelfParamKind::Ref => { 43 ast::SelfParamKind::Ref => {
@@ -93,12 +94,12 @@ pub struct TraitData {
93 94
94impl TraitData { 95impl TraitData {
95 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> { 96 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> {
96 let src = tr.source(db); 97 let src = tr.lookup(db).source(db);
97 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 98 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
98 let auto = src.value.is_auto(); 99 let auto = src.value.is_auto();
99 let ast_id_map = db.ast_id_map(src.file_id); 100 let ast_id_map = db.ast_id_map(src.file_id);
100 101
101 let container = ContainerId::TraitId(tr); 102 let container = AssocContainerId::TraitId(tr);
102 let items = if let Some(item_list) = src.value.item_list() { 103 let items = if let Some(item_list) = src.value.item_list() {
103 item_list 104 item_list
104 .impl_items() 105 .impl_items()
@@ -166,46 +167,24 @@ pub struct ImplData {
166 167
167impl ImplData { 168impl ImplData {
168 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { 169 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
169 let src = id.source(db); 170 let impl_loc = id.lookup(db);
170 let items = db.ast_id_map(src.file_id); 171 let src = impl_loc.source(db);
171 172
172 let target_trait = src.value.target_trait().map(TypeRef::from_ast); 173 let target_trait = src.value.target_trait().map(TypeRef::from_ast);
173 let target_type = TypeRef::from_ast_opt(src.value.target_type()); 174 let target_type = TypeRef::from_ast_opt(src.value.target_type());
174 let is_negative = src.value.is_negative(); 175 let is_negative = src.value.is_negative();
176 let module_id = impl_loc.container.module(db);
175 177
176 let items = if let Some(item_list) = src.value.item_list() { 178 let mut items = Vec::new();
177 item_list 179 if let Some(item_list) = src.value.item_list() {
178 .impl_items() 180 items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
179 .map(|item_node| match item_node { 181 items.extend(collect_impl_items_in_macros(
180 ast::ImplItem::FnDef(it) => { 182 db,
181 let def = FunctionLoc { 183 module_id,
182 container: ContainerId::ImplId(id), 184 &src.with_value(item_list),
183 ast_id: AstId::new(src.file_id, items.ast_id(&it)), 185 id,
184 } 186 ));
185 .intern(db); 187 }
186 def.into()
187 }
188 ast::ImplItem::ConstDef(it) => {
189 let def = ConstLoc {
190 container: ContainerId::ImplId(id),
191 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
192 }
193 .intern(db);
194 def.into()
195 }
196 ast::ImplItem::TypeAliasDef(it) => {
197 let def = TypeAliasLoc {
198 container: ContainerId::ImplId(id),
199 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
200 }
201 .intern(db);
202 def.into()
203 }
204 })
205 .collect()
206 } else {
207 Vec::new()
208 };
209 188
210 let res = ImplData { target_trait, target_type, items, is_negative }; 189 let res = ImplData { target_trait, target_type, items, is_negative };
211 Arc::new(res) 190 Arc::new(res)
@@ -236,3 +215,92 @@ impl ConstData {
236 ConstData { name, type_ref } 215 ConstData { name, type_ref }
237 } 216 }
238} 217}
218
219fn collect_impl_items_in_macros(
220 db: &impl DefDatabase,
221 module_id: ModuleId,
222 impl_block: &InFile<ast::ItemList>,
223 id: ImplId,
224) -> Vec<AssocItemId> {
225 let mut expander = Expander::new(db, impl_block.file_id, module_id);
226 let mut res = Vec::new();
227
228 // We set a limit to protect against infinite recursion
229 let limit = 100;
230
231 for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) {
232 res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit))
233 }
234
235 res
236}
237
238fn collect_impl_items_in_macro(
239 db: &impl DefDatabase,
240 expander: &mut Expander,
241 m: ast::MacroCall,
242 id: ImplId,
243 limit: usize,
244) -> Vec<AssocItemId> {
245 if limit == 0 {
246 return Vec::new();
247 }
248
249 if let Some((mark, items)) = expander.enter_expand(db, m) {
250 let items: InFile<ast::MacroItems> = expander.to_source(items);
251 let mut res = collect_impl_items(
252 db,
253 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
254 items.file_id,
255 id,
256 );
257 // Recursive collect macros
258 // Note that ast::ModuleItem do not include ast::MacroCall
259 // We cannot use ModuleItemOwner::items here
260 for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
261 res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1))
262 }
263 expander.exit(db, mark);
264 res
265 } else {
266 Vec::new()
267 }
268}
269
270fn collect_impl_items(
271 db: &impl DefDatabase,
272 impl_items: impl Iterator<Item = ImplItem>,
273 file_id: crate::HirFileId,
274 id: ImplId,
275) -> Vec<AssocItemId> {
276 let items = db.ast_id_map(file_id);
277
278 impl_items
279 .map(|item_node| match item_node {
280 ast::ImplItem::FnDef(it) => {
281 let def = FunctionLoc {
282 container: AssocContainerId::ImplId(id),
283 ast_id: AstId::new(file_id, items.ast_id(&it)),
284 }
285 .intern(db);
286 def.into()
287 }
288 ast::ImplItem::ConstDef(it) => {
289 let def = ConstLoc {
290 container: AssocContainerId::ImplId(id),
291 ast_id: AstId::new(file_id, items.ast_id(&it)),
292 }
293 .intern(db);
294 def.into()
295 }
296 ast::ImplItem::TypeAliasDef(it) => {
297 let def = TypeAliasLoc {
298 container: AssocContainerId::ImplId(id),
299 ast_id: AstId::new(file_id, items.ast_id(&it)),
300 }
301 .intern(db);
302 def.into()
303 }
304 })
305 .collect()
306}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index ef5611ffc..c55fd4111 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase}; 5use ra_db::{salsa, CrateId, SourceDatabase};
6use ra_syntax::{ast, SmolStr}; 6use ra_syntax::SmolStr;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
@@ -13,13 +13,10 @@ use crate::{
13 docs::Documentation, 13 docs::Documentation,
14 generics::GenericParams, 14 generics::GenericParams,
15 lang_item::{LangItemTarget, LangItems}, 15 lang_item::{LangItemTarget, LangItems},
16 nameres::{ 16 nameres::{raw::RawItems, CrateDefMap},
17 raw::{ImportSourceMap, RawItems}, 17 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
18 CrateDefMap, 18 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
19 }, 19 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
21 ImplId, ItemLoc, ModuleId, StaticId, StaticLoc, StructId, TraitId, TypeAliasId, TypeAliasLoc,
22 UnionId,
23}; 20};
24 21
25#[salsa::query_group(InternDatabaseStorage)] 22#[salsa::query_group(InternDatabaseStorage)]
@@ -27,31 +24,25 @@ pub trait InternDatabase: SourceDatabase {
27 #[salsa::interned] 24 #[salsa::interned]
28 fn intern_function(&self, loc: FunctionLoc) -> FunctionId; 25 fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
29 #[salsa::interned] 26 #[salsa::interned]
30 fn intern_struct(&self, loc: ItemLoc<ast::StructDef>) -> StructId; 27 fn intern_struct(&self, loc: StructLoc) -> StructId;
31 #[salsa::interned] 28 #[salsa::interned]
32 fn intern_union(&self, loc: ItemLoc<ast::UnionDef>) -> UnionId; 29 fn intern_union(&self, loc: UnionLoc) -> UnionId;
33 #[salsa::interned] 30 #[salsa::interned]
34 fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId; 31 fn intern_enum(&self, loc: EnumLoc) -> EnumId;
35 #[salsa::interned] 32 #[salsa::interned]
36 fn intern_const(&self, loc: ConstLoc) -> ConstId; 33 fn intern_const(&self, loc: ConstLoc) -> ConstId;
37 #[salsa::interned] 34 #[salsa::interned]
38 fn intern_static(&self, loc: StaticLoc) -> StaticId; 35 fn intern_static(&self, loc: StaticLoc) -> StaticId;
39 #[salsa::interned] 36 #[salsa::interned]
40 fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId; 37 fn intern_trait(&self, loc: TraitLoc) -> TraitId;
41 #[salsa::interned] 38 #[salsa::interned]
42 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; 39 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
43 #[salsa::interned] 40 #[salsa::interned]
44 fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId; 41 fn intern_impl(&self, loc: ImplLoc) -> ImplId;
45} 42}
46 43
47#[salsa::query_group(DefDatabaseStorage)] 44#[salsa::query_group(DefDatabaseStorage)]
48pub trait DefDatabase: InternDatabase + AstDatabase { 45pub trait DefDatabase: InternDatabase + AstDatabase {
49 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
50 fn raw_items_with_source_map(
51 &self,
52 file_id: HirFileId,
53 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
54
55 #[salsa::invoke(RawItems::raw_items_query)] 46 #[salsa::invoke(RawItems::raw_items_query)]
56 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 47 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
57 48
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index eda9b2269..095498429 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -6,7 +6,7 @@ use hir_expand::diagnostics::Diagnostic;
6use ra_db::RelativePathBuf; 6use ra_db::RelativePathBuf;
7use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; 7use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
8 8
9use hir_expand::{HirFileId, Source}; 9use hir_expand::{HirFileId, InFile};
10 10
11#[derive(Debug)] 11#[derive(Debug)]
12pub struct UnresolvedModule { 12pub struct UnresolvedModule {
@@ -19,8 +19,8 @@ impl Diagnostic for UnresolvedModule {
19 fn message(&self) -> String { 19 fn message(&self) -> String {
20 "unresolved module".to_string() 20 "unresolved module".to_string()
21 } 21 }
22 fn source(&self) -> Source<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 Source { file_id: self.file, value: self.decl.into() } 23 InFile { file_id: self.file, value: self.decl.into() }
24 } 24 }
25 fn as_any(&self) -> &(dyn Any + Send + 'static) { 25 fn as_any(&self) -> &(dyn Any + Send + 'static) {
26 self 26 self
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs
index 34ed9b7a5..b29f142e3 100644
--- a/crates/ra_hir_def/src/docs.rs
+++ b/crates/ra_hir_def/src/docs.rs
@@ -5,10 +5,14 @@
5 5
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use hir_expand::either::Either; 8use either::Either;
9use ra_syntax::ast; 9use ra_syntax::ast;
10 10
11use crate::{db::DefDatabase, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup}; 11use crate::{
12 db::DefDatabase,
13 src::{HasChildSource, HasSource},
14 AdtId, AttrDefId, Lookup,
15};
12 16
13/// Holds documentation 17/// Holds documentation
14#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
@@ -42,21 +46,21 @@ impl Documentation {
42 AttrDefId::StructFieldId(it) => { 46 AttrDefId::StructFieldId(it) => {
43 let src = it.parent.child_source(db); 47 let src = it.parent.child_source(db);
44 match &src.value[it.local_id] { 48 match &src.value[it.local_id] {
45 Either::A(_tuple) => None, 49 Either::Left(_tuple) => None,
46 Either::B(record) => docs_from_ast(record), 50 Either::Right(record) => docs_from_ast(record),
47 } 51 }
48 } 52 }
49 AttrDefId::AdtId(it) => match it { 53 AttrDefId::AdtId(it) => match it {
50 AdtId::StructId(it) => docs_from_ast(&it.source(db).value), 54 AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value),
51 AdtId::EnumId(it) => docs_from_ast(&it.source(db).value), 55 AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value),
52 AdtId::UnionId(it) => docs_from_ast(&it.source(db).value), 56 AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
53 }, 57 },
54 AttrDefId::EnumVariantId(it) => { 58 AttrDefId::EnumVariantId(it) => {
55 let src = it.parent.child_source(db); 59 let src = it.parent.child_source(db);
56 docs_from_ast(&src.value[it.local_id]) 60 docs_from_ast(&src.value[it.local_id])
57 } 61 }
58 AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value), 62 AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value),
59 AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)), 63 AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db)),
60 AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), 64 AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value),
61 AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), 65 AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value),
62 AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), 66 AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs
new file mode 100644
index 000000000..6f269d7b0
--- /dev/null
+++ b/crates/ra_hir_def/src/dyn_map.rs
@@ -0,0 +1,108 @@
1//! This module defines a `DynMap` -- a container for heterogeneous maps.
2//!
3//! This means that `DynMap` stores a bunch of hash maps inside, and those maps
4//! can be of different types.
5//!
6//! It is used like this:
7//!
8//! ```
9//! // keys define submaps of a `DynMap`
10//! const STRING_TO_U32: Key<String, u32> = Key::new();
11//! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new();
12//!
13//! // Note: concrete type, no type params!
14//! let mut map = DynMap::new();
15//!
16//! // To access a specific map, index the `DynMap` by `Key`:
17//! map[STRING_TO_U32].insert("hello".to_string(), 92);
18//! let value = map[U32_TO_VEC].get(92);
19//! assert!(value.is_none());
20//! ```
21//!
22//! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are
23//! a coincidence.
24use std::{
25 hash::Hash,
26 marker::PhantomData,
27 ops::{Index, IndexMut},
28};
29
30use anymap::Map;
31use rustc_hash::FxHashMap;
32
33pub struct Key<K, V, P = (K, V)> {
34 _phantom: PhantomData<(K, V, P)>,
35}
36
37impl<K, V, P> Key<K, V, P> {
38 pub(crate) const fn new() -> Key<K, V, P> {
39 Key { _phantom: PhantomData }
40 }
41}
42
43impl<K, V, P> Copy for Key<K, V, P> {}
44
45impl<K, V, P> Clone for Key<K, V, P> {
46 fn clone(&self) -> Key<K, V, P> {
47 *self
48 }
49}
50
51pub trait Policy {
52 type K;
53 type V;
54
55 fn insert(map: &mut DynMap, key: Self::K, value: Self::V);
56 fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>;
57}
58
59impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) {
60 type K = K;
61 type V = V;
62 fn insert(map: &mut DynMap, key: K, value: V) {
63 map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value);
64 }
65 fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> {
66 map.map.get::<FxHashMap<K, V>>()?.get(key)
67 }
68}
69
70pub struct DynMap {
71 pub(crate) map: Map,
72}
73
74impl Default for DynMap {
75 fn default() -> Self {
76 DynMap { map: Map::new() }
77 }
78}
79
80#[repr(transparent)]
81pub struct KeyMap<KEY> {
82 map: DynMap,
83 _phantom: PhantomData<KEY>,
84}
85
86impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
87 pub fn insert(&mut self, key: P::K, value: P::V) {
88 P::insert(&mut self.map, key, value)
89 }
90 pub fn get(&self, key: &P::K) -> Option<&P::V> {
91 P::get(&self.map, key)
92 }
93}
94
95impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap {
96 type Output = KeyMap<Key<P::K, P::V, P>>;
97 fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output {
98 // Safe due to `#[repr(transparent)]`.
99 unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) }
100 }
101}
102
103impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap {
104 fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output {
105 // Safe due to `#[repr(transparent)]`.
106 unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) }
107 }
108}
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index 04c1d8f69..a75ef9970 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -14,6 +14,7 @@
14 14
15use hir_expand::name::Name; 15use hir_expand::name::Name;
16use ra_arena::{impl_arena_id, RawId}; 16use ra_arena::{impl_arena_id, RawId};
17use ra_syntax::ast::RangeOp;
17 18
18use crate::{ 19use crate::{
19 builtin_type::{BuiltinFloat, BuiltinInt}, 20 builtin_type::{BuiltinFloat, BuiltinInt},
@@ -130,6 +131,11 @@ pub enum Expr {
130 rhs: ExprId, 131 rhs: ExprId,
131 op: Option<BinaryOp>, 132 op: Option<BinaryOp>,
132 }, 133 },
134 Range {
135 lhs: Option<ExprId>,
136 rhs: Option<ExprId>,
137 range_type: RangeOp,
138 },
133 Index { 139 Index {
134 base: ExprId, 140 base: ExprId,
135 index: ExprId, 141 index: ExprId,
@@ -137,6 +143,7 @@ pub enum Expr {
137 Lambda { 143 Lambda {
138 args: Vec<PatId>, 144 args: Vec<PatId>,
139 arg_types: Vec<Option<TypeRef>>, 145 arg_types: Vec<Option<TypeRef>>,
146 ret_type: Option<TypeRef>,
140 body: ExprId, 147 body: ExprId,
141 }, 148 },
142 Tuple { 149 Tuple {
@@ -288,6 +295,14 @@ impl Expr {
288 f(*lhs); 295 f(*lhs);
289 f(*rhs); 296 f(*rhs);
290 } 297 }
298 Expr::Range { lhs, rhs, .. } => {
299 if let Some(lhs) = rhs {
300 f(*lhs);
301 }
302 if let Some(rhs) = lhs {
303 f(*rhs);
304 }
305 }
291 Expr::Index { base, index } => { 306 Expr::Index { base, index } => {
292 f(*base); 307 f(*base);
293 f(*index); 308 f(*index);
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 3f94e40e4..e9c28c730 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -4,20 +4,29 @@
4//! in rustc. 4//! in rustc.
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use hir_expand::name::{self, AsName, Name}; 7use either::Either;
8use hir_expand::{
9 name::{name, AsName, Name},
10 InFile,
11};
12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId;
8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 14use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9 15
10use crate::{ 16use crate::{
17 child_by_source::ChildBySource,
11 db::DefDatabase, 18 db::DefDatabase,
19 dyn_map::DynMap,
20 keys,
21 src::HasChildSource,
22 src::HasSource,
12 type_ref::{TypeBound, TypeRef}, 23 type_ref::{TypeBound, TypeRef},
13 AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup, 24 AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
14}; 25};
15 26
16/// Data about a generic parameter (to a function, struct, impl, ...). 27/// Data about a generic parameter (to a function, struct, impl, ...).
17#[derive(Clone, PartialEq, Eq, Debug)] 28#[derive(Clone, PartialEq, Eq, Debug)]
18pub struct GenericParam { 29pub struct TypeParamData {
19 // FIXME: give generic params proper IDs
20 pub idx: u32,
21 pub name: Name, 30 pub name: Name,
22 pub default: Option<TypeRef>, 31 pub default: Option<TypeRef>,
23} 32}
@@ -25,8 +34,8 @@ pub struct GenericParam {
25/// Data about the generic parameters of a function, struct, impl, etc. 34/// Data about the generic parameters of a function, struct, impl, etc.
26#[derive(Clone, PartialEq, Eq, Debug)] 35#[derive(Clone, PartialEq, Eq, Debug)]
27pub struct GenericParams { 36pub struct GenericParams {
28 pub parent_params: Option<Arc<GenericParams>>, 37 pub types: Arena<LocalTypeParamId, TypeParamData>,
29 pub params: Vec<GenericParam>, 38 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
30 pub where_predicates: Vec<WherePredicate>, 39 pub where_predicates: Vec<WherePredicate>,
31} 40}
32 41
@@ -40,63 +49,87 @@ pub struct WherePredicate {
40 pub bound: TypeBound, 49 pub bound: TypeBound,
41} 50}
42 51
52type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
53
43impl GenericParams { 54impl GenericParams {
44 pub(crate) fn generic_params_query( 55 pub(crate) fn generic_params_query(
45 db: &impl DefDatabase, 56 db: &impl DefDatabase,
46 def: GenericDefId, 57 def: GenericDefId,
47 ) -> Arc<GenericParams> { 58 ) -> Arc<GenericParams> {
48 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); 59 let (params, _source_map) = GenericParams::new(db, def.into());
49 Arc::new(GenericParams::new(db, def.into(), parent_generics)) 60 Arc::new(params)
50 } 61 }
51 62
52 fn new( 63 fn new(db: &impl DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
53 db: &impl DefDatabase, 64 let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() };
54 def: GenericDefId, 65 let mut sm = ArenaMap::default();
55 parent_params: Option<Arc<GenericParams>>,
56 ) -> GenericParams {
57 let mut generics =
58 GenericParams { params: Vec::new(), parent_params, where_predicates: Vec::new() };
59 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
60 // FIXME: add `: Sized` bound for everything except for `Self` in traits 66 // FIXME: add `: Sized` bound for everything except for `Self` in traits
61 match def { 67 let file_id = match def {
62 GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start), 68 GenericDefId::FunctionId(it) => {
63 GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value, start), 69 let src = it.lookup(db).source(db);
64 GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value, start), 70 generics.fill(&mut sm, &src.value);
65 GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start), 71 src.file_id
72 }
73 GenericDefId::AdtId(AdtId::StructId(it)) => {
74 let src = it.lookup(db).source(db);
75 generics.fill(&mut sm, &src.value);
76 src.file_id
77 }
78 GenericDefId::AdtId(AdtId::UnionId(it)) => {
79 let src = it.lookup(db).source(db);
80 generics.fill(&mut sm, &src.value);
81 src.file_id
82 }
83 GenericDefId::AdtId(AdtId::EnumId(it)) => {
84 let src = it.lookup(db).source(db);
85 generics.fill(&mut sm, &src.value);
86 src.file_id
87 }
66 GenericDefId::TraitId(it) => { 88 GenericDefId::TraitId(it) => {
89 let src = it.lookup(db).source(db);
90
67 // traits get the Self type as an implicit first type parameter 91 // traits get the Self type as an implicit first type parameter
68 generics.params.push(GenericParam { 92 let self_param_id =
69 idx: start, 93 generics.types.alloc(TypeParamData { name: name![Self], default: None });
70 name: name::SELF_TYPE, 94 sm.insert(self_param_id, Either::Left(src.value.clone()));
71 default: None,
72 });
73 generics.fill(&it.source(db).value, start + 1);
74 // add super traits as bounds on Self 95 // add super traits as bounds on Self
75 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
76 let self_param = TypeRef::Path(name::SELF_TYPE.into()); 97 let self_param = TypeRef::Path(name![Self].into());
77 generics.fill_bounds(&it.source(db).value, self_param); 98 generics.fill_bounds(&src.value, self_param);
99
100 generics.fill(&mut sm, &src.value);
101 src.file_id
102 }
103 GenericDefId::TypeAliasId(it) => {
104 let src = it.lookup(db).source(db);
105 generics.fill(&mut sm, &src.value);
106 src.file_id
78 } 107 }
79 GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start),
80 // Note that we don't add `Self` here: in `impl`s, `Self` is not a 108 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
81 // type-parameter, but rather is a type-alias for impl's target 109 // type-parameter, but rather is a type-alias for impl's target
82 // type, so this is handled by the resolver. 110 // type, so this is handled by the resolver.
83 GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start), 111 GenericDefId::ImplId(it) => {
84 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {} 112 let src = it.lookup(db).source(db);
85 } 113 generics.fill(&mut sm, &src.value);
114 src.file_id
115 }
116 // We won't be using this ID anyway
117 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
118 };
86 119
87 generics 120 (generics, InFile::new(file_id, sm))
88 } 121 }
89 122
90 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { 123 fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) {
91 if let Some(params) = node.type_param_list() { 124 if let Some(params) = node.type_param_list() {
92 self.fill_params(params, start) 125 self.fill_params(sm, params)
93 } 126 }
94 if let Some(where_clause) = node.where_clause() { 127 if let Some(where_clause) = node.where_clause() {
95 self.fill_where_predicates(where_clause); 128 self.fill_where_predicates(where_clause);
96 } 129 }
97 } 130 }
98 131
99 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) { 132 fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) {
100 for bound in 133 for bound in
101 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) 134 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
102 { 135 {
@@ -104,13 +137,14 @@ impl GenericParams {
104 } 137 }
105 } 138 }
106 139
107 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { 140 fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) {
108 for (idx, type_param) in params.type_params().enumerate() { 141 for type_param in params.type_params() {
109 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 142 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
110 // FIXME: Use `Path::from_src` 143 // FIXME: Use `Path::from_src`
111 let default = type_param.default_type().map(TypeRef::from_ast); 144 let default = type_param.default_type().map(TypeRef::from_ast);
112 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; 145 let param = TypeParamData { name: name.clone(), default };
113 self.params.push(param); 146 let param_id = self.types.alloc(param);
147 sm.insert(param_id, Either::Right(type_param.clone()));
114 148
115 let type_ref = TypeRef::Path(name.into()); 149 let type_ref = TypeRef::Path(name.into());
116 self.fill_bounds(&type_param, type_ref); 150 self.fill_bounds(&type_param, type_ref);
@@ -139,45 +173,31 @@ impl GenericParams {
139 self.where_predicates.push(WherePredicate { type_ref, bound }); 173 self.where_predicates.push(WherePredicate { type_ref, bound });
140 } 174 }
141 175
142 pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 176 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
143 self.params.iter().find(|p| &p.name == name) 177 self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None })
144 }
145
146 pub fn count_parent_params(&self) -> usize {
147 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
148 }
149
150 pub fn count_params_including_parent(&self) -> usize {
151 let parent_count = self.count_parent_params();
152 parent_count + self.params.len()
153 }
154
155 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
156 if let Some(parent) = &self.parent_params {
157 parent.for_each_param(f);
158 }
159 self.params.iter().for_each(f);
160 } 178 }
179}
161 180
162 pub fn params_including_parent(&self) -> Vec<&GenericParam> { 181impl HasChildSource for GenericDefId {
163 let mut vec = Vec::with_capacity(self.count_params_including_parent()); 182 type ChildId = LocalTypeParamId;
164 self.for_each_param(&mut |p| vec.push(p)); 183 type Value = Either<ast::TraitDef, ast::TypeParam>;
165 vec 184 fn child_source(&self, db: &impl DefDatabase) -> InFile<SourceMap> {
185 let (_, sm) = GenericParams::new(db, *self);
186 sm
166 } 187 }
167} 188}
168 189
169fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> { 190impl ChildBySource for GenericDefId {
170 let container = match def { 191 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
171 GenericDefId::FunctionId(it) => it.lookup(db).container, 192 let mut res = DynMap::default();
172 GenericDefId::TypeAliasId(it) => it.lookup(db).container, 193 let arena_map = self.child_source(db);
173 GenericDefId::ConstId(it) => it.lookup(db).container, 194 let arena_map = arena_map.as_ref();
174 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), 195 for (local_id, src) in arena_map.value.iter() {
175 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, 196 let id = TypeParamId { parent: *self, local_id };
176 }; 197 if let Either::Right(type_param) = src {
177 198 res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id)
178 match container { 199 }
179 ContainerId::ImplId(it) => Some(it.into()), 200 }
180 ContainerId::TraitId(it) => Some(it.into()), 201 res
181 ContainerId::ModuleId(_) => None,
182 } 202 }
183} 203}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
new file mode 100644
index 000000000..b0288ee8d
--- /dev/null
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -0,0 +1,172 @@
1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks.
3
4use hir_expand::name::Name;
5use once_cell::sync::Lazy;
6use rustc_hash::FxHashMap;
7
8use crate::{per_ns::PerNs, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId};
9
10#[derive(Debug, Default, PartialEq, Eq)]
11pub struct ItemScope {
12 visible: FxHashMap<Name, PerNs>,
13 defs: Vec<ModuleDefId>,
14 impls: Vec<ImplId>,
15 /// Macros visible in current module in legacy textual scope
16 ///
17 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
18 /// If it yields no result, then it turns to module scoped `macros`.
19 /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
20 /// and only normal scoped `macros` will be searched in.
21 ///
22 /// Note that this automatically inherit macros defined textually before the definition of module itself.
23 ///
24 /// Module scoped macros will be inserted into `items` instead of here.
25 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
26 // be all resolved to the last one defined if shadowing happens.
27 legacy_macros: FxHashMap<Name, MacroDefId>,
28}
29
30static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
31 BuiltinType::ALL
32 .iter()
33 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into())))
34 .collect()
35});
36
37/// Shadow mode for builtin type which can be shadowed by module.
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
39pub(crate) enum BuiltinShadowMode {
40 // Prefer Module
41 Module,
42 // Prefer Other Types
43 Other,
44}
45
46/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
47/// Other methods will only resolve values, types and module scoped macros only.
48impl ItemScope {
49 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
50 //FIXME: shadowing
51 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def))
52 }
53
54 pub fn entries_without_primitives<'a>(
55 &'a self,
56 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
57 self.visible.iter().map(|(n, def)| (n, *def))
58 }
59
60 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
61 self.defs.iter().copied()
62 }
63
64 pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
65 self.impls.iter().copied()
66 }
67
68 /// Iterate over all module scoped macros
69 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
70 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
71 }
72
73 /// Iterate over all legacy textual scoped macros visible at the end of the module
74 pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
75 self.legacy_macros.iter().map(|(name, def)| (name, *def))
76 }
77
78 /// Get a name from current module scope, legacy macros are not included
79 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs {
80 match shadow {
81 BuiltinShadowMode::Module => self
82 .visible
83 .get(name)
84 .or_else(|| BUILTIN_SCOPE.get(name))
85 .copied()
86 .unwrap_or_else(PerNs::none),
87 BuiltinShadowMode::Other => {
88 let item = self.visible.get(name).copied();
89 if let Some(def) = item {
90 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
91 return BUILTIN_SCOPE
92 .get(name)
93 .copied()
94 .or(item)
95 .unwrap_or_else(PerNs::none);
96 }
97 }
98
99 item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
100 }
101 }
102 }
103
104 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
105 self.visible.values().filter_map(|def| match def.take_types() {
106 Some(ModuleDefId::TraitId(t)) => Some(t),
107 _ => None,
108 })
109 }
110
111 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
112 self.defs.push(def)
113 }
114
115 pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
116 self.legacy_macros.get(name).copied()
117 }
118
119 pub(crate) fn define_impl(&mut self, imp: ImplId) {
120 self.impls.push(imp)
121 }
122
123 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
124 self.legacy_macros.insert(name, mac);
125 }
126
127 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
128 let mut changed = false;
129 let existing = self.visible.entry(name.clone()).or_default();
130
131 if existing.types.is_none() && def.types.is_some() {
132 existing.types = def.types;
133 changed = true;
134 }
135 if existing.values.is_none() && def.values.is_some() {
136 existing.values = def.values;
137 changed = true;
138 }
139 if existing.macros.is_none() && def.macros.is_some() {
140 existing.macros = def.macros;
141 changed = true;
142 }
143
144 changed
145 }
146
147 pub(crate) fn collect_resolutions(&self) -> Vec<(Name, PerNs)> {
148 self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect()
149 }
150
151 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
152 self.legacy_macros.clone()
153 }
154}
155
156impl From<ModuleDefId> for PerNs {
157 fn from(def: ModuleDefId) -> PerNs {
158 match def {
159 ModuleDefId::ModuleId(_) => PerNs::types(def),
160 ModuleDefId::FunctionId(_) => PerNs::values(def),
161 ModuleDefId::AdtId(adt) => match adt {
162 AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def),
163 AdtId::EnumId(_) => PerNs::types(def),
164 },
165 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def),
166 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def),
167 ModuleDefId::TraitId(_) => PerNs::types(def),
168 ModuleDefId::TypeAliasId(_) => PerNs::types(def),
169 ModuleDefId::BuiltinType(_) => PerNs::types(def),
170 }
171 }
172}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
new file mode 100644
index 000000000..d844f7a62
--- /dev/null
+++ b/crates/ra_hir_def/src/keys.rs
@@ -0,0 +1,56 @@
1//! keys to be used with `DynMap`
2
3use std::marker::PhantomData;
4
5use hir_expand::InFile;
6use ra_syntax::{ast, AstNode, AstPtr};
7use rustc_hash::FxHashMap;
8
9use crate::{
10 dyn_map::{DynMap, Policy},
11 ConstId, EnumId, EnumVariantId, FunctionId, ImplId, StaticId, StructFieldId, StructId, TraitId,
12 TypeAliasId, TypeParamId, UnionId,
13};
14
15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
16
17pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new();
18pub const CONST: Key<ast::ConstDef, ConstId> = Key::new();
19pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new();
20pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
21pub const IMPL: Key<ast::ImplBlock, ImplId> = Key::new();
22pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new();
23pub const STRUCT: Key<ast::StructDef, StructId> = Key::new();
24pub const UNION: Key<ast::UnionDef, UnionId> = Key::new();
25pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new();
26
27pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new();
28pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new();
29pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new();
30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
31
32/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
33/// equal if they point to exactly the same object.
34///
35/// In general, we do not guarantee that we have exactly one instance of a
36/// syntax tree for each file. We probably should add such guarantee, but, for
37/// the time being, we will use identity-less AstPtr comparison.
38pub struct AstPtrPolicy<AST, ID> {
39 _phantom: PhantomData<(AST, ID)>,
40}
41
42impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> {
43 type K = InFile<AST>;
44 type V = ID;
45 fn insert(map: &mut DynMap, key: InFile<AST>, value: ID) {
46 let key = key.as_ref().map(AstPtr::new);
47 map.map
48 .entry::<FxHashMap<InFile<AstPtr<AST>>, ID>>()
49 .or_insert_with(Default::default)
50 .insert(key, value);
51 }
52 fn get<'a>(map: &'a DynMap, key: &InFile<AST>) -> Option<&'a ID> {
53 let key = key.as_ref().map(AstPtr::new);
54 map.map.get::<FxHashMap<InFile<AstPtr<AST>>, ID>>()?.get(&key)
55 }
56}
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index f4fdbdcfc..cef061837 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -81,7 +81,7 @@ impl LangItems {
81 // Look for impl targets 81 // Look for impl targets
82 let def_map = db.crate_def_map(module.krate); 82 let def_map = db.crate_def_map(module.krate);
83 let module_data = &def_map[module.local_id]; 83 let module_data = &def_map[module.local_id];
84 for &impl_block in module_data.impls.iter() { 84 for impl_block in module_data.scope.impls() {
85 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId) 85 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId)
86 } 86 }
87 87
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index bc5530896..f6c7f38d1 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -15,6 +15,10 @@ pub mod type_ref;
15pub mod builtin_type; 15pub mod builtin_type;
16pub mod diagnostics; 16pub mod diagnostics;
17pub mod per_ns; 17pub mod per_ns;
18pub mod item_scope;
19
20pub mod dyn_map;
21pub mod keys;
18 22
19pub mod adt; 23pub mod adt;
20pub mod data; 24pub mod data;
@@ -29,23 +33,23 @@ pub mod resolver;
29mod trace; 33mod trace;
30pub mod nameres; 34pub mod nameres;
31 35
36pub mod src;
37pub mod child_by_source;
38
32#[cfg(test)] 39#[cfg(test)]
33mod test_db; 40mod test_db;
34#[cfg(test)] 41#[cfg(test)]
35mod marks; 42mod marks;
36 43
37use std::hash::{Hash, Hasher}; 44use std::hash::Hash;
38 45
39use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, MacroDefId, Source}; 46use hir_expand::{ast_id_map::FileAstId, AstId, HirFileId, InFile, MacroDefId};
40use ra_arena::{impl_arena_id, map::ArenaMap, RawId}; 47use ra_arena::{impl_arena_id, RawId};
41use ra_db::{impl_intern_key, salsa, CrateId}; 48use ra_db::{impl_intern_key, salsa, CrateId};
42use ra_syntax::{ast, AstNode}; 49use ra_syntax::{ast, AstNode};
43 50
44use crate::{builtin_type::BuiltinType, db::InternDatabase}; 51use crate::body::Expander;
45 52use crate::builtin_type::BuiltinType;
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct LocalImportId(RawId);
48impl_arena_id!(LocalImportId);
49 53
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub struct ModuleId { 55pub struct ModuleId {
@@ -59,122 +63,57 @@ pub struct ModuleId {
59pub struct LocalModuleId(RawId); 63pub struct LocalModuleId(RawId);
60impl_arena_id!(LocalModuleId); 64impl_arena_id!(LocalModuleId);
61 65
62#[derive(Debug)] 66#[derive(Debug, Clone, PartialEq, Eq, Hash)]
63pub struct ItemLoc<N: AstNode> { 67pub struct ItemLoc<N: AstNode> {
64 pub(crate) module: ModuleId, 68 pub container: ContainerId,
65 ast_id: AstId<N>, 69 pub ast_id: AstId<N>,
66}
67
68impl<N: AstNode> PartialEq for ItemLoc<N> {
69 fn eq(&self, other: &Self) -> bool {
70 self.module == other.module && self.ast_id == other.ast_id
71 }
72}
73impl<N: AstNode> Eq for ItemLoc<N> {}
74impl<N: AstNode> Hash for ItemLoc<N> {
75 fn hash<H: Hasher>(&self, hasher: &mut H) {
76 self.module.hash(hasher);
77 self.ast_id.hash(hasher);
78 }
79}
80
81impl<N: AstNode> Clone for ItemLoc<N> {
82 fn clone(&self) -> ItemLoc<N> {
83 ItemLoc { module: self.module, ast_id: self.ast_id }
84 }
85} 70}
86 71
87#[derive(Clone, Copy)] 72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub struct LocationCtx<DB> { 73pub struct AssocItemLoc<N: AstNode> {
89 db: DB, 74 pub container: AssocContainerId,
90 module: ModuleId, 75 pub ast_id: AstId<N>,
91 file_id: HirFileId,
92} 76}
93 77
94impl<'a, DB> LocationCtx<&'a DB> { 78macro_rules! impl_intern {
95 pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { 79 ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
96 LocationCtx { db, module, file_id } 80 impl_intern_key!($id);
97 }
98}
99 81
100pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { 82 impl Intern for $loc {
101 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self; 83 type ID = $id;
102 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>; 84 fn intern(self, db: &impl db::DefDatabase) -> $id {
85 db.$intern(self)
86 }
87 }
103 88
104 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self { 89 impl Lookup for $id {
105 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; 90 type Data = $loc;
106 Self::intern(ctx.db, loc) 91 fn lookup(&self, db: &impl db::DefDatabase) -> $loc {
107 } 92 db.$lookup(*self)
108 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> { 93 }
109 let loc = self.lookup_intern(db); 94 }
110 let value = loc.ast_id.to_node(db); 95 };
111 Source { file_id: loc.ast_id.file_id(), value }
112 }
113 fn module(self, db: &impl InternDatabase) -> ModuleId {
114 let loc = self.lookup_intern(db);
115 loc.module
116 }
117} 96}
118 97
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct FunctionId(salsa::InternId); 99pub struct FunctionId(salsa::InternId);
121impl_intern_key!(FunctionId); 100type FunctionLoc = AssocItemLoc<ast::FnDef>;
122 101impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
124pub struct FunctionLoc {
125 pub container: ContainerId,
126 pub ast_id: AstId<ast::FnDef>,
127}
128
129impl Intern for FunctionLoc {
130 type ID = FunctionId;
131 fn intern(self, db: &impl db::DefDatabase) -> FunctionId {
132 db.intern_function(self)
133 }
134}
135
136impl Lookup for FunctionId {
137 type Data = FunctionLoc;
138 fn lookup(&self, db: &impl db::DefDatabase) -> FunctionLoc {
139 db.lookup_intern_function(*self)
140 }
141}
142 102
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144pub struct StructId(salsa::InternId); 104pub struct StructId(salsa::InternId);
145impl_intern_key!(StructId); 105type StructLoc = ItemLoc<ast::StructDef>;
146impl AstItemDef<ast::StructDef> for StructId { 106impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
147 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
148 db.intern_struct(loc)
149 }
150 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
151 db.lookup_intern_struct(self)
152 }
153}
154 107
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156pub struct UnionId(salsa::InternId); 109pub struct UnionId(salsa::InternId);
157impl_intern_key!(UnionId); 110pub type UnionLoc = ItemLoc<ast::UnionDef>;
158impl AstItemDef<ast::UnionDef> for UnionId { 111impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
159 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::UnionDef>) -> Self {
160 db.intern_union(loc)
161 }
162 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::UnionDef> {
163 db.lookup_intern_union(self)
164 }
165}
166 112
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub struct EnumId(salsa::InternId); 114pub struct EnumId(salsa::InternId);
169impl_intern_key!(EnumId); 115pub type EnumLoc = ItemLoc<ast::EnumDef>;
170impl AstItemDef<ast::EnumDef> for EnumId { 116impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
171 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
172 db.intern_enum(loc)
173 }
174 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
175 db.lookup_intern_enum(self)
176 }
177}
178 117
179// FIXME: rename to `VariantId`, only enums can ave variants 118// FIXME: rename to `VariantId`, only enums can ave variants
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -199,98 +138,38 @@ impl_arena_id!(LocalStructFieldId);
199 138
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
201pub struct ConstId(salsa::InternId); 140pub struct ConstId(salsa::InternId);
202impl_intern_key!(ConstId); 141type ConstLoc = AssocItemLoc<ast::ConstDef>;
203#[derive(Debug, Clone, PartialEq, Eq, Hash)] 142impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
204pub struct ConstLoc {
205 pub container: ContainerId,
206 pub ast_id: AstId<ast::ConstDef>,
207}
208
209impl Intern for ConstLoc {
210 type ID = ConstId;
211 fn intern(self, db: &impl db::DefDatabase) -> ConstId {
212 db.intern_const(self)
213 }
214}
215
216impl Lookup for ConstId {
217 type Data = ConstLoc;
218 fn lookup(&self, db: &impl db::DefDatabase) -> ConstLoc {
219 db.lookup_intern_const(*self)
220 }
221}
222 143
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
224pub struct StaticId(salsa::InternId); 145pub struct StaticId(salsa::InternId);
225impl_intern_key!(StaticId); 146pub type StaticLoc = ItemLoc<ast::StaticDef>;
226 147impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct StaticLoc {
229 pub container: ModuleId,
230 pub ast_id: AstId<ast::StaticDef>,
231}
232
233impl Intern for StaticLoc {
234 type ID = StaticId;
235 fn intern(self, db: &impl db::DefDatabase) -> StaticId {
236 db.intern_static(self)
237 }
238}
239
240impl Lookup for StaticId {
241 type Data = StaticLoc;
242 fn lookup(&self, db: &impl db::DefDatabase) -> StaticLoc {
243 db.lookup_intern_static(*self)
244 }
245}
246 148
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
248pub struct TraitId(salsa::InternId); 150pub struct TraitId(salsa::InternId);
249impl_intern_key!(TraitId); 151pub type TraitLoc = ItemLoc<ast::TraitDef>;
250impl AstItemDef<ast::TraitDef> for TraitId { 152impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
251 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
252 db.intern_trait(loc)
253 }
254 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
255 db.lookup_intern_trait(self)
256 }
257}
258 153
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
260pub struct TypeAliasId(salsa::InternId); 155pub struct TypeAliasId(salsa::InternId);
261impl_intern_key!(TypeAliasId); 156type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>;
262 157impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
263#[derive(Debug, Clone, PartialEq, Eq, Hash)]
264pub struct TypeAliasLoc {
265 pub container: ContainerId,
266 pub ast_id: AstId<ast::TypeAliasDef>,
267}
268 158
269impl Intern for TypeAliasLoc { 159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
270 type ID = TypeAliasId; 160pub struct ImplId(salsa::InternId);
271 fn intern(self, db: &impl db::DefDatabase) -> TypeAliasId { 161type ImplLoc = ItemLoc<ast::ImplBlock>;
272 db.intern_type_alias(self) 162impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
273 }
274}
275 163
276impl Lookup for TypeAliasId { 164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277 type Data = TypeAliasLoc; 165pub struct TypeParamId {
278 fn lookup(&self, db: &impl db::DefDatabase) -> TypeAliasLoc { 166 pub parent: GenericDefId,
279 db.lookup_intern_type_alias(*self) 167 pub local_id: LocalTypeParamId,
280 }
281} 168}
282 169
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
284pub struct ImplId(salsa::InternId); 171pub struct LocalTypeParamId(RawId);
285impl_intern_key!(ImplId); 172impl_arena_id!(LocalTypeParamId);
286impl AstItemDef<ast::ImplBlock> for ImplId {
287 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self {
288 db.intern_impl(loc)
289 }
290 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> {
291 db.lookup_intern_impl(self)
292 }
293}
294 173
295macro_rules! impl_froms { 174macro_rules! impl_froms {
296 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { 175 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
@@ -314,9 +193,16 @@ macro_rules! impl_froms {
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
315pub enum ContainerId { 194pub enum ContainerId {
316 ModuleId(ModuleId), 195 ModuleId(ModuleId),
196 DefWithBodyId(DefWithBodyId),
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
200pub enum AssocContainerId {
201 ContainerId(ContainerId),
317 ImplId(ImplId), 202 ImplId(ImplId),
318 TraitId(TraitId), 203 TraitId(TraitId),
319} 204}
205impl_froms!(AssocContainerId: ContainerId);
320 206
321/// A Data Type 207/// A Data Type
322#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 208#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -459,43 +345,39 @@ pub trait HasModule {
459 fn module(&self, db: &impl db::DefDatabase) -> ModuleId; 345 fn module(&self, db: &impl db::DefDatabase) -> ModuleId;
460} 346}
461 347
462impl HasModule for FunctionLoc { 348impl HasModule for ContainerId {
463 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 349 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
464 match self.container { 350 match *self {
465 ContainerId::ModuleId(it) => it, 351 ContainerId::ModuleId(it) => it,
466 ContainerId::ImplId(it) => it.module(db), 352 ContainerId::DefWithBodyId(it) => it.module(db),
467 ContainerId::TraitId(it) => it.module(db),
468 } 353 }
469 } 354 }
470} 355}
471 356
472impl HasModule for TypeAliasLoc { 357impl HasModule for AssocContainerId {
473 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 358 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
474 match self.container { 359 match *self {
475 ContainerId::ModuleId(it) => it, 360 AssocContainerId::ContainerId(it) => it.module(db),
476 ContainerId::ImplId(it) => it.module(db), 361 AssocContainerId::ImplId(it) => it.lookup(db).container.module(db),
477 ContainerId::TraitId(it) => it.module(db), 362 AssocContainerId::TraitId(it) => it.lookup(db).container.module(db),
478 } 363 }
479 } 364 }
480} 365}
481 366
482impl HasModule for ConstLoc { 367impl<N: AstNode> HasModule for AssocItemLoc<N> {
483 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 368 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
484 match self.container { 369 self.container.module(db)
485 ContainerId::ModuleId(it) => it,
486 ContainerId::ImplId(it) => it.module(db),
487 ContainerId::TraitId(it) => it.module(db),
488 }
489 } 370 }
490} 371}
491 372
492impl HasModule for AdtId { 373impl HasModule for AdtId {
493 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 374 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
494 match self { 375 match self {
495 AdtId::StructId(it) => it.module(db), 376 AdtId::StructId(it) => it.lookup(db).container,
496 AdtId::UnionId(it) => it.module(db), 377 AdtId::UnionId(it) => it.lookup(db).container,
497 AdtId::EnumId(it) => it.module(db), 378 AdtId::EnumId(it) => it.lookup(db).container,
498 } 379 }
380 .module(db)
499 } 381 }
500} 382}
501 383
@@ -509,58 +391,22 @@ impl HasModule for DefWithBodyId {
509 } 391 }
510} 392}
511 393
512impl HasModule for StaticLoc { 394impl HasModule for GenericDefId {
513 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { 395 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
514 self.container 396 match self {
515 } 397 GenericDefId::FunctionId(it) => it.lookup(db).module(db),
516} 398 GenericDefId::AdtId(it) => it.module(db),
517 399 GenericDefId::TraitId(it) => it.lookup(db).container.module(db),
518pub trait HasSource { 400 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
519 type Value; 401 GenericDefId::ImplId(it) => it.lookup(db).container.module(db),
520 fn source(&self, db: &impl db::DefDatabase) -> Source<Self::Value>; 402 GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db),
521} 403 GenericDefId::ConstId(it) => it.lookup(db).module(db),
522 404 }
523impl HasSource for FunctionLoc {
524 type Value = ast::FnDef;
525
526 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::FnDef> {
527 let node = self.ast_id.to_node(db);
528 Source::new(self.ast_id.file_id(), node)
529 }
530}
531
532impl HasSource for TypeAliasLoc {
533 type Value = ast::TypeAliasDef;
534
535 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::TypeAliasDef> {
536 let node = self.ast_id.to_node(db);
537 Source::new(self.ast_id.file_id(), node)
538 }
539}
540
541impl HasSource for ConstLoc {
542 type Value = ast::ConstDef;
543
544 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::ConstDef> {
545 let node = self.ast_id.to_node(db);
546 Source::new(self.ast_id.file_id(), node)
547 } 405 }
548} 406}
549 407
550impl HasSource for StaticLoc { 408impl HasModule for StaticLoc {
551 type Value = ast::StaticDef; 409 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
552 410 self.container.module(db)
553 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::StaticDef> {
554 let node = self.ast_id.to_node(db);
555 Source::new(self.ast_id.file_id(), node)
556 } 411 }
557} 412}
558
559pub trait HasChildSource {
560 type ChildId;
561 type Value;
562 fn child_source(
563 &self,
564 db: &impl db::DefDatabase,
565 ) -> Source<ArenaMap<Self::ChildId, Self::Value>>;
566}
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs
index 65239ca0a..457ba4abe 100644
--- a/crates/ra_hir_def/src/marks.rs
+++ b/crates/ra_hir_def/src/marks.rs
@@ -5,6 +5,7 @@ test_utils::marks!(
5 name_res_works_for_broken_modules 5 name_res_works_for_broken_modules
6 can_import_enum_variant 6 can_import_enum_variant
7 glob_enum 7 glob_enum
8 glob_enum_group
8 glob_across_crates 9 glob_across_crates
9 std_prelude 10 std_prelude
10 macro_rules_from_other_crates_are_visible_with_macro_use 11 macro_rules_from_other_crates_are_visible_with_macro_use
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 2359386c2..5d4ca73a3 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -57,24 +57,23 @@ mod tests;
57 57
58use std::sync::Arc; 58use std::sync::Arc;
59 59
60use hir_expand::{ 60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
61 ast_id_map::FileAstId, diagnostics::DiagnosticSink, either::Either, name::Name, MacroDefId,
62 Source,
63};
64use once_cell::sync::Lazy;
65use ra_arena::Arena; 61use ra_arena::Arena;
66use ra_db::{CrateId, Edition, FileId}; 62use ra_db::{CrateId, Edition, FileId, FilePosition};
67use ra_prof::profile; 63use ra_prof::profile;
68use ra_syntax::ast; 64use ra_syntax::{
65 ast::{self, AstNode},
66 SyntaxNode,
67};
69use rustc_hash::FxHashMap; 68use rustc_hash::FxHashMap;
70 69
71use crate::{ 70use crate::{
72 builtin_type::BuiltinType,
73 db::DefDatabase, 71 db::DefDatabase,
72 item_scope::{BuiltinShadowMode, ItemScope},
74 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 73 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
75 path::Path, 74 path::ModPath,
76 per_ns::PerNs, 75 per_ns::PerNs,
77 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId, 76 AstId, LocalModuleId, ModuleDefId, ModuleId,
78}; 77};
79 78
80/// Contains all top-level defs from a macro-expanded crate 79/// Contains all top-level defs from a macro-expanded crate
@@ -100,106 +99,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap {
100 } 99 }
101} 100}
102 101
103#[derive(Default, Debug, PartialEq, Eq)] 102#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
104pub struct ModuleData { 103pub enum ModuleOrigin {
105 pub parent: Option<LocalModuleId>, 104 CrateRoot {
106 pub children: FxHashMap<Name, LocalModuleId>, 105 definition: FileId,
107 pub scope: ModuleScope, 106 },
108
109 // FIXME: these can't be both null, we need a three-state enum here.
110 /// None for root
111 pub declaration: Option<AstId<ast::Module>>,
112 /// None for inline modules.
113 ///
114 /// Note that non-inline modules, by definition, live inside non-macro file. 107 /// Note that non-inline modules, by definition, live inside non-macro file.
115 pub definition: Option<FileId>, 108 File {
116 109 declaration: AstId<ast::Module>,
117 pub impls: Vec<ImplId>, 110 definition: FileId,
118} 111 },
119 112 Inline {
120#[derive(Default, Debug, PartialEq, Eq)] 113 definition: AstId<ast::Module>,
121pub(crate) struct Declarations { 114 },
122 fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>,
123} 115}
124 116
125#[derive(Debug, Default, PartialEq, Eq)] 117impl Default for ModuleOrigin {
126pub struct ModuleScope { 118 fn default() -> Self {
127 items: FxHashMap<Name, Resolution>, 119 ModuleOrigin::CrateRoot { definition: FileId(0) }
128 /// Macros visable in current module in legacy textual scope
129 ///
130 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
131 /// If it yields no result, then it turns to module scoped `macros`.
132 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
133 /// and only normal scoped `macros` will be searched in.
134 ///
135 /// Note that this automatically inherit macros defined textually before the definition of module itself.
136 ///
137 /// Module scoped macros will be inserted into `items` instead of here.
138 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
139 // be all resolved to the last one defined if shadowing happens.
140 legacy_macros: FxHashMap<Name, MacroDefId>,
141}
142
143static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
144 BuiltinType::ALL
145 .iter()
146 .map(|(name, ty)| {
147 (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
148 })
149 .collect()
150});
151
152/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
153/// Other methods will only resolve values, types and module scoped macros only.
154impl ModuleScope {
155 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
156 //FIXME: shadowing
157 self.items.iter().chain(BUILTIN_SCOPE.iter())
158 }
159
160 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
161 self.entries()
162 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
163 .flat_map(|per_ns| {
164 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
165 })
166 }
167
168 /// Iterate over all module scoped macros
169 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
170 self.items
171 .iter()
172 .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
173 } 120 }
121}
174 122
175 /// Iterate over all legacy textual scoped macros visable at the end of the module 123impl ModuleOrigin {
176 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 124 pub(crate) fn not_sure_file(file: Option<FileId>, declaration: AstId<ast::Module>) -> Self {
177 self.legacy_macros.iter().map(|(name, def)| (name, *def)) 125 match file {
126 None => ModuleOrigin::Inline { definition: declaration },
127 Some(definition) => ModuleOrigin::File { declaration, definition },
128 }
178 } 129 }
179 130
180 /// Get a name from current module scope, legacy macros are not included 131 fn declaration(&self) -> Option<AstId<ast::Module>> {
181 pub fn get(&self, name: &Name) -> Option<&Resolution> { 132 match self {
182 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) 133 ModuleOrigin::File { declaration: module, .. }
134 | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
135 ModuleOrigin::CrateRoot { .. } => None,
136 }
183 } 137 }
184 138
185 pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 139 pub fn file_id(&self) -> Option<FileId> {
186 self.items.values().filter_map(|r| match r.def.take_types() { 140 match self {
187 Some(ModuleDefId::TraitId(t)) => Some(t), 141 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
142 Some(*definition)
143 }
188 _ => None, 144 _ => None,
189 }) 145 }
190 } 146 }
191 147
192 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { 148 /// Returns a node which defines this module.
193 self.legacy_macros.get(name).copied() 149 /// That is, a file or a `mod foo {}` with items.
150 fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
151 match self {
152 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
153 let file_id = *definition;
154 let sf = db.parse(file_id).tree();
155 return InFile::new(file_id.into(), ModuleSource::SourceFile(sf));
156 }
157 ModuleOrigin::Inline { definition } => {
158 InFile::new(definition.file_id, ModuleSource::Module(definition.to_node(db)))
159 }
160 }
194 } 161 }
195} 162}
196 163
197#[derive(Debug, Clone, PartialEq, Eq, Default)] 164#[derive(Default, Debug, PartialEq, Eq)]
198pub struct Resolution { 165pub struct ModuleData {
199 /// None for unresolved 166 pub parent: Option<LocalModuleId>,
200 pub def: PerNs, 167 pub children: FxHashMap<Name, LocalModuleId>,
201 /// ident by which this is imported into local scope. 168 pub scope: ItemScope,
202 pub import: Option<LocalImportId>, 169
170 /// Where does this module come from?
171 pub origin: ModuleOrigin,
203} 172}
204 173
205impl CrateDefMap { 174impl CrateDefMap {
@@ -241,7 +210,7 @@ impl CrateDefMap {
241 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { 210 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
242 self.modules 211 self.modules
243 .iter() 212 .iter()
244 .filter(move |(_id, data)| data.definition == Some(file_id)) 213 .filter(move |(_id, data)| data.origin.file_id() == Some(file_id))
245 .map(|(id, _data)| id) 214 .map(|(id, _data)| id)
246 } 215 }
247 216
@@ -249,33 +218,62 @@ impl CrateDefMap {
249 &self, 218 &self,
250 db: &impl DefDatabase, 219 db: &impl DefDatabase,
251 original_module: LocalModuleId, 220 original_module: LocalModuleId,
252 path: &Path, 221 path: &ModPath,
222 shadow: BuiltinShadowMode,
253 ) -> (PerNs, Option<usize>) { 223 ) -> (PerNs, Option<usize>) {
254 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 224 let res =
225 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
255 (res.resolved_def, res.segment_index) 226 (res.resolved_def, res.segment_index)
256 } 227 }
257} 228}
258 229
259impl ModuleData { 230impl ModuleData {
260 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 231 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
261 pub fn definition_source( 232 pub fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
262 &self, 233 self.origin.definition_source(db)
263 db: &impl DefDatabase,
264 ) -> Source<Either<ast::SourceFile, ast::Module>> {
265 if let Some(file_id) = self.definition {
266 let sf = db.parse(file_id).tree();
267 return Source::new(file_id.into(), Either::A(sf));
268 }
269 let decl = self.declaration.unwrap();
270 Source::new(decl.file_id(), Either::B(decl.to_node(db)))
271 } 234 }
272 235
273 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 236 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
274 /// `None` for the crate root. 237 /// `None` for the crate root or block.
275 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<Source<ast::Module>> { 238 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> {
276 let decl = self.declaration?; 239 let decl = self.origin.declaration()?;
277 let value = decl.to_node(db); 240 let value = decl.to_node(db);
278 Some(Source { file_id: decl.file_id(), value }) 241 Some(InFile { file_id: decl.file_id, value })
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
246pub enum ModuleSource {
247 SourceFile(ast::SourceFile),
248 Module(ast::Module),
249}
250
251impl ModuleSource {
252 // FIXME: this methods do not belong here
253 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource {
254 let parse = db.parse(position.file_id);
255 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
256 parse.tree().syntax(),
257 position.offset,
258 ) {
259 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
260 _ => {
261 let source_file = parse.tree();
262 ModuleSource::SourceFile(source_file)
263 }
264 }
265 }
266
267 pub fn from_child_node(db: &impl DefDatabase, child: InFile<&SyntaxNode>) -> ModuleSource {
268 if let Some(m) =
269 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
270 {
271 ModuleSource::Module(m)
272 } else {
273 let file_id = child.file_id.original_file(db);
274 let source_file = db.parse(file_id).tree();
275 ModuleSource::SourceFile(source_file)
276 }
279 } 277 }
280} 278}
281 279
@@ -309,7 +307,7 @@ mod diagnostics {
309 } 307 }
310 let decl = declaration.to_node(db); 308 let decl = declaration.to_node(db);
311 sink.push(UnresolvedModule { 309 sink.push(UnresolvedModule {
312 file: declaration.file_id(), 310 file: declaration.file_id,
313 decl: AstPtr::new(&decl), 311 decl: AstPtr::new(&decl),
314 candidate: candidate.clone(), 312 candidate: candidate.clone(),
315 }) 313 })
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index fd8245113..b9f40d3dd 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -4,14 +4,15 @@
4//! resolves imports and expands macros. 4//! resolves imports and expands macros.
5 5
6use hir_expand::{ 6use hir_expand::{
7 builtin_derive::find_builtin_derive,
7 builtin_macro::find_builtin_macro, 8 builtin_macro::find_builtin_macro,
8 name::{self, AsName, Name}, 9 name::{name, AsName, Name},
9 HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
10}; 11};
11use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
12use ra_db::{CrateId, FileId}; 13use ra_db::{CrateId, FileId};
13use ra_syntax::ast; 14use ra_syntax::ast;
14use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
15use test_utils::tested_by; 16use test_utils::tested_by;
16 17
17use crate::{ 18use crate::{
@@ -19,13 +20,12 @@ use crate::{
19 db::DefDatabase, 20 db::DefDatabase,
20 nameres::{ 21 nameres::{
21 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
22 raw, CrateDefMap, ModuleData, Resolution, ResolveMode, 23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
23 }, 24 },
24 path::{Path, PathKind}, 25 path::{ModPath, PathKind},
25 per_ns::PerNs, 26 per_ns::PerNs,
26 AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId, 27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
27 Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId, 28 LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
28 TraitId, TypeAliasLoc, UnionId,
29}; 29};
30 30
31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -57,68 +57,63 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
57 def_map, 57 def_map,
58 glob_imports: FxHashMap::default(), 58 glob_imports: FxHashMap::default(),
59 unresolved_imports: Vec::new(), 59 unresolved_imports: Vec::new(),
60 resolved_imports: Vec::new(),
61
60 unexpanded_macros: Vec::new(), 62 unexpanded_macros: Vec::new(),
63 unexpanded_attribute_macros: Vec::new(),
61 mod_dirs: FxHashMap::default(), 64 mod_dirs: FxHashMap::default(),
62 macro_stack_monitor: MacroStackMonitor::default(),
63 poison_macros: FxHashSet::default(),
64 cfg_options, 65 cfg_options,
65 }; 66 };
66 collector.collect(); 67 collector.collect();
67 collector.finish() 68 collector.finish()
68} 69}
69 70
70#[derive(Default)] 71#[derive(Copy, Clone, Debug, Eq, PartialEq)]
71struct MacroStackMonitor { 72enum PartialResolvedImport {
72 counts: FxHashMap<MacroDefId, u32>, 73 /// None of any namespaces is resolved
73 74 Unresolved,
74 /// Mainly use for test 75 /// One of namespaces is resolved
75 validator: Option<Box<dyn Fn(u32) -> bool>>, 76 Indeterminate(PerNs),
77 /// All namespaces are resolved, OR it is came from other crate
78 Resolved(PerNs),
76} 79}
77 80
78impl MacroStackMonitor { 81impl PartialResolvedImport {
79 fn increase(&mut self, macro_def_id: MacroDefId) { 82 fn namespaces(&self) -> PerNs {
80 *self.counts.entry(macro_def_id).or_default() += 1; 83 match self {
81 } 84 PartialResolvedImport::Unresolved => PerNs::none(),
82 85 PartialResolvedImport::Indeterminate(ns) => *ns,
83 fn decrease(&mut self, macro_def_id: MacroDefId) { 86 PartialResolvedImport::Resolved(ns) => *ns,
84 *self.counts.entry(macro_def_id).or_default() -= 1; 87 }
85 } 88 }
89}
86 90
87 fn is_poison(&self, macro_def_id: MacroDefId) -> bool { 91#[derive(Clone, Debug, Eq, PartialEq)]
88 let cur = *self.counts.get(&macro_def_id).unwrap_or(&0); 92struct ImportDirective {
93 module_id: LocalModuleId,
94 import_id: raw::Import,
95 import: raw::ImportData,
96 status: PartialResolvedImport,
97}
89 98
90 if let Some(validator) = &self.validator { 99#[derive(Clone, Debug, Eq, PartialEq)]
91 validator(cur) 100struct MacroDirective {
92 } else { 101 module_id: LocalModuleId,
93 cur > 100 102 ast_id: AstId<ast::MacroCall>,
94 } 103 path: ModPath,
95 } 104 legacy: Option<MacroCallId>,
96} 105}
97 106
98/// Walks the tree of module recursively 107/// Walks the tree of module recursively
99struct DefCollector<'a, DB> { 108struct DefCollector<'a, DB> {
100 db: &'a DB, 109 db: &'a DB,
101 def_map: CrateDefMap, 110 def_map: CrateDefMap,
102 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, 111 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>,
103 unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, 112 unresolved_imports: Vec<ImportDirective>,
104 unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, 113 resolved_imports: Vec<ImportDirective>,
114 unexpanded_macros: Vec<MacroDirective>,
115 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
105 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 116 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
106
107 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
108 /// To prevent stack overflow, we add a deep counter here for prevent that.
109 macro_stack_monitor: MacroStackMonitor,
110 /// Some macros are not well-behavior, which leads to infinite loop
111 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
112 /// We mark it down and skip it in collector
113 ///
114 /// FIXME:
115 /// Right now it only handle a poison macro in a single crate,
116 /// such that if other crate try to call that macro,
117 /// the whole process will do again until it became poisoned in that crate.
118 /// We should handle this macro set globally
119 /// However, do we want to put it as a global variable?
120 poison_macros: FxHashSet<MacroDefId>,
121
122 cfg_options: &'a CfgOptions, 117 cfg_options: &'a CfgOptions,
123} 118}
124 119
@@ -131,7 +126,7 @@ where
131 let file_id = crate_graph.crate_root(self.def_map.krate); 126 let file_id = crate_graph.crate_root(self.def_map.krate);
132 let raw_items = self.db.raw_items(file_id.into()); 127 let raw_items = self.db.raw_items(file_id.into());
133 let module_id = self.def_map.root; 128 let module_id = self.def_map.root;
134 self.def_map.modules[module_id].definition = Some(file_id); 129 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
135 ModCollector { 130 ModCollector {
136 def_collector: &mut *self, 131 def_collector: &mut *self,
137 module_id, 132 module_id,
@@ -145,9 +140,11 @@ where
145 let mut i = 0; 140 let mut i = 0;
146 loop { 141 loop {
147 self.db.check_canceled(); 142 self.db.check_canceled();
148 match (self.resolve_imports(), self.resolve_macros()) { 143 self.resolve_imports();
149 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break, 144
150 _ => i += 1, 145 match self.resolve_macros() {
146 ReachedFixedPoint::Yes => break,
147 ReachedFixedPoint::No => i += 1,
151 } 148 }
152 if i == 1000 { 149 if i == 1000 {
153 log::error!("name resolution is stuck"); 150 log::error!("name resolution is stuck");
@@ -155,10 +152,26 @@ where
155 } 152 }
156 } 153 }
157 154
155 // Resolve all indeterminate resolved imports again
156 // As some of the macros will expand newly import shadowing partial resolved imports
157 // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
158 // correctly
159 let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
160 if let PartialResolvedImport::Indeterminate(_) = directive.status {
161 let mut directive = directive.clone();
162 directive.status = PartialResolvedImport::Unresolved;
163 Some(directive)
164 } else {
165 None
166 }
167 });
168 self.unresolved_imports.extend(partial_resolved);
169 self.resolve_imports();
170
158 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 171 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
159 // show unresolved imports in completion, etc 172 // show unresolved imports in completion, etc
160 for (module_id, import, import_data) in unresolved_imports { 173 for directive in unresolved_imports {
161 self.record_resolved_import(module_id, PerNs::none(), import, &import_data) 174 self.record_resolved_import(&directive)
162 } 175 }
163 } 176 }
164 177
@@ -201,24 +214,20 @@ where
201 // In Rust, `#[macro_export]` macros are unconditionally visible at the 214 // In Rust, `#[macro_export]` macros are unconditionally visible at the
202 // crate root, even if the parent modules is **not** visible. 215 // crate root, even if the parent modules is **not** visible.
203 if export { 216 if export {
204 self.update( 217 self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]);
205 self.def_map.root,
206 None,
207 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
208 );
209 } 218 }
210 } 219 }
211 220
212 /// Define a legacy textual scoped macro in module 221 /// Define a legacy textual scoped macro in module
213 /// 222 ///
214 /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. 223 /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
215 /// It will clone all macros from parent legacy scope, whose definition is prior to 224 /// It will clone all macros from parent legacy scope, whose definition is prior to
216 /// the definition of current module. 225 /// the definition of current module.
217 /// And also, `macro_use` on a module will import all legacy macros visable inside to 226 /// And also, `macro_use` on a module will import all legacy macros visible inside to
218 /// current legacy scope, with possible shadowing. 227 /// current legacy scope, with possible shadowing.
219 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) { 228 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
220 // Always shadowing 229 // Always shadowing
221 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); 230 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
222 } 231 }
223 232
224 /// Import macros from `#[macro_use] extern crate`. 233 /// Import macros from `#[macro_use] extern crate`.
@@ -259,31 +268,43 @@ where
259 } 268 }
260 } 269 }
261 270
262 fn resolve_imports(&mut self) -> ReachedFixedPoint { 271 /// Import resolution
263 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 272 ///
264 let mut resolved = Vec::new(); 273 /// This is a fix point algorithm. We resolve imports until no forward
265 imports.retain(|(module_id, import, import_data)| { 274 /// progress in resolving imports is made
266 let (def, fp) = self.resolve_import(*module_id, import_data); 275 fn resolve_imports(&mut self) {
267 if fp == ReachedFixedPoint::Yes { 276 let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
268 resolved.push((*module_id, def, *import, import_data.clone())) 277
278 while self.unresolved_imports.len() < n_previous_unresolved {
279 n_previous_unresolved = self.unresolved_imports.len();
280 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
281 for mut directive in imports {
282 directive.status = self.resolve_import(directive.module_id, &directive.import);
283
284 match directive.status {
285 PartialResolvedImport::Indeterminate(_) => {
286 self.record_resolved_import(&directive);
287 // FIXME: For avoid performance regression,
288 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
289 self.resolved_imports.push(directive)
290 }
291 PartialResolvedImport::Resolved(_) => {
292 self.record_resolved_import(&directive);
293 self.resolved_imports.push(directive)
294 }
295 PartialResolvedImport::Unresolved => {
296 self.unresolved_imports.push(directive);
297 }
298 }
269 } 299 }
270 fp == ReachedFixedPoint::No
271 });
272 self.unresolved_imports = imports;
273 // Resolves imports, filling-in module scopes
274 let result =
275 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
276 for (module_id, def, import, import_data) in resolved {
277 self.record_resolved_import(module_id, def, import, &import_data)
278 } 300 }
279 result
280 } 301 }
281 302
282 fn resolve_import( 303 fn resolve_import(
283 &self, 304 &self,
284 module_id: LocalModuleId, 305 module_id: LocalModuleId,
285 import: &raw::ImportData, 306 import: &raw::ImportData,
286 ) -> (PerNs, ReachedFixedPoint) { 307 ) -> PartialResolvedImport {
287 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 308 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
288 if import.is_extern_crate { 309 if import.is_extern_crate {
289 let res = self.def_map.resolve_name_in_extern_prelude( 310 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -292,26 +313,45 @@ where
292 .as_ident() 313 .as_ident()
293 .expect("extern crate should have been desugared to one-element path"), 314 .expect("extern crate should have been desugared to one-element path"),
294 ); 315 );
295 (res, ReachedFixedPoint::Yes) 316 PartialResolvedImport::Resolved(res)
296 } else { 317 } else {
297 let res = self.def_map.resolve_path_fp_with_macro( 318 let res = self.def_map.resolve_path_fp_with_macro(
298 self.db, 319 self.db,
299 ResolveMode::Import, 320 ResolveMode::Import,
300 module_id, 321 module_id,
301 &import.path, 322 &import.path,
323 BuiltinShadowMode::Module,
302 ); 324 );
303 325
304 (res.resolved_def, res.reached_fixedpoint) 326 let def = res.resolved_def;
327 if res.reached_fixedpoint == ReachedFixedPoint::No {
328 return PartialResolvedImport::Unresolved;
329 }
330
331 if let Some(krate) = res.krate {
332 if krate != self.def_map.krate {
333 return PartialResolvedImport::Resolved(def);
334 }
335 }
336
337 // Check whether all namespace is resolved
338 if def.take_types().is_some()
339 && def.take_values().is_some()
340 && def.take_macros().is_some()
341 {
342 PartialResolvedImport::Resolved(def)
343 } else {
344 PartialResolvedImport::Indeterminate(def)
345 }
305 } 346 }
306 } 347 }
307 348
308 fn record_resolved_import( 349 fn record_resolved_import(&mut self, directive: &ImportDirective) {
309 &mut self, 350 let module_id = directive.module_id;
310 module_id: LocalModuleId, 351 let import_id = directive.import_id;
311 def: PerNs, 352 let import = &directive.import;
312 import_id: LocalImportId, 353 let def = directive.status.namespaces();
313 import: &raw::ImportData, 354
314 ) {
315 if import.is_glob { 355 if import.is_glob {
316 log::debug!("glob import: {:?}", import); 356 log::debug!("glob import: {:?}", import);
317 match def.take_types() { 357 match def.take_types() {
@@ -326,13 +366,9 @@ where
326 let scope = &item_map[m.local_id].scope; 366 let scope = &item_map[m.local_id].scope;
327 367
328 // Module scoped macros is included 368 // Module scoped macros is included
329 let items = scope 369 let items = scope.collect_resolutions();
330 .items
331 .iter()
332 .map(|(name, res)| (name.clone(), res.clone()))
333 .collect::<Vec<_>>();
334 370
335 self.update(module_id, Some(import_id), &items); 371 self.update(module_id, &items);
336 } else { 372 } else {
337 // glob import from same crate => we do an initial 373 // glob import from same crate => we do an initial
338 // import, and then need to propagate any further 374 // import, and then need to propagate any further
@@ -340,18 +376,14 @@ where
340 let scope = &self.def_map[m.local_id].scope; 376 let scope = &self.def_map[m.local_id].scope;
341 377
342 // Module scoped macros is included 378 // Module scoped macros is included
343 let items = scope 379 let items = scope.collect_resolutions();
344 .items
345 .iter()
346 .map(|(name, res)| (name.clone(), res.clone()))
347 .collect::<Vec<_>>();
348 380
349 self.update(module_id, Some(import_id), &items); 381 self.update(module_id, &items);
350 // record the glob import in case we add further items 382 // record the glob import in case we add further items
351 self.glob_imports 383 let glob = self.glob_imports.entry(m.local_id).or_default();
352 .entry(m.local_id) 384 if !glob.iter().any(|it| *it == (module_id, import_id)) {
353 .or_default() 385 glob.push((module_id, import_id));
354 .push((module_id, import_id)); 386 }
355 } 387 }
356 } 388 }
357 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { 389 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
@@ -361,17 +393,14 @@ where
361 let resolutions = enum_data 393 let resolutions = enum_data
362 .variants 394 .variants
363 .iter() 395 .iter()
364 .filter_map(|(local_id, variant_data)| { 396 .map(|(local_id, variant_data)| {
365 let name = variant_data.name.clone(); 397 let name = variant_data.name.clone();
366 let variant = EnumVariantId { parent: e, local_id }; 398 let variant = EnumVariantId { parent: e, local_id };
367 let res = Resolution { 399 let res = PerNs::both(variant.into(), variant.into());
368 def: PerNs::both(variant.into(), variant.into()), 400 (name, res)
369 import: Some(import_id),
370 };
371 Some((name, res))
372 }) 401 })
373 .collect::<Vec<_>>(); 402 .collect::<Vec<_>>();
374 self.update(module_id, Some(import_id), &resolutions); 403 self.update(module_id, &resolutions);
375 } 404 }
376 Some(d) => { 405 Some(d) => {
377 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 406 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -383,7 +412,7 @@ where
383 } else { 412 } else {
384 match import.path.segments.last() { 413 match import.path.segments.last() {
385 Some(last_segment) => { 414 Some(last_segment) => {
386 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); 415 let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
387 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 416 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
388 417
389 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 418 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
@@ -393,62 +422,31 @@ where
393 } 422 }
394 } 423 }
395 424
396 let resolution = Resolution { def, import: Some(import_id) }; 425 self.update(module_id, &[(name, def)]);
397 self.update(module_id, Some(import_id), &[(name, resolution)]);
398 } 426 }
399 None => tested_by!(bogus_paths), 427 None => tested_by!(bogus_paths),
400 } 428 }
401 } 429 }
402 } 430 }
403 431
404 fn update( 432 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) {
405 &mut self, 433 self.update_recursive(module_id, resolutions, 0)
406 module_id: LocalModuleId,
407 import: Option<LocalImportId>,
408 resolutions: &[(Name, Resolution)],
409 ) {
410 self.update_recursive(module_id, import, resolutions, 0)
411 } 434 }
412 435
413 fn update_recursive( 436 fn update_recursive(
414 &mut self, 437 &mut self,
415 module_id: LocalModuleId, 438 module_id: LocalModuleId,
416 import: Option<LocalImportId>, 439 resolutions: &[(Name, PerNs)],
417 resolutions: &[(Name, Resolution)],
418 depth: usize, 440 depth: usize,
419 ) { 441 ) {
420 if depth > 100 { 442 if depth > 100 {
421 // prevent stack overflows (but this shouldn't be possible) 443 // prevent stack overflows (but this shouldn't be possible)
422 panic!("infinite recursion in glob imports!"); 444 panic!("infinite recursion in glob imports!");
423 } 445 }
424 let module_items = &mut self.def_map.modules[module_id].scope; 446 let scope = &mut self.def_map.modules[module_id].scope;
425 let mut changed = false; 447 let mut changed = false;
426 for (name, res) in resolutions { 448 for (name, res) in resolutions {
427 let existing = module_items.items.entry(name.clone()).or_default(); 449 changed |= scope.push_res(name.clone(), *res);
428
429 if existing.def.types.is_none() && res.def.types.is_some() {
430 existing.def.types = res.def.types;
431 existing.import = import.or(res.import);
432 changed = true;
433 }
434 if existing.def.values.is_none() && res.def.values.is_some() {
435 existing.def.values = res.def.values;
436 existing.import = import.or(res.import);
437 changed = true;
438 }
439 if existing.def.macros.is_none() && res.def.macros.is_some() {
440 existing.def.macros = res.def.macros;
441 existing.import = import.or(res.import);
442 changed = true;
443 }
444
445 if existing.def.is_none()
446 && res.def.is_none()
447 && existing.import.is_none()
448 && res.import.is_some()
449 {
450 existing.import = res.import;
451 }
452 } 450 }
453 451
454 if !changed { 452 if !changed {
@@ -461,27 +459,48 @@ where
461 .flat_map(|v| v.iter()) 459 .flat_map(|v| v.iter())
462 .cloned() 460 .cloned()
463 .collect::<Vec<_>>(); 461 .collect::<Vec<_>>();
464 for (glob_importing_module, glob_import) in glob_imports { 462 for (glob_importing_module, _glob_import) in glob_imports {
465 // We pass the glob import so that the tracked import in those modules is that glob import 463 // We pass the glob import so that the tracked import in those modules is that glob import
466 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); 464 self.update_recursive(glob_importing_module, resolutions, depth + 1);
467 } 465 }
468 } 466 }
469 467
470 fn resolve_macros(&mut self) -> ReachedFixedPoint { 468 fn resolve_macros(&mut self) -> ReachedFixedPoint {
471 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 469 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
470 let mut attribute_macros =
471 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
472 let mut resolved = Vec::new(); 472 let mut resolved = Vec::new();
473 let mut res = ReachedFixedPoint::Yes; 473 let mut res = ReachedFixedPoint::Yes;
474 macros.retain(|(module_id, ast_id, path)| { 474 macros.retain(|directive| {
475 if let Some(call_id) = directive.legacy {
476 res = ReachedFixedPoint::No;
477 resolved.push((directive.module_id, call_id));
478 return false;
479 }
480
475 let resolved_res = self.def_map.resolve_path_fp_with_macro( 481 let resolved_res = self.def_map.resolve_path_fp_with_macro(
476 self.db, 482 self.db,
477 ResolveMode::Other, 483 ResolveMode::Other,
478 *module_id, 484 directive.module_id,
479 path, 485 &directive.path,
486 BuiltinShadowMode::Module,
480 ); 487 );
481 488
482 if let Some(def) = resolved_res.resolved_def.take_macros() { 489 if let Some(def) = resolved_res.resolved_def.take_macros() {
483 let call_id = def.as_call_id(self.db, *ast_id); 490 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
484 resolved.push((*module_id, call_id, def)); 491 resolved.push((directive.module_id, call_id));
492 res = ReachedFixedPoint::No;
493 return false;
494 }
495
496 true
497 });
498 attribute_macros.retain(|(module_id, ast_id, path)| {
499 let resolved_res = self.resolve_attribute_macro(path);
500
501 if let Some(def) = resolved_res {
502 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
503 resolved.push((*module_id, call_id));
485 res = ReachedFixedPoint::No; 504 res = ReachedFixedPoint::No;
486 return false; 505 return false;
487 } 506 }
@@ -490,44 +509,41 @@ where
490 }); 509 });
491 510
492 self.unexpanded_macros = macros; 511 self.unexpanded_macros = macros;
512 self.unexpanded_attribute_macros = attribute_macros;
493 513
494 for (module_id, macro_call_id, macro_def_id) in resolved { 514 for (module_id, macro_call_id) in resolved {
495 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 515 self.collect_macro_expansion(module_id, macro_call_id);
496 } 516 }
497 517
498 res 518 res
499 } 519 }
500 520
501 fn collect_macro_expansion( 521 fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
502 &mut self, 522 // FIXME this is currently super hacky, just enough to support the
503 module_id: LocalModuleId, 523 // built-in derives
504 macro_call_id: MacroCallId, 524 if let Some(name) = path.as_ident() {
505 macro_def_id: MacroDefId, 525 // FIXME this should actually be handled with the normal name
506 ) { 526 // resolution; the std lib defines built-in stubs for the derives,
507 if self.poison_macros.contains(&macro_def_id) { 527 // but these are new-style `macro`s, which we don't support yet
508 return; 528 if let Some(def_id) = find_builtin_derive(name) {
509 } 529 return Some(def_id);
510
511 self.macro_stack_monitor.increase(macro_def_id);
512
513 if !self.macro_stack_monitor.is_poison(macro_def_id) {
514 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
515 let raw_items = self.db.raw_items(file_id);
516 let mod_dir = self.mod_dirs[&module_id].clone();
517 ModCollector {
518 def_collector: &mut *self,
519 file_id,
520 module_id,
521 raw_items: &raw_items,
522 mod_dir,
523 } 530 }
524 .collect(raw_items.items());
525 } else {
526 log::error!("Too deep macro expansion: {:?}", macro_call_id);
527 self.poison_macros.insert(macro_def_id);
528 } 531 }
532 None
533 }
529 534
530 self.macro_stack_monitor.decrease(macro_def_id); 535 fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) {
536 let file_id: HirFileId = macro_call_id.as_file();
537 let raw_items = self.db.raw_items(file_id);
538 let mod_dir = self.mod_dirs[&module_id].clone();
539 ModCollector {
540 def_collector: &mut *self,
541 file_id,
542 module_id,
543 raw_items: &raw_items,
544 mod_dir,
545 }
546 .collect(raw_items.items());
531 } 547 }
532 548
533 fn finish(self) -> CrateDefMap { 549 fn finish(self) -> CrateDefMap {
@@ -581,20 +597,31 @@ where
581 raw::RawItemKind::Module(m) => { 597 raw::RawItemKind::Module(m) => {
582 self.collect_module(&self.raw_items[m], &item.attrs) 598 self.collect_module(&self.raw_items[m], &item.attrs)
583 } 599 }
584 raw::RawItemKind::Import(import_id) => self 600 raw::RawItemKind::Import(import_id) => {
585 .def_collector 601 self.def_collector.unresolved_imports.push(ImportDirective {
586 .unresolved_imports 602 module_id: self.module_id,
587 .push((self.module_id, import_id, self.raw_items[import_id].clone())), 603 import_id,
588 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), 604 import: self.raw_items[import_id].clone(),
605 status: PartialResolvedImport::Unresolved,
606 })
607 }
608 raw::RawItemKind::Def(def) => {
609 self.define_def(&self.raw_items[def], &item.attrs)
610 }
589 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 611 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
590 raw::RawItemKind::Impl(imp) => { 612 raw::RawItemKind::Impl(imp) => {
591 let module = ModuleId { 613 let module = ModuleId {
592 krate: self.def_collector.def_map.krate, 614 krate: self.def_collector.def_map.krate,
593 local_id: self.module_id, 615 local_id: self.module_id,
594 }; 616 };
595 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 617 let container = ContainerId::ModuleId(module);
596 let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); 618 let ast_id = self.raw_items[imp].ast_id;
597 self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) 619 let impl_id =
620 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
621 .intern(self.def_collector.db);
622 self.def_collector.def_map.modules[self.module_id]
623 .scope
624 .define_impl(impl_id)
598 } 625 }
599 } 626 }
600 } 627 }
@@ -667,72 +694,91 @@ where
667 let modules = &mut self.def_collector.def_map.modules; 694 let modules = &mut self.def_collector.def_map.modules;
668 let res = modules.alloc(ModuleData::default()); 695 let res = modules.alloc(ModuleData::default());
669 modules[res].parent = Some(self.module_id); 696 modules[res].parent = Some(self.module_id);
670 modules[res].declaration = Some(declaration); 697 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration);
671 modules[res].definition = definition; 698 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
672 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); 699 modules[res].scope.define_legacy_macro(name, mac)
700 }
673 modules[self.module_id].children.insert(name.clone(), res); 701 modules[self.module_id].children.insert(name.clone(), res);
674 let resolution = Resolution { 702 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
675 def: PerNs::types( 703 let def: ModuleDefId = module.into();
676 ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(), 704 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
677 ), 705 self.def_collector.update(self.module_id, &[(name, def.into())]);
678 import: None,
679 };
680 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
681 res 706 res
682 } 707 }
683 708
684 fn define_def(&mut self, def: &raw::DefData) { 709 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
685 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; 710 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
686 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 711 // FIXME: check attrs to see if this is an attribute macro invocation;
712 // in which case we don't add the invocation, just a single attribute
713 // macro invocation
687 714
688 let name = def.name.clone(); 715 self.collect_derives(attrs, def);
689 let def: PerNs = match def.kind {
690 raw::DefKind::Function(ast_id) => {
691 let def = FunctionLoc {
692 container: ContainerId::ModuleId(module),
693 ast_id: AstId::new(self.file_id, ast_id),
694 }
695 .intern(self.def_collector.db);
696 716
697 PerNs::values(def.into()) 717 let name = def.name.clone();
718 let container = ContainerId::ModuleId(module);
719 let def: ModuleDefId = match def.kind {
720 raw::DefKind::Function(ast_id) => FunctionLoc {
721 container: container.into(),
722 ast_id: AstId::new(self.file_id, ast_id),
698 } 723 }
724 .intern(self.def_collector.db)
725 .into(),
699 raw::DefKind::Struct(ast_id) => { 726 raw::DefKind::Struct(ast_id) => {
700 let id = StructId::from_ast_id(ctx, ast_id).into(); 727 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
701 PerNs::both(id, id) 728 .intern(self.def_collector.db)
729 .into()
702 } 730 }
703 raw::DefKind::Union(ast_id) => { 731 raw::DefKind::Union(ast_id) => {
704 let id = UnionId::from_ast_id(ctx, ast_id).into(); 732 UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
705 PerNs::both(id, id) 733 .intern(self.def_collector.db)
734 .into()
735 }
736 raw::DefKind::Enum(ast_id) => {
737 EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
738 .intern(self.def_collector.db)
739 .into()
706 } 740 }
707 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
708 raw::DefKind::Const(ast_id) => { 741 raw::DefKind::Const(ast_id) => {
709 let def = ConstLoc { 742 ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
710 container: ContainerId::ModuleId(module), 743 .intern(self.def_collector.db)
711 ast_id: AstId::new(self.file_id, ast_id), 744 .into()
712 }
713 .intern(self.def_collector.db);
714
715 PerNs::values(def.into())
716 } 745 }
717 raw::DefKind::Static(ast_id) => { 746 raw::DefKind::Static(ast_id) => {
718 let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } 747 StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
719 .intern(self.def_collector.db); 748 .intern(self.def_collector.db)
720 749 .into()
721 PerNs::values(def.into())
722 } 750 }
723 raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), 751 raw::DefKind::Trait(ast_id) => {
724 raw::DefKind::TypeAlias(ast_id) => { 752 TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
725 let def = TypeAliasLoc { 753 .intern(self.def_collector.db)
726 container: ContainerId::ModuleId(module), 754 .into()
727 ast_id: AstId::new(self.file_id, ast_id),
728 }
729 .intern(self.def_collector.db);
730
731 PerNs::types(def.into())
732 } 755 }
756 raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
757 container: container.into(),
758 ast_id: AstId::new(self.file_id, ast_id),
759 }
760 .intern(self.def_collector.db)
761 .into(),
733 }; 762 };
734 let resolution = Resolution { def, import: None }; 763 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
735 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 764 self.def_collector.update(self.module_id, &[(name, def.into())])
765 }
766
767 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
768 for derive_subtree in attrs.by_key("derive").tt_values() {
769 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
770 for tt in &derive_subtree.token_trees {
771 let ident = match &tt {
772 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
773 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
774 _ => continue, // anything else would be an error (which we currently ignore)
775 };
776 let path = ModPath::from_tt_ident(ident);
777
778 let ast_id = AstId::new(self.file_id, def.kind.ast_id());
779 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
780 }
781 }
736 } 782 }
737 783
738 fn collect_macro(&mut self, mac: &raw::MacroData) { 784 fn collect_macro(&mut self, mac: &raw::MacroData) {
@@ -758,8 +804,8 @@ where
758 if is_macro_rules(&mac.path) { 804 if is_macro_rules(&mac.path) {
759 if let Some(name) = &mac.name { 805 if let Some(name) = &mac.name {
760 let macro_id = MacroDefId { 806 let macro_id = MacroDefId {
761 ast_id, 807 ast_id: Some(ast_id),
762 krate: self.def_collector.def_map.krate, 808 krate: Some(self.def_collector.def_map.krate),
763 kind: MacroDefKind::Declarative, 809 kind: MacroDefKind::Declarative,
764 }; 810 };
765 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); 811 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
@@ -767,14 +813,20 @@ where
767 return; 813 return;
768 } 814 }
769 815
770 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 816 // Case 2: try to resolve in legacy scope and expand macro_rules
771 // recursive item collection.
772 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 817 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
773 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 818 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
774 }) { 819 }) {
775 let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); 820 let macro_call_id =
821 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
822
823 self.def_collector.unexpanded_macros.push(MacroDirective {
824 module_id: self.module_id,
825 path: mac.path.clone(),
826 ast_id,
827 legacy: Some(macro_call_id),
828 });
776 829
777 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
778 return; 830 return;
779 } 831 }
780 832
@@ -782,13 +834,19 @@ where
782 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. 834 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
783 let mut path = mac.path.clone(); 835 let mut path = mac.path.clone();
784 if path.is_ident() { 836 if path.is_ident() {
785 path.kind = PathKind::Self_; 837 path.kind = PathKind::Super(0);
786 } 838 }
787 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); 839
840 self.def_collector.unexpanded_macros.push(MacroDirective {
841 module_id: self.module_id,
842 path,
843 ast_id,
844 legacy: None,
845 });
788 } 846 }
789 847
790 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { 848 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
791 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 849 let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
792 for (name, macro_) in macros { 850 for (name, macro_) in macros {
793 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 851 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
794 } 852 }
@@ -803,45 +861,35 @@ where
803 } 861 }
804} 862}
805 863
806fn is_macro_rules(path: &Path) -> bool { 864fn is_macro_rules(path: &ModPath) -> bool {
807 path.as_ident() == Some(&name::MACRO_RULES) 865 path.as_ident() == Some(&name![macro_rules])
808} 866}
809 867
810#[cfg(test)] 868#[cfg(test)]
811mod tests { 869mod tests {
870 use crate::{db::DefDatabase, test_db::TestDB};
812 use ra_arena::Arena; 871 use ra_arena::Arena;
813 use ra_db::{fixture::WithFixture, SourceDatabase}; 872 use ra_db::{fixture::WithFixture, SourceDatabase};
814 use rustc_hash::FxHashSet;
815
816 use crate::{db::DefDatabase, test_db::TestDB};
817 873
818 use super::*; 874 use super::*;
819 875
820 fn do_collect_defs( 876 fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
821 db: &impl DefDatabase,
822 def_map: CrateDefMap,
823 monitor: MacroStackMonitor,
824 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
825 let mut collector = DefCollector { 877 let mut collector = DefCollector {
826 db, 878 db,
827 def_map, 879 def_map,
828 glob_imports: FxHashMap::default(), 880 glob_imports: FxHashMap::default(),
829 unresolved_imports: Vec::new(), 881 unresolved_imports: Vec::new(),
882 resolved_imports: Vec::new(),
830 unexpanded_macros: Vec::new(), 883 unexpanded_macros: Vec::new(),
884 unexpanded_attribute_macros: Vec::new(),
831 mod_dirs: FxHashMap::default(), 885 mod_dirs: FxHashMap::default(),
832 macro_stack_monitor: monitor,
833 poison_macros: FxHashSet::default(),
834 cfg_options: &CfgOptions::default(), 886 cfg_options: &CfgOptions::default(),
835 }; 887 };
836 collector.collect(); 888 collector.collect();
837 (collector.def_map, collector.poison_macros) 889 collector.def_map
838 } 890 }
839 891
840 fn do_limited_resolve( 892 fn do_resolve(code: &str) -> CrateDefMap {
841 code: &str,
842 limit: u32,
843 poison_limit: u32,
844 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
845 let (db, _file_id) = TestDB::with_single_file(&code); 893 let (db, _file_id) = TestDB::with_single_file(&code);
846 let krate = db.test_crate(); 894 let krate = db.test_crate();
847 895
@@ -859,59 +907,18 @@ mod tests {
859 diagnostics: Vec::new(), 907 diagnostics: Vec::new(),
860 } 908 }
861 }; 909 };
862 910 do_collect_defs(&db, def_map)
863 let mut monitor = MacroStackMonitor::default();
864 monitor.validator = Some(Box::new(move |count| {
865 assert!(count < limit);
866 count >= poison_limit
867 }));
868
869 do_collect_defs(&db, def_map, monitor)
870 } 911 }
871 912
872 #[test] 913 #[test]
873 fn test_macro_expand_limit_width() { 914 fn test_macro_expand_will_stop() {
874 do_limited_resolve( 915 do_resolve(
875 r#" 916 r#"
876 macro_rules! foo { 917 macro_rules! foo {
877 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } 918 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
878 } 919 }
879foo!(KABOOM); 920foo!(KABOOM);
880 "#, 921 "#,
881 16,
882 1000,
883 ); 922 );
884 } 923 }
885
886 #[test]
887 fn test_macro_expand_poisoned() {
888 let (_, poison_macros) = do_limited_resolve(
889 r#"
890 macro_rules! foo {
891 ($ty:ty) => { foo!($ty); }
892 }
893foo!(KABOOM);
894 "#,
895 100,
896 16,
897 );
898
899 assert_eq!(poison_macros.len(), 1);
900 }
901
902 #[test]
903 fn test_macro_expand_normal() {
904 let (_, poison_macros) = do_limited_resolve(
905 r#"
906 macro_rules! foo {
907 ($ident:ident) => { struct $ident {} }
908 }
909foo!(Bar);
910 "#,
911 16,
912 16,
913 );
914
915 assert_eq!(poison_macros.len(), 0);
916 }
917} 924}
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index b72c55bd1..695014c7b 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -10,16 +10,18 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
13use hir_expand::name::Name; 15use hir_expand::name::Name;
14use ra_db::Edition; 16use ra_db::Edition;
15use test_utils::tested_by; 17use test_utils::tested_by;
16 18
17use crate::{ 19use crate::{
18 db::DefDatabase, 20 db::DefDatabase,
19 nameres::CrateDefMap, 21 nameres::{BuiltinShadowMode, CrateDefMap},
20 path::{Path, PathKind}, 22 path::{ModPath, PathKind},
21 per_ns::PerNs, 23 per_ns::PerNs,
22 AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 24 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
23}; 25};
24 26
25#[derive(Debug, Clone, Copy, PartialEq, Eq)] 27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult {
39 pub(super) resolved_def: PerNs, 41 pub(super) resolved_def: PerNs,
40 pub(super) segment_index: Option<usize>, 42 pub(super) segment_index: Option<usize>,
41 pub(super) reached_fixedpoint: ReachedFixedPoint, 43 pub(super) reached_fixedpoint: ReachedFixedPoint,
44 pub(super) krate: Option<CrateId>,
42} 45}
43 46
44impl ResolvePathResult { 47impl ResolvePathResult {
45 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 48 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
46 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) 49 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
47 } 50 }
48 51
49 fn with( 52 fn with(
50 resolved_def: PerNs, 53 resolved_def: PerNs,
51 reached_fixedpoint: ReachedFixedPoint, 54 reached_fixedpoint: ReachedFixedPoint,
52 segment_index: Option<usize>, 55 segment_index: Option<usize>,
56 krate: Option<CrateId>,
53 ) -> ResolvePathResult { 57 ) -> ResolvePathResult {
54 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } 58 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate }
55 } 59 }
56} 60}
57 61
@@ -67,8 +71,18 @@ impl CrateDefMap {
67 db: &impl DefDatabase, 71 db: &impl DefDatabase,
68 mode: ResolveMode, 72 mode: ResolveMode,
69 original_module: LocalModuleId, 73 original_module: LocalModuleId,
70 path: &Path, 74 path: &ModPath,
75 shadow: BuiltinShadowMode,
71 ) -> ResolvePathResult { 76 ) -> ResolvePathResult {
77 // if it is not the last segment, we prefer the module to the builtin
78 let prefer_module = |index| {
79 if index == path.segments.len() - 1 {
80 shadow
81 } else {
82 BuiltinShadowMode::Module
83 }
84 };
85
72 let mut segments = path.segments.iter().enumerate(); 86 let mut segments = path.segments.iter().enumerate();
73 let mut curr_per_ns: PerNs = match path.kind { 87 let mut curr_per_ns: PerNs = match path.kind {
74 PathKind::DollarCrate(krate) => { 88 PathKind::DollarCrate(krate) => {
@@ -85,9 +99,6 @@ impl CrateDefMap {
85 PathKind::Crate => { 99 PathKind::Crate => {
86 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) 100 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
87 } 101 }
88 PathKind::Self_ => {
89 PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into())
90 }
91 // plain import or absolute path in 2015: crate-relative with 102 // plain import or absolute path in 2015: crate-relative with
92 // fallback to extern prelude (with the simplification in 103 // fallback to extern prelude (with the simplification in
93 // rust-lang/rust#57745) 104 // rust-lang/rust#57745)
@@ -96,24 +107,26 @@ impl CrateDefMap {
96 if self.edition == Edition::Edition2015 107 if self.edition == Edition::Edition2015
97 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => 108 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
98 { 109 {
99 let segment = match segments.next() { 110 let (idx, segment) = match segments.next() {
100 Some((_, segment)) => segment, 111 Some((idx, segment)) => (idx, segment),
101 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 112 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
102 }; 113 };
103 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 114 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
104 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) 115 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx))
105 } 116 }
106 PathKind::Plain => { 117 PathKind::Plain => {
107 let segment = match segments.next() { 118 let (idx, segment) = match segments.next() {
108 Some((_, segment)) => segment, 119 Some((idx, segment)) => (idx, segment),
109 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 120 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
110 }; 121 };
111 log::debug!("resolving {:?} in module", segment); 122 log::debug!("resolving {:?} in module", segment);
112 self.resolve_name_in_module(db, original_module, &segment.name) 123 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx))
113 } 124 }
114 PathKind::Super => { 125 PathKind::Super(lvl) => {
115 if let Some(p) = self.modules[original_module].parent { 126 let m = successors(Some(original_module), |m| self.modules[*m].parent)
116 PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) 127 .nth(lvl as usize);
128 if let Some(local_id) = m {
129 PerNs::types(ModuleId { krate: self.krate, local_id }.into())
117 } else { 130 } else {
118 log::debug!("super path in root module"); 131 log::debug!("super path in root module");
119 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 132 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -125,18 +138,13 @@ impl CrateDefMap {
125 Some((_, segment)) => segment, 138 Some((_, segment)) => segment,
126 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 139 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
127 }; 140 };
128 if let Some(def) = self.extern_prelude.get(&segment.name) { 141 if let Some(def) = self.extern_prelude.get(&segment) {
129 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 142 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
130 PerNs::types(*def) 143 PerNs::types(*def)
131 } else { 144 } else {
132 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 145 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
133 } 146 }
134 } 147 }
135 PathKind::Type(_) => {
136 // This is handled in `infer::infer_path_expr`
137 // The result returned here does not matter
138 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
139 }
140 }; 148 };
141 149
142 for (i, segment) in segments { 150 for (i, segment) in segments {
@@ -156,32 +164,29 @@ impl CrateDefMap {
156 curr_per_ns = match curr { 164 curr_per_ns = match curr {
157 ModuleDefId::ModuleId(module) => { 165 ModuleDefId::ModuleId(module) => {
158 if module.krate != self.krate { 166 if module.krate != self.krate {
159 let path = 167 let path = ModPath {
160 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 168 segments: path.segments[i..].to_vec(),
169 kind: PathKind::Super(0),
170 };
161 log::debug!("resolving {:?} in other crate", path); 171 log::debug!("resolving {:?} in other crate", path);
162 let defp_map = db.crate_def_map(module.krate); 172 let defp_map = db.crate_def_map(module.krate);
163 let (def, s) = defp_map.resolve_path(db, module.local_id, &path); 173 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
164 return ResolvePathResult::with( 174 return ResolvePathResult::with(
165 def, 175 def,
166 ReachedFixedPoint::Yes, 176 ReachedFixedPoint::Yes,
167 s.map(|s| s + i), 177 s.map(|s| s + i),
178 Some(module.krate),
168 ); 179 );
169 } 180 }
170 181
171 // Since it is a qualified path here, it should not contains legacy macros 182 // Since it is a qualified path here, it should not contains legacy macros
172 match self[module.local_id].scope.get(&segment.name) { 183 self[module.local_id].scope.get(&segment, prefer_module(i))
173 Some(res) => res.def,
174 _ => {
175 log::debug!("path segment {:?} not found", segment.name);
176 return ResolvePathResult::empty(ReachedFixedPoint::No);
177 }
178 }
179 } 184 }
180 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 185 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
181 // enum variant 186 // enum variant
182 tested_by!(can_import_enum_variant); 187 tested_by!(can_import_enum_variant);
183 let enum_data = db.enum_data(e); 188 let enum_data = db.enum_data(e);
184 match enum_data.variant(&segment.name) { 189 match enum_data.variant(&segment) {
185 Some(local_id) => { 190 Some(local_id) => {
186 let variant = EnumVariantId { parent: e, local_id }; 191 let variant = EnumVariantId { parent: e, local_id };
187 PerNs::both(variant.into(), variant.into()) 192 PerNs::both(variant.into(), variant.into())
@@ -191,6 +196,7 @@ impl CrateDefMap {
191 PerNs::types(e.into()), 196 PerNs::types(e.into()),
192 ReachedFixedPoint::Yes, 197 ReachedFixedPoint::Yes,
193 Some(i), 198 Some(i),
199 Some(self.krate),
194 ); 200 );
195 } 201 }
196 } 202 }
@@ -200,7 +206,7 @@ impl CrateDefMap {
200 // (`Struct::method`), or some other kind of associated item 206 // (`Struct::method`), or some other kind of associated item
201 log::debug!( 207 log::debug!(
202 "path segment {:?} resolved to non-module {:?}, but is not last", 208 "path segment {:?} resolved to non-module {:?}, but is not last",
203 segment.name, 209 segment,
204 curr, 210 curr,
205 ); 211 );
206 212
@@ -208,11 +214,13 @@ impl CrateDefMap {
208 PerNs::types(s), 214 PerNs::types(s),
209 ReachedFixedPoint::Yes, 215 ReachedFixedPoint::Yes,
210 Some(i), 216 Some(i),
217 Some(self.krate),
211 ); 218 );
212 } 219 }
213 }; 220 };
214 } 221 }
215 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 222
223 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
216 } 224 }
217 225
218 fn resolve_name_in_module( 226 fn resolve_name_in_module(
@@ -220,6 +228,7 @@ impl CrateDefMap {
220 db: &impl DefDatabase, 228 db: &impl DefDatabase,
221 module: LocalModuleId, 229 module: LocalModuleId,
222 name: &Name, 230 name: &Name,
231 shadow: BuiltinShadowMode,
223 ) -> PerNs { 232 ) -> PerNs {
224 // Resolve in: 233 // Resolve in:
225 // - legacy scope of macro 234 // - legacy scope of macro
@@ -228,23 +237,31 @@ impl CrateDefMap {
228 // - std prelude 237 // - std prelude
229 let from_legacy_macro = 238 let from_legacy_macro =
230 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); 239 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
231 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); 240 let from_scope = self[module].scope.get(name, shadow);
232 let from_extern_prelude = 241 let from_extern_prelude =
233 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 242 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
234 let from_prelude = self.resolve_in_prelude(db, name); 243 let from_prelude = self.resolve_in_prelude(db, name, shadow);
235 244
236 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 245 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
237 } 246 }
238 247
239 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 248 fn resolve_name_in_crate_root_or_extern_prelude(
240 let from_crate_root = 249 &self,
241 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); 250 name: &Name,
251 shadow: BuiltinShadowMode,
252 ) -> PerNs {
253 let from_crate_root = self[self.root].scope.get(name, shadow);
242 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 254 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
243 255
244 from_crate_root.or(from_extern_prelude) 256 from_crate_root.or(from_extern_prelude)
245 } 257 }
246 258
247 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { 259 fn resolve_in_prelude(
260 &self,
261 db: &impl DefDatabase,
262 name: &Name,
263 shadow: BuiltinShadowMode,
264 ) -> PerNs {
248 if let Some(prelude) = self.prelude { 265 if let Some(prelude) = self.prelude {
249 let keep; 266 let keep;
250 let def_map = if prelude.krate == self.krate { 267 let def_map = if prelude.krate == self.krate {
@@ -254,7 +271,7 @@ impl CrateDefMap {
254 keep = db.crate_def_map(prelude.krate); 271 keep = db.crate_def_map(prelude.krate);
255 &keep 272 &keep
256 }; 273 };
257 def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) 274 def_map[prelude.local_id].scope.get(name, shadow)
258 } else { 275 } else {
259 PerNs::none() 276 PerNs::none()
260 } 277 }
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 6eb106094..73dc08745 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -10,21 +10,18 @@ use std::{ops::Index, sync::Arc};
10use hir_expand::{ 10use hir_expand::{
11 ast_id_map::AstIdMap, 11 ast_id_map::AstIdMap,
12 db::AstDatabase, 12 db::AstDatabase,
13 either::Either,
14 hygiene::Hygiene, 13 hygiene::Hygiene,
15 name::{AsName, Name}, 14 name::{AsName, Name},
16}; 15};
17use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 16use ra_arena::{impl_arena_id, Arena, RawId};
17use ra_prof::profile;
18use ra_syntax::{ 18use ra_syntax::{
19 ast::{self, AttrsOwner, NameOwner}, 19 ast::{self, AttrsOwner, NameOwner},
20 AstNode, AstPtr, 20 AstNode,
21}; 21};
22use test_utils::tested_by; 22use test_utils::tested_by;
23 23
24use crate::{ 24use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile};
25 attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, LocalImportId,
26 Source,
27};
28 25
29/// `RawItems` is a set of top-level items in a file (except for impls). 26/// `RawItems` is a set of top-level items in a file (except for impls).
30/// 27///
@@ -33,7 +30,7 @@ use crate::{
33#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
34pub struct RawItems { 31pub struct RawItems {
35 modules: Arena<Module, ModuleData>, 32 modules: Arena<Module, ModuleData>,
36 imports: Arena<LocalImportId, ImportData>, 33 imports: Arena<Import, ImportData>,
37 defs: Arena<Def, DefData>, 34 defs: Arena<Def, DefData>,
38 macros: Arena<Macro, MacroData>, 35 macros: Arena<Macro, MacroData>,
39 impls: Arena<Impl, ImplData>, 36 impls: Arena<Impl, ImplData>,
@@ -41,35 +38,15 @@ pub struct RawItems {
41 items: Vec<RawItem>, 38 items: Vec<RawItem>,
42} 39}
43 40
44#[derive(Debug, Default, PartialEq, Eq)]
45pub struct ImportSourceMap {
46 map: ArenaMap<LocalImportId, ImportSourcePtr>,
47}
48
49type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
50
51impl ImportSourceMap {
52 pub fn get(&self, import: LocalImportId) -> ImportSourcePtr {
53 self.map[import].clone()
54 }
55}
56
57impl RawItems { 41impl RawItems {
58 pub(crate) fn raw_items_query( 42 pub(crate) fn raw_items_query(
59 db: &(impl DefDatabase + AstDatabase), 43 db: &(impl DefDatabase + AstDatabase),
60 file_id: HirFileId, 44 file_id: HirFileId,
61 ) -> Arc<RawItems> { 45 ) -> Arc<RawItems> {
62 db.raw_items_with_source_map(file_id).0 46 let _p = profile("raw_items_query");
63 }
64
65 pub(crate) fn raw_items_with_source_map_query(
66 db: &(impl DefDatabase + AstDatabase),
67 file_id: HirFileId,
68 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
69 let mut collector = RawItemsCollector { 47 let mut collector = RawItemsCollector {
70 raw_items: RawItems::default(), 48 raw_items: RawItems::default(),
71 source_ast_id_map: db.ast_id_map(file_id), 49 source_ast_id_map: db.ast_id_map(file_id),
72 imports: Trace::new(),
73 file_id, 50 file_id,
74 hygiene: Hygiene::new(db, file_id), 51 hygiene: Hygiene::new(db, file_id),
75 }; 52 };
@@ -80,11 +57,8 @@ impl RawItems {
80 collector.process_module(None, item_list); 57 collector.process_module(None, item_list);
81 } 58 }
82 } 59 }
83 let mut raw_items = collector.raw_items; 60 let raw_items = collector.raw_items;
84 let (arena, map) = collector.imports.into_arena_and_map(); 61 Arc::new(raw_items)
85 raw_items.imports = arena;
86 let source_map = ImportSourceMap { map };
87 (Arc::new(raw_items), Arc::new(source_map))
88 } 62 }
89 63
90 pub(super) fn items(&self) -> &[RawItem] { 64 pub(super) fn items(&self) -> &[RawItem] {
@@ -99,9 +73,9 @@ impl Index<Module> for RawItems {
99 } 73 }
100} 74}
101 75
102impl Index<LocalImportId> for RawItems { 76impl Index<Import> for RawItems {
103 type Output = ImportData; 77 type Output = ImportData;
104 fn index(&self, idx: LocalImportId) -> &ImportData { 78 fn index(&self, idx: Import) -> &ImportData {
105 &self.imports[idx] 79 &self.imports[idx]
106 } 80 }
107} 81}
@@ -136,7 +110,7 @@ pub(super) struct RawItem {
136#[derive(Debug, PartialEq, Eq, Clone, Copy)] 110#[derive(Debug, PartialEq, Eq, Clone, Copy)]
137pub(super) enum RawItemKind { 111pub(super) enum RawItemKind {
138 Module(Module), 112 Module(Module),
139 Import(LocalImportId), 113 Import(Import),
140 Def(Def), 114 Def(Def),
141 Macro(Macro), 115 Macro(Macro),
142 Impl(Impl), 116 Impl(Impl),
@@ -152,9 +126,13 @@ pub(super) enum ModuleData {
152 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 126 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
153} 127}
154 128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130pub(crate) struct Import(RawId);
131impl_arena_id!(Import);
132
155#[derive(Debug, Clone, PartialEq, Eq)] 133#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct ImportData { 134pub struct ImportData {
157 pub(super) path: Path, 135 pub(super) path: ModPath,
158 pub(super) alias: Option<Name>, 136 pub(super) alias: Option<Name>,
159 pub(super) is_glob: bool, 137 pub(super) is_glob: bool,
160 pub(super) is_prelude: bool, 138 pub(super) is_prelude: bool,
@@ -184,6 +162,21 @@ pub(super) enum DefKind {
184 TypeAlias(FileAstId<ast::TypeAliasDef>), 162 TypeAlias(FileAstId<ast::TypeAliasDef>),
185} 163}
186 164
165impl DefKind {
166 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> {
167 match self {
168 DefKind::Function(it) => it.upcast(),
169 DefKind::Struct(it) => it.upcast(),
170 DefKind::Union(it) => it.upcast(),
171 DefKind::Enum(it) => it.upcast(),
172 DefKind::Const(it) => it.upcast(),
173 DefKind::Static(it) => it.upcast(),
174 DefKind::Trait(it) => it.upcast(),
175 DefKind::TypeAlias(it) => it.upcast(),
176 }
177 }
178}
179
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188pub(super) struct Macro(RawId); 181pub(super) struct Macro(RawId);
189impl_arena_id!(Macro); 182impl_arena_id!(Macro);
@@ -191,7 +184,7 @@ impl_arena_id!(Macro);
191#[derive(Debug, PartialEq, Eq)] 184#[derive(Debug, PartialEq, Eq)]
192pub(super) struct MacroData { 185pub(super) struct MacroData {
193 pub(super) ast_id: FileAstId<ast::MacroCall>, 186 pub(super) ast_id: FileAstId<ast::MacroCall>,
194 pub(super) path: Path, 187 pub(super) path: ModPath,
195 pub(super) name: Option<Name>, 188 pub(super) name: Option<Name>,
196 pub(super) export: bool, 189 pub(super) export: bool,
197 pub(super) builtin: bool, 190 pub(super) builtin: bool,
@@ -208,7 +201,6 @@ pub(super) struct ImplData {
208 201
209struct RawItemsCollector { 202struct RawItemsCollector {
210 raw_items: RawItems, 203 raw_items: RawItems,
211 imports: Trace<LocalImportId, ImportData, ImportSourcePtr>,
212 source_ast_id_map: Arc<AstIdMap>, 204 source_ast_id_map: Arc<AstIdMap>,
213 file_id: HirFileId, 205 file_id: HirFileId,
214 hygiene: Hygiene, 206 hygiene: Hygiene,
@@ -312,10 +304,10 @@ impl RawItemsCollector {
312 let attrs = self.parse_attrs(&use_item); 304 let attrs = self.parse_attrs(&use_item);
313 305
314 let mut buf = Vec::new(); 306 let mut buf = Vec::new();
315 Path::expand_use_item( 307 ModPath::expand_use_item(
316 Source { value: use_item, file_id: self.file_id }, 308 InFile { value: use_item, file_id: self.file_id },
317 &self.hygiene, 309 &self.hygiene,
318 |path, use_tree, is_glob, alias| { 310 |path, _use_tree, is_glob, alias| {
319 let import_data = ImportData { 311 let import_data = ImportData {
320 path, 312 path,
321 alias, 313 alias,
@@ -324,11 +316,11 @@ impl RawItemsCollector {
324 is_extern_crate: false, 316 is_extern_crate: false,
325 is_macro_use: false, 317 is_macro_use: false,
326 }; 318 };
327 buf.push((import_data, Either::A(AstPtr::new(use_tree)))); 319 buf.push(import_data);
328 }, 320 },
329 ); 321 );
330 for (import_data, ptr) in buf { 322 for import_data in buf {
331 self.push_import(current_module, attrs.clone(), import_data, ptr); 323 self.push_import(current_module, attrs.clone(), import_data);
332 } 324 }
333 } 325 }
334 326
@@ -338,7 +330,7 @@ impl RawItemsCollector {
338 extern_crate: ast::ExternCrateItem, 330 extern_crate: ast::ExternCrateItem,
339 ) { 331 ) {
340 if let Some(name_ref) = extern_crate.name_ref() { 332 if let Some(name_ref) = extern_crate.name_ref() {
341 let path = Path::from_name_ref(&name_ref); 333 let path = ModPath::from_name_ref(&name_ref);
342 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 334 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
343 let attrs = self.parse_attrs(&extern_crate); 335 let attrs = self.parse_attrs(&extern_crate);
344 // FIXME: cfg_attr 336 // FIXME: cfg_attr
@@ -351,18 +343,13 @@ impl RawItemsCollector {
351 is_extern_crate: true, 343 is_extern_crate: true,
352 is_macro_use, 344 is_macro_use,
353 }; 345 };
354 self.push_import( 346 self.push_import(current_module, attrs, import_data);
355 current_module,
356 attrs,
357 import_data,
358 Either::B(AstPtr::new(&extern_crate)),
359 );
360 } 347 }
361 } 348 }
362 349
363 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 350 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
364 let attrs = self.parse_attrs(&m); 351 let attrs = self.parse_attrs(&m);
365 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { 352 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
366 Some(it) => it, 353 Some(it) => it,
367 _ => return, 354 _ => return,
368 }; 355 };
@@ -387,14 +374,8 @@ impl RawItemsCollector {
387 self.push_item(current_module, attrs, RawItemKind::Impl(imp)) 374 self.push_item(current_module, attrs, RawItemKind::Impl(imp))
388 } 375 }
389 376
390 fn push_import( 377 fn push_import(&mut self, current_module: Option<Module>, attrs: Attrs, data: ImportData) {
391 &mut self, 378 let import = self.raw_items.imports.alloc(data);
392 current_module: Option<Module>,
393 attrs: Attrs,
394 data: ImportData,
395 source: ImportSourcePtr,
396 ) {
397 let import = self.imports.alloc(|| source, || data);
398 self.push_item(current_module, attrs, RawItemKind::Import(import)) 379 self.push_item(current_module, attrs, RawItemKind::Import(import))
399 } 380 }
400 381
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 87fcd617c..ff474b53b 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -32,27 +32,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
32 *buf += path; 32 *buf += path;
33 *buf += "\n"; 33 *buf += "\n";
34 34
35 let mut entries = map.modules[module] 35 let mut entries = map.modules[module].scope.collect_resolutions();
36 .scope 36 entries.sort_by_key(|(name, _)| name.clone());
37 .items 37
38 .iter() 38 for (name, def) in entries {
39 .map(|(name, res)| (name, res.def))
40 .collect::<Vec<_>>();
41 entries.sort_by_key(|(name, _)| *name);
42
43 for (name, res) in entries {
44 *buf += &format!("{}:", name); 39 *buf += &format!("{}:", name);
45 40
46 if res.types.is_some() { 41 if def.types.is_some() {
47 *buf += " t"; 42 *buf += " t";
48 } 43 }
49 if res.values.is_some() { 44 if def.values.is_some() {
50 *buf += " v"; 45 *buf += " v";
51 } 46 }
52 if res.macros.is_some() { 47 if def.macros.is_some() {
53 *buf += " m"; 48 *buf += " m";
54 } 49 }
55 if res.is_none() { 50 if def.is_none() {
56 *buf += " _"; 51 *buf += " _";
57 } 52 }
58 53
@@ -558,3 +553,35 @@ fn cfg_test() {
558 â‹®Foo: t v 553 â‹®Foo: t v
559 "###); 554 "###);
560} 555}
556
557#[test]
558fn infer_multiple_namespace() {
559 let map = def_map(
560 r#"
561//- /main.rs
562mod a {
563 pub type T = ();
564 pub use crate::b::*;
565}
566
567use crate::a::T;
568
569mod b {
570 pub const T: () = ();
571}
572"#,
573 );
574
575 assert_snapshot!(map, @r###"
576 â‹®crate
577 â‹®T: t v
578 â‹®a: t
579 â‹®b: t
580 â‹®
581 â‹®crate::b
582 â‹®T: v
583 â‹®
584 â‹®crate::a
585 â‹®T: t v
586"###);
587}
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 5b03fe365..5e24cb94d 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -112,3 +112,24 @@ fn glob_enum() {
112 "### 112 "###
113 ); 113 );
114} 114}
115
116#[test]
117fn glob_enum_group() {
118 covers!(glob_enum_group);
119 let map = def_map(
120 "
121 //- /lib.rs
122 enum Foo {
123 Bar, Baz
124 }
125 use self::Foo::{*};
126 ",
127 );
128 assert_snapshot!(map, @r###"
129 â‹®crate
130 â‹®Bar: t v
131 â‹®Baz: t v
132 â‹®Foo: t
133 "###
134 );
135}
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 903a22771..ef2e9435c 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let crate_def_map = db.crate_def_map(krate); 117 let crate_def_map = db.crate_def_map(krate);
118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
119 assert_eq!(module_data.scope.items.len(), 1); 119 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
120 }); 120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 } 122 }
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
126 let events = db.log_executed(|| { 126 let events = db.log_executed(|| {
127 let crate_def_map = db.crate_def_map(krate); 127 let crate_def_map = db.crate_def_map(krate);
128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
129 assert_eq!(module_data.scope.items.len(), 1); 129 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
130 }); 130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 } 132 }
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 704065633..d104f5993 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
600 â‹®bar: t v 600 â‹®bar: t v
601 "###); 601 "###);
602} 602}
603
604#[test]
605fn expand_derive() {
606 let map = compute_crate_def_map(
607 "
608 //- /main.rs
609 #[derive(Clone)]
610 struct Foo;
611 ",
612 );
613 assert_eq!(map.modules[map.root].scope.impls().len(), 1);
614}
615
616#[test]
617fn expand_multiple_derive() {
618 let map = compute_crate_def_map(
619 "
620 //- /main.rs
621 #[derive(Copy, Clone)]
622 struct Foo;
623 ",
624 );
625 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
626}
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index e11530062..e800cc68e 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -668,7 +668,7 @@ fn unresolved_module_diagnostics() {
668 module: LocalModuleId( 668 module: LocalModuleId(
669 0, 669 0,
670 ), 670 ),
671 declaration: AstId { 671 declaration: InFile {
672 file_id: HirFileId( 672 file_id: HirFileId(
673 FileId( 673 FileId(
674 FileId( 674 FileId(
@@ -676,7 +676,7 @@ fn unresolved_module_diagnostics() {
676 ), 676 ),
677 ), 677 ),
678 ), 678 ),
679 file_ast_id: FileAstId { 679 value: FileAstId {
680 raw: ErasedFileAstId( 680 raw: ErasedFileAstId(
681 1, 681 1,
682 ), 682 ),
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 6810a26db..8e1294201 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -1,35 +1,97 @@
1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. 1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
2mod lower;
2 3
3use std::{iter, sync::Arc}; 4use std::{iter, sync::Arc};
4 5
5use hir_expand::{ 6use hir_expand::{
6 either::Either,
7 hygiene::Hygiene, 7 hygiene::Hygiene,
8 name::{self, AsName, Name}, 8 name::{AsName, Name},
9}; 9};
10use ra_db::CrateId; 10use ra_db::CrateId;
11use ra_syntax::{ 11use ra_syntax::ast;
12 ast::{self, NameOwner, TypeAscriptionOwner},
13 AstNode,
14};
15 12
16use crate::{type_ref::TypeRef, Source}; 13use crate::{type_ref::TypeRef, InFile};
17 14
18#[derive(Debug, Clone, PartialEq, Eq, Hash)] 15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Path { 16pub struct ModPath {
20 pub kind: PathKind, 17 pub kind: PathKind,
21 pub segments: Vec<PathSegment>, 18 pub segments: Vec<Name>,
22} 19}
23 20
24#[derive(Debug, Clone, PartialEq, Eq, Hash)] 21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct PathSegment { 22pub enum PathKind {
26 pub name: Name, 23 Plain,
27 pub args_and_bindings: Option<Arc<GenericArgs>>, 24 /// `self::` is `Super(0)`
25 Super(u8),
26 Crate,
27 /// Absolute path (::foo)
28 Abs,
29 /// `$crate` from macro expansion
30 DollarCrate(CrateId),
31}
32
33impl ModPath {
34 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
35 lower::lower_path(path, hygiene).map(|it| it.mod_path)
36 }
37
38 pub fn from_simple_segments(
39 kind: PathKind,
40 segments: impl IntoIterator<Item = Name>,
41 ) -> ModPath {
42 let segments = segments.into_iter().collect::<Vec<_>>();
43 ModPath { kind, segments }
44 }
45
46 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
47 name_ref.as_name().into()
48 }
49
50 /// Converts an `tt::Ident` into a single-identifier `Path`.
51 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
52 ident.as_name().into()
53 }
54
55 /// Calls `cb` with all paths, represented by this use item.
56 pub(crate) fn expand_use_item(
57 item_src: InFile<ast::UseItem>,
58 hygiene: &Hygiene,
59 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
60 ) {
61 if let Some(tree) = item_src.value.use_tree() {
62 lower::lower_use_tree(None, tree, hygiene, &mut cb);
63 }
64 }
65
66 pub fn is_ident(&self) -> bool {
67 self.kind == PathKind::Plain && self.segments.len() == 1
68 }
69
70 pub fn is_self(&self) -> bool {
71 self.kind == PathKind::Super(0) && self.segments.is_empty()
72 }
73
74 /// If this path is a single identifier, like `foo`, return its name.
75 pub fn as_ident(&self) -> Option<&Name> {
76 if self.kind != PathKind::Plain || self.segments.len() > 1 {
77 return None;
78 }
79 self.segments.first()
80 }
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
84pub struct Path {
85 /// Type based path like `<T>::foo`.
86 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
87 type_anchor: Option<Box<TypeRef>>,
88 mod_path: ModPath,
89 /// Invariant: the same len as self.path.segments
90 generic_args: Vec<Option<Arc<GenericArgs>>>,
28} 91}
29 92
30/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 93/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
31/// can (in the future) also include bindings of associated types, like in 94/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
32/// `Iterator<Item = Foo>`.
33#[derive(Debug, Clone, PartialEq, Eq, Hash)] 95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct GenericArgs { 96pub struct GenericArgs {
35 pub args: Vec<GenericArg>, 97 pub args: Vec<GenericArg>,
@@ -50,234 +112,111 @@ pub enum GenericArg {
50 // or lifetime... 112 // or lifetime...
51} 113}
52 114
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathKind {
55 Plain,
56 Self_,
57 Super,
58 Crate,
59 // Absolute path
60 Abs,
61 // Type based path like `<T>::foo`
62 Type(Box<TypeRef>),
63 // `$crate` from macro expansion
64 DollarCrate(CrateId),
65}
66
67impl Path { 115impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub(crate) fn expand_use_item(
70 item_src: Source<ast::UseItem>,
71 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.value.use_tree() {
75 expand_use_tree(None, tree, hygiene, &mut cb);
76 }
77 }
78
79 pub(crate) fn from_simple_segments(
80 kind: PathKind,
81 segments: impl IntoIterator<Item = Name>,
82 ) -> Path {
83 Path {
84 kind,
85 segments: segments
86 .into_iter()
87 .map(|name| PathSegment { name, args_and_bindings: None })
88 .collect(),
89 }
90 }
91
92 /// Converts an `ast::Path` to `Path`. Works with use trees. 116 /// Converts an `ast::Path` to `Path`. Works with use trees.
93 /// DEPRECATED: It does not handle `$crate` from macro call. 117 /// DEPRECATED: It does not handle `$crate` from macro call.
94 pub fn from_ast(path: ast::Path) -> Option<Path> { 118 pub fn from_ast(path: ast::Path) -> Option<Path> {
95 Path::from_src(path, &Hygiene::new_unhygienic()) 119 lower::lower_path(path, &Hygiene::new_unhygienic())
96 } 120 }
97 121
98 /// Converts an `ast::Path` to `Path`. Works with use trees. 122 /// Converts an `ast::Path` to `Path`. Works with use trees.
99 /// It correctly handles `$crate` based path from macro call. 123 /// It correctly handles `$crate` based path from macro call.
100 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 124 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
101 let mut kind = PathKind::Plain; 125 lower::lower_path(path, hygiene)
102 let mut segments = Vec::new();
103 loop {
104 let segment = path.segment()?;
105
106 if segment.has_colon_colon() {
107 kind = PathKind::Abs;
108 }
109
110 match segment.kind()? {
111 ast::PathSegmentKind::Name(name_ref) => {
112 // FIXME: this should just return name
113 match hygiene.name_ref_to_name(name_ref) {
114 Either::A(name) => {
115 let args = segment
116 .type_arg_list()
117 .and_then(GenericArgs::from_ast)
118 .or_else(|| {
119 GenericArgs::from_fn_like_path_ast(
120 segment.param_list(),
121 segment.ret_type(),
122 )
123 })
124 .map(Arc::new);
125 let segment = PathSegment { name, args_and_bindings: args };
126 segments.push(segment);
127 }
128 Either::B(crate_id) => {
129 kind = PathKind::DollarCrate(crate_id);
130 break;
131 }
132 }
133 }
134 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
135 assert!(path.qualifier().is_none()); // this can only occur at the first segment
136
137 let self_type = TypeRef::from_ast(type_ref?);
138
139 match trait_ref {
140 // <T>::foo
141 None => {
142 kind = PathKind::Type(Box::new(self_type));
143 }
144 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
145 Some(trait_ref) => {
146 let path = Path::from_src(trait_ref.path()?, hygiene)?;
147 kind = path.kind;
148 let mut prefix_segments = path.segments;
149 prefix_segments.reverse();
150 segments.extend(prefix_segments);
151 // Insert the type reference (T in the above example) as Self parameter for the trait
152 let mut last_segment = segments.last_mut()?;
153 if last_segment.args_and_bindings.is_none() {
154 last_segment.args_and_bindings =
155 Some(Arc::new(GenericArgs::empty()));
156 };
157 let args = last_segment.args_and_bindings.as_mut().unwrap();
158 let mut args_inner = Arc::make_mut(args);
159 args_inner.has_self_type = true;
160 args_inner.args.insert(0, GenericArg::Type(self_type));
161 }
162 }
163 }
164 ast::PathSegmentKind::CrateKw => {
165 kind = PathKind::Crate;
166 break;
167 }
168 ast::PathSegmentKind::SelfKw => {
169 kind = PathKind::Self_;
170 break;
171 }
172 ast::PathSegmentKind::SuperKw => {
173 kind = PathKind::Super;
174 break;
175 }
176 }
177 path = match qualifier(&path) {
178 Some(it) => it,
179 None => break,
180 };
181 }
182 segments.reverse();
183 return Some(Path { kind, segments });
184
185 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
186 if let Some(q) = path.qualifier() {
187 return Some(q);
188 }
189 // FIXME: this bottom up traversal is not too precise.
190 // Should we handle do a top-down analysis, recording results?
191 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
192 let use_tree = use_tree_list.parent_use_tree();
193 use_tree.path()
194 }
195 } 126 }
196 127
197 /// Converts an `ast::NameRef` into a single-identifier `Path`. 128 /// Converts an `ast::NameRef` into a single-identifier `Path`.
198 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { 129 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
199 name_ref.as_name().into() 130 Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
200 } 131 }
201 132
202 /// `true` is this path is a single identifier, like `foo` 133 pub fn kind(&self) -> &PathKind {
203 pub fn is_ident(&self) -> bool { 134 &self.mod_path.kind
204 self.kind == PathKind::Plain && self.segments.len() == 1
205 } 135 }
206 136
207 /// `true` if this path is just a standalone `self` 137 pub fn type_anchor(&self) -> Option<&TypeRef> {
208 pub fn is_self(&self) -> bool { 138 self.type_anchor.as_deref()
209 self.kind == PathKind::Self_ && self.segments.is_empty()
210 } 139 }
211 140
212 /// If this path is a single identifier, like `foo`, return its name. 141 pub fn segments(&self) -> PathSegments<'_> {
213 pub fn as_ident(&self) -> Option<&Name> { 142 PathSegments {
214 if self.kind != PathKind::Plain || self.segments.len() > 1 { 143 segments: self.mod_path.segments.as_slice(),
215 return None; 144 generic_args: self.generic_args.as_slice(),
216 } 145 }
217 self.segments.first().map(|s| &s.name)
218 } 146 }
219 147
220 pub fn expand_macro_expr(&self) -> Option<Name> { 148 pub fn mod_path(&self) -> &ModPath {
221 self.as_ident().and_then(|name| Some(name.clone())) 149 &self.mod_path
222 } 150 }
223 151
224 pub fn is_type_relative(&self) -> bool { 152 pub fn qualifier(&self) -> Option<Path> {
225 match self.kind { 153 if self.mod_path.is_ident() {
226 PathKind::Type(_) => true, 154 return None;
227 _ => false,
228 } 155 }
156 let res = Path {
157 type_anchor: self.type_anchor.clone(),
158 mod_path: ModPath {
159 kind: self.mod_path.kind.clone(),
160 segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
161 },
162 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
163 };
164 Some(res)
229 } 165 }
230} 166}
231 167
232impl GenericArgs { 168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
233 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { 169pub struct PathSegment<'a> {
234 let mut args = Vec::new(); 170 pub name: &'a Name,
235 for type_arg in node.type_args() { 171 pub args_and_bindings: Option<&'a GenericArgs>,
236 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 172}
237 args.push(GenericArg::Type(type_ref)); 173
238 } 174pub struct PathSegments<'a> {
239 // lifetimes ignored for now 175 segments: &'a [Name],
240 let mut bindings = Vec::new(); 176 generic_args: &'a [Option<Arc<GenericArgs>>],
241 for assoc_type_arg in node.assoc_type_args() { 177}
242 if let Some(name_ref) = assoc_type_arg.name_ref() { 178
243 let name = name_ref.as_name(); 179impl<'a> PathSegments<'a> {
244 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); 180 pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
245 bindings.push((name, type_ref)); 181 pub fn is_empty(&self) -> bool {
246 } 182 self.len() == 0
247 } 183 }
248 if args.is_empty() && bindings.is_empty() { 184 pub fn len(&self) -> usize {
249 None 185 self.segments.len()
250 } else { 186 }
251 Some(GenericArgs { args, has_self_type: false, bindings }) 187 pub fn first(&self) -> Option<PathSegment<'a>> {
252 } 188 self.get(0)
189 }
190 pub fn last(&self) -> Option<PathSegment<'a>> {
191 self.get(self.len().checked_sub(1)?)
192 }
193 pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
194 assert_eq!(self.segments.len(), self.generic_args.len());
195 let res = PathSegment {
196 name: self.segments.get(idx)?,
197 args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
198 };
199 Some(res)
200 }
201 pub fn skip(&self, len: usize) -> PathSegments<'a> {
202 assert_eq!(self.segments.len(), self.generic_args.len());
203 PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
204 }
205 pub fn take(&self, len: usize) -> PathSegments<'a> {
206 assert_eq!(self.segments.len(), self.generic_args.len());
207 PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
208 }
209 pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
210 self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
211 name,
212 args_and_bindings: args.as_ref().map(|it| &**it),
213 })
253 } 214 }
215}
254 216
255 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) 217impl GenericArgs {
256 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). 218 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
257 pub(crate) fn from_fn_like_path_ast( 219 lower::lower_generic_args(node)
258 params: Option<ast::ParamList>,
259 ret_type: Option<ast::RetType>,
260 ) -> Option<GenericArgs> {
261 let mut args = Vec::new();
262 let mut bindings = Vec::new();
263 if let Some(params) = params {
264 let mut param_types = Vec::new();
265 for param in params.params() {
266 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
267 param_types.push(type_ref);
268 }
269 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
270 args.push(arg);
271 }
272 if let Some(ret_type) = ret_type {
273 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
274 bindings.push((name::OUTPUT_TYPE, type_ref))
275 }
276 if args.is_empty() && bindings.is_empty() {
277 None
278 } else {
279 Some(GenericArgs { args, has_self_type: false, bindings })
280 }
281 } 220 }
282 221
283 pub(crate) fn empty() -> GenericArgs { 222 pub(crate) fn empty() -> GenericArgs {
@@ -287,137 +226,51 @@ impl GenericArgs {
287 226
288impl From<Name> for Path { 227impl From<Name> for Path {
289 fn from(name: Name) -> Path { 228 fn from(name: Name) -> Path {
290 Path::from_simple_segments(PathKind::Plain, iter::once(name)) 229 Path {
230 type_anchor: None,
231 mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
232 generic_args: vec![None],
233 }
291 } 234 }
292} 235}
293 236
294fn expand_use_tree( 237impl From<Name> for ModPath {
295 prefix: Option<Path>, 238 fn from(name: Name) -> ModPath {
296 tree: ast::UseTree, 239 ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
297 hygiene: &Hygiene,
298 cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
299) {
300 if let Some(use_tree_list) = tree.use_tree_list() {
301 let prefix = match tree.path() {
302 // E.g. use something::{{{inner}}};
303 None => prefix,
304 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
305 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
306 Some(path) => match convert_path(prefix, path, hygiene) {
307 Some(it) => Some(it),
308 None => return, // FIXME: report errors somewhere
309 },
310 };
311 for child_tree in use_tree_list.use_trees() {
312 expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
313 }
314 } else {
315 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
316 if let Some(ast_path) = tree.path() {
317 // Handle self in a path.
318 // E.g. `use something::{self, <...>}`
319 if ast_path.qualifier().is_none() {
320 if let Some(segment) = ast_path.segment() {
321 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
322 if let Some(prefix) = prefix {
323 cb(prefix, &tree, false, alias);
324 return;
325 }
326 }
327 }
328 }
329 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
330 let is_glob = tree.has_star();
331 cb(path, &tree, is_glob, alias)
332 }
333 // FIXME: report errors somewhere
334 // We get here if we do
335 }
336 } 240 }
337} 241}
338 242
339fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 243pub use hir_expand::name as __name;
340 let prefix = if let Some(qual) = path.qualifier() { 244
341 Some(convert_path(prefix, qual, hygiene)?) 245#[macro_export]
342 } else { 246macro_rules! __known_path {
343 prefix 247 (std::iter::IntoIterator) => {};
344 }; 248 (std::result::Result) => {};
345 249 (std::ops::Range) => {};
346 let segment = path.segment()?; 250 (std::ops::RangeFrom) => {};
347 let res = match segment.kind()? { 251 (std::ops::RangeFull) => {};
348 ast::PathSegmentKind::Name(name_ref) => { 252 (std::ops::RangeTo) => {};
349 match hygiene.name_ref_to_name(name_ref) { 253 (std::ops::RangeToInclusive) => {};
350 Either::A(name) => { 254 (std::ops::RangeInclusive) => {};
351 // no type args in use 255 (std::boxed::Box) => {};
352 let mut res = prefix.unwrap_or_else(|| Path { 256 (std::future::Future) => {};
353 kind: PathKind::Plain, 257 (std::ops::Try) => {};
354 segments: Vec::with_capacity(1), 258 (std::ops::Neg) => {};
355 }); 259 (std::ops::Not) => {};
356 res.segments.push(PathSegment { 260 (std::ops::Index) => {};
357 name, 261 ($path:path) => {
358 args_and_bindings: None, // no type args in use 262 compile_error!("Please register your known path in the path module")
359 });
360 res
361 }
362 Either::B(crate_id) => {
363 return Some(Path::from_simple_segments(
364 PathKind::DollarCrate(crate_id),
365 iter::empty(),
366 ))
367 }
368 }
369 }
370 ast::PathSegmentKind::CrateKw => {
371 if prefix.is_some() {
372 return None;
373 }
374 Path::from_simple_segments(PathKind::Crate, iter::empty())
375 }
376 ast::PathSegmentKind::SelfKw => {
377 if prefix.is_some() {
378 return None;
379 }
380 Path::from_simple_segments(PathKind::Self_, iter::empty())
381 }
382 ast::PathSegmentKind::SuperKw => {
383 if prefix.is_some() {
384 return None;
385 }
386 Path::from_simple_segments(PathKind::Super, iter::empty())
387 }
388 ast::PathSegmentKind::Type { .. } => {
389 // not allowed in imports
390 return None;
391 }
392 }; 263 };
393 Some(res)
394} 264}
395 265
396pub mod known { 266#[macro_export]
397 use hir_expand::name; 267macro_rules! __path {
398 268 ($start:ident $(:: $seg:ident)*) => ({
399 use super::{Path, PathKind}; 269 $crate::__known_path!($start $(:: $seg)*);
400 270 $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
401 pub fn std_iter_into_iterator() -> Path { 271 $crate::path::__name![$start], $($crate::path::__name![$seg],)*
402 Path::from_simple_segments( 272 ])
403 PathKind::Abs, 273 });
404 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
405 )
406 }
407
408 pub fn std_ops_try() -> Path {
409 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
410 }
411
412 pub fn std_result_result() -> Path {
413 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
414 }
415
416 pub fn std_future_future() -> Path {
417 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
418 }
419
420 pub fn std_boxed_box() -> Path {
421 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
422 }
423} 274}
275
276pub use crate::__path as path;
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
new file mode 100644
index 000000000..62aafd508
--- /dev/null
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -0,0 +1,178 @@
1//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
2
3mod lower_use;
4
5use std::sync::Arc;
6
7use either::Either;
8use hir_expand::{
9 hygiene::Hygiene,
10 name::{name, AsName},
11};
12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner};
13
14use crate::{
15 path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
16 type_ref::TypeRef,
17};
18
19pub(super) use lower_use::lower_use_tree;
20
21/// Converts an `ast::Path` to `Path`. Works with use trees.
22/// It correctly handles `$crate` based path from macro call.
23pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
24 let mut kind = PathKind::Plain;
25 let mut type_anchor = None;
26 let mut segments = Vec::new();
27 let mut generic_args = Vec::new();
28 loop {
29 let segment = path.segment()?;
30
31 if segment.has_colon_colon() {
32 kind = PathKind::Abs;
33 }
34
35 match segment.kind()? {
36 ast::PathSegmentKind::Name(name_ref) => {
37 // FIXME: this should just return name
38 match hygiene.name_ref_to_name(name_ref) {
39 Either::Left(name) => {
40 let args = segment
41 .type_arg_list()
42 .and_then(lower_generic_args)
43 .or_else(|| {
44 lower_generic_args_from_fn_path(
45 segment.param_list(),
46 segment.ret_type(),
47 )
48 })
49 .map(Arc::new);
50 segments.push(name);
51 generic_args.push(args)
52 }
53 Either::Right(crate_id) => {
54 kind = PathKind::DollarCrate(crate_id);
55 break;
56 }
57 }
58 }
59 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
60 assert!(path.qualifier().is_none()); // this can only occur at the first segment
61
62 let self_type = TypeRef::from_ast(type_ref?);
63
64 match trait_ref {
65 // <T>::foo
66 None => {
67 type_anchor = Some(Box::new(self_type));
68 kind = PathKind::Plain;
69 }
70 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
71 Some(trait_ref) => {
72 let path = Path::from_src(trait_ref.path()?, hygiene)?;
73 kind = path.mod_path.kind;
74
75 let mut prefix_segments = path.mod_path.segments;
76 prefix_segments.reverse();
77 segments.extend(prefix_segments);
78
79 let mut prefix_args = path.generic_args;
80 prefix_args.reverse();
81 generic_args.extend(prefix_args);
82
83 // Insert the type reference (T in the above example) as Self parameter for the trait
84 let last_segment = generic_args.last_mut()?;
85 if last_segment.is_none() {
86 *last_segment = Some(Arc::new(GenericArgs::empty()));
87 };
88 let args = last_segment.as_mut().unwrap();
89 let mut args_inner = Arc::make_mut(args);
90 args_inner.has_self_type = true;
91 args_inner.args.insert(0, GenericArg::Type(self_type));
92 }
93 }
94 }
95 ast::PathSegmentKind::CrateKw => {
96 kind = PathKind::Crate;
97 break;
98 }
99 ast::PathSegmentKind::SelfKw => {
100 kind = PathKind::Super(0);
101 break;
102 }
103 ast::PathSegmentKind::SuperKw => {
104 kind = PathKind::Super(1);
105 break;
106 }
107 }
108 path = match qualifier(&path) {
109 Some(it) => it,
110 None => break,
111 };
112 }
113 segments.reverse();
114 generic_args.reverse();
115 let mod_path = ModPath { kind, segments };
116 return Some(Path { type_anchor, mod_path, generic_args });
117
118 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
119 if let Some(q) = path.qualifier() {
120 return Some(q);
121 }
122 // FIXME: this bottom up traversal is not too precise.
123 // Should we handle do a top-down analysis, recording results?
124 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
125 let use_tree = use_tree_list.parent_use_tree();
126 use_tree.path()
127 }
128}
129
130pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> {
131 let mut args = Vec::new();
132 for type_arg in node.type_args() {
133 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
134 args.push(GenericArg::Type(type_ref));
135 }
136 // lifetimes ignored for now
137 let mut bindings = Vec::new();
138 for assoc_type_arg in node.assoc_type_args() {
139 if let Some(name_ref) = assoc_type_arg.name_ref() {
140 let name = name_ref.as_name();
141 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
142 bindings.push((name, type_ref));
143 }
144 }
145 if args.is_empty() && bindings.is_empty() {
146 None
147 } else {
148 Some(GenericArgs { args, has_self_type: false, bindings })
149 }
150}
151
152/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
153/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
154fn lower_generic_args_from_fn_path(
155 params: Option<ast::ParamList>,
156 ret_type: Option<ast::RetType>,
157) -> Option<GenericArgs> {
158 let mut args = Vec::new();
159 let mut bindings = Vec::new();
160 if let Some(params) = params {
161 let mut param_types = Vec::new();
162 for param in params.params() {
163 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
164 param_types.push(type_ref);
165 }
166 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
167 args.push(arg);
168 }
169 if let Some(ret_type) = ret_type {
170 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
171 bindings.push((name![Output], type_ref))
172 }
173 if args.is_empty() && bindings.is_empty() {
174 None
175 } else {
176 Some(GenericArgs { args, has_self_type: false, bindings })
177 }
178}
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
new file mode 100644
index 000000000..3218eaf0a
--- /dev/null
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -0,0 +1,118 @@
1//! Lowers a single complex use like `use foo::{bar, baz};` into a list of paths like
2//! `foo::bar`, `foo::baz`;
3
4use std::iter;
5
6use either::Either;
7use hir_expand::{
8 hygiene::Hygiene,
9 name::{AsName, Name},
10};
11use ra_syntax::ast::{self, NameOwner};
12use test_utils::tested_by;
13
14use crate::path::{ModPath, PathKind};
15
16pub(crate) fn lower_use_tree(
17 prefix: Option<ModPath>,
18 tree: ast::UseTree,
19 hygiene: &Hygiene,
20 cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<Name>),
21) {
22 if let Some(use_tree_list) = tree.use_tree_list() {
23 let prefix = match tree.path() {
24 // E.g. use something::{{{inner}}};
25 None => prefix,
26 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
27 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
28 Some(path) => match convert_path(prefix, path, hygiene) {
29 Some(it) => Some(it),
30 None => return, // FIXME: report errors somewhere
31 },
32 };
33 for child_tree in use_tree_list.use_trees() {
34 lower_use_tree(prefix.clone(), child_tree, hygiene, cb);
35 }
36 } else {
37 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
38 let is_glob = tree.has_star();
39 if let Some(ast_path) = tree.path() {
40 // Handle self in a path.
41 // E.g. `use something::{self, <...>}`
42 if ast_path.qualifier().is_none() {
43 if let Some(segment) = ast_path.segment() {
44 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
45 if let Some(prefix) = prefix {
46 cb(prefix, &tree, false, alias);
47 return;
48 }
49 }
50 }
51 }
52 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
53 cb(path, &tree, is_glob, alias)
54 }
55 // FIXME: report errors somewhere
56 // We get here if we do
57 } else if is_glob {
58 tested_by!(glob_enum_group);
59 if let Some(prefix) = prefix {
60 cb(prefix, &tree, is_glob, None)
61 }
62 }
63 }
64}
65
66fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
67 let prefix = if let Some(qual) = path.qualifier() {
68 Some(convert_path(prefix, qual, hygiene)?)
69 } else {
70 prefix
71 };
72
73 let segment = path.segment()?;
74 let res = match segment.kind()? {
75 ast::PathSegmentKind::Name(name_ref) => {
76 match hygiene.name_ref_to_name(name_ref) {
77 Either::Left(name) => {
78 // no type args in use
79 let mut res = prefix.unwrap_or_else(|| ModPath {
80 kind: PathKind::Plain,
81 segments: Vec::with_capacity(1),
82 });
83 res.segments.push(name);
84 res
85 }
86 Either::Right(crate_id) => {
87 return Some(ModPath::from_simple_segments(
88 PathKind::DollarCrate(crate_id),
89 iter::empty(),
90 ))
91 }
92 }
93 }
94 ast::PathSegmentKind::CrateKw => {
95 if prefix.is_some() {
96 return None;
97 }
98 ModPath::from_simple_segments(PathKind::Crate, iter::empty())
99 }
100 ast::PathSegmentKind::SelfKw => {
101 if prefix.is_some() {
102 return None;
103 }
104 ModPath::from_simple_segments(PathKind::Super(0), iter::empty())
105 }
106 ast::PathSegmentKind::SuperKw => {
107 if prefix.is_some() {
108 return None;
109 }
110 ModPath::from_simple_segments(PathKind::Super(1), iter::empty())
111 }
112 ast::PathSegmentKind::Type { .. } => {
113 // not allowed in imports
114 return None;
115 }
116 };
117 Some(res)
118}
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 00e866bf9..3a5105028 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -11,8 +11,6 @@ use crate::ModuleDefId;
11pub struct PerNs { 11pub struct PerNs {
12 pub types: Option<ModuleDefId>, 12 pub types: Option<ModuleDefId>,
13 pub values: Option<ModuleDefId>, 13 pub values: Option<ModuleDefId>,
14 /// Since macros has different type, many methods simply ignore it.
15 /// We can only use special method like `get_macros` to access it.
16 pub macros: Option<MacroDefId>, 14 pub macros: Option<MacroDefId>,
17} 15}
18 16
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 0847f6dcf..cf3c33d78 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -2,7 +2,7 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_expand::{ 4use hir_expand::{
5 name::{self, Name}, 5 name::{name, Name},
6 MacroDefId, 6 MacroDefId,
7}; 7};
8use ra_db::CrateId; 8use ra_db::CrateId;
@@ -10,20 +10,23 @@ use rustc_hash::FxHashSet;
10 10
11use crate::{ 11use crate::{
12 body::scope::{ExprScopes, ScopeId}, 12 body::scope::{ExprScopes, ScopeId},
13 body::Body,
13 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
14 db::DefDatabase, 15 db::DefDatabase,
15 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
16 generics::GenericParams, 17 generics::GenericParams,
18 item_scope::BuiltinShadowMode,
17 nameres::CrateDefMap, 19 nameres::CrateDefMap,
18 path::{Path, PathKind}, 20 path::{ModPath, PathKind},
19 per_ns::PerNs, 21 per_ns::PerNs,
20 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, 22 AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId,
21 GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, 23 FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
22 StructId, TraitId, TypeAliasId, 24 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
23}; 25};
24 26
25#[derive(Debug, Clone, Default)] 27#[derive(Debug, Clone, Default)]
26pub struct Resolver { 28pub struct Resolver {
29 // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton?
27 scopes: Vec<Scope>, 30 scopes: Vec<Scope>,
28} 31}
29 32
@@ -53,12 +56,14 @@ enum Scope {
53 AdtScope(AdtId), 56 AdtScope(AdtId),
54 /// Local bindings 57 /// Local bindings
55 ExprScope(ExprScope), 58 ExprScope(ExprScope),
59 /// Temporary hack to support local items.
60 LocalItemsScope(Arc<Body>),
56} 61}
57 62
58#[derive(Debug, Clone, PartialEq, Eq, Hash)] 63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59pub enum TypeNs { 64pub enum TypeNs {
60 SelfType(ImplId), 65 SelfType(ImplId),
61 GenericParam(u32), 66 GenericParam(TypeParamId),
62 AdtId(AdtId), 67 AdtId(AdtId),
63 AdtSelfType(AdtId), 68 AdtSelfType(AdtId),
64 // Yup, enum variants are added to the types ns, but any usage of variant as 69 // Yup, enum variants are added to the types ns, but any usage of variant as
@@ -90,8 +95,8 @@ pub enum ValueNs {
90 95
91impl Resolver { 96impl Resolver {
92 /// Resolve known trait from std, like `std::futures::Future` 97 /// Resolve known trait from std, like `std::futures::Future`
93 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> { 98 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &ModPath) -> Option<TraitId> {
94 let res = self.resolve_module_path(db, path).take_types()?; 99 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
95 match res { 100 match res {
96 ModuleDefId::TraitId(it) => Some(it), 101 ModuleDefId::TraitId(it) => Some(it),
97 _ => None, 102 _ => None,
@@ -99,8 +104,8 @@ impl Resolver {
99 } 104 }
100 105
101 /// Resolve known struct from std, like `std::boxed::Box` 106 /// Resolve known struct from std, like `std::boxed::Box`
102 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> { 107 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &ModPath) -> Option<StructId> {
103 let res = self.resolve_module_path(db, path).take_types()?; 108 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
104 match res { 109 match res {
105 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), 110 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
106 _ => None, 111 _ => None,
@@ -108,87 +113,116 @@ impl Resolver {
108 } 113 }
109 114
110 /// Resolve known enum from std, like `std::result::Result` 115 /// Resolve known enum from std, like `std::result::Result`
111 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> { 116 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &ModPath) -> Option<EnumId> {
112 let res = self.resolve_module_path(db, path).take_types()?; 117 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
113 match res { 118 match res {
114 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), 119 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
115 _ => None, 120 _ => None,
116 } 121 }
117 } 122 }
118 123
119 /// pub only for source-binder 124 fn resolve_module_path(
120 pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs { 125 &self,
126 db: &impl DefDatabase,
127 path: &ModPath,
128 shadow: BuiltinShadowMode,
129 ) -> PerNs {
121 let (item_map, module) = match self.module() { 130 let (item_map, module) = match self.module() {
122 Some(it) => it, 131 Some(it) => it,
123 None => return PerNs::none(), 132 None => return PerNs::none(),
124 }; 133 };
125 let (module_res, segment_index) = item_map.resolve_path(db, module, path); 134 let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow);
126 if segment_index.is_some() { 135 if segment_index.is_some() {
127 return PerNs::none(); 136 return PerNs::none();
128 } 137 }
129 module_res 138 module_res
130 } 139 }
131 140
141 pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &ModPath) -> PerNs {
142 self.resolve_module_path(db, path, BuiltinShadowMode::Module)
143 }
144
132 pub fn resolve_path_in_type_ns( 145 pub fn resolve_path_in_type_ns(
133 &self, 146 &self,
134 db: &impl DefDatabase, 147 db: &impl DefDatabase,
135 path: &Path, 148 path: &ModPath,
136 ) -> Option<(TypeNs, Option<usize>)> { 149 ) -> Option<(TypeNs, Option<usize>)> {
137 if path.is_type_relative() { 150 let first_name = path.segments.first()?;
138 return None;
139 }
140 let first_name = &path.segments.first()?.name;
141 let skip_to_mod = path.kind != PathKind::Plain; 151 let skip_to_mod = path.kind != PathKind::Plain;
142 for scope in self.scopes.iter().rev() { 152 for scope in self.scopes.iter().rev() {
143 match scope { 153 match scope {
144 Scope::ExprScope(_) => continue, 154 Scope::ExprScope(_) => continue,
145 Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, 155 Scope::GenericParams { .. }
156 | Scope::ImplBlockScope(_)
157 | Scope::LocalItemsScope(_)
158 if skip_to_mod =>
159 {
160 continue
161 }
146 162
147 Scope::GenericParams { params, .. } => { 163 Scope::GenericParams { params, def } => {
148 if let Some(param) = params.find_by_name(first_name) { 164 if let Some(local_id) = params.find_by_name(first_name) {
149 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 165 let idx = if path.segments.len() == 1 { None } else { Some(1) };
150 return Some((TypeNs::GenericParam(param.idx), idx)); 166 return Some((
167 TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
168 idx,
169 ));
151 } 170 }
152 } 171 }
153 Scope::ImplBlockScope(impl_) => { 172 Scope::ImplBlockScope(impl_) => {
154 if first_name == &name::SELF_TYPE { 173 if first_name == &name![Self] {
155 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 174 let idx = if path.segments.len() == 1 { None } else { Some(1) };
156 return Some((TypeNs::SelfType(*impl_), idx)); 175 return Some((TypeNs::SelfType(*impl_), idx));
157 } 176 }
158 } 177 }
159 Scope::AdtScope(adt) => { 178 Scope::AdtScope(adt) => {
160 if first_name == &name::SELF_TYPE { 179 if first_name == &name![Self] {
161 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 180 let idx = if path.segments.len() == 1 { None } else { Some(1) };
162 return Some((TypeNs::AdtSelfType(*adt), idx)); 181 return Some((TypeNs::AdtSelfType(*adt), idx));
163 } 182 }
164 } 183 }
165 Scope::ModuleScope(m) => { 184 Scope::ModuleScope(m) => {
166 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 185 let (module_def, idx) = m.crate_def_map.resolve_path(
167 let res = match module_def.take_types()? { 186 db,
168 ModuleDefId::AdtId(it) => TypeNs::AdtId(it), 187 m.module_id,
169 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), 188 &path,
170 189 BuiltinShadowMode::Other,
171 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), 190 );
172 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), 191 let res = to_type_ns(module_def)?;
173
174 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
175
176 ModuleDefId::FunctionId(_)
177 | ModuleDefId::ConstId(_)
178 | ModuleDefId::StaticId(_)
179 | ModuleDefId::ModuleId(_) => return None,
180 };
181 return Some((res, idx)); 192 return Some((res, idx));
182 } 193 }
194 Scope::LocalItemsScope(body) => {
195 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
196 if let Some(res) = to_type_ns(def) {
197 return Some((res, None));
198 }
199 }
183 } 200 }
184 } 201 }
185 None 202 return None;
203 fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
204 let res = match per_ns.take_types()? {
205 ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
206 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
207
208 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
209 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
210
211 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
212
213 ModuleDefId::FunctionId(_)
214 | ModuleDefId::ConstId(_)
215 | ModuleDefId::StaticId(_)
216 | ModuleDefId::ModuleId(_) => return None,
217 };
218 Some(res)
219 }
186 } 220 }
187 221
188 pub fn resolve_path_in_type_ns_fully( 222 pub fn resolve_path_in_type_ns_fully(
189 &self, 223 &self,
190 db: &impl DefDatabase, 224 db: &impl DefDatabase,
191 path: &Path, 225 path: &ModPath,
192 ) -> Option<TypeNs> { 226 ) -> Option<TypeNs> {
193 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; 227 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
194 if unresolved.is_some() { 228 if unresolved.is_some() {
@@ -197,17 +231,14 @@ impl Resolver {
197 Some(res) 231 Some(res)
198 } 232 }
199 233
200 pub fn resolve_path_in_value_ns<'p>( 234 pub fn resolve_path_in_value_ns(
201 &self, 235 &self,
202 db: &impl DefDatabase, 236 db: &impl DefDatabase,
203 path: &'p Path, 237 path: &ModPath,
204 ) -> Option<ResolveValueResult> { 238 ) -> Option<ResolveValueResult> {
205 if path.is_type_relative() {
206 return None;
207 }
208 let n_segments = path.segments.len(); 239 let n_segments = path.segments.len();
209 let tmp = name::SELF_PARAM; 240 let tmp = name![self];
210 let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; 241 let first_name = if path.is_self() { &tmp } else { &path.segments.first()? };
211 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 242 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
212 for scope in self.scopes.iter().rev() { 243 for scope in self.scopes.iter().rev() {
213 match scope { 244 match scope {
@@ -215,6 +246,7 @@ impl Resolver {
215 | Scope::ExprScope(_) 246 | Scope::ExprScope(_)
216 | Scope::GenericParams { .. } 247 | Scope::GenericParams { .. }
217 | Scope::ImplBlockScope(_) 248 | Scope::ImplBlockScope(_)
249 | Scope::LocalItemsScope(_)
218 if skip_to_mod => 250 if skip_to_mod =>
219 { 251 {
220 continue 252 continue
@@ -233,22 +265,22 @@ impl Resolver {
233 } 265 }
234 Scope::ExprScope(_) => continue, 266 Scope::ExprScope(_) => continue,
235 267
236 Scope::GenericParams { params, .. } if n_segments > 1 => { 268 Scope::GenericParams { params, def } if n_segments > 1 => {
237 if let Some(param) = params.find_by_name(first_name) { 269 if let Some(local_id) = params.find_by_name(first_name) {
238 let ty = TypeNs::GenericParam(param.idx); 270 let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
239 return Some(ResolveValueResult::Partial(ty, 1)); 271 return Some(ResolveValueResult::Partial(ty, 1));
240 } 272 }
241 } 273 }
242 Scope::GenericParams { .. } => continue, 274 Scope::GenericParams { .. } => continue,
243 275
244 Scope::ImplBlockScope(impl_) if n_segments > 1 => { 276 Scope::ImplBlockScope(impl_) if n_segments > 1 => {
245 if first_name == &name::SELF_TYPE { 277 if first_name == &name![Self] {
246 let ty = TypeNs::SelfType(*impl_); 278 let ty = TypeNs::SelfType(*impl_);
247 return Some(ResolveValueResult::Partial(ty, 1)); 279 return Some(ResolveValueResult::Partial(ty, 1));
248 } 280 }
249 } 281 }
250 Scope::AdtScope(adt) if n_segments > 1 => { 282 Scope::AdtScope(adt) if n_segments > 1 => {
251 if first_name == &name::SELF_TYPE { 283 if first_name == &name![Self] {
252 let ty = TypeNs::AdtSelfType(*adt); 284 let ty = TypeNs::AdtSelfType(*adt);
253 return Some(ResolveValueResult::Partial(ty, 1)); 285 return Some(ResolveValueResult::Partial(ty, 1));
254 } 286 }
@@ -256,23 +288,15 @@ impl Resolver {
256 Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue, 288 Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
257 289
258 Scope::ModuleScope(m) => { 290 Scope::ModuleScope(m) => {
259 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 291 let (module_def, idx) = m.crate_def_map.resolve_path(
292 db,
293 m.module_id,
294 &path,
295 BuiltinShadowMode::Other,
296 );
260 return match idx { 297 return match idx {
261 None => { 298 None => {
262 let value = match module_def.take_values()? { 299 let value = to_value_ns(module_def)?;
263 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
264 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
265 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
266 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
267 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
268
269 ModuleDefId::AdtId(AdtId::EnumId(_))
270 | ModuleDefId::AdtId(AdtId::UnionId(_))
271 | ModuleDefId::TraitId(_)
272 | ModuleDefId::TypeAliasId(_)
273 | ModuleDefId::BuiltinType(_)
274 | ModuleDefId::ModuleId(_) => return None,
275 };
276 Some(ResolveValueResult::ValueNs(value)) 300 Some(ResolveValueResult::ValueNs(value))
277 } 301 }
278 Some(idx) => { 302 Some(idx) => {
@@ -292,15 +316,39 @@ impl Resolver {
292 } 316 }
293 }; 317 };
294 } 318 }
319 Scope::LocalItemsScope(body) => {
320 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
321 if let Some(res) = to_value_ns(def) {
322 return Some(ResolveValueResult::ValueNs(res));
323 }
324 }
295 } 325 }
296 } 326 }
297 None 327 return None;
328
329 fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
330 let res = match per_ns.take_values()? {
331 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
332 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
333 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
334 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
335 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
336
337 ModuleDefId::AdtId(AdtId::EnumId(_))
338 | ModuleDefId::AdtId(AdtId::UnionId(_))
339 | ModuleDefId::TraitId(_)
340 | ModuleDefId::TypeAliasId(_)
341 | ModuleDefId::BuiltinType(_)
342 | ModuleDefId::ModuleId(_) => return None,
343 };
344 Some(res)
345 }
298 } 346 }
299 347
300 pub fn resolve_path_in_value_ns_fully( 348 pub fn resolve_path_in_value_ns_fully(
301 &self, 349 &self,
302 db: &impl DefDatabase, 350 db: &impl DefDatabase,
303 path: &Path, 351 path: &ModPath,
304 ) -> Option<ValueNs> { 352 ) -> Option<ValueNs> {
305 match self.resolve_path_in_value_ns(db, path)? { 353 match self.resolve_path_in_value_ns(db, path)? {
306 ResolveValueResult::ValueNs(it) => Some(it), 354 ResolveValueResult::ValueNs(it) => Some(it),
@@ -308,9 +356,13 @@ impl Resolver {
308 } 356 }
309 } 357 }
310 358
311 pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 359 pub fn resolve_path_as_macro(
360 &self,
361 db: &impl DefDatabase,
362 path: &ModPath,
363 ) -> Option<MacroDefId> {
312 let (item_map, module) = self.module()?; 364 let (item_map, module) = self.module()?;
313 item_map.resolve_path(db, module, path).0.take_macros() 365 item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros()
314 } 366 }
315 367
316 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { 368 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -350,6 +402,7 @@ impl Resolver {
350 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { 402 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a {
351 self.scopes 403 self.scopes
352 .iter() 404 .iter()
405 .rev()
353 .filter_map(|scope| match scope { 406 .filter_map(|scope| match scope {
354 Scope::GenericParams { params, .. } => Some(params), 407 Scope::GenericParams { params, .. } => Some(params),
355 _ => None, 408 _ => None,
@@ -358,14 +411,14 @@ impl Resolver {
358 } 411 }
359 412
360 pub fn generic_def(&self) -> Option<GenericDefId> { 413 pub fn generic_def(&self) -> Option<GenericDefId> {
361 self.scopes.iter().find_map(|scope| match scope { 414 self.scopes.iter().rev().find_map(|scope| match scope {
362 Scope::GenericParams { def, .. } => Some(*def), 415 Scope::GenericParams { def, .. } => Some(*def),
363 _ => None, 416 _ => None,
364 }) 417 })
365 } 418 }
366 419
367 pub fn body_owner(&self) -> Option<DefWithBodyId> { 420 pub fn body_owner(&self) -> Option<DefWithBodyId> {
368 self.scopes.iter().find_map(|scope| match scope { 421 self.scopes.iter().rev().find_map(|scope| match scope {
369 Scope::ExprScope(it) => Some(it.owner), 422 Scope::ExprScope(it) => Some(it.owner),
370 _ => None, 423 _ => None,
371 }) 424 })
@@ -376,7 +429,7 @@ pub enum ScopeDef {
376 PerNs(PerNs), 429 PerNs(PerNs),
377 ImplSelfType(ImplId), 430 ImplSelfType(ImplId),
378 AdtSelfType(AdtId), 431 AdtSelfType(AdtId),
379 GenericParam(u32), 432 GenericParam(TypeParamId),
380 Local(PatId), 433 Local(PatId),
381} 434}
382 435
@@ -391,8 +444,8 @@ impl Scope {
391 // def: m.module.into(), 444 // def: m.module.into(),
392 // }), 445 // }),
393 // ); 446 // );
394 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { 447 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, def)| {
395 f(name.clone(), ScopeDef::PerNs(res.def)); 448 f(name.clone(), ScopeDef::PerNs(def));
396 }); 449 });
397 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { 450 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
398 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); 451 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_)));
@@ -402,21 +455,29 @@ impl Scope {
402 }); 455 });
403 if let Some(prelude) = m.crate_def_map.prelude { 456 if let Some(prelude) = m.crate_def_map.prelude {
404 let prelude_def_map = db.crate_def_map(prelude.krate); 457 let prelude_def_map = db.crate_def_map(prelude.krate);
405 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, res)| { 458 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
406 f(name.clone(), ScopeDef::PerNs(res.def)); 459 f(name.clone(), ScopeDef::PerNs(def));
407 }); 460 });
408 } 461 }
409 } 462 }
410 Scope::GenericParams { params, .. } => { 463 Scope::LocalItemsScope(body) => {
411 for param in params.params.iter() { 464 body.item_scope.entries_without_primitives().for_each(|(name, def)| {
412 f(param.name.clone(), ScopeDef::GenericParam(param.idx)) 465 f(name.clone(), ScopeDef::PerNs(def));
466 })
467 }
468 Scope::GenericParams { params, def } => {
469 for (local_id, param) in params.types.iter() {
470 f(
471 param.name.clone(),
472 ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
473 )
413 } 474 }
414 } 475 }
415 Scope::ImplBlockScope(i) => { 476 Scope::ImplBlockScope(i) => {
416 f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into())); 477 f(name![Self], ScopeDef::ImplSelfType((*i).into()));
417 } 478 }
418 Scope::AdtScope(i) => { 479 Scope::AdtScope(i) => {
419 f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into())); 480 f(name![Self], ScopeDef::AdtSelfType((*i).into()));
420 } 481 }
421 Scope::ExprScope(scope) => { 482 Scope::ExprScope(scope) => {
422 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { 483 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
@@ -439,6 +500,7 @@ pub fn resolver_for_scope(
439 scope_id: Option<ScopeId>, 500 scope_id: Option<ScopeId>,
440) -> Resolver { 501) -> Resolver {
441 let mut r = owner.resolver(db); 502 let mut r = owner.resolver(db);
503 r = r.push_local_items_scope(db.body(owner));
442 let scopes = db.expr_scopes(owner); 504 let scopes = db.expr_scopes(owner);
443 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); 505 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
444 for scope in scope_chain.into_iter().rev() { 506 for scope in scope_chain.into_iter().rev() {
@@ -455,7 +517,7 @@ impl Resolver {
455 517
456 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { 518 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
457 let params = db.generic_params(def); 519 let params = db.generic_params(def);
458 if params.params.is_empty() { 520 if params.types.is_empty() {
459 self 521 self
460 } else { 522 } else {
461 self.push_scope(Scope::GenericParams { def, params }) 523 self.push_scope(Scope::GenericParams { def, params })
@@ -474,6 +536,10 @@ impl Resolver {
474 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) 536 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
475 } 537 }
476 538
539 fn push_local_items_scope(self, body: Arc<Body>) -> Resolver {
540 self.push_scope(Scope::LocalItemsScope(body))
541 }
542
477 fn push_expr_scope( 543 fn push_expr_scope(
478 self, 544 self,
479 owner: DefWithBodyId, 545 owner: DefWithBodyId,
@@ -498,7 +564,7 @@ impl HasResolver for ModuleId {
498 564
499impl HasResolver for TraitId { 565impl HasResolver for TraitId {
500 fn resolver(self, db: &impl DefDatabase) -> Resolver { 566 fn resolver(self, db: &impl DefDatabase) -> Resolver {
501 self.module(db).resolver(db).push_generic_params_scope(db, self.into()) 567 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
502 } 568 }
503} 569}
504 570
@@ -518,16 +584,6 @@ impl HasResolver for FunctionId {
518 } 584 }
519} 585}
520 586
521impl HasResolver for DefWithBodyId {
522 fn resolver(self, db: &impl DefDatabase) -> Resolver {
523 match self {
524 DefWithBodyId::ConstId(c) => c.resolver(db),
525 DefWithBodyId::FunctionId(f) => f.resolver(db),
526 DefWithBodyId::StaticId(s) => s.resolver(db),
527 }
528 }
529}
530
531impl HasResolver for ConstId { 587impl HasResolver for ConstId {
532 fn resolver(self, db: &impl DefDatabase) -> Resolver { 588 fn resolver(self, db: &impl DefDatabase) -> Resolver {
533 self.lookup(db).container.resolver(db) 589 self.lookup(db).container.resolver(db)
@@ -546,12 +602,41 @@ impl HasResolver for TypeAliasId {
546 } 602 }
547} 603}
548 604
605impl HasResolver for ImplId {
606 fn resolver(self, db: &impl DefDatabase) -> Resolver {
607 self.lookup(db)
608 .container
609 .resolver(db)
610 .push_generic_params_scope(db, self.into())
611 .push_impl_block_scope(self)
612 }
613}
614
615impl HasResolver for DefWithBodyId {
616 fn resolver(self, db: &impl DefDatabase) -> Resolver {
617 match self {
618 DefWithBodyId::ConstId(c) => c.resolver(db),
619 DefWithBodyId::FunctionId(f) => f.resolver(db),
620 DefWithBodyId::StaticId(s) => s.resolver(db),
621 }
622 }
623}
624
549impl HasResolver for ContainerId { 625impl HasResolver for ContainerId {
550 fn resolver(self, db: &impl DefDatabase) -> Resolver { 626 fn resolver(self, db: &impl DefDatabase) -> Resolver {
551 match self { 627 match self {
552 ContainerId::TraitId(it) => it.resolver(db),
553 ContainerId::ImplId(it) => it.resolver(db),
554 ContainerId::ModuleId(it) => it.resolver(db), 628 ContainerId::ModuleId(it) => it.resolver(db),
629 ContainerId::DefWithBodyId(it) => it.resolver(db),
630 }
631 }
632}
633
634impl HasResolver for AssocContainerId {
635 fn resolver(self, db: &impl DefDatabase) -> Resolver {
636 match self {
637 AssocContainerId::ContainerId(it) => it.resolver(db),
638 AssocContainerId::TraitId(it) => it.resolver(db),
639 AssocContainerId::ImplId(it) => it.resolver(db),
555 } 640 }
556 } 641 }
557} 642}
@@ -570,11 +655,12 @@ impl HasResolver for GenericDefId {
570 } 655 }
571} 656}
572 657
573impl HasResolver for ImplId { 658impl HasResolver for VariantId {
574 fn resolver(self, db: &impl DefDatabase) -> Resolver { 659 fn resolver(self, db: &impl DefDatabase) -> Resolver {
575 self.module(db) 660 match self {
576 .resolver(db) 661 VariantId::EnumVariantId(it) => it.parent.resolver(db),
577 .push_generic_params_scope(db, self.into()) 662 VariantId::StructId(it) => it.resolver(db),
578 .push_impl_block_scope(self) 663 VariantId::UnionId(it) => it.resolver(db),
664 }
579 } 665 }
580} 666}
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs
new file mode 100644
index 000000000..499375b80
--- /dev/null
+++ b/crates/ra_hir_def/src/src.rs
@@ -0,0 +1,36 @@
1//! Utilities for mapping between hir IDs and the surface syntax.
2
3use hir_expand::InFile;
4use ra_arena::map::ArenaMap;
5use ra_syntax::AstNode;
6
7use crate::{db::DefDatabase, AssocItemLoc, ItemLoc};
8
9pub trait HasSource {
10 type Value;
11 fn source(&self, db: &impl DefDatabase) -> InFile<Self::Value>;
12}
13
14impl<N: AstNode> HasSource for AssocItemLoc<N> {
15 type Value = N;
16
17 fn source(&self, db: &impl DefDatabase) -> InFile<N> {
18 let node = self.ast_id.to_node(db);
19 InFile::new(self.ast_id.file_id, node)
20 }
21}
22
23impl<N: AstNode> HasSource for ItemLoc<N> {
24 type Value = N;
25
26 fn source(&self, db: &impl DefDatabase) -> InFile<N> {
27 let node = self.ast_id.to_node(db);
28 InFile::new(self.ast_id.file_id, node)
29 }
30}
31
32pub trait HasChildSource {
33 type ChildId;
34 type Value;
35 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>>;
36}
diff --git a/crates/ra_hir_def/src/trace.rs b/crates/ra_hir_def/src/trace.rs
index 2bcd707bc..9769e88df 100644
--- a/crates/ra_hir_def/src/trace.rs
+++ b/crates/ra_hir_def/src/trace.rs
@@ -18,10 +18,6 @@ pub(crate) struct Trace<ID: ArenaId, T, V> {
18} 18}
19 19
20impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> { 20impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> {
21 pub(crate) fn new() -> Trace<ID, T, V> {
22 Trace { arena: Some(Arena::default()), map: Some(ArenaMap::default()), len: 0 }
23 }
24
25 pub(crate) fn new_for_arena() -> Trace<ID, T, V> { 21 pub(crate) fn new_for_arena() -> Trace<ID, T, V> {
26 Trace { arena: Some(Arena::default()), map: None, len: 0 } 22 Trace { arena: Some(Arena::default()), map: None, len: 0 }
27 } 23 }
@@ -52,8 +48,4 @@ impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> {
52 pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> { 48 pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> {
53 self.map.take().unwrap() 49 self.map.take().unwrap()
54 } 50 }
55
56 pub(crate) fn into_arena_and_map(mut self) -> (Arena<ID, T>, ArenaMap<ID, V>) {
57 (self.arena.take().unwrap(), self.map.take().unwrap())
58 }
59} 51}
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index c60152a79..3ae4376dc 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -9,6 +9,7 @@ doctest = false
9 9
10[dependencies] 10[dependencies]
11log = "0.4.5" 11log = "0.4.5"
12either = "1.5"
12 13
13ra_arena = { path = "../ra_arena" } 14ra_arena = { path = "../ra_arena" }
14ra_db = { path = "../ra_db" } 15ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index cb464c3ff..a764bdf24 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -39,6 +39,16 @@ impl<N: AstNode> Hash for FileAstId<N> {
39 } 39 }
40} 40}
41 41
42impl<N: AstNode> FileAstId<N> {
43 // Can't make this a From implementation because of coherence
44 pub fn upcast<M: AstNode>(self) -> FileAstId<M>
45 where
46 M: From<N>,
47 {
48 FileAstId { raw: self.raw, _ty: PhantomData }
49 }
50}
51
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43struct ErasedFileAstId(RawId); 53struct ErasedFileAstId(RawId);
44impl_arena_id!(ErasedFileAstId); 54impl_arena_id!(ErasedFileAstId);
@@ -53,7 +63,7 @@ impl AstIdMap {
53 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { 63 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
54 assert!(node.parent().is_none()); 64 assert!(node.parent().is_none());
55 let mut res = AstIdMap { arena: Arena::default() }; 65 let mut res = AstIdMap { arena: Arena::default() };
56 // By walking the tree in bread-first order we make sure that parents 66 // By walking the tree in breadth-first order we make sure that parents
57 // get lower ids then children. That is, adding a new child does not 67 // get lower ids then children. That is, adding a new child does not
58 // change parent's id. This means that, say, adding a new function to a 68 // change parent's id. This means that, say, adding a new function to a
59 // trait does not change ids of top-level items, which helps caching. 69 // trait does not change ids of top-level items, which helps caching.
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
new file mode 100644
index 000000000..62c60e336
--- /dev/null
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -0,0 +1,321 @@
1//! Builtin derives.
2
3use log::debug;
4
5use ra_parser::FragmentKind;
6use ra_syntax::{
7 ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner},
8 match_ast,
9};
10
11use crate::db::AstDatabase;
12use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind};
13
14macro_rules! register_builtin {
15 ( $($trait:ident => $expand:ident),* ) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub enum BuiltinDeriveExpander {
18 $($trait),*
19 }
20
21 impl BuiltinDeriveExpander {
22 pub fn expand(
23 &self,
24 db: &dyn AstDatabase,
25 id: MacroCallId,
26 tt: &tt::Subtree,
27 ) -> Result<tt::Subtree, mbe::ExpandError> {
28 let expander = match *self {
29 $( BuiltinDeriveExpander::$trait => $expand, )*
30 };
31 expander(db, id, tt)
32 }
33 }
34
35 pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
36 let kind = match ident {
37 $( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )*
38 _ => return None,
39 };
40
41 Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) })
42 }
43 };
44}
45
46register_builtin! {
47 Copy => copy_expand,
48 Clone => clone_expand,
49 Default => default_expand,
50 Debug => debug_expand,
51 Hash => hash_expand,
52 Ord => ord_expand,
53 PartialOrd => partial_ord_expand,
54 Eq => eq_expand,
55 PartialEq => partial_eq_expand
56}
57
58struct BasicAdtInfo {
59 name: tt::Ident,
60 type_params: usize,
61}
62
63fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
64 let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, FragmentKind::Items)?; // FragmentKind::Items doesn't parse attrs?
65 let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
66 debug!("derive node didn't parse");
67 mbe::ExpandError::UnexpectedToken
68 })?;
69 let item = macro_items.items().next().ok_or_else(|| {
70 debug!("no module item parsed");
71 mbe::ExpandError::NoMatchingRule
72 })?;
73 let node = item.syntax();
74 let (name, params) = match_ast! {
75 match node {
76 ast::StructDef(it) => { (it.name(), it.type_param_list()) },
77 ast::EnumDef(it) => { (it.name(), it.type_param_list()) },
78 ast::UnionDef(it) => { (it.name(), it.type_param_list()) },
79 _ => {
80 debug!("unexpected node is {:?}", node);
81 return Err(mbe::ExpandError::ConversionError)
82 },
83 }
84 };
85 let name = name.ok_or_else(|| {
86 debug!("parsed item has no name");
87 mbe::ExpandError::NoMatchingRule
88 })?;
89 let name_token_id = token_map.token_by_range(name.syntax().text_range()).ok_or_else(|| {
90 debug!("name token not found");
91 mbe::ExpandError::ConversionError
92 })?;
93 let name_token = tt::Ident { id: name_token_id, text: name.text().clone() };
94 let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
95 Ok(BasicAdtInfo { name: name_token, type_params })
96}
97
98fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
99 let mut result = Vec::<tt::TokenTree>::new();
100 result.push(
101 tt::Leaf::Punct(tt::Punct {
102 char: '<',
103 spacing: tt::Spacing::Alone,
104 id: tt::TokenId::unspecified(),
105 })
106 .into(),
107 );
108 for i in 0..n {
109 if i > 0 {
110 result.push(
111 tt::Leaf::Punct(tt::Punct {
112 char: ',',
113 spacing: tt::Spacing::Alone,
114 id: tt::TokenId::unspecified(),
115 })
116 .into(),
117 );
118 }
119 result.push(
120 tt::Leaf::Ident(tt::Ident {
121 id: tt::TokenId::unspecified(),
122 text: format!("T{}", i).into(),
123 })
124 .into(),
125 );
126 result.extend(bound.iter().cloned());
127 }
128 result.push(
129 tt::Leaf::Punct(tt::Punct {
130 char: '>',
131 spacing: tt::Spacing::Alone,
132 id: tt::TokenId::unspecified(),
133 })
134 .into(),
135 );
136 result
137}
138
139fn expand_simple_derive(
140 tt: &tt::Subtree,
141 trait_path: tt::Subtree,
142) -> Result<tt::Subtree, mbe::ExpandError> {
143 let info = parse_adt(tt)?;
144 let name = info.name;
145 let trait_path_clone = trait_path.token_trees.clone();
146 let bound = (quote! { : ##trait_path_clone }).token_trees;
147 let type_params = make_type_args(info.type_params, bound);
148 let type_args = make_type_args(info.type_params, Vec::new());
149 let trait_path = trait_path.token_trees;
150 let expanded = quote! {
151 impl ##type_params ##trait_path for #name ##type_args {}
152 };
153 Ok(expanded)
154}
155
156fn copy_expand(
157 _db: &dyn AstDatabase,
158 _id: MacroCallId,
159 tt: &tt::Subtree,
160) -> Result<tt::Subtree, mbe::ExpandError> {
161 expand_simple_derive(tt, quote! { std::marker::Copy })
162}
163
164fn clone_expand(
165 _db: &dyn AstDatabase,
166 _id: MacroCallId,
167 tt: &tt::Subtree,
168) -> Result<tt::Subtree, mbe::ExpandError> {
169 expand_simple_derive(tt, quote! { std::clone::Clone })
170}
171
172fn default_expand(
173 _db: &dyn AstDatabase,
174 _id: MacroCallId,
175 tt: &tt::Subtree,
176) -> Result<tt::Subtree, mbe::ExpandError> {
177 expand_simple_derive(tt, quote! { std::default::Default })
178}
179
180fn debug_expand(
181 _db: &dyn AstDatabase,
182 _id: MacroCallId,
183 tt: &tt::Subtree,
184) -> Result<tt::Subtree, mbe::ExpandError> {
185 expand_simple_derive(tt, quote! { std::fmt::Debug })
186}
187
188fn hash_expand(
189 _db: &dyn AstDatabase,
190 _id: MacroCallId,
191 tt: &tt::Subtree,
192) -> Result<tt::Subtree, mbe::ExpandError> {
193 expand_simple_derive(tt, quote! { std::hash::Hash })
194}
195
196fn eq_expand(
197 _db: &dyn AstDatabase,
198 _id: MacroCallId,
199 tt: &tt::Subtree,
200) -> Result<tt::Subtree, mbe::ExpandError> {
201 expand_simple_derive(tt, quote! { std::cmp::Eq })
202}
203
204fn partial_eq_expand(
205 _db: &dyn AstDatabase,
206 _id: MacroCallId,
207 tt: &tt::Subtree,
208) -> Result<tt::Subtree, mbe::ExpandError> {
209 expand_simple_derive(tt, quote! { std::cmp::PartialEq })
210}
211
212fn ord_expand(
213 _db: &dyn AstDatabase,
214 _id: MacroCallId,
215 tt: &tt::Subtree,
216) -> Result<tt::Subtree, mbe::ExpandError> {
217 expand_simple_derive(tt, quote! { std::cmp::Ord })
218}
219
220fn partial_ord_expand(
221 _db: &dyn AstDatabase,
222 _id: MacroCallId,
223 tt: &tt::Subtree,
224) -> Result<tt::Subtree, mbe::ExpandError> {
225 expand_simple_derive(tt, quote! { std::cmp::PartialOrd })
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc};
232 use ra_db::{fixture::WithFixture, SourceDatabase};
233
234 fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String {
235 let (db, file_id) = TestDB::with_single_file(&s);
236 let parsed = db.parse(file_id);
237 let items: Vec<_> =
238 parsed.syntax_node().descendants().filter_map(|it| ast::ModuleItem::cast(it)).collect();
239
240 let ast_id_map = db.ast_id_map(file_id.into());
241
242 // the first one should be a macro_rules
243 let def =
244 MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(expander) };
245
246 let loc = MacroCallLoc {
247 def,
248 kind: MacroCallKind::Attr(AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]))),
249 };
250
251 let id = db.intern_macro(loc);
252 let parsed = db.parse_or_expand(id.as_file()).unwrap();
253
254 // FIXME text() for syntax nodes parsed from token tree looks weird
255 // because there's no whitespace, see below
256 parsed.text().to_string()
257 }
258
259 #[test]
260 fn test_copy_expand_simple() {
261 let expanded = expand_builtin_derive(
262 r#"
263 #[derive(Copy)]
264 struct Foo;
265"#,
266 BuiltinDeriveExpander::Copy,
267 );
268
269 assert_eq!(expanded, "impl <>std::marker::CopyforFoo <>{}");
270 }
271
272 #[test]
273 fn test_copy_expand_with_type_params() {
274 let expanded = expand_builtin_derive(
275 r#"
276 #[derive(Copy)]
277 struct Foo<A, B>;
278"#,
279 BuiltinDeriveExpander::Copy,
280 );
281
282 assert_eq!(
283 expanded,
284 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
285 );
286 }
287
288 #[test]
289 fn test_copy_expand_with_lifetimes() {
290 let expanded = expand_builtin_derive(
291 r#"
292 #[derive(Copy)]
293 struct Foo<A, B, 'a, 'b>;
294"#,
295 BuiltinDeriveExpander::Copy,
296 );
297
298 // We currently just ignore lifetimes
299
300 assert_eq!(
301 expanded,
302 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
303 );
304 }
305
306 #[test]
307 fn test_clone_expand() {
308 let expanded = expand_builtin_derive(
309 r#"
310 #[derive(Clone)]
311 struct Foo<A, B>;
312"#,
313 BuiltinDeriveExpander::Clone,
314 );
315
316 assert_eq!(
317 expanded,
318 "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}"
319 );
320 }
321}
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index d370dfb34..2c119269c 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -2,8 +2,7 @@
2use crate::db::AstDatabase; 2use crate::db::AstDatabase;
3use crate::{ 3use crate::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, TextUnit,
6 TextUnit,
7}; 6};
8 7
9use crate::quote; 8use crate::quote;
@@ -27,6 +26,13 @@ macro_rules! register_builtin {
27 }; 26 };
28 expander(db, id, tt) 27 expander(db, id, tt)
29 } 28 }
29
30 fn by_name(ident: &name::Name) -> Option<BuiltinFnLikeExpander> {
31 match ident {
32 $( id if id == &name::name![$name] => Some(BuiltinFnLikeExpander::$kind), )*
33 _ => return None,
34 }
35 }
30 } 36 }
31 37
32 pub fn find_builtin_macro( 38 pub fn find_builtin_macro(
@@ -34,22 +40,25 @@ macro_rules! register_builtin {
34 krate: CrateId, 40 krate: CrateId,
35 ast_id: AstId<ast::MacroCall>, 41 ast_id: AstId<ast::MacroCall>,
36 ) -> Option<MacroDefId> { 42 ) -> Option<MacroDefId> {
37 let kind = match ident { 43 let kind = BuiltinFnLikeExpander::by_name(ident)?;
38 $( id if id == &name::$name => BuiltinFnLikeExpander::$kind, )*
39 _ => return None,
40 };
41 44
42 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) }) 45 Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind) })
43 } 46 }
44 }; 47 };
45} 48}
46 49
47register_builtin! { 50register_builtin! {
48 (COLUMN_MACRO, Column) => column_expand, 51 (column, Column) => column_expand,
49 (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, 52 (compile_error, CompileError) => compile_error_expand,
50 (FILE_MACRO, File) => file_expand, 53 (file, File) => file_expand,
51 (LINE_MACRO, Line) => line_expand, 54 (line, Line) => line_expand,
52 (STRINGIFY_MACRO, Stringify) => stringify_expand 55 (stringify, Stringify) => stringify_expand,
56 (format_args, FormatArgs) => format_args_expand,
57 (env, Env) => env_expand,
58 (option_env, OptionEnv) => option_env_expand,
59 // format_args_nl only differs in that it adds a newline in the end,
60 // so we use the same stub expansion for now
61 (format_args_nl, FormatArgsNl) => format_args_expand
53} 62}
54 63
55fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 64fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
@@ -82,12 +91,11 @@ fn line_expand(
82 _tt: &tt::Subtree, 91 _tt: &tt::Subtree,
83) -> Result<tt::Subtree, mbe::ExpandError> { 92) -> Result<tt::Subtree, mbe::ExpandError> {
84 let loc = db.lookup_intern_macro(id); 93 let loc = db.lookup_intern_macro(id);
85 let macro_call = loc.ast_id.to_node(db);
86 94
87 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 95 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
88 let arg_start = arg.syntax().text_range().start(); 96 let arg_start = arg.text_range().start();
89 97
90 let file = id.as_file(MacroFileKind::Expr); 98 let file = id.as_file();
91 let line_num = to_line_number(db, file, arg_start); 99 let line_num = to_line_number(db, file, arg_start);
92 100
93 let expanded = quote! { 101 let expanded = quote! {
@@ -103,11 +111,10 @@ fn stringify_expand(
103 _tt: &tt::Subtree, 111 _tt: &tt::Subtree,
104) -> Result<tt::Subtree, mbe::ExpandError> { 112) -> Result<tt::Subtree, mbe::ExpandError> {
105 let loc = db.lookup_intern_macro(id); 113 let loc = db.lookup_intern_macro(id);
106 let macro_call = loc.ast_id.to_node(db);
107 114
108 let macro_content = { 115 let macro_content = {
109 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 116 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
110 let macro_args = arg.syntax().clone(); 117 let macro_args = arg;
111 let text = macro_args.text(); 118 let text = macro_args.text();
112 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); 119 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')');
113 text.slice(without_parens).to_string() 120 text.slice(without_parens).to_string()
@@ -120,6 +127,28 @@ fn stringify_expand(
120 Ok(expanded) 127 Ok(expanded)
121} 128}
122 129
130fn env_expand(
131 _db: &dyn AstDatabase,
132 _id: MacroCallId,
133 _tt: &tt::Subtree,
134) -> Result<tt::Subtree, mbe::ExpandError> {
135 // dummy implementation for type-checking purposes
136 let expanded = quote! { "" };
137
138 Ok(expanded)
139}
140
141fn option_env_expand(
142 _db: &dyn AstDatabase,
143 _id: MacroCallId,
144 _tt: &tt::Subtree,
145) -> Result<tt::Subtree, mbe::ExpandError> {
146 // dummy implementation for type-checking purposes
147 let expanded = quote! { std::option::Option::None::<&str> };
148
149 Ok(expanded)
150}
151
123fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 152fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
124 // FIXME: Use expansion info 153 // FIXME: Use expansion info
125 let file_id = file.original_file(db); 154 let file_id = file.original_file(db);
@@ -137,7 +166,7 @@ fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize
137 if c == '\n' { 166 if c == '\n' {
138 break; 167 break;
139 } 168 }
140 col_num = col_num + 1; 169 col_num += 1;
141 } 170 }
142 col_num 171 col_num
143} 172}
@@ -148,12 +177,15 @@ fn column_expand(
148 _tt: &tt::Subtree, 177 _tt: &tt::Subtree,
149) -> Result<tt::Subtree, mbe::ExpandError> { 178) -> Result<tt::Subtree, mbe::ExpandError> {
150 let loc = db.lookup_intern_macro(id); 179 let loc = db.lookup_intern_macro(id);
151 let macro_call = loc.ast_id.to_node(db); 180 let macro_call = match loc.kind {
181 crate::MacroCallKind::FnLike(ast_id) => ast_id.to_node(db),
182 _ => panic!("column macro called as attr"),
183 };
152 184
153 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 185 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
154 let col_start = macro_call.syntax().text_range().start(); 186 let col_start = macro_call.syntax().text_range().start();
155 187
156 let file = id.as_file(MacroFileKind::Expr); 188 let file = id.as_file();
157 let col_num = to_col_number(db, file, col_start); 189 let col_num = to_col_number(db, file, col_start);
158 190
159 let expanded = quote! { 191 let expanded = quote! {
@@ -164,15 +196,10 @@ fn column_expand(
164} 196}
165 197
166fn file_expand( 198fn file_expand(
167 db: &dyn AstDatabase, 199 _db: &dyn AstDatabase,
168 id: MacroCallId, 200 _id: MacroCallId,
169 _tt: &tt::Subtree, 201 _tt: &tt::Subtree,
170) -> Result<tt::Subtree, mbe::ExpandError> { 202) -> Result<tt::Subtree, mbe::ExpandError> {
171 let loc = db.lookup_intern_macro(id);
172 let macro_call = loc.ast_id.to_node(db);
173
174 let _ = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
175
176 // FIXME: RA purposefully lacks knowledge of absolute file names 203 // FIXME: RA purposefully lacks knowledge of absolute file names
177 // so just return "". 204 // so just return "".
178 let file_name = ""; 205 let file_name = "";
@@ -204,13 +231,56 @@ fn compile_error_expand(
204 Err(mbe::ExpandError::BindingError("Must be a string".into())) 231 Err(mbe::ExpandError::BindingError("Must be a string".into()))
205} 232}
206 233
234fn format_args_expand(
235 _db: &dyn AstDatabase,
236 _id: MacroCallId,
237 tt: &tt::Subtree,
238) -> Result<tt::Subtree, mbe::ExpandError> {
239 // We expand `format_args!("", a1, a2)` to
240 // ```
241 // std::fmt::Arguments::new_v1(&[], &[
242 // std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
243 // std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
244 // ])
245 // ```,
246 // which is still not really correct, but close enough for now
247 let mut args = Vec::new();
248 let mut current = Vec::new();
249 for tt in tt.token_trees.iter().cloned() {
250 match tt {
251 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
252 args.push(current);
253 current = Vec::new();
254 }
255 _ => {
256 current.push(tt);
257 }
258 }
259 }
260 if !current.is_empty() {
261 args.push(current);
262 }
263 if args.is_empty() {
264 return Err(mbe::ExpandError::NoMatchingRule);
265 }
266 let _format_string = args.remove(0);
267 let arg_tts = args.into_iter().flat_map(|arg| {
268 quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), }
269 }.token_trees).collect::<Vec<_>>();
270 let expanded = quote! {
271 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
272 };
273 Ok(expanded)
274}
275
207#[cfg(test)] 276#[cfg(test)]
208mod tests { 277mod tests {
209 use super::*; 278 use super::*;
210 use crate::{test_db::TestDB, MacroCallLoc}; 279 use crate::{name::AsName, test_db::TestDB, MacroCallKind, MacroCallLoc};
211 use ra_db::{fixture::WithFixture, SourceDatabase}; 280 use ra_db::{fixture::WithFixture, SourceDatabase};
281 use ra_syntax::ast::NameOwner;
212 282
213 fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String { 283 fn expand_builtin_macro(s: &str) -> String {
214 let (db, file_id) = TestDB::with_single_file(&s); 284 let (db, file_id) = TestDB::with_single_file(&s);
215 let parsed = db.parse(file_id); 285 let parsed = db.parse(file_id);
216 let macro_calls: Vec<_> = 286 let macro_calls: Vec<_> =
@@ -218,20 +288,26 @@ mod tests {
218 288
219 let ast_id_map = db.ast_id_map(file_id.into()); 289 let ast_id_map = db.ast_id_map(file_id.into());
220 290
291 let expander =
292 BuiltinFnLikeExpander::by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
293
221 // the first one should be a macro_rules 294 // the first one should be a macro_rules
222 let def = MacroDefId { 295 let def = MacroDefId {
223 krate: CrateId(0), 296 krate: Some(CrateId(0)),
224 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0])), 297 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
225 kind: MacroDefKind::BuiltIn(expander), 298 kind: MacroDefKind::BuiltIn(expander),
226 }; 299 };
227 300
228 let loc = MacroCallLoc { 301 let loc = MacroCallLoc {
229 def, 302 def,
230 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[1])), 303 kind: MacroCallKind::FnLike(AstId::new(
304 file_id.into(),
305 ast_id_map.ast_id(&macro_calls[1]),
306 )),
231 }; 307 };
232 308
233 let id = db.intern_macro(loc); 309 let id = db.intern_macro(loc);
234 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Expr)).unwrap(); 310 let parsed = db.parse_or_expand(id.as_file()).unwrap();
235 311
236 parsed.text().to_string() 312 parsed.text().to_string()
237 } 313 }
@@ -240,25 +316,23 @@ mod tests {
240 fn test_column_expand() { 316 fn test_column_expand() {
241 let expanded = expand_builtin_macro( 317 let expanded = expand_builtin_macro(
242 r#" 318 r#"
243 #[rustc_builtin_macro] 319 #[rustc_builtin_macro]
244 macro_rules! column {() => {}} 320 macro_rules! column {() => {}}
245 column!() 321 column!()
246"#, 322 "#,
247 BuiltinFnLikeExpander::Column,
248 ); 323 );
249 324
250 assert_eq!(expanded, "9"); 325 assert_eq!(expanded, "13");
251 } 326 }
252 327
253 #[test] 328 #[test]
254 fn test_line_expand() { 329 fn test_line_expand() {
255 let expanded = expand_builtin_macro( 330 let expanded = expand_builtin_macro(
256 r#" 331 r#"
257 #[rustc_builtin_macro] 332 #[rustc_builtin_macro]
258 macro_rules! line {() => {}} 333 macro_rules! line {() => {}}
259 line!() 334 line!()
260"#, 335 "#,
261 BuiltinFnLikeExpander::Line,
262 ); 336 );
263 337
264 assert_eq!(expanded, "4"); 338 assert_eq!(expanded, "4");
@@ -268,25 +342,49 @@ mod tests {
268 fn test_stringify_expand() { 342 fn test_stringify_expand() {
269 let expanded = expand_builtin_macro( 343 let expanded = expand_builtin_macro(
270 r#" 344 r#"
271 #[rustc_builtin_macro] 345 #[rustc_builtin_macro]
272 macro_rules! stringify {() => {}} 346 macro_rules! stringify {() => {}}
273 stringify!(a b c) 347 stringify!(a b c)
274"#, 348 "#,
275 BuiltinFnLikeExpander::Stringify,
276 ); 349 );
277 350
278 assert_eq!(expanded, "\"a b c\""); 351 assert_eq!(expanded, "\"a b c\"");
279 } 352 }
280 353
281 #[test] 354 #[test]
355 fn test_env_expand() {
356 let expanded = expand_builtin_macro(
357 r#"
358 #[rustc_builtin_macro]
359 macro_rules! env {() => {}}
360 env!("TEST_ENV_VAR")
361 "#,
362 );
363
364 assert_eq!(expanded, "\"\"");
365 }
366
367 #[test]
368 fn test_option_env_expand() {
369 let expanded = expand_builtin_macro(
370 r#"
371 #[rustc_builtin_macro]
372 macro_rules! option_env {() => {}}
373 option_env!("TEST_ENV_VAR")
374 "#,
375 );
376
377 assert_eq!(expanded, "std::option::Option::None:: <&str>");
378 }
379
380 #[test]
282 fn test_file_expand() { 381 fn test_file_expand() {
283 let expanded = expand_builtin_macro( 382 let expanded = expand_builtin_macro(
284 r#" 383 r#"
285 #[rustc_builtin_macro] 384 #[rustc_builtin_macro]
286 macro_rules! file {() => {}} 385 macro_rules! file {() => {}}
287 file!() 386 file!()
288"#, 387 "#,
289 BuiltinFnLikeExpander::File,
290 ); 388 );
291 389
292 assert_eq!(expanded, "\"\""); 390 assert_eq!(expanded, "\"\"");
@@ -296,16 +394,34 @@ mod tests {
296 fn test_compile_error_expand() { 394 fn test_compile_error_expand() {
297 let expanded = expand_builtin_macro( 395 let expanded = expand_builtin_macro(
298 r#" 396 r#"
299 #[rustc_builtin_macro] 397 #[rustc_builtin_macro]
300 macro_rules! compile_error { 398 macro_rules! compile_error {
301 ($msg:expr) => ({ /* compiler built-in */ }); 399 ($msg:expr) => ({ /* compiler built-in */ });
302 ($msg:expr,) => ({ /* compiler built-in */ }) 400 ($msg:expr,) => ({ /* compiler built-in */ })
303 } 401 }
304 compile_error!("error!"); 402 compile_error!("error!");
305"#, 403 "#,
306 BuiltinFnLikeExpander::CompileError,
307 ); 404 );
308 405
309 assert_eq!(expanded, r#"loop{"error!"}"#); 406 assert_eq!(expanded, r#"loop{"error!"}"#);
310 } 407 }
408
409 #[test]
410 fn test_format_args_expand() {
411 let expanded = expand_builtin_macro(
412 r#"
413 #[rustc_builtin_macro]
414 macro_rules! format_args {
415 ($fmt:expr) => ({ /* compiler built-in */ });
416 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
417 }
418 format_args!("{} {:?}", arg1(a, b, c), arg2);
419 "#,
420 );
421
422 assert_eq!(
423 expanded,
424 r#"std::fmt::Arguments::new_v1(&[] ,&[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
425 );
426 }
311} 427}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 8e46fa177..2e12e126f 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,17 +6,18 @@ use mbe::MacroRules;
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr,
13 MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, 13 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
14}; 14};
15 15
16#[derive(Debug, Clone, Eq, PartialEq)] 16#[derive(Debug, Clone, Eq, PartialEq)]
17pub enum TokenExpander { 17pub enum TokenExpander {
18 MacroRules(mbe::MacroRules), 18 MacroRules(mbe::MacroRules),
19 Builtin(BuiltinFnLikeExpander), 19 Builtin(BuiltinFnLikeExpander),
20 BuiltinDerive(BuiltinDeriveExpander),
20} 21}
21 22
22impl TokenExpander { 23impl TokenExpander {
@@ -29,6 +30,7 @@ impl TokenExpander {
29 match self { 30 match self {
30 TokenExpander::MacroRules(it) => it.expand(tt), 31 TokenExpander::MacroRules(it) => it.expand(tt),
31 TokenExpander::Builtin(it) => it.expand(db, id, tt), 32 TokenExpander::Builtin(it) => it.expand(db, id, tt),
33 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
32 } 34 }
33 } 35 }
34 36
@@ -36,13 +38,15 @@ impl TokenExpander {
36 match self { 38 match self {
37 TokenExpander::MacroRules(it) => it.map_id_down(id), 39 TokenExpander::MacroRules(it) => it.map_id_down(id),
38 TokenExpander::Builtin(..) => id, 40 TokenExpander::Builtin(..) => id,
41 TokenExpander::BuiltinDerive(..) => id,
39 } 42 }
40 } 43 }
41 44
42 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 45 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
43 match self { 46 match self {
44 TokenExpander::MacroRules(it) => it.map_id_up(id), 47 TokenExpander::MacroRules(it) => it.map_id_up(id),
45 TokenExpander::Builtin(..) => (id, mbe::Origin::Def), 48 TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
49 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
46 } 50 }
47 } 51 }
48} 52}
@@ -76,7 +80,7 @@ pub(crate) fn macro_def(
76) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 80) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
77 match id.kind { 81 match id.kind {
78 MacroDefKind::Declarative => { 82 MacroDefKind::Declarative => {
79 let macro_call = id.ast_id.to_node(db); 83 let macro_call = id.ast_id?.to_node(db);
80 let arg = macro_call.token_tree()?; 84 let arg = macro_call.token_tree()?;
81 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 85 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
82 log::warn!("fail on macro_def to token tree: {:#?}", arg); 86 log::warn!("fail on macro_def to token tree: {:#?}", arg);
@@ -89,7 +93,10 @@ pub(crate) fn macro_def(
89 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 93 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
90 } 94 }
91 MacroDefKind::BuiltIn(expander) => { 95 MacroDefKind::BuiltIn(expander) => {
92 Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) 96 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
97 }
98 MacroDefKind::BuiltInDerive(expander) => {
99 Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
93 } 100 }
94 } 101 }
95} 102}
@@ -99,9 +106,8 @@ pub(crate) fn macro_arg(
99 id: MacroCallId, 106 id: MacroCallId,
100) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 107) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
101 let loc = db.lookup_intern_macro(id); 108 let loc = db.lookup_intern_macro(id);
102 let macro_call = loc.ast_id.to_node(db); 109 let arg = loc.kind.arg(db)?;
103 let arg = macro_call.token_tree()?; 110 let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?;
104 let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
105 Some(Arc::new((tt, tmap))) 111 Some(Arc::new((tt, tmap)))
106} 112}
107 113
@@ -148,11 +154,43 @@ pub(crate) fn parse_macro(
148 }) 154 })
149 .ok()?; 155 .ok()?;
150 156
151 let fragment_kind = match macro_file.macro_file_kind { 157 let fragment_kind = to_fragment_kind(db, macro_call_id);
152 MacroFileKind::Items => FragmentKind::Items, 158
153 MacroFileKind::Expr => FragmentKind::Expr,
154 MacroFileKind::Statements => FragmentKind::Statements,
155 };
156 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; 159 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
157 Some((parse, Arc::new(rev_token_map))) 160 Some((parse, Arc::new(rev_token_map)))
158} 161}
162
163/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
164/// FIXME: Not completed
165fn to_fragment_kind(db: &dyn AstDatabase, macro_call_id: MacroCallId) -> FragmentKind {
166 let syn = db.lookup_intern_macro(macro_call_id).kind.node(db).value;
167
168 let parent = match syn.parent() {
169 Some(it) => it,
170 None => {
171 // FIXME:
172 // If it is root, which means the parent HirFile
173 // MacroKindFile must be non-items
174 // return expr now.
175 return FragmentKind::Expr;
176 }
177 };
178
179 match parent.kind() {
180 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
181 LET_STMT => {
182 // FIXME: Handle Pattern
183 FragmentKind::Expr
184 }
185 // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
186 EXPR_STMT | BLOCK => FragmentKind::Expr,
187 ARG_LIST => FragmentKind::Expr,
188 TRY_EXPR => FragmentKind::Expr,
189 TUPLE_EXPR => FragmentKind::Expr,
190 ITEM_LIST => FragmentKind::Items,
191 _ => {
192 // Unknown , Just guess it is `Items`
193 FragmentKind::Items
194 }
195 }
196}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 3d37e9335..108c1e38c 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -18,11 +18,11 @@ use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; 19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
20 20
21use crate::{db::AstDatabase, Source}; 21use crate::{db::AstDatabase, InFile};
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> Source<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn highlight_range(&self) -> TextRange { 26 fn highlight_range(&self) -> TextRange {
27 self.source().value.range() 27 self.source().value.range()
28 } 28 }
diff --git a/crates/ra_hir_expand/src/either.rs b/crates/ra_hir_expand/src/either.rs
deleted file mode 100644
index 83583ef8b..000000000
--- a/crates/ra_hir_expand/src/either.rs
+++ /dev/null
@@ -1,54 +0,0 @@
1//! FIXME: write short doc here
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub enum Either<A, B> {
5 A(A),
6 B(B),
7}
8
9impl<A, B> Either<A, B> {
10 pub fn either<R, F1, F2>(self, f1: F1, f2: F2) -> R
11 where
12 F1: FnOnce(A) -> R,
13 F2: FnOnce(B) -> R,
14 {
15 match self {
16 Either::A(a) => f1(a),
17 Either::B(b) => f2(b),
18 }
19 }
20 pub fn map<U, V, F1, F2>(self, f1: F1, f2: F2) -> Either<U, V>
21 where
22 F1: FnOnce(A) -> U,
23 F2: FnOnce(B) -> V,
24 {
25 match self {
26 Either::A(a) => Either::A(f1(a)),
27 Either::B(b) => Either::B(f2(b)),
28 }
29 }
30 pub fn map_a<U, F>(self, f: F) -> Either<U, B>
31 where
32 F: FnOnce(A) -> U,
33 {
34 self.map(f, |it| it)
35 }
36 pub fn a(self) -> Option<A> {
37 match self {
38 Either::A(it) => Some(it),
39 Either::B(_) => None,
40 }
41 }
42 pub fn b(self) -> Option<B> {
43 match self {
44 Either::A(_) => None,
45 Either::B(it) => Some(it),
46 }
47 }
48 pub fn as_ref(&self) -> Either<&A, &B> {
49 match self {
50 Either::A(it) => Either::A(it),
51 Either::B(it) => Either::B(it),
52 }
53 }
54}
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs
index 379562a2c..2e8a533f7 100644
--- a/crates/ra_hir_expand/src/hygiene.rs
+++ b/crates/ra_hir_expand/src/hygiene.rs
@@ -2,12 +2,12 @@
2//! 2//!
3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at 3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
4//! this moment, this is horribly incomplete and handles only `$crate`. 4//! this moment, this is horribly incomplete and handles only `$crate`.
5use either::Either;
5use ra_db::CrateId; 6use ra_db::CrateId;
6use ra_syntax::ast; 7use ra_syntax::ast;
7 8
8use crate::{ 9use crate::{
9 db::AstDatabase, 10 db::AstDatabase,
10 either::Either,
11 name::{AsName, Name}, 11 name::{AsName, Name},
12 HirFileId, HirFileIdRepr, MacroDefKind, 12 HirFileId, HirFileIdRepr, MacroDefKind,
13}; 13};
@@ -25,8 +25,9 @@ impl Hygiene {
25 HirFileIdRepr::MacroFile(macro_file) => { 25 HirFileIdRepr::MacroFile(macro_file) => {
26 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 26 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
27 match loc.def.kind { 27 match loc.def.kind {
28 MacroDefKind::Declarative => Some(loc.def.krate), 28 MacroDefKind::Declarative => loc.def.krate,
29 MacroDefKind::BuiltIn(_) => None, 29 MacroDefKind::BuiltIn(_) => None,
30 MacroDefKind::BuiltInDerive(_) => None,
30 } 31 }
31 } 32 }
32 }; 33 };
@@ -41,9 +42,9 @@ impl Hygiene {
41 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { 42 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
42 if let Some(def_crate) = self.def_crate { 43 if let Some(def_crate) = self.def_crate {
43 if name_ref.text() == "$crate" { 44 if name_ref.text() == "$crate" {
44 return Either::B(def_crate); 45 return Either::Right(def_crate);
45 } 46 }
46 } 47 }
47 Either::A(name_ref.as_name()) 48 Either::Left(name_ref.as_name())
48 } 49 }
49} 50}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index b6a739cda..2fa5d5140 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -6,14 +6,14 @@
6 6
7pub mod db; 7pub mod db;
8pub mod ast_id_map; 8pub mod ast_id_map;
9pub mod either;
10pub mod name; 9pub mod name;
11pub mod hygiene; 10pub mod hygiene;
12pub mod diagnostics; 11pub mod diagnostics;
12pub mod builtin_derive;
13pub mod builtin_macro; 13pub mod builtin_macro;
14pub mod quote; 14pub mod quote;
15 15
16use std::hash::{Hash, Hasher}; 16use std::hash::Hash;
17use std::sync::Arc; 17use std::sync::Arc;
18 18
19use ra_db::{salsa, CrateId, FileId}; 19use ra_db::{salsa, CrateId, FileId};
@@ -24,6 +24,7 @@ use ra_syntax::{
24}; 24};
25 25
26use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_derive::BuiltinDeriveExpander;
27use crate::builtin_macro::BuiltinFnLikeExpander; 28use crate::builtin_macro::BuiltinFnLikeExpander;
28 29
29#[cfg(test)] 30#[cfg(test)]
@@ -70,7 +71,18 @@ impl HirFileId {
70 HirFileIdRepr::FileId(file_id) => file_id, 71 HirFileIdRepr::FileId(file_id) => file_id,
71 HirFileIdRepr::MacroFile(macro_file) => { 72 HirFileIdRepr::MacroFile(macro_file) => {
72 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 73 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
73 loc.ast_id.file_id().original_file(db) 74 loc.kind.file_id().original_file(db)
75 }
76 }
77 }
78
79 /// If this is a macro call, returns the syntax node of the call.
80 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
81 match self.0 {
82 HirFileIdRepr::FileId(_) => None,
83 HirFileIdRepr::MacroFile(macro_file) => {
84 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
85 Some(loc.kind.node(db))
74 } 86 }
75 } 87 }
76 } 88 }
@@ -82,17 +94,17 @@ impl HirFileId {
82 HirFileIdRepr::MacroFile(macro_file) => { 94 HirFileIdRepr::MacroFile(macro_file) => {
83 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); 95 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
84 96
85 let arg_tt = loc.ast_id.to_node(db).token_tree()?; 97 let arg_tt = loc.kind.arg(db)?;
86 let def_tt = loc.def.ast_id.to_node(db).token_tree()?; 98 let def_tt = loc.def.ast_id?.to_node(db).token_tree()?;
87 99
88 let macro_def = db.macro_def(loc.def)?; 100 let macro_def = db.macro_def(loc.def)?;
89 let (parse, exp_map) = db.parse_macro(macro_file)?; 101 let (parse, exp_map) = db.parse_macro(macro_file)?;
90 let macro_arg = db.macro_arg(macro_file.macro_call_id)?; 102 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
91 103
92 Some(ExpansionInfo { 104 Some(ExpansionInfo {
93 expanded: Source::new(self, parse.syntax_node()), 105 expanded: InFile::new(self, parse.syntax_node()),
94 arg: Source::new(loc.ast_id.file_id, arg_tt), 106 arg: InFile::new(loc.kind.file_id(), arg_tt),
95 def: Source::new(loc.ast_id.file_id, def_tt), 107 def: InFile::new(loc.def.ast_id?.file_id, def_tt),
96 macro_arg, 108 macro_arg,
97 macro_def, 109 macro_def,
98 exp_map, 110 exp_map,
@@ -105,14 +117,6 @@ impl HirFileId {
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct MacroFile { 118pub struct MacroFile {
107 macro_call_id: MacroCallId, 119 macro_call_id: MacroCallId,
108 macro_file_kind: MacroFileKind,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112pub enum MacroFileKind {
113 Items,
114 Expr,
115 Statements,
116} 120}
117 121
118/// `MacroCallId` identifies a particular macro invocation, like 122/// `MacroCallId` identifies a particular macro invocation, like
@@ -130,18 +134,20 @@ impl salsa::InternKey for MacroCallId {
130 134
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
132pub struct MacroDefId { 136pub struct MacroDefId {
133 pub krate: CrateId, 137 // FIXME: krate and ast_id are currently optional because we don't have a
134 pub ast_id: AstId<ast::MacroCall>, 138 // definition location for built-in derives. There is one, though: the
139 // standard library defines them. The problem is that it uses the new
140 // `macro` syntax for this, which we don't support yet. As soon as we do
141 // (which will probably require touching this code), we can instead use
142 // that (and also remove the hacks for resolving built-in derives).
143 pub krate: Option<CrateId>,
144 pub ast_id: Option<AstId<ast::MacroCall>>,
135 pub kind: MacroDefKind, 145 pub kind: MacroDefKind,
136} 146}
137 147
138impl MacroDefId { 148impl MacroDefId {
139 pub fn as_call_id( 149 pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId {
140 self, 150 db.intern_macro(MacroCallLoc { def: self, kind })
141 db: &dyn db::AstDatabase,
142 ast_id: AstId<ast::MacroCall>,
143 ) -> MacroCallId {
144 db.intern_macro(MacroCallLoc { def: self, ast_id })
145 } 151 }
146} 152}
147 153
@@ -149,64 +155,103 @@ impl MacroDefId {
149pub enum MacroDefKind { 155pub enum MacroDefKind {
150 Declarative, 156 Declarative,
151 BuiltIn(BuiltinFnLikeExpander), 157 BuiltIn(BuiltinFnLikeExpander),
158 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
159 BuiltInDerive(BuiltinDeriveExpander),
152} 160}
153 161
154#[derive(Debug, Clone, PartialEq, Eq, Hash)] 162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155pub struct MacroCallLoc { 163pub struct MacroCallLoc {
156 pub(crate) def: MacroDefId, 164 pub(crate) def: MacroDefId,
157 pub(crate) ast_id: AstId<ast::MacroCall>, 165 pub(crate) kind: MacroCallKind,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
169pub enum MacroCallKind {
170 FnLike(AstId<ast::MacroCall>),
171 Attr(AstId<ast::ModuleItem>),
172}
173
174impl MacroCallKind {
175 pub fn file_id(&self) -> HirFileId {
176 match self {
177 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
178 MacroCallKind::Attr(ast_id) => ast_id.file_id,
179 }
180 }
181
182 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
183 match self {
184 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
185 MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
186 }
187 }
188
189 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
190 match self {
191 MacroCallKind::FnLike(ast_id) => {
192 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
193 }
194 MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()),
195 }
196 }
158} 197}
159 198
160impl MacroCallId { 199impl MacroCallId {
161 pub fn as_file(self, kind: MacroFileKind) -> HirFileId { 200 pub fn as_file(self) -> HirFileId {
162 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; 201 MacroFile { macro_call_id: self }.into()
163 macro_file.into()
164 } 202 }
165} 203}
166 204
167/// ExpansionInfo mainly describes how to map text range between src and expanded macro 205/// ExpansionInfo mainly describes how to map text range between src and expanded macro
168#[derive(Debug, Clone, PartialEq, Eq)] 206#[derive(Debug, Clone, PartialEq, Eq)]
169pub struct ExpansionInfo { 207pub struct ExpansionInfo {
170 expanded: Source<SyntaxNode>, 208 expanded: InFile<SyntaxNode>,
171 arg: Source<ast::TokenTree>, 209 arg: InFile<SyntaxNode>,
172 def: Source<ast::TokenTree>, 210 def: InFile<ast::TokenTree>,
173 211
174 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 212 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
175 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 213 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
176 exp_map: Arc<mbe::TokenMap>, 214 exp_map: Arc<mbe::TokenMap>,
177} 215}
178 216
217pub use mbe::Origin;
218
179impl ExpansionInfo { 219impl ExpansionInfo {
180 pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { 220 pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
221 Some(self.arg.with_value(self.arg.value.parent()?))
222 }
223
224 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> {
181 assert_eq!(token.file_id, self.arg.file_id); 225 assert_eq!(token.file_id, self.arg.file_id);
182 let range = 226 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
183 token.value.text_range().checked_sub(self.arg.value.syntax().text_range().start())?;
184 let token_id = self.macro_arg.1.token_by_range(range)?; 227 let token_id = self.macro_arg.1.token_by_range(range)?;
185 let token_id = self.macro_def.0.map_id_down(token_id); 228 let token_id = self.macro_def.0.map_id_down(token_id);
186 229
187 let range = self.exp_map.range_by_token(token_id)?; 230 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
188 231
189 let token = algo::find_covering_element(&self.expanded.value, range).into_token()?; 232 let token = algo::find_covering_element(&self.expanded.value, range).into_token()?;
190 233
191 Some(self.expanded.with_value(token)) 234 Some(self.expanded.with_value(token))
192 } 235 }
193 236
194 pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { 237 pub fn map_token_up(
238 &self,
239 token: InFile<&SyntaxToken>,
240 ) -> Option<(InFile<SyntaxToken>, Origin)> {
195 let token_id = self.exp_map.token_by_range(token.value.text_range())?; 241 let token_id = self.exp_map.token_by_range(token.value.text_range())?;
196 242
197 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 243 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
198 let (token_map, tt) = match origin { 244 let (token_map, tt) = match origin {
199 mbe::Origin::Call => (&self.macro_arg.1, &self.arg), 245 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
200 mbe::Origin::Def => (&self.macro_def.1, &self.def), 246 mbe::Origin::Def => {
247 (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone()))
248 }
201 }; 249 };
202 250
203 let range = token_map.range_by_token(token_id)?; 251 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
204 let token = algo::find_covering_element( 252 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
205 tt.value.syntax(), 253 .into_token()?;
206 range + tt.value.syntax().text_range().start(), 254 Some((tt.with_value(token), origin))
207 )
208 .into_token()?;
209 Some(tt.with_value(token))
210 } 255 }
211} 256}
212 257
@@ -214,76 +259,66 @@ impl ExpansionInfo {
214/// 259///
215/// It is stable across reparses, and can be used as salsa key/value. 260/// It is stable across reparses, and can be used as salsa key/value.
216// FIXME: isn't this just a `Source<FileAstId<N>>` ? 261// FIXME: isn't this just a `Source<FileAstId<N>>` ?
217#[derive(Debug)] 262pub type AstId<N> = InFile<FileAstId<N>>;
218pub struct AstId<N: AstNode> {
219 file_id: HirFileId,
220 file_ast_id: FileAstId<N>,
221}
222
223impl<N: AstNode> Clone for AstId<N> {
224 fn clone(&self) -> AstId<N> {
225 *self
226 }
227}
228impl<N: AstNode> Copy for AstId<N> {}
229
230impl<N: AstNode> PartialEq for AstId<N> {
231 fn eq(&self, other: &Self) -> bool {
232 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
233 }
234}
235impl<N: AstNode> Eq for AstId<N> {}
236impl<N: AstNode> Hash for AstId<N> {
237 fn hash<H: Hasher>(&self, hasher: &mut H) {
238 (self.file_id, self.file_ast_id).hash(hasher);
239 }
240}
241 263
242impl<N: AstNode> AstId<N> { 264impl<N: AstNode> AstId<N> {
243 pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
244 AstId { file_id, file_ast_id }
245 }
246
247 pub fn file_id(&self) -> HirFileId {
248 self.file_id
249 }
250
251 pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { 265 pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
252 let root = db.parse_or_expand(self.file_id).unwrap(); 266 let root = db.parse_or_expand(self.file_id).unwrap();
253 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) 267 db.ast_id_map(self.file_id).get(self.value).to_node(&root)
254 } 268 }
255} 269}
256 270
257/// `Source<T>` stores a value of `T` inside a particular file/syntax tree. 271/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
258/// 272///
259/// Typical usages are: 273/// Typical usages are:
260/// 274///
261/// * `Source<SyntaxNode>` -- syntax node in a file 275/// * `InFile<SyntaxNode>` -- syntax node in a file
262/// * `Source<ast::FnDef>` -- ast node in a file 276/// * `InFile<ast::FnDef>` -- ast node in a file
263/// * `Source<TextUnit>` -- offset in a file 277/// * `InFile<TextUnit>` -- offset in a file
264#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 278#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
265pub struct Source<T> { 279pub struct InFile<T> {
266 pub file_id: HirFileId, 280 pub file_id: HirFileId,
267 pub value: T, 281 pub value: T,
268} 282}
269 283
270impl<T> Source<T> { 284impl<T> InFile<T> {
271 pub fn new(file_id: HirFileId, value: T) -> Source<T> { 285 pub fn new(file_id: HirFileId, value: T) -> InFile<T> {
272 Source { file_id, value } 286 InFile { file_id, value }
273 } 287 }
274 288
275 // Similarly, naming here is stupid... 289 // Similarly, naming here is stupid...
276 pub fn with_value<U>(&self, value: U) -> Source<U> { 290 pub fn with_value<U>(&self, value: U) -> InFile<U> {
277 Source::new(self.file_id, value) 291 InFile::new(self.file_id, value)
278 } 292 }
279 293
280 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 294 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
281 Source::new(self.file_id, f(self.value)) 295 InFile::new(self.file_id, f(self.value))
282 } 296 }
283 pub fn as_ref(&self) -> Source<&T> { 297 pub fn as_ref(&self) -> InFile<&T> {
284 self.with_value(&self.value) 298 self.with_value(&self.value)
285 } 299 }
286 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { 300 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
287 db.parse_or_expand(self.file_id).expect("source created from invalid file") 301 db.parse_or_expand(self.file_id).expect("source created from invalid file")
288 } 302 }
289} 303}
304
305impl<T: Clone> InFile<&T> {
306 pub fn cloned(&self) -> InFile<T> {
307 self.with_value(self.value.clone())
308 }
309}
310
311impl InFile<SyntaxNode> {
312 pub fn ancestors_with_macros<'a>(
313 self,
314 db: &'a impl crate::db::AstDatabase,
315 ) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a {
316 std::iter::successors(Some(self), move |node| match node.value.parent() {
317 Some(parent) => Some(node.with_value(parent)),
318 None => {
319 let parent_node = node.file_id.call_node(db)?;
320 Some(parent_node)
321 }
322 })
323 }
324}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 7824489d7..e62693b68 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -38,8 +38,8 @@ impl Name {
38 } 38 }
39 39
40 /// Shortcut to create inline plain text name 40 /// Shortcut to create inline plain text name
41 const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { 41 const fn new_inline_ascii(text: &[u8]) -> Name {
42 Name::new_text(SmolStr::new_inline_from_ascii(len, text)) 42 Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
43 } 43 }
44 44
45 /// Resolve a name from the text of token. 45 /// Resolve a name from the text of token.
@@ -83,6 +83,12 @@ impl AsName for ast::Name {
83 } 83 }
84} 84}
85 85
86impl AsName for tt::Ident {
87 fn as_name(&self) -> Name {
88 Name::resolve(&self.text)
89 }
90}
91
86impl AsName for ast::FieldKind { 92impl AsName for ast::FieldKind {
87 fn as_name(&self) -> Name { 93 fn as_name(&self) -> Name {
88 match self { 94 match self {
@@ -98,52 +104,102 @@ impl AsName for ra_db::Dependency {
98 } 104 }
99} 105}
100 106
101// Primitives 107pub mod known {
102pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); 108 macro_rules! known_names {
103pub const I8: Name = Name::new_inline_ascii(2, b"i8"); 109 ($($ident:ident),* $(,)?) => {
104pub const I16: Name = Name::new_inline_ascii(3, b"i16"); 110 $(
105pub const I32: Name = Name::new_inline_ascii(3, b"i32"); 111 #[allow(bad_style)]
106pub const I64: Name = Name::new_inline_ascii(3, b"i64"); 112 pub const $ident: super::Name =
107pub const I128: Name = Name::new_inline_ascii(4, b"i128"); 113 super::Name::new_inline_ascii(stringify!($ident).as_bytes());
108pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); 114 )*
109pub const U8: Name = Name::new_inline_ascii(2, b"u8"); 115 };
110pub const U16: Name = Name::new_inline_ascii(3, b"u16"); 116 }
111pub const U32: Name = Name::new_inline_ascii(3, b"u32"); 117
112pub const U64: Name = Name::new_inline_ascii(3, b"u64"); 118 known_names!(
113pub const U128: Name = Name::new_inline_ascii(4, b"u128"); 119 // Primitives
114pub const F32: Name = Name::new_inline_ascii(3, b"f32"); 120 isize,
115pub const F64: Name = Name::new_inline_ascii(3, b"f64"); 121 i8,
116pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); 122 i16,
117pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); 123 i32,
118pub const STR: Name = Name::new_inline_ascii(3, b"str"); 124 i64,
119 125 i128,
120// Special names 126 usize,
121pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); 127 u8,
122pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); 128 u16,
123pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); 129 u32,
124 130 u64,
125// Components of known path (value or mod name) 131 u128,
126pub const STD: Name = Name::new_inline_ascii(3, b"std"); 132 f32,
127pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); 133 f64,
128pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); 134 bool,
129pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); 135 char,
130pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); 136 str,
131pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); 137 // Special names
132 138 macro_rules,
133// Components of known path (type name) 139 // Components of known path (value or mod name)
134pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); 140 std,
135pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); 141 iter,
136pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); 142 ops,
137pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); 143 future,
138pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); 144 result,
139pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); 145 boxed,
140pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); 146 // Components of known path (type name)
141pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); 147 IntoIterator,
142pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); 148 Item,
143 149 Try,
144// Builtin Macros 150 Ok,
145pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); 151 Future,
146pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); 152 Result,
147pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); 153 Output,
148pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); 154 Target,
149pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); 155 Box,
156 RangeFrom,
157 RangeFull,
158 RangeInclusive,
159 RangeToInclusive,
160 RangeTo,
161 Range,
162 Neg,
163 Not,
164 Index,
165 // Builtin macros
166 file,
167 column,
168 compile_error,
169 line,
170 stringify,
171 format_args,
172 format_args_nl,
173 env,
174 option_env,
175 // Builtin derives
176 Copy,
177 Clone,
178 Default,
179 Debug,
180 Hash,
181 Ord,
182 PartialOrd,
183 Eq,
184 PartialEq,
185 );
186
187 // self/Self cannot be used as an identifier
188 pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
189 pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
190
191 #[macro_export]
192 macro_rules! name {
193 (self) => {
194 $crate::name::known::SELF_PARAM
195 };
196 (Self) => {
197 $crate::name::known::SELF_TYPE
198 };
199 ($ident:ident) => {
200 $crate::name::known::$ident
201 };
202 }
203}
204
205pub use crate::name;
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 65a35e52f..4de219ce4 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -16,7 +16,10 @@ macro_rules! __quote {
16 { 16 {
17 let children = $crate::__quote!($($tt)*); 17 let children = $crate::__quote!($($tt)*);
18 let subtree = tt::Subtree { 18 let subtree = tt::Subtree {
19 delimiter: tt::Delimiter::$delim, 19 delimiter: Some(tt::Delimiter {
20 kind: tt::DelimiterKind::$delim,
21 id: tt::TokenId::unspecified(),
22 }),
20 token_trees: $crate::quote::IntoTt::to_tokens(children), 23 token_trees: $crate::quote::IntoTt::to_tokens(children),
21 }; 24 };
22 subtree 25 subtree
@@ -29,6 +32,7 @@ macro_rules! __quote {
29 tt::Leaf::Punct(tt::Punct { 32 tt::Leaf::Punct(tt::Punct {
30 char: $first, 33 char: $first,
31 spacing: tt::Spacing::Alone, 34 spacing: tt::Spacing::Alone,
35 id: tt::TokenId::unspecified(),
32 }).into() 36 }).into()
33 ] 37 ]
34 } 38 }
@@ -40,10 +44,12 @@ macro_rules! __quote {
40 tt::Leaf::Punct(tt::Punct { 44 tt::Leaf::Punct(tt::Punct {
41 char: $first, 45 char: $first,
42 spacing: tt::Spacing::Joint, 46 spacing: tt::Spacing::Joint,
47 id: tt::TokenId::unspecified(),
43 }).into(), 48 }).into(),
44 tt::Leaf::Punct(tt::Punct { 49 tt::Leaf::Punct(tt::Punct {
45 char: $sec, 50 char: $sec,
46 spacing: tt::Spacing::Alone, 51 spacing: tt::Spacing::Alone,
52 id: tt::TokenId::unspecified(),
47 }).into() 53 }).into()
48 ] 54 ]
49 } 55 }
@@ -60,6 +66,15 @@ macro_rules! __quote {
60 } 66 }
61 }; 67 };
62 68
69 ( ## $first:ident $($tail:tt)* ) => {
70 {
71 let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
72 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
73 tokens.append(&mut tail_tokens);
74 tokens
75 }
76 };
77
63 // Brace 78 // Brace
64 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; 79 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
65 // Bracket 80 // Bracket
@@ -85,7 +100,10 @@ macro_rules! __quote {
85 ( & ) => {$crate::__quote!(@PUNCT '&')}; 100 ( & ) => {$crate::__quote!(@PUNCT '&')};
86 ( , ) => {$crate::__quote!(@PUNCT ',')}; 101 ( , ) => {$crate::__quote!(@PUNCT ',')};
87 ( : ) => {$crate::__quote!(@PUNCT ':')}; 102 ( : ) => {$crate::__quote!(@PUNCT ':')};
103 ( :: ) => {$crate::__quote!(@PUNCT ':', ':')};
88 ( . ) => {$crate::__quote!(@PUNCT '.')}; 104 ( . ) => {$crate::__quote!(@PUNCT '.')};
105 ( < ) => {$crate::__quote!(@PUNCT '<')};
106 ( > ) => {$crate::__quote!(@PUNCT '>')};
89 107
90 ( $first:tt $($tail:tt)+ ) => { 108 ( $first:tt $($tail:tt)+ ) => {
91 { 109 {
@@ -114,7 +132,7 @@ pub(crate) trait IntoTt {
114 132
115impl IntoTt for Vec<tt::TokenTree> { 133impl IntoTt for Vec<tt::TokenTree> {
116 fn to_subtree(self) -> tt::Subtree { 134 fn to_subtree(self) -> tt::Subtree {
117 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self } 135 tt::Subtree { delimiter: None, token_trees: self }
118 } 136 }
119 137
120 fn to_tokens(self) -> Vec<tt::TokenTree> { 138 fn to_tokens(self) -> Vec<tt::TokenTree> {
@@ -169,15 +187,15 @@ macro_rules! impl_to_to_tokentrees {
169} 187}
170 188
171impl_to_to_tokentrees! { 189impl_to_to_tokentrees! {
172 u32 => self { tt::Literal{text: self.to_string().into()} }; 190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
173 usize => self { tt::Literal{text: self.to_string().into()}}; 191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
174 i32 => self { tt::Literal{text: self.to_string().into()}}; 192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
175 tt::Leaf => self { self }; 193 tt::Leaf => self { self };
176 tt::Literal => self { self }; 194 tt::Literal => self { self };
177 tt::Ident => self { self }; 195 tt::Ident => self { self };
178 tt::Punct => self { self }; 196 tt::Punct => self { self };
179 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}}; 197 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}};
180 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}} 198 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}
181} 199}
182 200
183#[cfg(test)] 201#[cfg(test)]
@@ -244,7 +262,13 @@ mod tests {
244 let fields = 262 let fields =
245 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten(); 263 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
246 264
247 let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; 265 let list = tt::Subtree {
266 delimiter: Some(tt::Delimiter {
267 kind: tt::DelimiterKind::Brace,
268 id: tt::TokenId::unspecified(),
269 }),
270 token_trees: fields.collect(),
271 };
248 272
249 let quoted = quote! { 273 let quoted = quote! {
250 impl Clone for #struct_name { 274 impl Clone for #struct_name {
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 429242870..60793db44 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -21,10 +21,9 @@ ra_prof = { path = "../ra_prof" }
21ra_syntax = { path = "../ra_syntax" } 21ra_syntax = { path = "../ra_syntax" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
23 23
24# https://github.com/rust-lang/chalk/pull/294 24chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
25chalk-solve = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } 25chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
26chalk-rust-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } 26chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
27chalk-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" }
28 27
29lalrpop-intern = "0.15.1" 28lalrpop-intern = "0.15.1"
30 29
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 9d1d4e48c..f32d5786a 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -6,14 +6,14 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9use hir_expand::name; 9use hir_expand::name::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
13use crate::db::HirDatabase; 13use crate::{
14 14 db::HirDatabase,
15use super::{
16 traits::{InEnvironment, Solution}, 15 traits::{InEnvironment, Solution},
16 utils::generics,
17 Canonical, Substs, Ty, TypeWalk, 17 Canonical, Substs, Ty, TypeWalk,
18}; 18};
19 19
@@ -48,14 +48,14 @@ fn deref_by_trait(
48 krate: CrateId, 48 krate: CrateId,
49 ty: InEnvironment<&Canonical<Ty>>, 49 ty: InEnvironment<&Canonical<Ty>>,
50) -> Option<Canonical<Ty>> { 50) -> Option<Canonical<Ty>> {
51 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 51 let deref_trait = match db.lang_item(krate, "deref".into())? {
52 LangItemTarget::TraitId(it) => it, 52 LangItemTarget::TraitId(it) => it,
53 _ => return None, 53 _ => return None,
54 }; 54 };
55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
56 56
57 let generic_params = db.generic_params(target.into()); 57 let generic_params = generics(db, target.into());
58 if generic_params.count_params_including_parent() != 1 { 58 if generic_params.len() != 1 {
59 // the Target type + Deref trait should only have one generic parameter, 59 // the Target type + Deref trait should only have one generic parameter,
60 // namely Deref's Self type 60 // namely Deref's Self type
61 return None; 61 return None;
@@ -78,7 +78,7 @@ fn deref_by_trait(
78 78
79 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; 79 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env };
80 80
81 let solution = db.trait_solve(krate.into(), canonical)?; 81 let solution = db.trait_solve(krate, canonical)?;
82 82
83 match &solution { 83 match &solution {
84 Solution::Unique(vars) => { 84 Solution::Unique(vars) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 9ce154593..d52f65b83 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -10,8 +10,8 @@ use ra_db::{salsa, CrateId};
10 10
11use crate::{ 11use crate::{
12 method_resolution::CrateImplBlocks, 12 method_resolution::CrateImplBlocks,
13 traits::{AssocTyValue, Impl}, 13 traits::{chalk, AssocTyValue, Impl},
14 CallableDef, FnSig, GenericPredicate, ImplTy, InferenceResult, Substs, Ty, TyDefId, TypeCtor, 14 CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor,
15 ValueTyDefId, 15 ValueTyDefId,
16}; 16};
17 17
@@ -22,13 +22,18 @@ pub trait HirDatabase: DefDatabase {
22 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; 22 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
23 23
24 #[salsa::invoke(crate::lower::ty_query)] 24 #[salsa::invoke(crate::lower::ty_query)]
25 #[salsa::cycle(crate::lower::ty_recover)]
25 fn ty(&self, def: TyDefId) -> Ty; 26 fn ty(&self, def: TyDefId) -> Ty;
26 27
27 #[salsa::invoke(crate::lower::value_ty_query)] 28 #[salsa::invoke(crate::lower::value_ty_query)]
28 fn value_ty(&self, def: ValueTyDefId) -> Ty; 29 fn value_ty(&self, def: ValueTyDefId) -> Ty;
29 30
30 #[salsa::invoke(crate::lower::impl_ty_query)] 31 #[salsa::invoke(crate::lower::impl_self_ty_query)]
31 fn impl_ty(&self, def: ImplId) -> ImplTy; 32 #[salsa::cycle(crate::lower::impl_self_ty_recover)]
33 fn impl_self_ty(&self, def: ImplId) -> Ty;
34
35 #[salsa::invoke(crate::lower::impl_trait_query)]
36 fn impl_trait(&self, def: ImplId) -> Option<TraitRef>;
32 37
33 #[salsa::invoke(crate::lower::field_types_query)] 38 #[salsa::invoke(crate::lower::field_types_query)]
34 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>; 39 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
@@ -37,6 +42,7 @@ pub trait HirDatabase: DefDatabase {
37 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 42 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
38 43
39 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] 44 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
45 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
40 fn generic_predicates_for_param( 46 fn generic_predicates_for_param(
41 &self, 47 &self,
42 def: GenericDefId, 48 def: GenericDefId,
@@ -71,39 +77,24 @@ pub trait HirDatabase: DefDatabase {
71 #[salsa::interned] 77 #[salsa::interned]
72 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; 78 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
73 79
74 #[salsa::invoke(crate::traits::chalk::associated_ty_data_query)] 80 #[salsa::invoke(chalk::associated_ty_data_query)]
75 fn associated_ty_data( 81 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>;
76 &self,
77 id: chalk_ir::TypeId,
78 ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;
79 82
80 #[salsa::invoke(crate::traits::chalk::trait_datum_query)] 83 #[salsa::invoke(chalk::trait_datum_query)]
81 fn trait_datum( 84 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>;
82 &self,
83 krate: CrateId,
84 trait_id: chalk_ir::TraitId,
85 ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;
86 85
87 #[salsa::invoke(crate::traits::chalk::struct_datum_query)] 86 #[salsa::invoke(chalk::struct_datum_query)]
88 fn struct_datum( 87 fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>;
89 &self,
90 krate: CrateId,
91 struct_id: chalk_ir::StructId,
92 ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;
93 88
94 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 89 #[salsa::invoke(crate::traits::chalk::impl_datum_query)]
95 fn impl_datum( 90 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
96 &self,
97 krate: CrateId,
98 impl_id: chalk_ir::ImplId,
99 ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;
100 91
101 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 92 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
102 fn associated_ty_value( 93 fn associated_ty_value(
103 &self, 94 &self,
104 krate: CrateId, 95 krate: CrateId,
105 id: chalk_rust_ir::AssociatedTyValueId, 96 id: chalk::AssociatedTyValueId,
106 ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>; 97 ) -> Arc<chalk::AssociatedTyValue>;
107 98
108 #[salsa::invoke(crate::traits::trait_solve_query)] 99 #[salsa::invoke(crate::traits::trait_solve_query)]
109 fn trait_solve( 100 fn trait_solve(
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 4a13fac23..5054189cc 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -2,7 +2,7 @@
2 2
3use std::any::Any; 3use std::any::Any;
4 4
5use hir_expand::{db::AstDatabase, name::Name, HirFileId, Source}; 5use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
7 7
8pub use hir_def::diagnostics::UnresolvedModule; 8pub use hir_def::diagnostics::UnresolvedModule;
@@ -19,8 +19,8 @@ impl Diagnostic for NoSuchField {
19 "no such field".to_string() 19 "no such field".to_string()
20 } 20 }
21 21
22 fn source(&self) -> Source<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 Source { file_id: self.file, value: self.field.into() } 23 InFile { file_id: self.file, value: self.field.into() }
24 } 24 }
25 25
26 fn as_any(&self) -> &(dyn Any + Send + 'static) { 26 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -44,8 +44,8 @@ impl Diagnostic for MissingFields {
44 } 44 }
45 message 45 message
46 } 46 }
47 fn source(&self) -> Source<SyntaxNodePtr> { 47 fn source(&self) -> InFile<SyntaxNodePtr> {
48 Source { file_id: self.file, value: self.field_list.into() } 48 InFile { file_id: self.file, value: self.field_list.into() }
49 } 49 }
50 fn as_any(&self) -> &(dyn Any + Send + 'static) { 50 fn as_any(&self) -> &(dyn Any + Send + 'static) {
51 self 51 self
@@ -72,8 +72,8 @@ impl Diagnostic for MissingOkInTailExpr {
72 fn message(&self) -> String { 72 fn message(&self) -> String {
73 "wrap return expression in Ok".to_string() 73 "wrap return expression in Ok".to_string()
74 } 74 }
75 fn source(&self) -> Source<SyntaxNodePtr> { 75 fn source(&self) -> InFile<SyntaxNodePtr> {
76 Source { file_id: self.file, value: self.expr.into() } 76 InFile { file_id: self.file, value: self.expr.into() }
77 } 77 }
78 fn as_any(&self) -> &(dyn Any + Send + 'static) { 78 fn as_any(&self) -> &(dyn Any + Send + 'static) {
79 self 79 self
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 9bb3ece6c..dcca1bace 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -10,6 +10,7 @@ pub struct HirFormatter<'a, 'b, DB> {
10 buf: String, 10 buf: String,
11 curr_size: usize, 11 curr_size: usize,
12 max_size: Option<usize>, 12 max_size: Option<usize>,
13 should_display_default_types: bool,
13} 14}
14 15
15pub trait HirDisplay { 16pub trait HirDisplay {
@@ -19,7 +20,7 @@ pub trait HirDisplay {
19 where 20 where
20 Self: Sized, 21 Self: Sized,
21 { 22 {
22 HirDisplayWrapper(db, self, None) 23 HirDisplayWrapper(db, self, None, true)
23 } 24 }
24 25
25 fn display_truncated<'a, DB>( 26 fn display_truncated<'a, DB>(
@@ -30,7 +31,7 @@ pub trait HirDisplay {
30 where 31 where
31 Self: Sized, 32 Self: Sized,
32 { 33 {
33 HirDisplayWrapper(db, self, max_size) 34 HirDisplayWrapper(db, self, max_size, false)
34 } 35 }
35} 36}
36 37
@@ -72,9 +73,13 @@ where
72 false 73 false
73 } 74 }
74 } 75 }
76
77 pub fn should_display_default_types(&self) -> bool {
78 self.should_display_default_types
79 }
75} 80}
76 81
77pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<usize>); 82pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<usize>, bool);
78 83
79impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T> 84impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
80where 85where
@@ -88,6 +93,7 @@ where
88 buf: String::with_capacity(20), 93 buf: String::with_capacity(20),
89 curr_size: 0, 94 curr_size: 0,
90 max_size: self.2, 95 max_size: self.2,
96 should_display_default_types: self.3,
91 }) 97 })
92 } 98 }
93} 99}
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 5c65f9370..f752a9f09 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 path::{known, Path}, 6 path::{path, Path},
7 resolver::HasResolver, 7 resolver::HasResolver,
8 AdtId, FunctionId, 8 AdtId, FunctionId,
9}; 9};
@@ -97,7 +97,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
97 let (_, source_map) = db.body_with_source_map(self.func.into()); 97 let (_, source_map) = db.body_with_source_map(self.func.into());
98 98
99 if let Some(source_ptr) = source_map.expr_syntax(id) { 99 if let Some(source_ptr) = source_map.expr_syntax(id) {
100 if let Some(expr) = source_ptr.value.a() { 100 if let Some(expr) = source_ptr.value.left() {
101 let root = source_ptr.file_syntax(db); 101 let root = source_ptr.file_syntax(db);
102 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { 102 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
103 if let Some(field_list) = record_lit.record_field_list() { 103 if let Some(field_list) = record_lit.record_field_list() {
@@ -124,7 +124,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
124 None => return, 124 None => return,
125 }; 125 };
126 126
127 let std_result_path = known::std_result_result(); 127 let std_result_path = path![std::result::Result];
128 128
129 let resolver = self.func.resolver(db); 129 let resolver = self.func.resolver(db);
130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { 130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
@@ -142,7 +142,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
142 let (_, source_map) = db.body_with_source_map(self.func.into()); 142 let (_, source_map) = db.body_with_source_map(self.func.into());
143 143
144 if let Some(source_ptr) = source_map.expr_syntax(id) { 144 if let Some(source_ptr) = source_map.expr_syntax(id) {
145 if let Some(expr) = source_ptr.value.a() { 145 if let Some(expr) = source_ptr.value.left() {
146 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); 146 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
147 } 147 }
148 } 148 }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 1e9f4b208..e97b81473 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -18,19 +18,18 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
22use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
23 22
24use hir_def::{ 23use hir_def::{
25 body::Body, 24 body::Body,
26 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData},
27 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
28 path::{known, Path}, 27 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 29 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, 30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
32}; 31};
33use hir_expand::{diagnostics::DiagnosticSink, name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
35use ra_prof::profile; 34use ra_prof::profile;
36use test_utils::tested_by; 35use test_utils::tested_by;
@@ -43,6 +42,8 @@ use super::{
43}; 42};
44use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; 43use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic};
45 44
45pub(crate) use unify::unify;
46
46macro_rules! ty_app { 47macro_rules! ty_app {
47 ($ctor:pat, $param:pat) => { 48 ($ctor:pat, $param:pat) => {
48 crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) 49 crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param })
@@ -191,11 +192,16 @@ struct InferenceContext<'a, D: HirDatabase> {
191 owner: DefWithBodyId, 192 owner: DefWithBodyId,
192 body: Arc<Body>, 193 body: Arc<Body>,
193 resolver: Resolver, 194 resolver: Resolver,
194 var_unification_table: InPlaceUnificationTable<TypeVarId>, 195 table: unify::InferenceTable,
195 trait_env: Arc<TraitEnvironment>, 196 trait_env: Arc<TraitEnvironment>,
196 obligations: Vec<Obligation>, 197 obligations: Vec<Obligation>,
197 result: InferenceResult, 198 result: InferenceResult,
198 /// The return type of the function being inferred. 199 /// The return type of the function being inferred, or the closure if we're
200 /// currently within one.
201 ///
202 /// We might consider using a nested inference context for checking
203 /// closures, but currently this is the only field that will change there,
204 /// so it doesn't make sense.
199 return_ty: Ty, 205 return_ty: Ty,
200 206
201 /// Impls of `CoerceUnsized` used in coercion. 207 /// Impls of `CoerceUnsized` used in coercion.
@@ -209,7 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
209 fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self { 215 fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self {
210 InferenceContext { 216 InferenceContext {
211 result: InferenceResult::default(), 217 result: InferenceResult::default(),
212 var_unification_table: InPlaceUnificationTable::new(), 218 table: unify::InferenceTable::new(),
213 obligations: Vec::default(), 219 obligations: Vec::default(),
214 return_ty: Ty::Unknown, // set in collect_fn_signature 220 return_ty: Ty::Unknown, // set in collect_fn_signature
215 trait_env: TraitEnvironment::lower(db, &resolver), 221 trait_env: TraitEnvironment::lower(db, &resolver),
@@ -224,13 +230,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
224 fn resolve_all(mut self) -> InferenceResult { 230 fn resolve_all(mut self) -> InferenceResult {
225 // FIXME resolve obligations as well (use Guidance if necessary) 231 // FIXME resolve obligations as well (use Guidance if necessary)
226 let mut result = mem::replace(&mut self.result, InferenceResult::default()); 232 let mut result = mem::replace(&mut self.result, InferenceResult::default());
227 let mut tv_stack = Vec::new();
228 for ty in result.type_of_expr.values_mut() { 233 for ty in result.type_of_expr.values_mut() {
229 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); 234 let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
230 *ty = resolved; 235 *ty = resolved;
231 } 236 }
232 for ty in result.type_of_pat.values_mut() { 237 for ty in result.type_of_pat.values_mut() {
233 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); 238 let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
234 *ty = resolved; 239 *ty = resolved;
235 } 240 }
236 result 241 result
@@ -275,96 +280,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
275 self.normalize_associated_types_in(ty) 280 self.normalize_associated_types_in(ty)
276 } 281 }
277 282
278 fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { 283 /// Replaces `impl Trait` in `ty` by type variables and obligations for
279 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) 284 /// those variables. This is done for function arguments when calling a
280 } 285 /// function, and for return types when inside the function body, i.e. in
281 286 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
282 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 287 /// Trait` is represented by `Ty::Opaque`.
283 self.unify_inner(ty1, ty2, 0) 288 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
284 } 289 ty.fold(&mut |ty| match ty {
285 290 Ty::Opaque(preds) => {
286 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 291 tested_by!(insert_vars_for_impl_trait);
287 if depth > 1000 { 292 let var = self.table.new_type_var();
288 // prevent stackoverflows 293 let var_subst = Substs::builder(1).push(var.clone()).build();
289 panic!("infinite recursion in unification"); 294 self.obligations.extend(
290 } 295 preds
291 if ty1 == ty2 { 296 .iter()
292 return true; 297 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
293 } 298 .filter_map(Obligation::from_predicate),
294 // try to resolve type vars first 299 );
295 let ty1 = self.resolve_ty_shallow(ty1); 300 var
296 let ty2 = self.resolve_ty_shallow(ty2);
297 match (&*ty1, &*ty2) {
298 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
299 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
300 }
301 _ => self.unify_inner_trivial(&ty1, &ty2),
302 }
303 }
304
305 fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
306 match (ty1, ty2) {
307 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
308
309 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
310 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
311 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
312 | (
313 Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)),
314 Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)),
315 ) => {
316 // both type vars are unknown since we tried to resolve them
317 self.var_unification_table.union(*tv1, *tv2);
318 true
319 }
320
321 // The order of MaybeNeverTypeVar matters here.
322 // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar.
323 // Unifying MaybeNeverTypeVar and other concrete type will let the former become it.
324 (Ty::Infer(InferTy::TypeVar(tv)), other)
325 | (other, Ty::Infer(InferTy::TypeVar(tv)))
326 | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other)
327 | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv)))
328 | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_)))
329 | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv)))
330 | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_)))
331 | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => {
332 // the type var is unknown since we tried to resolve it
333 self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
334 true
335 } 301 }
336 302 _ => ty,
337 _ => false, 303 })
338 }
339 }
340
341 fn new_type_var(&mut self) -> Ty {
342 Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
343 }
344
345 fn new_integer_var(&mut self) -> Ty {
346 Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
347 }
348
349 fn new_float_var(&mut self) -> Ty {
350 Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
351 }
352
353 fn new_maybe_never_type_var(&mut self) -> Ty {
354 Ty::Infer(InferTy::MaybeNeverTypeVar(
355 self.var_unification_table.new_key(TypeVarValue::Unknown),
356 ))
357 } 304 }
358 305
359 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 306 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
360 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 307 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
361 match ty { 308 match ty {
362 Ty::Unknown => self.new_type_var(), 309 Ty::Unknown => self.table.new_type_var(),
363 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { 310 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => {
364 self.new_integer_var() 311 self.table.new_integer_var()
365 } 312 }
366 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { 313 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => {
367 self.new_float_var() 314 self.table.new_float_var()
368 } 315 }
369 _ => ty, 316 _ => ty,
370 } 317 }
@@ -402,64 +349,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
402 } 349 }
403 } 350 }
404 351
352 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
353 self.table.unify(ty1, ty2)
354 }
355
405 /// Resolves the type as far as currently possible, replacing type variables 356 /// Resolves the type as far as currently possible, replacing type variables
406 /// by their known types. All types returned by the infer_* functions should 357 /// by their known types. All types returned by the infer_* functions should
407 /// be resolved as far as possible, i.e. contain no type variables with 358 /// be resolved as far as possible, i.e. contain no type variables with
408 /// known type. 359 /// known type.
409 fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 360 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
410 self.resolve_obligations_as_possible(); 361 self.resolve_obligations_as_possible();
411 362
412 ty.fold(&mut |ty| match ty { 363 self.table.resolve_ty_as_possible(ty)
413 Ty::Infer(tv) => {
414 let inner = tv.to_inner();
415 if tv_stack.contains(&inner) {
416 tested_by!(type_var_cycles_resolve_as_possible);
417 // recursive type
418 return tv.fallback_value();
419 }
420 if let Some(known_ty) =
421 self.var_unification_table.inlined_probe_value(inner).known()
422 {
423 // known_ty may contain other variables that are known by now
424 tv_stack.push(inner);
425 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
426 tv_stack.pop();
427 result
428 } else {
429 ty
430 }
431 }
432 _ => ty,
433 })
434 } 364 }
435 365
436 /// If `ty` is a type variable with known type, returns that type;
437 /// otherwise, return ty.
438 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { 366 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
439 let mut ty = Cow::Borrowed(ty); 367 self.table.resolve_ty_shallow(ty)
440 // The type variable could resolve to a int/float variable. Hence try 368 }
441 // resolving up to three times; each type of variable shouldn't occur 369
442 // more than once 370 fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
443 for i in 0..3 { 371 self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
444 if i > 0 { 372 }
445 tested_by!(type_var_resolves_to_int_var); 373
446 } 374 fn resolve_associated_type_with_params(
447 match &*ty { 375 &mut self,
448 Ty::Infer(tv) => { 376 inner_ty: Ty,
449 let inner = tv.to_inner(); 377 assoc_ty: Option<TypeAliasId>,
450 match self.var_unification_table.inlined_probe_value(inner).known() { 378 params: &[Ty],
451 Some(known_ty) => { 379 ) -> Ty {
452 // The known_ty can't be a type var itself 380 match assoc_ty {
453 ty = Cow::Owned(known_ty.clone()); 381 Some(res_assoc_ty) => {
454 } 382 let ty = self.table.new_type_var();
455 _ => return ty, 383 let builder = Substs::build_for_def(self.db, res_assoc_ty)
456 } 384 .push(inner_ty)
457 } 385 .fill(params.iter().cloned());
458 _ => return ty, 386 let projection = ProjectionPredicate {
387 ty: ty.clone(),
388 projection_ty: ProjectionTy {
389 associated_ty: res_assoc_ty,
390 parameters: builder.build(),
391 },
392 };
393 self.obligations.push(Obligation::Projection(projection));
394 self.resolve_ty_as_possible(ty)
459 } 395 }
396 None => Ty::Unknown,
460 } 397 }
461 log::error!("Inference variable still not resolved: {:?}", ty);
462 ty
463 } 398 }
464 399
465 /// Recurses through the given type, normalizing associated types mentioned 400 /// Recurses through the given type, normalizing associated types mentioned
@@ -469,7 +404,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
469 /// call). `make_ty` handles this already, but e.g. for field types we need 404 /// call). `make_ty` handles this already, but e.g. for field types we need
470 /// to do it as well. 405 /// to do it as well.
471 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 406 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
472 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 407 let ty = self.resolve_ty_as_possible(ty);
473 ty.fold(&mut |ty| match ty { 408 ty.fold(&mut |ty| match ty {
474 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), 409 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty),
475 _ => ty, 410 _ => ty,
@@ -477,40 +412,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
477 } 412 }
478 413
479 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 414 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
480 let var = self.new_type_var(); 415 let var = self.table.new_type_var();
481 let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; 416 let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() };
482 let obligation = Obligation::Projection(predicate); 417 let obligation = Obligation::Projection(predicate);
483 self.obligations.push(obligation); 418 self.obligations.push(obligation);
484 var 419 var
485 } 420 }
486 421
487 /// Resolves the type completely; type variables without known type are
488 /// replaced by Ty::Unknown.
489 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
490 ty.fold(&mut |ty| match ty {
491 Ty::Infer(tv) => {
492 let inner = tv.to_inner();
493 if tv_stack.contains(&inner) {
494 tested_by!(type_var_cycles_resolve_completely);
495 // recursive type
496 return tv.fallback_value();
497 }
498 if let Some(known_ty) =
499 self.var_unification_table.inlined_probe_value(inner).known()
500 {
501 // known_ty may contain other variables that are known by now
502 tv_stack.push(inner);
503 let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
504 tv_stack.pop();
505 result
506 } else {
507 tv.fallback_value()
508 }
509 }
510 _ => ty,
511 })
512 }
513
514 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) { 422 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) {
515 let path = match path { 423 let path = match path {
516 Some(path) => path, 424 Some(path) => path,
@@ -519,7 +427,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
519 let resolver = &self.resolver; 427 let resolver = &self.resolver;
520 // FIXME: this should resolve assoc items as well, see this example: 428 // FIXME: this should resolve assoc items as well, see this example:
521 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 429 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
522 match resolver.resolve_path_in_type_ns_fully(self.db, &path) { 430 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
523 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 431 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
524 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); 432 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
525 let ty = self.db.ty(strukt.into()); 433 let ty = self.db.ty(strukt.into());
@@ -547,93 +455,90 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
547 455
548 self.infer_pat(*pat, &ty, BindingMode::default()); 456 self.infer_pat(*pat, &ty, BindingMode::default());
549 } 457 }
550 self.return_ty = self.make_ty(&data.ret_type); 458 let return_ty = self.make_ty(&data.ret_type);
459 self.return_ty = self.insert_vars_for_impl_trait(return_ty);
551 } 460 }
552 461
553 fn infer_body(&mut self) { 462 fn infer_body(&mut self) {
554 self.infer_expr(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); 463 self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
555 } 464 }
556 465
557 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { 466 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
558 let path = known::std_iter_into_iterator(); 467 let path = path![std::iter::IntoIterator];
559 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 468 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
560 self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE) 469 self.db.trait_data(trait_).associated_type_by_name(&name![Item])
561 } 470 }
562 471
563 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { 472 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
564 let path = known::std_ops_try(); 473 let path = path![std::ops::Try];
474 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
475 self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
476 }
477
478 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
479 let path = path![std::ops::Neg];
480 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
481 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
482 }
483
484 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
485 let path = path![std::ops::Not];
565 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 486 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
566 self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) 487 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
567 } 488 }
568 489
569 fn resolve_future_future_output(&self) -> Option<TypeAliasId> { 490 fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
570 let path = known::std_future_future(); 491 let path = path![std::future::Future];
571 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 492 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
572 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 493 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
573 } 494 }
574 495
575 fn resolve_boxed_box(&self) -> Option<AdtId> { 496 fn resolve_boxed_box(&self) -> Option<AdtId> {
576 let path = known::std_boxed_box(); 497 let path = path![std::boxed::Box];
577 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 498 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
578 Some(struct_.into()) 499 Some(struct_.into())
579 } 500 }
580}
581
582/// The ID of a type variable.
583#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
584pub struct TypeVarId(pub(super) u32);
585
586impl UnifyKey for TypeVarId {
587 type Value = TypeVarValue;
588 501
589 fn index(&self) -> u32 { 502 fn resolve_range_full(&self) -> Option<AdtId> {
590 self.0 503 let path = path![std::ops::RangeFull];
504 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
505 Some(struct_.into())
591 } 506 }
592 507
593 fn from_index(i: u32) -> Self { 508 fn resolve_range(&self) -> Option<AdtId> {
594 TypeVarId(i) 509 let path = path![std::ops::Range];
510 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
511 Some(struct_.into())
595 } 512 }
596 513
597 fn tag() -> &'static str { 514 fn resolve_range_inclusive(&self) -> Option<AdtId> {
598 "TypeVarId" 515 let path = path![std::ops::RangeInclusive];
516 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
517 Some(struct_.into())
599 } 518 }
600}
601
602/// The value of a type variable: either we already know the type, or we don't
603/// know it yet.
604#[derive(Clone, PartialEq, Eq, Debug)]
605pub enum TypeVarValue {
606 Known(Ty),
607 Unknown,
608}
609 519
610impl TypeVarValue { 520 fn resolve_range_from(&self) -> Option<AdtId> {
611 fn known(&self) -> Option<&Ty> { 521 let path = path![std::ops::RangeFrom];
612 match self { 522 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
613 TypeVarValue::Known(ty) => Some(ty), 523 Some(struct_.into())
614 TypeVarValue::Unknown => None,
615 }
616 } 524 }
617}
618 525
619impl UnifyValue for TypeVarValue { 526 fn resolve_range_to(&self) -> Option<AdtId> {
620 type Error = NoError; 527 let path = path![std::ops::RangeTo];
621 528 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
622 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { 529 Some(struct_.into())
623 match (value1, value2) { 530 }
624 // We should never equate two type variables, both of which have
625 // known types. Instead, we recursively equate those types.
626 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
627 "equating two type variables, both of which have known types: {:?} and {:?}",
628 t1, t2
629 ),
630 531
631 // If one side is known, prefer that one. 532 fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
632 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), 533 let path = path![std::ops::RangeToInclusive];
633 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), 534 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
535 Some(struct_.into())
536 }
634 537
635 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), 538 fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
636 } 539 let path = path![std::ops::Index];
540 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
541 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
637 } 542 }
638} 543}
639 544
@@ -643,14 +548,14 @@ impl UnifyValue for TypeVarValue {
643/// several integer types). 548/// several integer types).
644#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 549#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
645pub enum InferTy { 550pub enum InferTy {
646 TypeVar(TypeVarId), 551 TypeVar(unify::TypeVarId),
647 IntVar(TypeVarId), 552 IntVar(unify::TypeVarId),
648 FloatVar(TypeVarId), 553 FloatVar(unify::TypeVarId),
649 MaybeNeverTypeVar(TypeVarId), 554 MaybeNeverTypeVar(unify::TypeVarId),
650} 555}
651 556
652impl InferTy { 557impl InferTy {
653 fn to_inner(self) -> TypeVarId { 558 fn to_inner(self) -> unify::TypeVarId {
654 match self { 559 match self {
655 InferTy::TypeVar(ty) 560 InferTy::TypeVar(ty)
656 | InferTy::IntVar(ty) 561 | InferTy::IntVar(ty)
@@ -693,7 +598,7 @@ impl Expectation {
693} 598}
694 599
695mod diagnostics { 600mod diagnostics {
696 use hir_def::{expr::ExprId, FunctionId, HasSource, Lookup}; 601 use hir_def::{expr::ExprId, src::HasSource, FunctionId, Lookup};
697 use hir_expand::diagnostics::DiagnosticSink; 602 use hir_expand::diagnostics::DiagnosticSink;
698 603
699 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 604 use crate::{db::HirDatabase, diagnostics::NoSuchField};
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 719a0f395..83c0c2c3f 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -8,9 +8,9 @@ use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutabilit
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use test_utils::tested_by; 9use test_utils::tested_by;
10 10
11use crate::{autoderef, db::HirDatabase, ImplTy, Substs, Ty, TypeCtor, TypeWalk}; 11use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk};
12 12
13use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; 13use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext};
14 14
15impl<'a, D: HirDatabase> InferenceContext<'a, D> { 15impl<'a, D: HirDatabase> InferenceContext<'a, D> {
16 /// Unify two types, but may coerce the first one to the second one 16 /// Unify two types, but may coerce the first one to the second one
@@ -54,10 +54,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
54 impls 54 impls
55 .iter() 55 .iter()
56 .filter_map(|&impl_id| { 56 .filter_map(|&impl_id| {
57 let trait_ref = match db.impl_ty(impl_id) { 57 let trait_ref = db.impl_trait(impl_id)?;
58 ImplTy::TraitRef(it) => it,
59 ImplTy::Inherent(_) => return None,
60 };
61 58
62 // `CoerseUnsized` has one generic parameter for the target type. 59 // `CoerseUnsized` has one generic parameter for the target type.
63 let cur_from_ty = trait_ref.substs.0.get(0)?; 60 let cur_from_ty = trait_ref.substs.0.get(0)?;
@@ -88,8 +85,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
88 match (&from_ty, to_ty) { 85 match (&from_ty, to_ty) {
89 // Never type will make type variable to fallback to Never Type instead of Unknown. 86 // Never type will make type variable to fallback to Never Type instead of Unknown.
90 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { 87 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => {
91 let var = self.new_maybe_never_type_var(); 88 let var = self.table.new_maybe_never_type_var();
92 self.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); 89 self.table.var_unification_table.union_value(*tv, TypeVarValue::Known(var));
93 return true; 90 return true;
94 } 91 }
95 (ty_app!(TypeCtor::Never), _) => return true, 92 (ty_app!(TypeCtor::Never), _) => return true,
@@ -97,7 +94,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
97 // Trivial cases, this should go after `never` check to 94 // Trivial cases, this should go after `never` check to
98 // avoid infer result type to be never 95 // avoid infer result type to be never
99 _ => { 96 _ => {
100 if self.unify_inner_trivial(&from_ty, &to_ty) { 97 if self.table.unify_inner_trivial(&from_ty, &to_ty) {
101 return true; 98 return true;
102 } 99 }
103 } 100 }
@@ -137,6 +134,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
137 } 134 }
138 } 135 }
139 136
137 (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => {
138 from_ty = params[0].clone();
139 }
140
140 _ => {} 141 _ => {}
141 } 142 }
142 143
@@ -333,9 +334,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
333 // Stop when constructor matches. 334 // Stop when constructor matches.
334 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { 335 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => {
335 // It will not recurse to `coerce`. 336 // It will not recurse to `coerce`.
336 return self.unify_substs(st1, st2, 0); 337 return self.table.unify_substs(st1, st2, 0);
338 }
339 _ => {
340 if self.table.unify_inner_trivial(&derefed_ty, &to_ty) {
341 return true;
342 }
337 } 343 }
338 _ => {}
339 } 344 }
340 } 345 }
341 346
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 2f9ca4bbb..3af05394c 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -6,17 +6,21 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 builtin_type::Signedness, 7 builtin_type::Signedness,
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 generics::GenericParams,
10 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
11 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
12 AdtId, ContainerId, Lookup, StructFieldId, 11 AdtId, AssocContainerId, Lookup, StructFieldId,
13}; 12};
14use hir_expand::name::{self, Name}; 13use hir_expand::name::{name, Name};
14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
17 autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, 17 autoderef,
18 CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, 18 db::HirDatabase,
19 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 19 method_resolution, op,
20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics},
22 ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty,
23 TypeCtor, TypeWalk, Uncertain,
20}; 24};
21 25
22use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -31,13 +35,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
31 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, 35 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
32 ); 36 );
33 } 37 }
34 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 38 let ty = self.resolve_ty_as_possible(ty);
35 ty 39 ty
36 } 40 }
37 41
38 /// Infer type of expression with possibly implicit coerce to the expected type. 42 /// Infer type of expression with possibly implicit coerce to the expected type.
39 /// Return the type after possible coercion. 43 /// Return the type after possible coercion.
40 fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 44 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
41 let ty = self.infer_expr_inner(expr, &expected); 45 let ty = self.infer_expr_inner(expr, &expected);
42 let ty = if !self.coerce(&ty, &expected.ty) { 46 let ty = if !self.coerce(&ty, &expected.ty) {
43 self.result 47 self.result
@@ -52,7 +56,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
52 expected.ty.clone() 56 expected.ty.clone()
53 }; 57 };
54 58
55 self.resolve_ty_as_possible(&mut vec![], ty) 59 self.resolve_ty_as_possible(ty)
56 } 60 }
57 61
58 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 62 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
@@ -91,27 +95,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
91 Expr::For { iterable, body, pat } => { 95 Expr::For { iterable, body, pat } => {
92 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 96 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
93 97
94 let pat_ty = match self.resolve_into_iter_item() { 98 let pat_ty =
95 Some(into_iter_item_alias) => { 99 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
96 let pat_ty = self.new_type_var();
97 let projection = ProjectionPredicate {
98 ty: pat_ty.clone(),
99 projection_ty: ProjectionTy {
100 associated_ty: into_iter_item_alias,
101 parameters: Substs::single(iterable_ty),
102 },
103 };
104 self.obligations.push(Obligation::Projection(projection));
105 self.resolve_ty_as_possible(&mut vec![], pat_ty)
106 }
107 None => Ty::Unknown,
108 };
109 100
110 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 101 self.infer_pat(*pat, &pat_ty, BindingMode::default());
111 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 102 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
112 Ty::unit() 103 Ty::unit()
113 } 104 }
114 Expr::Lambda { body, args, arg_types } => { 105 Expr::Lambda { body, args, ret_type, arg_types } => {
115 assert_eq!(args.len(), arg_types.len()); 106 assert_eq!(args.len(), arg_types.len());
116 107
117 let mut sig_tys = Vec::new(); 108 let mut sig_tys = Vec::new();
@@ -127,7 +118,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
127 } 118 }
128 119
129 // add return type 120 // add return type
130 let ret_ty = self.new_type_var(); 121 let ret_ty = match ret_type {
122 Some(type_ref) => self.make_ty(type_ref),
123 None => self.table.new_type_var(),
124 };
131 sig_tys.push(ret_ty.clone()); 125 sig_tys.push(ret_ty.clone());
132 let sig_ty = Ty::apply( 126 let sig_ty = Ty::apply(
133 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 127 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
@@ -143,7 +137,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
143 // infer the body. 137 // infer the body.
144 self.coerce(&closure_ty, &expected.ty); 138 self.coerce(&closure_ty, &expected.ty);
145 139
146 self.infer_expr(*body, &Expectation::has_type(ret_ty)); 140 let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone());
141
142 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
143
144 self.return_ty = prev_ret_ty;
145
147 closure_ty 146 closure_ty
148 } 147 }
149 Expr::Call { callee, args } => { 148 Expr::Call { callee, args } => {
@@ -166,7 +165,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
166 Expr::Match { expr, arms } => { 165 Expr::Match { expr, arms } => {
167 let input_ty = self.infer_expr(*expr, &Expectation::none()); 166 let input_ty = self.infer_expr(*expr, &Expectation::none());
168 167
169 let mut result_ty = self.new_maybe_never_type_var(); 168 let mut result_ty = self.table.new_maybe_never_type_var();
170 169
171 for arm in arms { 170 for arm in arms {
172 for &pat in &arm.pats { 171 for &pat in &arm.pats {
@@ -200,7 +199,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
200 } 199 }
201 Expr::Return { expr } => { 200 Expr::Return { expr } => {
202 if let Some(expr) = expr { 201 if let Some(expr) = expr {
203 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); 202 self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
203 } else {
204 let unit = Ty::unit();
205 self.coerce(&unit, &self.return_ty.clone());
204 } 206 }
205 Ty::simple(TypeCtor::Never) 207 Ty::simple(TypeCtor::Never)
206 } 208 }
@@ -244,7 +246,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
244 ty 246 ty
245 } 247 }
246 Expr::Field { expr, name } => { 248 Expr::Field { expr, name } => {
247 let receiver_ty = self.infer_expr(*expr, &Expectation::none()); 249 let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
248 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); 250 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty);
249 let ty = autoderef::autoderef( 251 let ty = autoderef::autoderef(
250 self.db, 252 self.db,
@@ -279,45 +281,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
279 self.normalize_associated_types_in(ty) 281 self.normalize_associated_types_in(ty)
280 } 282 }
281 Expr::Await { expr } => { 283 Expr::Await { expr } => {
282 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 284 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
283 let ty = match self.resolve_future_future_output() { 285 let ty =
284 Some(future_future_output_alias) => { 286 self.resolve_associated_type(inner_ty, self.resolve_future_future_output());
285 let ty = self.new_type_var();
286 let projection = ProjectionPredicate {
287 ty: ty.clone(),
288 projection_ty: ProjectionTy {
289 associated_ty: future_future_output_alias,
290 parameters: Substs::single(inner_ty),
291 },
292 };
293 self.obligations.push(Obligation::Projection(projection));
294 self.resolve_ty_as_possible(&mut vec![], ty)
295 }
296 None => Ty::Unknown,
297 };
298 ty 287 ty
299 } 288 }
300 Expr::Try { expr } => { 289 Expr::Try { expr } => {
301 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 290 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
302 let ty = match self.resolve_ops_try_ok() { 291 let ty = self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok());
303 Some(ops_try_ok_alias) => {
304 let ty = self.new_type_var();
305 let projection = ProjectionPredicate {
306 ty: ty.clone(),
307 projection_ty: ProjectionTy {
308 associated_ty: ops_try_ok_alias,
309 parameters: Substs::single(inner_ty),
310 },
311 };
312 self.obligations.push(Obligation::Projection(projection));
313 self.resolve_ty_as_possible(&mut vec![], ty)
314 }
315 None => Ty::Unknown,
316 };
317 ty 292 ty
318 } 293 }
319 Expr::Cast { expr, type_ref } => { 294 Expr::Cast { expr, type_ref } => {
320 let _inner_ty = self.infer_expr(*expr, &Expectation::none()); 295 let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
321 let cast_ty = self.make_ty(type_ref); 296 let cast_ty = self.make_ty(type_ref);
322 // FIXME check the cast... 297 // FIXME check the cast...
323 cast_ty 298 cast_ty
@@ -333,12 +308,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
333 } else { 308 } else {
334 Expectation::none() 309 Expectation::none()
335 }; 310 };
336 // FIXME reference coercions etc. 311 let inner_ty = self.infer_expr_inner(*expr, &expectation);
337 let inner_ty = self.infer_expr(*expr, &expectation);
338 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 312 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
339 } 313 }
340 Expr::Box { expr } => { 314 Expr::Box { expr } => {
341 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 315 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
342 if let Some(box_) = self.resolve_boxed_box() { 316 if let Some(box_) = self.resolve_boxed_box() {
343 Ty::apply_one(TypeCtor::Adt(box_), inner_ty) 317 Ty::apply_one(TypeCtor::Adt(box_), inner_ty)
344 } else { 318 } else {
@@ -346,7 +320,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
346 } 320 }
347 } 321 }
348 Expr::UnaryOp { expr, op } => { 322 Expr::UnaryOp { expr, op } => {
349 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 323 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
350 match op { 324 match op {
351 UnaryOp::Deref => match self.resolver.krate() { 325 UnaryOp::Deref => match self.resolver.krate() {
352 Some(krate) => { 326 Some(krate) => {
@@ -369,31 +343,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
369 }, 343 },
370 UnaryOp::Neg => { 344 UnaryOp::Neg => {
371 match &inner_ty { 345 match &inner_ty {
372 Ty::Apply(a_ty) => match a_ty.ctor { 346 // Fast path for builtins
373 TypeCtor::Int(Uncertain::Unknown) 347 Ty::Apply(ApplicationTy {
374 | TypeCtor::Int(Uncertain::Known(IntTy { 348 ctor:
375 signedness: Signedness::Signed, 349 TypeCtor::Int(Uncertain::Known(IntTy {
376 .. 350 signedness: Signedness::Signed,
377 })) 351 ..
378 | TypeCtor::Float(..) => inner_ty, 352 })),
379 _ => Ty::Unknown, 353 ..
380 }, 354 })
381 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => { 355 | Ty::Apply(ApplicationTy {
382 inner_ty 356 ctor: TypeCtor::Int(Uncertain::Unknown),
383 } 357 ..
384 // FIXME: resolve ops::Neg trait 358 })
385 _ => Ty::Unknown, 359 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. })
360 | Ty::Infer(InferTy::IntVar(..))
361 | Ty::Infer(InferTy::FloatVar(..)) => inner_ty,
362 // Otherwise we resolve via the std::ops::Neg trait
363 _ => self
364 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
386 } 365 }
387 } 366 }
388 UnaryOp::Not => { 367 UnaryOp::Not => {
389 match &inner_ty { 368 match &inner_ty {
390 Ty::Apply(a_ty) => match a_ty.ctor { 369 // Fast path for builtins
391 TypeCtor::Bool | TypeCtor::Int(_) => inner_ty, 370 Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })
392 _ => Ty::Unknown, 371 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. })
393 }, 372 | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
394 Ty::Infer(InferTy::IntVar(..)) => inner_ty, 373 // Otherwise we resolve via the std::ops::Not trait
395 // FIXME: resolve ops::Not trait for inner_ty 374 _ => self
396 _ => Ty::Unknown, 375 .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
397 } 376 }
398 } 377 }
399 } 378 }
@@ -415,21 +394,63 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
415 } 394 }
416 _ => Ty::Unknown, 395 _ => Ty::Unknown,
417 }, 396 },
397 Expr::Range { lhs, rhs, range_type } => {
398 let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
399 let rhs_expect = lhs_ty
400 .as_ref()
401 .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
402 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
403 match (range_type, lhs_ty, rhs_ty) {
404 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
405 Some(adt) => Ty::simple(TypeCtor::Adt(adt)),
406 None => Ty::Unknown,
407 },
408 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
409 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
410 None => Ty::Unknown,
411 },
412 (RangeOp::Inclusive, None, Some(ty)) => {
413 match self.resolve_range_to_inclusive() {
414 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
415 None => Ty::Unknown,
416 }
417 }
418 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
419 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
420 None => Ty::Unknown,
421 },
422 (RangeOp::Inclusive, Some(_), Some(ty)) => {
423 match self.resolve_range_inclusive() {
424 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
425 None => Ty::Unknown,
426 }
427 }
428 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
429 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
430 None => Ty::Unknown,
431 },
432 (RangeOp::Inclusive, _, None) => Ty::Unknown,
433 }
434 }
418 Expr::Index { base, index } => { 435 Expr::Index { base, index } => {
419 let _base_ty = self.infer_expr(*base, &Expectation::none()); 436 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
420 let _index_ty = self.infer_expr(*index, &Expectation::none()); 437 let index_ty = self.infer_expr(*index, &Expectation::none());
421 // FIXME: use `std::ops::Index::Output` to figure out the real return type 438
422 Ty::Unknown 439 self.resolve_associated_type_with_params(
440 base_ty,
441 self.resolve_ops_index_output(),
442 &[index_ty],
443 )
423 } 444 }
424 Expr::Tuple { exprs } => { 445 Expr::Tuple { exprs } => {
425 let mut tys = match &expected.ty { 446 let mut tys = match &expected.ty {
426 ty_app!(TypeCtor::Tuple { .. }, st) => st 447 ty_app!(TypeCtor::Tuple { .. }, st) => st
427 .iter() 448 .iter()
428 .cloned() 449 .cloned()
429 .chain(repeat_with(|| self.new_type_var())) 450 .chain(repeat_with(|| self.table.new_type_var()))
430 .take(exprs.len()) 451 .take(exprs.len())
431 .collect::<Vec<_>>(), 452 .collect::<Vec<_>>(),
432 _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(), 453 _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
433 }; 454 };
434 455
435 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { 456 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
@@ -443,7 +464,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
443 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { 464 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
444 st.as_single().clone() 465 st.as_single().clone()
445 } 466 }
446 _ => self.new_type_var(), 467 _ => self.table.new_type_var(),
447 }; 468 };
448 469
449 match array { 470 match array {
@@ -485,7 +506,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
485 }; 506 };
486 // use a new type variable if we got Ty::Unknown here 507 // use a new type variable if we got Ty::Unknown here
487 let ty = self.insert_type_vars_shallow(ty); 508 let ty = self.insert_type_vars_shallow(ty);
488 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 509 let ty = self.resolve_ty_as_possible(ty);
489 self.write_expr_ty(tgt_expr, ty.clone()); 510 self.write_expr_ty(tgt_expr, ty.clone());
490 ty 511 ty
491 } 512 }
@@ -514,7 +535,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
514 } 535 }
515 } 536 }
516 537
517 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 538 let ty = self.resolve_ty_as_possible(ty);
518 self.infer_pat(*pat, &ty, BindingMode::default()); 539 self.infer_pat(*pat, &ty, BindingMode::default());
519 } 540 }
520 Statement::Expr(expr) => { 541 Statement::Expr(expr) => {
@@ -558,7 +579,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
558 Some((ty, func)) => { 579 Some((ty, func)) => {
559 let ty = canonicalized_receiver.decanonicalize_ty(ty); 580 let ty = canonicalized_receiver.decanonicalize_ty(ty);
560 self.write_method_resolution(tgt_expr, func); 581 self.write_method_resolution(tgt_expr, func);
561 (ty, self.db.value_ty(func.into()), Some(self.db.generic_params(func.into()))) 582 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into())))
562 } 583 }
563 None => (receiver_ty, Ty::Unknown, None), 584 None => (receiver_ty, Ty::Unknown, None),
564 }; 585 };
@@ -607,6 +628,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
607 continue; 628 continue;
608 } 629 }
609 630
631 let param_ty = self.insert_vars_for_impl_trait(param_ty);
610 let param_ty = self.normalize_associated_types_in(param_ty); 632 let param_ty = self.normalize_associated_types_in(param_ty);
611 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 633 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
612 } 634 }
@@ -615,17 +637,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
615 637
616 fn substs_for_method_call( 638 fn substs_for_method_call(
617 &mut self, 639 &mut self,
618 def_generics: Option<Arc<GenericParams>>, 640 def_generics: Option<Generics>,
619 generic_args: Option<&GenericArgs>, 641 generic_args: Option<&GenericArgs>,
620 receiver_ty: &Ty, 642 receiver_ty: &Ty,
621 ) -> Substs { 643 ) -> Substs {
622 let (parent_param_count, param_count) = 644 let (total_len, _parent_len, child_len) =
623 def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 645 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split());
624 let mut substs = Vec::with_capacity(parent_param_count + param_count); 646 let mut substs = Vec::with_capacity(total_len);
625 // Parent arguments are unknown, except for the receiver type 647 // Parent arguments are unknown, except for the receiver type
626 if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { 648 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
627 for param in &parent_generics.params { 649 for (_id, param) in parent_generics {
628 if param.name == name::SELF_TYPE { 650 if param.name == name![Self] {
629 substs.push(receiver_ty.clone()); 651 substs.push(receiver_ty.clone());
630 } else { 652 } else {
631 substs.push(Ty::Unknown); 653 substs.push(Ty::Unknown);
@@ -635,7 +657,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
635 // handle provided type arguments 657 // handle provided type arguments
636 if let Some(generic_args) = generic_args { 658 if let Some(generic_args) = generic_args {
637 // if args are provided, it should be all of them, but we can't rely on that 659 // if args are provided, it should be all of them, but we can't rely on that
638 for arg in generic_args.args.iter().take(param_count) { 660 for arg in generic_args.args.iter().take(child_len) {
639 match arg { 661 match arg {
640 GenericArg::Type(type_ref) => { 662 GenericArg::Type(type_ref) => {
641 let ty = self.make_ty(type_ref); 663 let ty = self.make_ty(type_ref);
@@ -645,10 +667,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
645 } 667 }
646 }; 668 };
647 let supplied_params = substs.len(); 669 let supplied_params = substs.len();
648 for _ in supplied_params..parent_param_count + param_count { 670 for _ in supplied_params..total_len {
649 substs.push(Ty::Unknown); 671 substs.push(Ty::Unknown);
650 } 672 }
651 assert_eq!(substs.len(), parent_param_count + param_count); 673 assert_eq!(substs.len(), total_len);
652 Substs(substs.into()) 674 Substs(substs.into())
653 } 675 }
654 676
@@ -665,13 +687,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
665 // add obligation for trait implementation, if this is a trait method 687 // add obligation for trait implementation, if this is a trait method
666 match def { 688 match def {
667 CallableDef::FunctionId(f) => { 689 CallableDef::FunctionId(f) => {
668 if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { 690 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db).container {
669 // construct a TraitDef 691 // construct a TraitDef
670 let substs = a_ty.parameters.prefix( 692 let substs =
671 self.db 693 a_ty.parameters.prefix(generics(self.db, trait_.into()).len());
672 .generic_params(trait_.into())
673 .count_params_including_parent(),
674 );
675 self.obligations.push(Obligation::Trait(TraitRef { 694 self.obligations.push(Obligation::Trait(TraitRef {
676 trait_: trait_.into(), 695 trait_: trait_.into(),
677 substs, 696 substs,
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 1ebb36239..a14662884 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -170,7 +170,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
170 } 170 }
171 BindingMode::Move => inner_ty.clone(), 171 BindingMode::Move => inner_ty.clone(),
172 }; 172 };
173 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); 173 let bound_ty = self.resolve_ty_as_possible(bound_ty);
174 self.write_pat_ty(pat, bound_ty); 174 self.write_pat_ty(pat, bound_ty);
175 return inner_ty; 175 return inner_ty;
176 } 176 }
@@ -179,7 +179,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
179 // use a new type variable if we got Ty::Unknown here 179 // use a new type variable if we got Ty::Unknown here
180 let ty = self.insert_type_vars_shallow(ty); 180 let ty = self.insert_type_vars_shallow(ty);
181 self.unify(&ty, expected); 181 self.unify(&ty, expected);
182 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 182 let ty = self.resolve_ty_as_possible(ty);
183 self.write_pat_ty(pat, ty.clone()); 183 self.write_pat_ty(pat, ty.clone());
184 ty 184 ty
185 } 185 }
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 14be66836..ffd358367 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -1,9 +1,11 @@
1//! Path expression resolution. 1//! Path expression resolution.
2 2
3use std::iter;
4
3use hir_def::{ 5use hir_def::{
4 path::{Path, PathKind, PathSegment}, 6 path::{Path, PathSegment},
5 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
6 AssocItemId, ContainerId, Lookup, 8 AssocContainerId, AssocItemId, Lookup,
7}; 9};
8use hir_expand::name::Name; 10use hir_expand::name::Name;
9 11
@@ -30,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
30 path: &Path, 32 path: &Path,
31 id: ExprOrPatId, 33 id: ExprOrPatId,
32 ) -> Option<Ty> { 34 ) -> Option<Ty> {
33 let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { 35 let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
34 if path.segments.is_empty() { 36 if path.segments().is_empty() {
35 // This can't actually happen syntax-wise 37 // This can't actually happen syntax-wise
36 return None; 38 return None;
37 } 39 }
38 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
39 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
40 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
41 self.resolve_ty_assoc_item( 43 self.resolve_ty_assoc_item(
42 ty, 44 ty,
43 &path.segments.last().expect("path had at least one segment").name, 45 &path.segments().last().expect("path had at least one segment").name,
44 id, 46 id,
45 )? 47 )?
46 } else { 48 } else {
47 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; 49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?;
48 50
49 match value_or_partial { 51 match value_or_partial {
50 ResolveValueResult::ValueNs(it) => (it, None), 52 ResolveValueResult::ValueNs(it) => (it, None),
@@ -57,7 +59,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
57 let typable: ValueTyDefId = match value { 59 let typable: ValueTyDefId = match value {
58 ValueNs::LocalBinding(pat) => { 60 ValueNs::LocalBinding(pat) => {
59 let ty = self.result.type_of_pat.get(pat)?.clone(); 61 let ty = self.result.type_of_pat.get(pat)?.clone();
60 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 62 let ty = self.resolve_ty_as_possible(ty);
61 return Some(ty); 63 return Some(ty);
62 } 64 }
63 ValueNs::FunctionId(it) => it.into(), 65 ValueNs::FunctionId(it) => it.into(),
@@ -83,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
83 remaining_index: usize, 85 remaining_index: usize,
84 id: ExprOrPatId, 86 id: ExprOrPatId,
85 ) -> Option<(ValueNs, Option<Substs>)> { 87 ) -> Option<(ValueNs, Option<Substs>)> {
86 assert!(remaining_index < path.segments.len()); 88 assert!(remaining_index < path.segments().len());
87 // there may be more intermediate segments between the resolved one and 89 // there may be more intermediate segments between the resolved one and
88 // the end. Only the last segment needs to be resolved to a value; from 90 // the end. Only the last segment needs to be resolved to a value; from
89 // the segments before that, we need to get either a type or a trait ref. 91 // the segments before that, we need to get either a type or a trait ref.
90 92
91 let resolved_segment = &path.segments[remaining_index - 1]; 93 let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
92 let remaining_segments = &path.segments[remaining_index..]; 94 let remaining_segments = path.segments().skip(remaining_index);
93 let is_before_last = remaining_segments.len() == 1; 95 let is_before_last = remaining_segments.len() == 1;
94 96
95 match (def, is_before_last) { 97 match (def, is_before_last) {
@@ -110,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
110 // trait but it's not the last segment, so the next segment 112 // trait but it's not the last segment, so the next segment
111 // should resolve to an associated type of that trait (e.g. `<T 113 // should resolve to an associated type of that trait (e.g. `<T
112 // as Iterator>::Item::default`) 114 // as Iterator>::Item::default`)
113 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; 115 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1);
114 let ty = Ty::from_partly_resolved_hir_path( 117 let ty = Ty::from_partly_resolved_hir_path(
115 self.db, 118 self.db,
116 &self.resolver, 119 &self.resolver,
@@ -136,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
136 fn resolve_trait_assoc_item( 139 fn resolve_trait_assoc_item(
137 &mut self, 140 &mut self,
138 trait_ref: TraitRef, 141 trait_ref: TraitRef,
139 segment: &PathSegment, 142 segment: PathSegment<'_>,
140 id: ExprOrPatId, 143 id: ExprOrPatId,
141 ) -> Option<(ValueNs, Option<Substs>)> { 144 ) -> Option<(ValueNs, Option<Substs>)> {
142 let trait_ = trait_ref.trait_; 145 let trait_ = trait_ref.trait_;
@@ -148,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
148 .map(|(_name, id)| (*id).into()) 151 .map(|(_name, id)| (*id).into())
149 .find_map(|item| match item { 152 .find_map(|item| match item {
150 AssocItemId::FunctionId(func) => { 153 AssocItemId::FunctionId(func) => {
151 if segment.name == self.db.function_data(func).name { 154 if segment.name == &self.db.function_data(func).name {
152 Some(AssocItemId::FunctionId(func)) 155 Some(AssocItemId::FunctionId(func))
153 } else { 156 } else {
154 None 157 None
@@ -156,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
156 } 159 }
157 160
158 AssocItemId::ConstId(konst) => { 161 AssocItemId::ConstId(konst) => {
159 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) 162 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name)
160 { 163 {
161 Some(AssocItemId::ConstId(konst)) 164 Some(AssocItemId::ConstId(konst))
162 } else { 165 } else {
@@ -206,12 +209,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
206 AssocItemId::TypeAliasId(_) => unreachable!(), 209 AssocItemId::TypeAliasId(_) => unreachable!(),
207 }; 210 };
208 let substs = match container { 211 let substs = match container {
209 ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()), 212 AssocContainerId::ImplId(impl_id) => {
210 ContainerId::TraitId(trait_) => { 213 let impl_substs = Substs::build_for_def(self.db, impl_id)
214 .fill(iter::repeat_with(|| self.table.new_type_var()))
215 .build();
216 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs);
217 let substs = Substs::build_for_def(self.db, item)
218 .use_parent_substs(&impl_substs)
219 .fill_with_params()
220 .build();
221 self.unify(&impl_self_ty, &ty);
222 Some(substs)
223 }
224 AssocContainerId::TraitId(trait_) => {
211 // we're picking this method 225 // we're picking this method
212 let trait_substs = Substs::build_for_def(self.db, trait_) 226 let trait_substs = Substs::build_for_def(self.db, trait_)
213 .push(ty.clone()) 227 .push(ty.clone())
214 .fill(std::iter::repeat_with(|| self.new_type_var())) 228 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
215 .build(); 229 .build();
216 let substs = Substs::build_for_def(self.db, item) 230 let substs = Substs::build_for_def(self.db, item)
217 .use_parent_substs(&trait_substs) 231 .use_parent_substs(&trait_substs)
@@ -223,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
223 })); 237 }));
224 Some(substs) 238 Some(substs)
225 } 239 }
226 ContainerId::ModuleId(_) => None, 240 AssocContainerId::ContainerId(_) => None,
227 }; 241 };
228 242
229 self.write_assoc_resolution(id, item.into()); 243 self.write_assoc_resolution(id, item.into());
@@ -231,38 +245,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
231 }, 245 },
232 ) 246 )
233 } 247 }
234
235 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
236 if let ValueNs::FunctionId(func) = *def {
237 // We only do the infer if parent has generic params
238 let gen = self.db.generic_params(func.into());
239 if gen.count_parent_params() == 0 {
240 return None;
241 }
242
243 let impl_id = match func.lookup(self.db).container {
244 ContainerId::ImplId(it) => it,
245 _ => return None,
246 };
247 let self_ty = self.db.impl_ty(impl_id).self_type().clone();
248 let self_ty_substs = self_ty.substs()?;
249 let actual_substs = actual_def_ty.substs()?;
250
251 let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
252
253 // The following code *link up* the function actual parma type
254 // and impl_block type param index
255 self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
256 if let Ty::Param { idx, .. } = param {
257 if let Some(s) = new_substs.get_mut(*idx as usize) {
258 *s = pty.clone();
259 }
260 }
261 });
262
263 Some(Substs(new_substs.into()))
264 } else {
265 None
266 }
267 }
268} 248}
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index f3a875678..fe05642ae 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -1,9 +1,15 @@
1//! Unification and canonicalization logic. 1//! Unification and canonicalization logic.
2 2
3use std::borrow::Cow;
4
5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
6
7use test_utils::tested_by;
8
3use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
4use crate::{ 10use crate::{
5 db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate, 11 db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate,
6 ProjectionTy, Substs, TraitRef, Ty, TypeWalk, 12 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
7}; 13};
8 14
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 15impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@@ -24,7 +30,7 @@ where
24 /// A stack of type variables that is used to detect recursive types (which 30 /// A stack of type variables that is used to detect recursive types (which
25 /// are an error, but we need to protect against them to avoid stack 31 /// are an error, but we need to protect against them to avoid stack
26 /// overflows). 32 /// overflows).
27 var_stack: Vec<super::TypeVarId>, 33 var_stack: Vec<TypeVarId>,
28} 34}
29 35
30pub(super) struct Canonicalized<T> { 36pub(super) struct Canonicalized<T> {
@@ -53,14 +59,14 @@ where
53 return tv.fallback_value(); 59 return tv.fallback_value();
54 } 60 }
55 if let Some(known_ty) = 61 if let Some(known_ty) =
56 self.ctx.var_unification_table.inlined_probe_value(inner).known() 62 self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
57 { 63 {
58 self.var_stack.push(inner); 64 self.var_stack.push(inner);
59 let result = self.do_canonicalize_ty(known_ty.clone()); 65 let result = self.do_canonicalize_ty(known_ty.clone());
60 self.var_stack.pop(); 66 self.var_stack.pop();
61 result 67 result
62 } else { 68 } else {
63 let root = self.ctx.var_unification_table.find(inner); 69 let root = self.ctx.table.var_unification_table.find(inner);
64 let free_var = match tv { 70 let free_var = match tv {
65 InferTy::TypeVar(_) => InferTy::TypeVar(root), 71 InferTy::TypeVar(_) => InferTy::TypeVar(root),
66 InferTy::IntVar(_) => InferTy::IntVar(root), 72 InferTy::IntVar(_) => InferTy::IntVar(root),
@@ -153,10 +159,268 @@ impl<T> Canonicalized<T> {
153 solution: Canonical<Vec<Ty>>, 159 solution: Canonical<Vec<Ty>>,
154 ) { 160 ) {
155 // the solution may contain new variables, which we need to convert to new inference vars 161 // the solution may contain new variables, which we need to convert to new inference vars
156 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect()); 162 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect());
157 for (i, ty) in solution.value.into_iter().enumerate() { 163 for (i, ty) in solution.value.into_iter().enumerate() {
158 let var = self.free_vars[i]; 164 let var = self.free_vars[i];
159 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); 165 ctx.table.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));
166 }
167 }
168}
169
170pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
171 let mut table = InferenceTable::new();
172 let vars =
173 Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build();
174 let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars);
175 if !table.unify(&ty_with_vars, &ty2.value) {
176 return None;
177 }
178 Some(
179 Substs::builder(ty1.num_vars)
180 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
181 .build(),
182 )
183}
184
185#[derive(Clone, Debug)]
186pub(crate) struct InferenceTable {
187 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
188}
189
190impl InferenceTable {
191 pub fn new() -> Self {
192 InferenceTable { var_unification_table: InPlaceUnificationTable::new() }
193 }
194
195 pub fn new_type_var(&mut self) -> Ty {
196 Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
197 }
198
199 pub fn new_integer_var(&mut self) -> Ty {
200 Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
201 }
202
203 pub fn new_float_var(&mut self) -> Ty {
204 Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
205 }
206
207 pub fn new_maybe_never_type_var(&mut self) -> Ty {
208 Ty::Infer(InferTy::MaybeNeverTypeVar(
209 self.var_unification_table.new_key(TypeVarValue::Unknown),
210 ))
211 }
212
213 pub fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
214 self.resolve_ty_completely_inner(&mut Vec::new(), ty)
215 }
216
217 pub fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
218 self.resolve_ty_as_possible_inner(&mut Vec::new(), ty)
219 }
220
221 pub fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
222 self.unify_inner(ty1, ty2, 0)
223 }
224
225 pub fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
226 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth))
227 }
228
229 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
230 if depth > 1000 {
231 // prevent stackoverflows
232 panic!("infinite recursion in unification");
233 }
234 if ty1 == ty2 {
235 return true;
236 }
237 // try to resolve type vars first
238 let ty1 = self.resolve_ty_shallow(ty1);
239 let ty2 = self.resolve_ty_shallow(ty2);
240 match (&*ty1, &*ty2) {
241 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
242 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
243 }
244 _ => self.unify_inner_trivial(&ty1, &ty2),
245 }
246 }
247
248 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
249 match (ty1, ty2) {
250 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
251
252 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
253 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
254 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
255 | (
256 Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)),
257 Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)),
258 ) => {
259 // both type vars are unknown since we tried to resolve them
260 self.var_unification_table.union(*tv1, *tv2);
261 true
262 }
263
264 // The order of MaybeNeverTypeVar matters here.
265 // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar.
266 // Unifying MaybeNeverTypeVar and other concrete type will let the former become it.
267 (Ty::Infer(InferTy::TypeVar(tv)), other)
268 | (other, Ty::Infer(InferTy::TypeVar(tv)))
269 | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other)
270 | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv)))
271 | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_)))
272 | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv)))
273 | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_)))
274 | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => {
275 // the type var is unknown since we tried to resolve it
276 self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
277 true
278 }
279
280 _ => false,
281 }
282 }
283
284 /// If `ty` is a type variable with known type, returns that type;
285 /// otherwise, return ty.
286 pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
287 let mut ty = Cow::Borrowed(ty);
288 // The type variable could resolve to a int/float variable. Hence try
289 // resolving up to three times; each type of variable shouldn't occur
290 // more than once
291 for i in 0..3 {
292 if i > 0 {
293 tested_by!(type_var_resolves_to_int_var);
294 }
295 match &*ty {
296 Ty::Infer(tv) => {
297 let inner = tv.to_inner();
298 match self.var_unification_table.inlined_probe_value(inner).known() {
299 Some(known_ty) => {
300 // The known_ty can't be a type var itself
301 ty = Cow::Owned(known_ty.clone());
302 }
303 _ => return ty,
304 }
305 }
306 _ => return ty,
307 }
308 }
309 log::error!("Inference variable still not resolved: {:?}", ty);
310 ty
311 }
312
313 /// Resolves the type as far as currently possible, replacing type variables
314 /// by their known types. All types returned by the infer_* functions should
315 /// be resolved as far as possible, i.e. contain no type variables with
316 /// known type.
317 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
318 ty.fold(&mut |ty| match ty {
319 Ty::Infer(tv) => {
320 let inner = tv.to_inner();
321 if tv_stack.contains(&inner) {
322 tested_by!(type_var_cycles_resolve_as_possible);
323 // recursive type
324 return tv.fallback_value();
325 }
326 if let Some(known_ty) =
327 self.var_unification_table.inlined_probe_value(inner).known()
328 {
329 // known_ty may contain other variables that are known by now
330 tv_stack.push(inner);
331 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
332 tv_stack.pop();
333 result
334 } else {
335 ty
336 }
337 }
338 _ => ty,
339 })
340 }
341
342 /// Resolves the type completely; type variables without known type are
343 /// replaced by Ty::Unknown.
344 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
345 ty.fold(&mut |ty| match ty {
346 Ty::Infer(tv) => {
347 let inner = tv.to_inner();
348 if tv_stack.contains(&inner) {
349 tested_by!(type_var_cycles_resolve_completely);
350 // recursive type
351 return tv.fallback_value();
352 }
353 if let Some(known_ty) =
354 self.var_unification_table.inlined_probe_value(inner).known()
355 {
356 // known_ty may contain other variables that are known by now
357 tv_stack.push(inner);
358 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
359 tv_stack.pop();
360 result
361 } else {
362 tv.fallback_value()
363 }
364 }
365 _ => ty,
366 })
367 }
368}
369
370/// The ID of a type variable.
371#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
372pub struct TypeVarId(pub(super) u32);
373
374impl UnifyKey for TypeVarId {
375 type Value = TypeVarValue;
376
377 fn index(&self) -> u32 {
378 self.0
379 }
380
381 fn from_index(i: u32) -> Self {
382 TypeVarId(i)
383 }
384
385 fn tag() -> &'static str {
386 "TypeVarId"
387 }
388}
389
390/// The value of a type variable: either we already know the type, or we don't
391/// know it yet.
392#[derive(Clone, PartialEq, Eq, Debug)]
393pub enum TypeVarValue {
394 Known(Ty),
395 Unknown,
396}
397
398impl TypeVarValue {
399 fn known(&self) -> Option<&Ty> {
400 match self {
401 TypeVarValue::Known(ty) => Some(ty),
402 TypeVarValue::Unknown => None,
403 }
404 }
405}
406
407impl UnifyValue for TypeVarValue {
408 type Error = NoError;
409
410 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
411 match (value1, value2) {
412 // We should never equate two type variables, both of which have
413 // known types. Instead, we recursively equate those types.
414 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
415 "equating two type variables, both of which have known types: {:?} and {:?}",
416 t1, t2
417 ),
418
419 // If one side is known, prefer that one.
420 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()),
421 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()),
422
423 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown),
160 } 424 }
161 } 425 }
162} 426}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index b45c8f82f..48abf97c9 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -44,8 +44,8 @@ use std::sync::Arc;
44use std::{fmt, iter, mem}; 44use std::{fmt, iter, mem};
45 45
46use hir_def::{ 46use hir_def::{
47 expr::ExprId, generics::GenericParams, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, 47 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId,
48 GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 48 HasModule, Lookup, TraitId, TypeAliasId,
49}; 49};
50use hir_expand::name::Name; 50use hir_expand::name::Name;
51use ra_db::{impl_intern_key, salsa, CrateId}; 51use ra_db::{impl_intern_key, salsa, CrateId};
@@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
53use crate::{ 53use crate::{
54 db::HirDatabase, 54 db::HirDatabase,
55 primitive::{FloatTy, IntTy, Uncertain}, 55 primitive::{FloatTy, IntTy, Uncertain},
56 utils::make_mut_slice, 56 utils::{generics, make_mut_slice, Generics},
57}; 57};
58use display::{HirDisplay, HirFormatter}; 58use display::{HirDisplay, HirFormatter};
59 59
@@ -166,16 +166,16 @@ impl TypeCtor {
166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure 166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure
167 => 1, 167 => 1,
168 TypeCtor::Adt(adt) => { 168 TypeCtor::Adt(adt) => {
169 let generic_params = db.generic_params(AdtId::from(adt).into()); 169 let generic_params = generics(db, AdtId::from(adt).into());
170 generic_params.count_params_including_parent() 170 generic_params.len()
171 } 171 }
172 TypeCtor::FnDef(callable) => { 172 TypeCtor::FnDef(callable) => {
173 let generic_params = db.generic_params(callable.into()); 173 let generic_params = generics(db, callable.into());
174 generic_params.count_params_including_parent() 174 generic_params.len()
175 } 175 }
176 TypeCtor::AssociatedType(type_alias) => { 176 TypeCtor::AssociatedType(type_alias) => {
177 let generic_params = db.generic_params(type_alias.into()); 177 let generic_params = generics(db, type_alias.into());
178 generic_params.count_params_including_parent() 178 generic_params.len()
179 } 179 }
180 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 180 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
181 TypeCtor::Tuple { cardinality } => cardinality as usize, 181 TypeCtor::Tuple { cardinality } => cardinality as usize,
@@ -251,7 +251,7 @@ impl ProjectionTy {
251 251
252 fn trait_(&self, db: &impl HirDatabase) -> TraitId { 252 fn trait_(&self, db: &impl HirDatabase) -> TraitId {
253 match self.associated_ty.lookup(db).container { 253 match self.associated_ty.lookup(db).container {
254 ContainerId::TraitId(it) => it, 254 AssocContainerId::TraitId(it) => it,
255 _ => panic!("projection ty without parent trait"), 255 _ => panic!("projection ty without parent trait"),
256 } 256 }
257 } 257 }
@@ -364,36 +364,26 @@ impl Substs {
364 } 364 }
365 365
366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
367 pub fn identity(generic_params: &GenericParams) -> Substs { 367 pub(crate) fn identity(generic_params: &Generics) -> Substs {
368 Substs( 368 Substs(
369 generic_params 369 generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(),
370 .params_including_parent()
371 .into_iter()
372 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
373 .collect(),
374 ) 370 )
375 } 371 }
376 372
377 /// Return Substs that replace each parameter by a bound variable. 373 /// Return Substs that replace each parameter by a bound variable.
378 pub fn bound_vars(generic_params: &GenericParams) -> Substs { 374 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
379 Substs( 375 Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect())
380 generic_params
381 .params_including_parent()
382 .into_iter()
383 .map(|p| Ty::Bound(p.idx))
384 .collect(),
385 )
386 } 376 }
387 377
388 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { 378 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
389 let def = def.into(); 379 let def = def.into();
390 let params = db.generic_params(def); 380 let params = generics(db, def);
391 let param_count = params.count_params_including_parent(); 381 let param_count = params.len();
392 Substs::builder(param_count) 382 Substs::builder(param_count)
393 } 383 }
394 384
395 pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder { 385 pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder {
396 Substs::builder(generic_params.count_params_including_parent()) 386 Substs::builder(generic_params.len())
397 } 387 }
398 388
399 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder { 389 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
@@ -486,21 +476,6 @@ impl TypeWalk for TraitRef {
486 } 476 }
487} 477}
488 478
489#[derive(Clone, PartialEq, Eq, Debug)]
490pub enum ImplTy {
491 Inherent(Ty),
492 TraitRef(TraitRef),
493}
494
495impl ImplTy {
496 pub(crate) fn self_type(&self) -> &Ty {
497 match self {
498 ImplTy::Inherent(it) => it,
499 ImplTy::TraitRef(tr) => &tr.substs[0],
500 }
501 }
502}
503
504/// Like `generics::WherePredicate`, but with resolved types: A condition on the 479/// Like `generics::WherePredicate`, but with resolved types: A condition on the
505/// parameters of a generic item. 480/// parameters of a generic item.
506#[derive(Debug, Clone, PartialEq, Eq, Hash)] 481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -931,13 +906,44 @@ impl HirDisplay for ApplicationTy {
931 write!(f, "{}", name)?; 906 write!(f, "{}", name)?;
932 if self.parameters.len() > 0 { 907 if self.parameters.len() > 0 {
933 write!(f, "<")?; 908 write!(f, "<")?;
934 f.write_joined(&*self.parameters.0, ", ")?; 909
910 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
911 let parameters_to_write = if f.should_display_default_types() {
912 self.parameters.0.as_ref()
913 } else {
914 match self
915 .ctor
916 .as_generic_def()
917 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
918 .filter(|defaults| !defaults.is_empty())
919 {
920 Option::None => self.parameters.0.as_ref(),
921 Option::Some(default_parameters) => {
922 for (i, parameter) in self.parameters.iter().enumerate() {
923 match (parameter, default_parameters.get(i)) {
924 (&Ty::Unknown, _) | (_, None) => {
925 non_default_parameters.push(parameter.clone())
926 }
927 (_, Some(default_parameter))
928 if parameter != default_parameter =>
929 {
930 non_default_parameters.push(parameter.clone())
931 }
932 _ => (),
933 }
934 }
935 &non_default_parameters
936 }
937 }
938 };
939
940 f.write_joined(parameters_to_write, ", ")?;
935 write!(f, ">")?; 941 write!(f, ">")?;
936 } 942 }
937 } 943 }
938 TypeCtor::AssociatedType(type_alias) => { 944 TypeCtor::AssociatedType(type_alias) => {
939 let trait_ = match type_alias.lookup(f.db).container { 945 let trait_ = match type_alias.lookup(f.db).container {
940 ContainerId::TraitId(it) => it, 946 AssocContainerId::TraitId(it) => it,
941 _ => panic!("not an associated type"), 947 _ => panic!("not an associated type"),
942 }; 948 };
943 let trait_name = f.db.trait_data(trait_).name.clone(); 949 let trait_name = f.db.trait_data(trait_).name.clone();
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 091c60f4f..af3db2e1d 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -11,10 +11,10 @@ use std::sync::Arc;
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::WherePredicate,
14 path::{GenericArg, Path, PathKind, PathSegment}, 14 path::{GenericArg, Path, PathSegment, PathSegments},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},
16 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
17 AdtId, AstItemDef, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, 17 AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
18 LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, 18 LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
19}; 19};
20use ra_arena::map::ArenaMap; 20use ra_arena::map::ArenaMap;
@@ -24,11 +24,11 @@ use crate::{
24 db::HirDatabase, 24 db::HirDatabase,
25 primitive::{FloatTy, IntTy}, 25 primitive::{FloatTy, IntTy},
26 utils::{ 26 utils::{
27 all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, 27 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
28 variant_data, 28 variant_data,
29 }, 29 },
30 FnSig, GenericPredicate, ImplTy, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, 30 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
31 TraitRef, Ty, TypeCtor, TypeWalk, 31 Ty, TypeCtor, TypeWalk,
32}; 32};
33 33
34impl Ty { 34impl Ty {
@@ -101,17 +101,19 @@ impl Ty {
101 TypeRef::Path(path) => path, 101 TypeRef::Path(path) => path,
102 _ => return None, 102 _ => return None,
103 }; 103 };
104 if let PathKind::Type(_) = &path.kind { 104 if path.type_anchor().is_some() {
105 return None; 105 return None;
106 } 106 }
107 if path.segments.len() > 1 { 107 if path.segments().len() > 1 {
108 return None; 108 return None;
109 } 109 }
110 let resolution = match resolver.resolve_path_in_type_ns(db, path) { 110 let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
111 Some((it, None)) => it, 111 Some((it, None)) => it,
112 _ => return None, 112 _ => return None,
113 }; 113 };
114 if let TypeNs::GenericParam(idx) = resolution { 114 if let TypeNs::GenericParam(param_id) = resolution {
115 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
116 let idx = generics.param_idx(param_id);
115 Some(idx) 117 Some(idx)
116 } else { 118 } else {
117 None 119 None
@@ -122,11 +124,11 @@ impl Ty {
122 db: &impl HirDatabase, 124 db: &impl HirDatabase,
123 resolver: &Resolver, 125 resolver: &Resolver,
124 ty: Ty, 126 ty: Ty,
125 remaining_segments: &[PathSegment], 127 remaining_segments: PathSegments<'_>,
126 ) -> Ty { 128 ) -> Ty {
127 if remaining_segments.len() == 1 { 129 if remaining_segments.len() == 1 {
128 // resolve unselected assoc types 130 // resolve unselected assoc types
129 let segment = &remaining_segments[0]; 131 let segment = remaining_segments.first().unwrap();
130 Ty::select_associated_type(db, resolver, ty, segment) 132 Ty::select_associated_type(db, resolver, ty, segment)
131 } else if remaining_segments.len() > 1 { 133 } else if remaining_segments.len() > 1 {
132 // FIXME report error (ambiguous associated type) 134 // FIXME report error (ambiguous associated type)
@@ -140,15 +142,15 @@ impl Ty {
140 db: &impl HirDatabase, 142 db: &impl HirDatabase,
141 resolver: &Resolver, 143 resolver: &Resolver,
142 resolution: TypeNs, 144 resolution: TypeNs,
143 resolved_segment: &PathSegment, 145 resolved_segment: PathSegment<'_>,
144 remaining_segments: &[PathSegment], 146 remaining_segments: PathSegments<'_>,
145 ) -> Ty { 147 ) -> Ty {
146 let ty = match resolution { 148 let ty = match resolution {
147 TypeNs::TraitId(trait_) => { 149 TypeNs::TraitId(trait_) => {
148 let trait_ref = 150 let trait_ref =
149 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); 151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
150 return if remaining_segments.len() == 1 { 152 return if remaining_segments.len() == 1 {
151 let segment = &remaining_segments[0]; 153 let segment = remaining_segments.first().unwrap();
152 let associated_ty = associated_type_by_name_including_super_traits( 154 let associated_ty = associated_type_by_name_including_super_traits(
153 db, 155 db,
154 trait_ref.trait_, 156 trait_ref.trait_,
@@ -174,12 +176,14 @@ impl Ty {
174 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) 176 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
175 }; 177 };
176 } 178 }
177 TypeNs::GenericParam(idx) => { 179 TypeNs::GenericParam(param_id) => {
180 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
181 let idx = generics.param_idx(param_id);
178 // FIXME: maybe return name in resolution? 182 // FIXME: maybe return name in resolution?
179 let name = resolved_segment.name.clone(); 183 let name = generics.param_name(param_id);
180 Ty::Param { idx, name } 184 Ty::Param { idx, name }
181 } 185 }
182 TypeNs::SelfType(impl_id) => db.impl_ty(impl_id).self_type().clone(), 186 TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(),
183 TypeNs::AdtSelfType(adt) => db.ty(adt.into()), 187 TypeNs::AdtSelfType(adt) => db.ty(adt.into()),
184 188
185 TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), 189 TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
@@ -198,21 +202,21 @@ impl Ty {
198 202
199 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { 203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
200 // Resolve the path (in type namespace) 204 // Resolve the path (in type namespace)
201 if let PathKind::Type(type_ref) = &path.kind { 205 if let Some(type_ref) = path.type_anchor() {
202 let ty = Ty::from_hir(db, resolver, &type_ref); 206 let ty = Ty::from_hir(db, resolver, &type_ref);
203 let remaining_segments = &path.segments[..]; 207 return Ty::from_type_relative_path(db, resolver, ty, path.segments());
204 return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
205 } 208 }
206 let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { 209 let (resolution, remaining_index) =
207 Some(it) => it, 210 match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
208 None => return Ty::Unknown, 211 Some(it) => it,
209 }; 212 None => return Ty::Unknown,
213 };
210 let (resolved_segment, remaining_segments) = match remaining_index { 214 let (resolved_segment, remaining_segments) = match remaining_index {
211 None => ( 215 None => (
212 path.segments.last().expect("resolved path has at least one element"), 216 path.segments().last().expect("resolved path has at least one element"),
213 &[] as &[PathSegment], 217 PathSegments::EMPTY,
214 ), 218 ),
215 Some(i) => (&path.segments[i - 1], &path.segments[i..]), 219 Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
216 }; 220 };
217 Ty::from_partly_resolved_hir_path( 221 Ty::from_partly_resolved_hir_path(
218 db, 222 db,
@@ -227,7 +231,7 @@ impl Ty {
227 db: &impl HirDatabase, 231 db: &impl HirDatabase,
228 resolver: &Resolver, 232 resolver: &Resolver,
229 self_ty: Ty, 233 self_ty: Ty,
230 segment: &PathSegment, 234 segment: PathSegment<'_>,
231 ) -> Ty { 235 ) -> Ty {
232 let param_idx = match self_ty { 236 let param_idx = match self_ty {
233 Ty::Param { idx, .. } => idx, 237 Ty::Param { idx, .. } => idx,
@@ -257,7 +261,7 @@ impl Ty {
257 fn from_hir_path_inner( 261 fn from_hir_path_inner(
258 db: &impl HirDatabase, 262 db: &impl HirDatabase,
259 resolver: &Resolver, 263 resolver: &Resolver,
260 segment: &PathSegment, 264 segment: PathSegment<'_>,
261 typable: TyDefId, 265 typable: TyDefId,
262 ) -> Ty { 266 ) -> Ty {
263 let generic_def = match typable { 267 let generic_def = match typable {
@@ -280,7 +284,7 @@ impl Ty {
280 // special-case enum variants 284 // special-case enum variants
281 resolved: ValueTyDefId, 285 resolved: ValueTyDefId,
282 ) -> Substs { 286 ) -> Substs {
283 let last = path.segments.last().expect("path should have at least one segment"); 287 let last = path.segments().last().expect("path should have at least one segment");
284 let (segment, generic_def) = match resolved { 288 let (segment, generic_def) = match resolved {
285 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
286 ValueTyDefId::StructId(it) => (last, Some(it.into())), 290 ValueTyDefId::StructId(it) => (last, Some(it.into())),
@@ -292,13 +296,11 @@ impl Ty {
292 // referring to the variant. So `Option::<T>::None` and 296 // referring to the variant. So `Option::<T>::None` and
293 // `Option::None::<T>` are both allowed (though the former is 297 // `Option::None::<T>` are both allowed (though the former is
294 // preferred). See also `def_ids_for_path_segments` in rustc. 298 // preferred). See also `def_ids_for_path_segments` in rustc.
295 let len = path.segments.len(); 299 let len = path.segments().len();
296 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { 300 let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
297 // Option::<T>::None 301 let segment = match penultimate {
298 &path.segments[len - 2] 302 Some(segment) if segment.args_and_bindings.is_some() => segment,
299 } else { 303 _ => last,
300 // Option::None::<T>
301 last
302 }; 304 };
303 (segment, Some(var.parent.into())) 305 (segment, Some(var.parent.into()))
304 } 306 }
@@ -310,16 +312,15 @@ impl Ty {
310pub(super) fn substs_from_path_segment( 312pub(super) fn substs_from_path_segment(
311 db: &impl HirDatabase, 313 db: &impl HirDatabase,
312 resolver: &Resolver, 314 resolver: &Resolver,
313 segment: &PathSegment, 315 segment: PathSegment<'_>,
314 def_generic: Option<GenericDefId>, 316 def_generic: Option<GenericDefId>,
315 add_self_param: bool, 317 add_self_param: bool,
316) -> Substs { 318) -> Substs {
317 let mut substs = Vec::new(); 319 let mut substs = Vec::new();
318 let def_generics = def_generic.map(|def| db.generic_params(def.into())); 320 let def_generics = def_generic.map(|def| generics(db, def.into()));
319 321
320 let (parent_param_count, param_count) = 322 let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split());
321 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 323 substs.extend(iter::repeat(Ty::Unknown).take(parent_len));
322 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
323 if add_self_param { 324 if add_self_param {
324 // FIXME this add_self_param argument is kind of a hack: Traits have the 325 // FIXME this add_self_param argument is kind of a hack: Traits have the
325 // Self type as an implicit first type parameter, but it can't be 326 // Self type as an implicit first type parameter, but it can't be
@@ -330,8 +331,8 @@ pub(super) fn substs_from_path_segment(
330 if let Some(generic_args) = &segment.args_and_bindings { 331 if let Some(generic_args) = &segment.args_and_bindings {
331 // if args are provided, it should be all of them, but we can't rely on that 332 // if args are provided, it should be all of them, but we can't rely on that
332 let self_param_correction = if add_self_param { 1 } else { 0 }; 333 let self_param_correction = if add_self_param { 1 } else { 0 };
333 let param_count = param_count - self_param_correction; 334 let child_len = child_len + self_param_correction;
334 for arg in generic_args.args.iter().take(param_count) { 335 for arg in generic_args.args.iter().take(child_len) {
335 match arg { 336 match arg {
336 GenericArg::Type(type_ref) => { 337 GenericArg::Type(type_ref) => {
337 let ty = Ty::from_hir(db, resolver, type_ref); 338 let ty = Ty::from_hir(db, resolver, type_ref);
@@ -342,10 +343,10 @@ pub(super) fn substs_from_path_segment(
342 } 343 }
343 // add placeholders for args that were not provided 344 // add placeholders for args that were not provided
344 let supplied_params = substs.len(); 345 let supplied_params = substs.len();
345 for _ in supplied_params..parent_param_count + param_count { 346 for _ in supplied_params..total_len {
346 substs.push(Ty::Unknown); 347 substs.push(Ty::Unknown);
347 } 348 }
348 assert_eq!(substs.len(), parent_param_count + param_count); 349 assert_eq!(substs.len(), total_len);
349 350
350 // handle defaults 351 // handle defaults
351 if let Some(def_generic) = def_generic { 352 if let Some(def_generic) = def_generic {
@@ -369,11 +370,11 @@ impl TraitRef {
369 path: &Path, 370 path: &Path,
370 explicit_self_ty: Option<Ty>, 371 explicit_self_ty: Option<Ty>,
371 ) -> Option<Self> { 372 ) -> Option<Self> {
372 let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { 373 let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? {
373 TypeNs::TraitId(tr) => tr, 374 TypeNs::TraitId(tr) => tr,
374 _ => return None, 375 _ => return None,
375 }; 376 };
376 let segment = path.segments.last().expect("path should have at least one segment"); 377 let segment = path.segments().last().expect("path should have at least one segment");
377 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) 378 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty))
378 } 379 }
379 380
@@ -381,7 +382,7 @@ impl TraitRef {
381 db: &impl HirDatabase, 382 db: &impl HirDatabase,
382 resolver: &Resolver, 383 resolver: &Resolver,
383 resolved: TraitId, 384 resolved: TraitId,
384 segment: &PathSegment, 385 segment: PathSegment<'_>,
385 explicit_self_ty: Option<Ty>, 386 explicit_self_ty: Option<Ty>,
386 ) -> Self { 387 ) -> Self {
387 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); 388 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
@@ -407,7 +408,7 @@ impl TraitRef {
407 fn substs_from_path( 408 fn substs_from_path(
408 db: &impl HirDatabase, 409 db: &impl HirDatabase,
409 resolver: &Resolver, 410 resolver: &Resolver,
410 segment: &PathSegment, 411 segment: PathSegment<'_>,
411 resolved: TraitId, 412 resolved: TraitId,
412 ) -> Substs { 413 ) -> Substs {
413 let has_self_param = 414 let has_self_param =
@@ -461,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>(
461 trait_ref: TraitRef, 462 trait_ref: TraitRef,
462) -> impl Iterator<Item = GenericPredicate> + 'a { 463) -> impl Iterator<Item = GenericPredicate> + 'a {
463 let last_segment = match bound { 464 let last_segment = match bound {
464 TypeBound::Path(path) => path.segments.last(), 465 TypeBound::Path(path) => path.segments().last(),
465 TypeBound::Error => None, 466 TypeBound::Error => None,
466 }; 467 };
467 last_segment 468 last_segment
468 .into_iter() 469 .into_iter()
469 .flat_map(|segment| segment.args_and_bindings.iter()) 470 .flat_map(|segment| segment.args_and_bindings.into_iter())
470 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 471 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
471 .map(move |(name, type_ref)| { 472 .map(move |(name, type_ref)| {
472 let associated_ty = 473 let associated_ty =
@@ -532,6 +533,15 @@ pub(crate) fn generic_predicates_for_param_query(
532 .collect() 533 .collect()
533} 534}
534 535
536pub(crate) fn generic_predicates_for_param_recover(
537 _db: &impl HirDatabase,
538 _cycle: &[String],
539 _def: &GenericDefId,
540 _param_idx: &u32,
541) -> Arc<[GenericPredicate]> {
542 Arc::new([])
543}
544
535impl TraitEnvironment { 545impl TraitEnvironment {
536 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { 546 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
537 let predicates = resolver 547 let predicates = resolver
@@ -558,12 +568,11 @@ pub(crate) fn generic_predicates_query(
558/// Resolve the default type params from generics 568/// Resolve the default type params from generics
559pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { 569pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs {
560 let resolver = def.resolver(db); 570 let resolver = def.resolver(db);
561 let generic_params = db.generic_params(def.into()); 571 let generic_params = generics(db, def.into());
562 572
563 let defaults = generic_params 573 let defaults = generic_params
564 .params_including_parent() 574 .iter()
565 .into_iter() 575 .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
566 .map(|p| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
567 .collect(); 576 .collect();
568 577
569 Substs(defaults) 578 Substs(defaults)
@@ -580,7 +589,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig {
580/// Build the declared type of a function. This should not need to look at the 589/// Build the declared type of a function. This should not need to look at the
581/// function body. 590/// function body.
582fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { 591fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty {
583 let generics = db.generic_params(def.into()); 592 let generics = generics(db, def.into());
584 let substs = Substs::identity(&generics); 593 let substs = Substs::identity(&generics);
585 Ty::apply(TypeCtor::FnDef(def.into()), substs) 594 Ty::apply(TypeCtor::FnDef(def.into()), substs)
586} 595}
@@ -630,7 +639,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty {
630 if struct_data.variant_data.is_unit() { 639 if struct_data.variant_data.is_unit() {
631 return type_for_adt(db, def.into()); // Unit struct 640 return type_for_adt(db, def.into()); // Unit struct
632 } 641 }
633 let generics = db.generic_params(def.into()); 642 let generics = generics(db, def.into());
634 let substs = Substs::identity(&generics); 643 let substs = Substs::identity(&generics);
635 Ty::apply(TypeCtor::FnDef(def.into()), substs) 644 Ty::apply(TypeCtor::FnDef(def.into()), substs)
636} 645}
@@ -644,7 +653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId
644 .iter() 653 .iter()
645 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 654 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
646 .collect::<Vec<_>>(); 655 .collect::<Vec<_>>();
647 let generics = db.generic_params(def.parent.into()); 656 let generics = generics(db, def.parent.into());
648 let substs = Substs::identity(&generics); 657 let substs = Substs::identity(&generics);
649 let ret = type_for_adt(db, def.parent.into()).subst(&substs); 658 let ret = type_for_adt(db, def.parent.into()).subst(&substs);
650 FnSig::from_params_and_return(params, ret) 659 FnSig::from_params_and_return(params, ret)
@@ -657,18 +666,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId)
657 if var_data.is_unit() { 666 if var_data.is_unit() {
658 return type_for_adt(db, def.parent.into()); // Unit variant 667 return type_for_adt(db, def.parent.into()); // Unit variant
659 } 668 }
660 let generics = db.generic_params(def.parent.into()); 669 let generics = generics(db, def.parent.into());
661 let substs = Substs::identity(&generics); 670 let substs = Substs::identity(&generics);
662 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) 671 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs)
663} 672}
664 673
665fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { 674fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty {
666 let generics = db.generic_params(adt.into()); 675 let generics = generics(db, adt.into());
667 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) 676 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics))
668} 677}
669 678
670fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { 679fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty {
671 let generics = db.generic_params(t.into()); 680 let generics = generics(db, t.into());
672 let resolver = t.resolver(db); 681 let resolver = t.resolver(db);
673 let type_ref = &db.type_alias_data(t).type_ref; 682 let type_ref = &db.type_alias_data(t).type_ref;
674 let substs = Substs::identity(&generics); 683 let substs = Substs::identity(&generics);
@@ -687,10 +696,11 @@ impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId);
687impl CallableDef { 696impl CallableDef {
688 pub fn krate(self, db: &impl HirDatabase) -> CrateId { 697 pub fn krate(self, db: &impl HirDatabase) -> CrateId {
689 match self { 698 match self {
690 CallableDef::FunctionId(f) => f.lookup(db).module(db).krate, 699 CallableDef::FunctionId(f) => f.lookup(db).module(db),
691 CallableDef::StructId(s) => s.module(db).krate, 700 CallableDef::StructId(s) => s.lookup(db).container.module(db),
692 CallableDef::EnumVariantId(e) => e.parent.module(db).krate, 701 CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db),
693 } 702 }
703 .krate
694 } 704 }
695} 705}
696 706
@@ -733,6 +743,11 @@ pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Ty {
733 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), 743 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
734 } 744 }
735} 745}
746
747pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Ty {
748 Ty::Unknown
749}
750
736pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { 751pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
737 match def { 752 match def {
738 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 753 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
@@ -743,17 +758,24 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
743 } 758 }
744} 759}
745 760
746pub(crate) fn impl_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> ImplTy { 761pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty {
747 let impl_data = db.impl_data(impl_id); 762 let impl_data = db.impl_data(impl_id);
748 let resolver = impl_id.resolver(db); 763 let resolver = impl_id.resolver(db);
749 let self_ty = Ty::from_hir(db, &resolver, &impl_data.target_type); 764 Ty::from_hir(db, &resolver, &impl_data.target_type)
750 match impl_data.target_trait.as_ref() { 765}
751 Some(trait_ref) => { 766
752 match TraitRef::from_hir(db, &resolver, trait_ref, Some(self_ty.clone())) { 767pub(crate) fn impl_self_ty_recover(
753 Some(it) => ImplTy::TraitRef(it), 768 _db: &impl HirDatabase,
754 None => ImplTy::Inherent(self_ty), 769 _cycle: &[String],
755 } 770 _impl_id: &ImplId,
756 } 771) -> Ty {
757 None => ImplTy::Inherent(self_ty), 772 Ty::Unknown
758 } 773}
774
775pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option<TraitRef> {
776 let impl_data = db.impl_data(impl_id);
777 let resolver = impl_id.resolver(db);
778 let self_ty = db.impl_self_ty(impl_id);
779 let target_trait = impl_data.target_trait.as_ref()?;
780 TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone()))
759} 781}
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..fe74acf11 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 match_ergonomics_ref 7 match_ergonomics_ref
8 coerce_merge_fail_fallback 8 coerce_merge_fail_fallback
9 insert_vars_for_impl_trait
9); 10);
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index ee1936b0e..888dc3116 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -6,20 +6,21 @@ use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, 9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId,
10 FunctionId, HasModule, ImplId, TraitId, 10 AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use ra_db::CrateId; 13use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16 16
17use super::Substs;
17use crate::{ 18use crate::{
18 autoderef, 19 autoderef,
19 db::HirDatabase, 20 db::HirDatabase,
20 primitive::{FloatBitness, Uncertain}, 21 primitive::{FloatBitness, Uncertain},
21 utils::all_super_traits, 22 utils::all_super_traits,
22 Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, 23 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
23}; 24};
24 25
25/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -57,12 +58,13 @@ impl CrateImplBlocks {
57 58
58 let crate_def_map = db.crate_def_map(krate); 59 let crate_def_map = db.crate_def_map(krate);
59 for (_module_id, module_data) in crate_def_map.modules.iter() { 60 for (_module_id, module_data) in crate_def_map.modules.iter() {
60 for &impl_id in module_data.impls.iter() { 61 for impl_id in module_data.scope.impls() {
61 match db.impl_ty(impl_id) { 62 match db.impl_trait(impl_id) {
62 ImplTy::TraitRef(tr) => { 63 Some(tr) => {
63 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); 64 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id);
64 } 65 }
65 ImplTy::Inherent(self_ty) => { 66 None => {
67 let self_ty = db.impl_self_ty(impl_id);
66 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) { 68 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) {
67 res.impls.entry(self_ty_fp).or_default().push(impl_id); 69 res.impls.entry(self_ty_fp).or_default().push(impl_id);
68 } 70 }
@@ -132,7 +134,7 @@ impl Ty {
132 LangItemTarget::ImplBlockId(it) => Some(it), 134 LangItemTarget::ImplBlockId(it) => Some(it),
133 _ => None, 135 _ => None,
134 }) 136 })
135 .map(|it| it.module(db).krate) 137 .map(|it| it.lookup(db).container.module(db).krate)
136 .collect(); 138 .collect();
137 Some(res) 139 Some(res)
138 } 140 }
@@ -175,7 +177,6 @@ pub fn iterate_method_candidates<T>(
175 mode: LookupMode, 177 mode: LookupMode,
176 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 178 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
177) -> Option<T> { 179) -> Option<T> {
178 let krate = resolver.krate()?;
179 match mode { 180 match mode {
180 LookupMode::MethodCall => { 181 LookupMode::MethodCall => {
181 // For method calls, rust first does any number of autoderef, and then one 182 // For method calls, rust first does any number of autoderef, and then one
@@ -188,57 +189,159 @@ pub fn iterate_method_candidates<T>(
188 // rustc does an autoderef and then autoref again). 189 // rustc does an autoderef and then autoref again).
189 let environment = TraitEnvironment::lower(db, resolver); 190 let environment = TraitEnvironment::lower(db, resolver);
190 let ty = InEnvironment { value: ty.clone(), environment }; 191 let ty = InEnvironment { value: ty.clone(), environment };
191 for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { 192 let krate = resolver.krate()?;
192 if let Some(result) = 193
193 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) 194 // We have to be careful about the order we're looking at candidates
194 { 195 // in here. Consider the case where we're resolving `x.clone()`
195 return Some(result); 196 // where `x: &Vec<_>`. This resolves to the clone method with self
196 } 197 // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
197 if let Some(result) = iterate_trait_method_candidates( 198 // the receiver type exactly matches before cases where we have to
198 &derefed_ty, 199 // do autoref. But in the autoderef steps, the `&_` self type comes
200 // up *before* the `Vec<_>` self type.
201 //
202 // On the other hand, we don't want to just pick any by-value method
203 // before any by-autoref method; it's just that we need to consider
204 // the methods by autoderef order of *receiver types*, not *self
205 // types*.
206
207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208 for i in 0..deref_chain.len() {
209 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..],
199 db, 211 db,
200 resolver, 212 resolver,
201 name, 213 name,
202 mode,
203 &mut callback, 214 &mut callback,
204 ) { 215 ) {
205 return Some(result); 216 return Some(result);
206 } 217 }
207 } 218 }
219 None
208 } 220 }
209 LookupMode::Path => { 221 LookupMode::Path => {
210 // No autoderef for path lookups 222 // No autoderef for path lookups
211 if let Some(result) = 223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
212 iterate_inherent_methods(&ty, db, name, mode, krate.into(), &mut callback) 224 }
213 { 225 }
214 return Some(result); 226}
215 } 227
216 if let Some(result) = 228fn iterate_method_candidates_with_autoref<T>(
217 iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) 229 deref_chain: &[Canonical<Ty>],
218 { 230 db: &impl HirDatabase,
219 return Some(result); 231 resolver: &Resolver,
220 } 232 name: Option<&Name>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> {
235 if let Some(result) = iterate_method_candidates_by_receiver(
236 &deref_chain[0],
237 &deref_chain[1..],
238 db,
239 resolver,
240 name,
241 &mut callback,
242 ) {
243 return Some(result);
244 }
245 let refed = Canonical {
246 num_vars: deref_chain[0].num_vars,
247 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
248 };
249 if let Some(result) = iterate_method_candidates_by_receiver(
250 &refed,
251 deref_chain,
252 db,
253 resolver,
254 name,
255 &mut callback,
256 ) {
257 return Some(result);
258 }
259 let ref_muted = Canonical {
260 num_vars: deref_chain[0].num_vars,
261 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
262 };
263 if let Some(result) = iterate_method_candidates_by_receiver(
264 &ref_muted,
265 deref_chain,
266 db,
267 resolver,
268 name,
269 &mut callback,
270 ) {
271 return Some(result);
272 }
273 None
274}
275
276fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>,
278 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase,
280 resolver: &Resolver,
281 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> {
284 // We're looking for methods with *receiver* type receiver_ty. These could
285 // be found in any of the derefs of receiver_ty, so we have to go through
286 // that.
287 let krate = resolver.krate()?;
288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291 {
292 return Some(result);
293 }
294 }
295 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296 if let Some(result) = iterate_trait_method_candidates(
297 self_ty,
298 db,
299 resolver,
300 name,
301 Some(receiver_ty),
302 &mut callback,
303 ) {
304 return Some(result);
221 } 305 }
222 } 306 }
223 None 307 None
224} 308}
225 309
310fn iterate_method_candidates_for_self_ty<T>(
311 self_ty: &Canonical<Ty>,
312 db: &impl HirDatabase,
313 resolver: &Resolver,
314 name: Option<&Name>,
315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
316) -> Option<T> {
317 let krate = resolver.krate()?;
318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
319 return Some(result);
320 }
321 if let Some(result) =
322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
323 {
324 return Some(result);
325 }
326 None
327}
328
226fn iterate_trait_method_candidates<T>( 329fn iterate_trait_method_candidates<T>(
227 ty: &Canonical<Ty>, 330 self_ty: &Canonical<Ty>,
228 db: &impl HirDatabase, 331 db: &impl HirDatabase,
229 resolver: &Resolver, 332 resolver: &Resolver,
230 name: Option<&Name>, 333 name: Option<&Name>,
231 mode: LookupMode, 334 receiver_ty: Option<&Canonical<Ty>>,
232 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 335 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
233) -> Option<T> { 336) -> Option<T> {
234 let krate = resolver.krate()?; 337 let krate = resolver.krate()?;
235 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 338 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
236 let env = TraitEnvironment::lower(db, resolver); 339 let env = TraitEnvironment::lower(db, resolver);
237 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 340 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
238 let inherent_trait = ty.value.inherent_trait().into_iter(); 341 let inherent_trait = self_ty.value.inherent_trait().into_iter();
239 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 342 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
240 let traits_from_env = env 343 let traits_from_env = env
241 .trait_predicates_for_self_ty(&ty.value) 344 .trait_predicates_for_self_ty(&self_ty.value)
242 .map(|tr| tr.trait_) 345 .map(|tr| tr.trait_)
243 .flat_map(|t| all_super_traits(db, t)); 346 .flat_map(|t| all_super_traits(db, t));
244 let traits = 347 let traits =
@@ -251,17 +354,17 @@ fn iterate_trait_method_candidates<T>(
251 // iteration 354 // iteration
252 let mut known_implemented = false; 355 let mut known_implemented = false;
253 for (_name, item) in data.items.iter() { 356 for (_name, item) in data.items.iter() {
254 if !is_valid_candidate(db, name, mode, (*item).into()) { 357 if !is_valid_candidate(db, name, receiver_ty, (*item).into(), self_ty) {
255 continue; 358 continue;
256 } 359 }
257 if !known_implemented { 360 if !known_implemented {
258 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 361 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
259 if db.trait_solve(krate.into(), goal).is_none() { 362 if db.trait_solve(krate.into(), goal).is_none() {
260 continue 'traits; 363 continue 'traits;
261 } 364 }
262 } 365 }
263 known_implemented = true; 366 known_implemented = true;
264 if let Some(result) = callback(&ty.value, (*item).into()) { 367 if let Some(result) = callback(&self_ty.value, (*item).into()) {
265 return Some(result); 368 return Some(result);
266 } 369 }
267 } 370 }
@@ -270,22 +373,22 @@ fn iterate_trait_method_candidates<T>(
270} 373}
271 374
272fn iterate_inherent_methods<T>( 375fn iterate_inherent_methods<T>(
273 ty: &Canonical<Ty>, 376 self_ty: &Canonical<Ty>,
274 db: &impl HirDatabase, 377 db: &impl HirDatabase,
275 name: Option<&Name>, 378 name: Option<&Name>,
276 mode: LookupMode, 379 receiver_ty: Option<&Canonical<Ty>>,
277 krate: CrateId, 380 krate: CrateId,
278 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 381 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
279) -> Option<T> { 382) -> Option<T> {
280 for krate in ty.value.def_crates(db, krate)? { 383 for krate in self_ty.value.def_crates(db, krate)? {
281 let impls = db.impls_in_crate(krate); 384 let impls = db.impls_in_crate(krate);
282 385
283 for impl_block in impls.lookup_impl_blocks(&ty.value) { 386 for impl_block in impls.lookup_impl_blocks(&self_ty.value) {
284 for &item in db.impl_data(impl_block).items.iter() { 387 for &item in db.impl_data(impl_block).items.iter() {
285 if !is_valid_candidate(db, name, mode, item) { 388 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
286 continue; 389 continue;
287 } 390 }
288 if let Some(result) = callback(&ty.value, item.into()) { 391 if let Some(result) = callback(&self_ty.value, item) {
289 return Some(result); 392 return Some(result);
290 } 393 }
291 } 394 }
@@ -297,23 +400,68 @@ fn iterate_inherent_methods<T>(
297fn is_valid_candidate( 400fn is_valid_candidate(
298 db: &impl HirDatabase, 401 db: &impl HirDatabase,
299 name: Option<&Name>, 402 name: Option<&Name>,
300 mode: LookupMode, 403 receiver_ty: Option<&Canonical<Ty>>,
301 item: AssocItemId, 404 item: AssocItemId,
405 self_ty: &Canonical<Ty>,
302) -> bool { 406) -> bool {
303 match item { 407 match item {
304 AssocItemId::FunctionId(m) => { 408 AssocItemId::FunctionId(m) => {
305 let data = db.function_data(m); 409 let data = db.function_data(m);
306 name.map_or(true, |name| &data.name == name) 410 if let Some(name) = name {
307 && (data.has_self_param || mode == LookupMode::Path) 411 if &data.name != name {
412 return false;
413 }
414 }
415 if let Some(receiver_ty) = receiver_ty {
416 if !data.has_self_param {
417 return false;
418 }
419 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
420 Some(ty) => ty,
421 None => return false,
422 };
423 if transformed_receiver_ty != receiver_ty.value {
424 return false;
425 }
426 }
427 true
308 } 428 }
309 AssocItemId::ConstId(c) => { 429 AssocItemId::ConstId(c) => {
310 let data = db.const_data(c); 430 let data = db.const_data(c);
311 name.map_or(true, |name| data.name.as_ref() == Some(name)) && (mode == LookupMode::Path) 431 name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
312 } 432 }
313 _ => false, 433 _ => false,
314 } 434 }
315} 435}
316 436
437pub(crate) fn inherent_impl_substs(
438 db: &impl HirDatabase,
439 impl_id: ImplId,
440 self_ty: &Canonical<Ty>,
441) -> Option<Substs> {
442 let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444 let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars };
445 super::infer::unify(&self_ty_with_vars, self_ty)
446}
447
448fn transform_receiver_ty(
449 db: &impl HirDatabase,
450 function_id: FunctionId,
451 self_ty: &Canonical<Ty>,
452) -> Option<Ty> {
453 let substs = match function_id.lookup(db).container {
454 AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455 .push(self_ty.value.clone())
456 .fill_with_unknown()
457 .build(),
458 AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?,
459 AssocContainerId::ContainerId(_) => unreachable!(),
460 };
461 let sig = db.callable_item_signature(function_id.into());
462 Some(sig.params()[0].clone().subst(&substs))
463}
464
317pub fn implements_trait( 465pub fn implements_trait(
318 ty: &Canonical<Ty>, 466 ty: &Canonical<Ty>,
319 db: &impl HirDatabase, 467 db: &impl HirDatabase,
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 1dc9793f9..1a31b587b 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -74,7 +74,7 @@ impl TestDB {
74 for &krate in self.relevant_crates(file_id).iter() { 74 for &krate in self.relevant_crates(file_id).iter() {
75 let crate_def_map = self.crate_def_map(krate); 75 let crate_def_map = self.crate_def_map(krate);
76 for (local_id, data) in crate_def_map.modules.iter() { 76 for (local_id, data) in crate_def_map.modules.iter() {
77 if data.definition == Some(file_id) { 77 if data.origin.file_id() == Some(file_id) {
78 return ModuleId { krate, local_id }; 78 return ModuleId { krate, local_id };
79 } 79 }
80 } 80 }
@@ -98,7 +98,7 @@ impl TestDB {
98 } 98 }
99 } 99 }
100 100
101 for &impl_id in crate_def_map[module_id].impls.iter() { 101 for impl_id in crate_def_map[module_id].scope.impls() {
102 let impl_data = self.impl_data(impl_id); 102 let impl_data = self.impl_data(impl_id);
103 for item in impl_data.items.iter() { 103 for item in impl_data.items.iter() {
104 if let AssocItemId::FunctionId(f) = item { 104 if let AssocItemId::FunctionId(f) = item {
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index c8461b447..d447b4571 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -1,21 +1,26 @@
1mod never_type; 1mod never_type;
2mod coercion; 2mod coercion;
3mod regression;
4mod simple;
5mod patterns;
6mod traits;
7mod method_resolution;
8mod macros;
3 9
4use std::fmt::Write; 10use std::fmt::Write;
5use std::sync::Arc; 11use std::sync::Arc;
6 12
7use hir_def::{ 13use hir_def::{
8 body::BodySourceMap, db::DefDatabase, nameres::CrateDefMap, AssocItemId, DefWithBodyId, 14 body::BodySourceMap, child_by_source::ChildBySource, db::DefDatabase, keys,
9 LocalModuleId, Lookup, ModuleDefId, 15 nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
10}; 16};
11use hir_expand::Source; 17use hir_expand::InFile;
12use insta::assert_snapshot; 18use insta::assert_snapshot;
13use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 19use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
14use ra_syntax::{ 20use ra_syntax::{
15 algo, 21 algo,
16 ast::{self, AstNode}, 22 ast::{self, AstNode},
17}; 23};
18use test_utils::covers;
19 24
20use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult}; 25use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult};
21 26
@@ -23,4669 +28,20 @@ use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResu
23// against snapshots of the expected results using insta. Use cargo-insta to 28// against snapshots of the expected results using insta. Use cargo-insta to
24// update the snapshots. 29// update the snapshots.
25 30
26#[test]
27fn cfg_impl_block() {
28 let (db, pos) = TestDB::with_position(
29 r#"
30//- /main.rs crate:main deps:foo cfg:test
31use foo::S as T;
32struct S;
33
34#[cfg(test)]
35impl S {
36 fn foo1(&self) -> i32 { 0 }
37}
38
39#[cfg(not(test))]
40impl S {
41 fn foo2(&self) -> i32 { 0 }
42}
43
44fn test() {
45 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
46 t<|>;
47}
48
49//- /foo.rs crate:foo
50struct S;
51
52#[cfg(not(test))]
53impl S {
54 fn foo3(&self) -> i32 { 0 }
55}
56
57#[cfg(test)]
58impl S {
59 fn foo4(&self) -> i32 { 0 }
60}
61"#,
62 );
63 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
64}
65
66#[test]
67fn infer_await() {
68 let (db, pos) = TestDB::with_position(
69 r#"
70//- /main.rs crate:main deps:std
71
72struct IntFuture;
73
74impl Future for IntFuture {
75 type Output = u64;
76}
77
78fn test() {
79 let r = IntFuture;
80 let v = r.await;
81 v<|>;
82}
83
84//- /std.rs crate:std
85#[prelude_import] use future::*;
86mod future {
87 trait Future {
88 type Output;
89 }
90}
91
92"#,
93 );
94 assert_eq!("u64", type_at_pos(&db, pos));
95}
96
97#[test]
98fn infer_box() {
99 let (db, pos) = TestDB::with_position(
100 r#"
101//- /main.rs crate:main deps:std
102
103fn test() {
104 let x = box 1;
105 let t = (x, box x, box &1, box [1]);
106 t<|>;
107}
108
109//- /std.rs crate:std
110#[prelude_import] use prelude::*;
111mod prelude {}
112
113mod boxed {
114 pub struct Box<T: ?Sized> {
115 inner: *mut T,
116 }
117}
118
119"#,
120 );
121 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
122}
123
124#[test]
125fn infer_adt_self() {
126 let (db, pos) = TestDB::with_position(
127 r#"
128//- /main.rs
129enum Nat { Succ(Self), Demo(Nat), Zero }
130
131fn test() {
132 let foo: Nat = Nat::Zero;
133 if let Nat::Succ(x) = foo {
134 x<|>
135 }
136}
137
138"#,
139 );
140 assert_eq!("Nat", type_at_pos(&db, pos));
141}
142
143#[test]
144fn infer_try() {
145 let (db, pos) = TestDB::with_position(
146 r#"
147//- /main.rs crate:main deps:std
148
149fn test() {
150 let r: Result<i32, u64> = Result::Ok(1);
151 let v = r?;
152 v<|>;
153}
154
155//- /std.rs crate:std
156
157#[prelude_import] use ops::*;
158mod ops {
159 trait Try {
160 type Ok;
161 type Error;
162 }
163}
164
165#[prelude_import] use result::*;
166mod result {
167 enum Result<O, E> {
168 Ok(O),
169 Err(E)
170 }
171
172 impl<O, E> crate::ops::Try for Result<O, E> {
173 type Ok = O;
174 type Error = E;
175 }
176}
177
178"#,
179 );
180 assert_eq!("i32", type_at_pos(&db, pos));
181}
182
183#[test]
184fn infer_for_loop() {
185 let (db, pos) = TestDB::with_position(
186 r#"
187//- /main.rs crate:main deps:std
188
189use std::collections::Vec;
190
191fn test() {
192 let v = Vec::new();
193 v.push("foo");
194 for x in v {
195 x<|>;
196 }
197}
198
199//- /std.rs crate:std
200
201#[prelude_import] use iter::*;
202mod iter {
203 trait IntoIterator {
204 type Item;
205 }
206}
207
208mod collections {
209 struct Vec<T> {}
210 impl<T> Vec<T> {
211 fn new() -> Self { Vec {} }
212 fn push(&mut self, t: T) { }
213 }
214
215 impl<T> crate::iter::IntoIterator for Vec<T> {
216 type Item=T;
217 }
218}
219"#,
220 );
221 assert_eq!("&str", type_at_pos(&db, pos));
222}
223
224#[test]
225fn infer_while_let() {
226 let (db, pos) = TestDB::with_position(
227 r#"
228//- /main.rs
229enum Option<T> { Some(T), None }
230
231fn test() {
232 let foo: Option<f32> = None;
233 while let Option::Some(x) = foo {
234 <|>x
235 }
236}
237
238"#,
239 );
240 assert_eq!("f32", type_at_pos(&db, pos));
241}
242
243#[test]
244fn infer_basics() {
245 assert_snapshot!(
246 infer(r#"
247fn test(a: u32, b: isize, c: !, d: &str) {
248 a;
249 b;
250 c;
251 d;
252 1usize;
253 1isize;
254 "test";
255 1.0f32;
256}"#),
257 @r###"
258 [9; 10) 'a': u32
259 [17; 18) 'b': isize
260 [27; 28) 'c': !
261 [33; 34) 'd': &str
262 [42; 121) '{ ...f32; }': !
263 [48; 49) 'a': u32
264 [55; 56) 'b': isize
265 [62; 63) 'c': !
266 [69; 70) 'd': &str
267 [76; 82) '1usize': usize
268 [88; 94) '1isize': isize
269 [100; 106) '"test"': &str
270 [112; 118) '1.0f32': f32
271 "###
272 );
273}
274
275#[test]
276fn infer_let() {
277 assert_snapshot!(
278 infer(r#"
279fn test() {
280 let a = 1isize;
281 let b: usize = 1;
282 let c = b;
283 let d: u32;
284 let e;
285 let f: i32 = e;
286}
287"#),
288 @r###"
289 [11; 118) '{ ...= e; }': ()
290 [21; 22) 'a': isize
291 [25; 31) '1isize': isize
292 [41; 42) 'b': usize
293 [52; 53) '1': usize
294 [63; 64) 'c': usize
295 [67; 68) 'b': usize
296 [78; 79) 'd': u32
297 [94; 95) 'e': i32
298 [105; 106) 'f': i32
299 [114; 115) 'e': i32
300 "###
301 );
302}
303
304#[test]
305fn infer_paths() {
306 assert_snapshot!(
307 infer(r#"
308fn a() -> u32 { 1 }
309
310mod b {
311 fn c() -> u32 { 1 }
312}
313
314fn test() {
315 a();
316 b::c();
317}
318"#),
319 @r###"
320 [15; 20) '{ 1 }': u32
321 [17; 18) '1': u32
322 [48; 53) '{ 1 }': u32
323 [50; 51) '1': u32
324 [67; 91) '{ ...c(); }': ()
325 [73; 74) 'a': fn a() -> u32
326 [73; 76) 'a()': u32
327 [82; 86) 'b::c': fn c() -> u32
328 [82; 88) 'b::c()': u32
329 "###
330 );
331}
332
333#[test]
334fn infer_path_type() {
335 assert_snapshot!(
336 infer(r#"
337struct S;
338
339impl S {
340 fn foo() -> i32 { 1 }
341}
342
343fn test() {
344 S::foo();
345 <S>::foo();
346}
347"#),
348 @r###"
349 [41; 46) '{ 1 }': i32
350 [43; 44) '1': i32
351 [60; 93) '{ ...o(); }': ()
352 [66; 72) 'S::foo': fn foo() -> i32
353 [66; 74) 'S::foo()': i32
354 [80; 88) '<S>::foo': fn foo() -> i32
355 [80; 90) '<S>::foo()': i32
356 "###
357 );
358}
359
360#[test]
361fn infer_slice_method() {
362 assert_snapshot!(
363 infer(r#"
364#[lang = "slice"]
365impl<T> [T] {
366 fn foo(&self) -> T {
367 loop {}
368 }
369}
370
371#[lang = "slice_alloc"]
372impl<T> [T] {}
373
374fn test() {
375 <[_]>::foo(b"foo");
376}
377"#),
378 @r###"
379 [45; 49) 'self': &[T]
380 [56; 79) '{ ... }': T
381 [66; 73) 'loop {}': !
382 [71; 73) '{}': ()
383 [133; 160) '{ ...o"); }': ()
384 [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T
385 [139; 157) '<[_]>:..."foo")': u8
386 [150; 156) 'b"foo"': &[u8]
387 "###
388 );
389}
390
391#[test]
392fn infer_struct() {
393 assert_snapshot!(
394 infer(r#"
395struct A {
396 b: B,
397 c: C,
398}
399struct B;
400struct C(usize);
401
402fn test() {
403 let c = C(1);
404 B;
405 let a: A = A { b: B, c: C(1) };
406 a.b;
407 a.c;
408}
409"#),
410 @r###"
411 [72; 154) '{ ...a.c; }': ()
412 [82; 83) 'c': C
413 [86; 87) 'C': C(usize) -> C
414 [86; 90) 'C(1)': C
415 [88; 89) '1': usize
416 [96; 97) 'B': B
417 [107; 108) 'a': A
418 [114; 133) 'A { b:...C(1) }': A
419 [121; 122) 'B': B
420 [127; 128) 'C': C(usize) -> C
421 [127; 131) 'C(1)': C
422 [129; 130) '1': usize
423 [139; 140) 'a': A
424 [139; 142) 'a.b': B
425 [148; 149) 'a': A
426 [148; 151) 'a.c': C
427 "###
428 );
429}
430
431#[test]
432fn infer_enum() {
433 assert_snapshot!(
434 infer(r#"
435enum E {
436 V1 { field: u32 },
437 V2
438}
439fn test() {
440 E::V1 { field: 1 };
441 E::V2;
442}"#),
443 @r###"
444 [48; 82) '{ E:...:V2; }': ()
445 [52; 70) 'E::V1 ...d: 1 }': E
446 [67; 68) '1': u32
447 [74; 79) 'E::V2': E
448 "###
449 );
450}
451
452#[test]
453fn infer_refs() {
454 assert_snapshot!(
455 infer(r#"
456fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
457 a;
458 *a;
459 &a;
460 &mut a;
461 b;
462 *b;
463 &b;
464 c;
465 *c;
466 d;
467 *d;
468}
469"#),
470 @r###"
471 [9; 10) 'a': &u32
472 [18; 19) 'b': &mut u32
473 [31; 32) 'c': *const u32
474 [46; 47) 'd': *mut u32
475 [59; 150) '{ ... *d; }': ()
476 [65; 66) 'a': &u32
477 [72; 74) '*a': u32
478 [73; 74) 'a': &u32
479 [80; 82) '&a': &&u32
480 [81; 82) 'a': &u32
481 [88; 94) '&mut a': &mut &u32
482 [93; 94) 'a': &u32
483 [100; 101) 'b': &mut u32
484 [107; 109) '*b': u32
485 [108; 109) 'b': &mut u32
486 [115; 117) '&b': &&mut u32
487 [116; 117) 'b': &mut u32
488 [123; 124) 'c': *const u32
489 [130; 132) '*c': u32
490 [131; 132) 'c': *const u32
491 [138; 139) 'd': *mut u32
492 [145; 147) '*d': u32
493 [146; 147) 'd': *mut u32
494 "###
495 );
496}
497
498#[test]
499fn infer_literals() {
500 assert_snapshot!(
501 infer(r##"
502fn test() {
503 5i32;
504 5f32;
505 5f64;
506 "hello";
507 b"bytes";
508 'c';
509 b'b';
510 3.14;
511 5000;
512 false;
513 true;
514 r#"
515 //! doc
516 // non-doc
517 mod foo {}
518 "#;
519 br#"yolo"#;
520}
521"##),
522 @r###"
523 [11; 221) '{ ...o"#; }': ()
524 [17; 21) '5i32': i32
525 [27; 31) '5f32': f32
526 [37; 41) '5f64': f64
527 [47; 54) '"hello"': &str
528 [60; 68) 'b"bytes"': &[u8]
529 [74; 77) ''c'': char
530 [83; 87) 'b'b'': u8
531 [93; 97) '3.14': f64
532 [103; 107) '5000': i32
533 [113; 118) 'false': bool
534 [124; 128) 'true': bool
535 [134; 202) 'r#" ... "#': &str
536 [208; 218) 'br#"yolo"#': &[u8]
537 "###
538 );
539}
540
541#[test]
542fn infer_unary_op() {
543 assert_snapshot!(
544 infer(r#"
545enum SomeType {}
546
547fn test(x: SomeType) {
548 let b = false;
549 let c = !b;
550 let a = 100;
551 let d: i128 = -a;
552 let e = -100;
553 let f = !!!true;
554 let g = !42;
555 let h = !10u32;
556 let j = !a;
557 -3.14;
558 !3;
559 -x;
560 !x;
561 -"hello";
562 !"hello";
563}
564"#),
565 @r###"
566 [27; 28) 'x': SomeType
567 [40; 272) '{ ...lo"; }': ()
568 [50; 51) 'b': bool
569 [54; 59) 'false': bool
570 [69; 70) 'c': bool
571 [73; 75) '!b': bool
572 [74; 75) 'b': bool
573 [85; 86) 'a': i128
574 [89; 92) '100': i128
575 [102; 103) 'd': i128
576 [112; 114) '-a': i128
577 [113; 114) 'a': i128
578 [124; 125) 'e': i32
579 [128; 132) '-100': i32
580 [129; 132) '100': i32
581 [142; 143) 'f': bool
582 [146; 153) '!!!true': bool
583 [147; 153) '!!true': bool
584 [148; 153) '!true': bool
585 [149; 153) 'true': bool
586 [163; 164) 'g': i32
587 [167; 170) '!42': i32
588 [168; 170) '42': i32
589 [180; 181) 'h': u32
590 [184; 190) '!10u32': u32
591 [185; 190) '10u32': u32
592 [200; 201) 'j': i128
593 [204; 206) '!a': i128
594 [205; 206) 'a': i128
595 [212; 217) '-3.14': f64
596 [213; 217) '3.14': f64
597 [223; 225) '!3': i32
598 [224; 225) '3': i32
599 [231; 233) '-x': {unknown}
600 [232; 233) 'x': SomeType
601 [239; 241) '!x': {unknown}
602 [240; 241) 'x': SomeType
603 [247; 255) '-"hello"': {unknown}
604 [248; 255) '"hello"': &str
605 [261; 269) '!"hello"': {unknown}
606 [262; 269) '"hello"': &str
607 "###
608 );
609}
610
611#[test]
612fn infer_backwards() {
613 assert_snapshot!(
614 infer(r#"
615fn takes_u32(x: u32) {}
616
617struct S { i32_field: i32 }
618
619fn test() -> &mut &f64 {
620 let a = unknown_function();
621 takes_u32(a);
622 let b = unknown_function();
623 S { i32_field: b };
624 let c = unknown_function();
625 &mut &c
626}
627"#),
628 @r###"
629 [14; 15) 'x': u32
630 [22; 24) '{}': ()
631 [78; 231) '{ ...t &c }': &mut &f64
632 [88; 89) 'a': u32
633 [92; 108) 'unknow...nction': {unknown}
634 [92; 110) 'unknow...tion()': u32
635 [116; 125) 'takes_u32': fn takes_u32(u32) -> ()
636 [116; 128) 'takes_u32(a)': ()
637 [126; 127) 'a': u32
638 [138; 139) 'b': i32
639 [142; 158) 'unknow...nction': {unknown}
640 [142; 160) 'unknow...tion()': i32
641 [166; 184) 'S { i3...d: b }': S
642 [181; 182) 'b': i32
643 [194; 195) 'c': f64
644 [198; 214) 'unknow...nction': {unknown}
645 [198; 216) 'unknow...tion()': f64
646 [222; 229) '&mut &c': &mut &f64
647 [227; 229) '&c': &f64
648 [228; 229) 'c': f64
649 "###
650 );
651}
652
653#[test]
654fn infer_self() {
655 assert_snapshot!(
656 infer(r#"
657struct S;
658
659impl S {
660 fn test(&self) {
661 self;
662 }
663 fn test2(self: &Self) {
664 self;
665 }
666 fn test3() -> Self {
667 S {}
668 }
669 fn test4() -> Self {
670 Self {}
671 }
672}
673"#),
674 @r###"
675 [34; 38) 'self': &S
676 [40; 61) '{ ... }': ()
677 [50; 54) 'self': &S
678 [75; 79) 'self': &S
679 [88; 109) '{ ... }': ()
680 [98; 102) 'self': &S
681 [133; 153) '{ ... }': S
682 [143; 147) 'S {}': S
683 [177; 200) '{ ... }': S
684 [187; 194) 'Self {}': S
685 "###
686 );
687}
688
689#[test]
690fn infer_binary_op() {
691 assert_snapshot!(
692 infer(r#"
693fn f(x: bool) -> i32 {
694 0i32
695}
696
697fn test() -> bool {
698 let x = a && b;
699 let y = true || false;
700 let z = x == y;
701 let t = x != y;
702 let minus_forty: isize = -40isize;
703 let h = minus_forty <= CONST_2;
704 let c = f(z || y) + 5;
705 let d = b;
706 let g = minus_forty ^= i;
707 let ten: usize = 10;
708 let ten_is_eleven = ten == some_num;
709
710 ten < 3
711}
712"#),
713 @r###"
714 [6; 7) 'x': bool
715 [22; 34) '{ 0i32 }': i32
716 [28; 32) '0i32': i32
717 [54; 370) '{ ... < 3 }': bool
718 [64; 65) 'x': bool
719 [68; 69) 'a': bool
720 [68; 74) 'a && b': bool
721 [73; 74) 'b': bool
722 [84; 85) 'y': bool
723 [88; 92) 'true': bool
724 [88; 101) 'true || false': bool
725 [96; 101) 'false': bool
726 [111; 112) 'z': bool
727 [115; 116) 'x': bool
728 [115; 121) 'x == y': bool
729 [120; 121) 'y': bool
730 [131; 132) 't': bool
731 [135; 136) 'x': bool
732 [135; 141) 'x != y': bool
733 [140; 141) 'y': bool
734 [151; 162) 'minus_forty': isize
735 [172; 180) '-40isize': isize
736 [173; 180) '40isize': isize
737 [190; 191) 'h': bool
738 [194; 205) 'minus_forty': isize
739 [194; 216) 'minus_...ONST_2': bool
740 [209; 216) 'CONST_2': isize
741 [226; 227) 'c': i32
742 [230; 231) 'f': fn f(bool) -> i32
743 [230; 239) 'f(z || y)': i32
744 [230; 243) 'f(z || y) + 5': i32
745 [232; 233) 'z': bool
746 [232; 238) 'z || y': bool
747 [237; 238) 'y': bool
748 [242; 243) '5': i32
749 [253; 254) 'd': {unknown}
750 [257; 258) 'b': {unknown}
751 [268; 269) 'g': ()
752 [272; 283) 'minus_forty': isize
753 [272; 288) 'minus_...y ^= i': ()
754 [287; 288) 'i': isize
755 [298; 301) 'ten': usize
756 [311; 313) '10': usize
757 [323; 336) 'ten_is_eleven': bool
758 [339; 342) 'ten': usize
759 [339; 354) 'ten == some_num': bool
760 [346; 354) 'some_num': usize
761 [361; 364) 'ten': usize
762 [361; 368) 'ten < 3': bool
763 [367; 368) '3': usize
764 "###
765 );
766}
767
768#[test]
769fn infer_field_autoderef() {
770 assert_snapshot!(
771 infer(r#"
772struct A {
773 b: B,
774}
775struct B;
776
777fn test1(a: A) {
778 let a1 = a;
779 a1.b;
780 let a2 = &a;
781 a2.b;
782 let a3 = &mut a;
783 a3.b;
784 let a4 = &&&&&&&a;
785 a4.b;
786 let a5 = &mut &&mut &&mut a;
787 a5.b;
788}
789
790fn test2(a1: *const A, a2: *mut A) {
791 a1.b;
792 a2.b;
793}
794"#),
795 @r###"
796 [44; 45) 'a': A
797 [50; 213) '{ ...5.b; }': ()
798 [60; 62) 'a1': A
799 [65; 66) 'a': A
800 [72; 74) 'a1': A
801 [72; 76) 'a1.b': B
802 [86; 88) 'a2': &A
803 [91; 93) '&a': &A
804 [92; 93) 'a': A
805 [99; 101) 'a2': &A
806 [99; 103) 'a2.b': B
807 [113; 115) 'a3': &mut A
808 [118; 124) '&mut a': &mut A
809 [123; 124) 'a': A
810 [130; 132) 'a3': &mut A
811 [130; 134) 'a3.b': B
812 [144; 146) 'a4': &&&&&&&A
813 [149; 157) '&&&&&&&a': &&&&&&&A
814 [150; 157) '&&&&&&a': &&&&&&A
815 [151; 157) '&&&&&a': &&&&&A
816 [152; 157) '&&&&a': &&&&A
817 [153; 157) '&&&a': &&&A
818 [154; 157) '&&a': &&A
819 [155; 157) '&a': &A
820 [156; 157) 'a': A
821 [163; 165) 'a4': &&&&&&&A
822 [163; 167) 'a4.b': B
823 [177; 179) 'a5': &mut &&mut &&mut A
824 [182; 200) '&mut &...&mut a': &mut &&mut &&mut A
825 [187; 200) '&&mut &&mut a': &&mut &&mut A
826 [188; 200) '&mut &&mut a': &mut &&mut A
827 [193; 200) '&&mut a': &&mut A
828 [194; 200) '&mut a': &mut A
829 [199; 200) 'a': A
830 [206; 208) 'a5': &mut &&mut &&mut A
831 [206; 210) 'a5.b': B
832 [224; 226) 'a1': *const A
833 [238; 240) 'a2': *mut A
834 [250; 273) '{ ...2.b; }': ()
835 [256; 258) 'a1': *const A
836 [256; 260) 'a1.b': B
837 [266; 268) 'a2': *mut A
838 [266; 270) 'a2.b': B
839 "###
840 );
841}
842
843#[test]
844fn infer_argument_autoderef() {
845 assert_snapshot!(
846 infer(r#"
847#[lang = "deref"]
848pub trait Deref {
849 type Target;
850 fn deref(&self) -> &Self::Target;
851}
852
853struct A<T>(T);
854
855impl<T> A<T> {
856 fn foo(&self) -> &T {
857 &self.0
858 }
859}
860
861struct B<T>(T);
862
863impl<T> Deref for B<T> {
864 type Target = T;
865 fn deref(&self) -> &Self::Target {
866 &self.0
867 }
868}
869
870fn test() {
871 let t = A::foo(&&B(B(A(42))));
872}
873"#),
874 @r###"
875 [68; 72) 'self': &Self
876 [139; 143) 'self': &A<T>
877 [151; 174) '{ ... }': &T
878 [161; 168) '&self.0': &T
879 [162; 166) 'self': &A<T>
880 [162; 168) 'self.0': T
881 [255; 259) 'self': &B<T>
882 [278; 301) '{ ... }': &T
883 [288; 295) '&self.0': &T
884 [289; 293) 'self': &B<T>
885 [289; 295) 'self.0': T
886 [315; 353) '{ ...))); }': ()
887 [325; 326) 't': &i32
888 [329; 335) 'A::foo': fn foo<i32>(&A<T>) -> &T
889 [329; 350) 'A::foo...42))))': &i32
890 [336; 349) '&&B(B(A(42)))': &&B<B<A<i32>>>
891 [337; 349) '&B(B(A(42)))': &B<B<A<i32>>>
892 [338; 339) 'B': B<B<A<i32>>>(T) -> B<T>
893 [338; 349) 'B(B(A(42)))': B<B<A<i32>>>
894 [340; 341) 'B': B<A<i32>>(T) -> B<T>
895 [340; 348) 'B(A(42))': B<A<i32>>
896 [342; 343) 'A': A<i32>(T) -> A<T>
897 [342; 347) 'A(42)': A<i32>
898 [344; 346) '42': i32
899 "###
900 );
901}
902
903#[test]
904fn infer_method_argument_autoderef() {
905 assert_snapshot!(
906 infer(r#"
907#[lang = "deref"]
908pub trait Deref {
909 type Target;
910 fn deref(&self) -> &Self::Target;
911}
912
913struct A<T>(*mut T);
914
915impl<T> A<T> {
916 fn foo(&self, x: &A<T>) -> &T {
917 &*x.0
918 }
919}
920
921struct B<T>(T);
922
923impl<T> Deref for B<T> {
924 type Target = T;
925 fn deref(&self) -> &Self::Target {
926 &self.0
927 }
928}
929
930fn test(a: A<i32>) {
931 let t = A(0 as *mut _).foo(&&B(B(a)));
932}
933"#),
934 @r###"
935 [68; 72) 'self': &Self
936 [144; 148) 'self': &A<T>
937 [150; 151) 'x': &A<T>
938 [166; 187) '{ ... }': &T
939 [176; 181) '&*x.0': &T
940 [177; 181) '*x.0': T
941 [178; 179) 'x': &A<T>
942 [178; 181) 'x.0': *mut T
943 [268; 272) 'self': &B<T>
944 [291; 314) '{ ... }': &T
945 [301; 308) '&self.0': &T
946 [302; 306) 'self': &B<T>
947 [302; 308) 'self.0': T
948 [326; 327) 'a': A<i32>
949 [337; 383) '{ ...))); }': ()
950 [347; 348) 't': &i32
951 [351; 352) 'A': A<i32>(*mut T) -> A<T>
952 [351; 365) 'A(0 as *mut _)': A<i32>
953 [351; 380) 'A(0 as...B(a)))': &i32
954 [353; 354) '0': i32
955 [353; 364) '0 as *mut _': *mut i32
956 [370; 379) '&&B(B(a))': &&B<B<A<i32>>>
957 [371; 379) '&B(B(a))': &B<B<A<i32>>>
958 [372; 373) 'B': B<B<A<i32>>>(T) -> B<T>
959 [372; 379) 'B(B(a))': B<B<A<i32>>>
960 [374; 375) 'B': B<A<i32>>(T) -> B<T>
961 [374; 378) 'B(a)': B<A<i32>>
962 [376; 377) 'a': A<i32>
963 "###
964 );
965}
966
967#[test]
968fn bug_484() {
969 assert_snapshot!(
970 infer(r#"
971fn test() {
972 let x = if true {};
973}
974"#),
975 @r###"
976 [11; 37) '{ l... {}; }': ()
977 [20; 21) 'x': ()
978 [24; 34) 'if true {}': ()
979 [27; 31) 'true': bool
980 [32; 34) '{}': ()
981 "###
982 );
983}
984
985#[test]
986fn infer_in_elseif() {
987 assert_snapshot!(
988 infer(r#"
989struct Foo { field: i32 }
990fn main(foo: Foo) {
991 if true {
992
993 } else if false {
994 foo.field
995 }
996}
997"#),
998 @r###"
999 [35; 38) 'foo': Foo
1000 [45; 109) '{ ... } }': ()
1001 [51; 107) 'if tru... }': ()
1002 [54; 58) 'true': bool
1003 [59; 67) '{ }': ()
1004 [73; 107) 'if fal... }': ()
1005 [76; 81) 'false': bool
1006 [82; 107) '{ ... }': i32
1007 [92; 95) 'foo': Foo
1008 [92; 101) 'foo.field': i32
1009 "###
1010 )
1011}
1012
1013#[test]
1014fn infer_if_match_with_return() {
1015 assert_snapshot!(
1016 infer(r#"
1017fn foo() {
1018 let _x1 = if true {
1019 1
1020 } else {
1021 return;
1022 };
1023 let _x2 = if true {
1024 2
1025 } else {
1026 return
1027 };
1028 let _x3 = match true {
1029 true => 3,
1030 _ => {
1031 return;
1032 }
1033 };
1034 let _x4 = match true {
1035 true => 4,
1036 _ => return
1037 };
1038}"#),
1039 @r###"
1040 [10; 323) '{ ... }; }': ()
1041 [20; 23) '_x1': i32
1042 [26; 80) 'if tru... }': i32
1043 [29; 33) 'true': bool
1044 [34; 51) '{ ... }': i32
1045 [44; 45) '1': i32
1046 [57; 80) '{ ... }': !
1047 [67; 73) 'return': !
1048 [90; 93) '_x2': i32
1049 [96; 149) 'if tru... }': i32
1050 [99; 103) 'true': bool
1051 [104; 121) '{ ... }': i32
1052 [114; 115) '2': i32
1053 [127; 149) '{ ... }': !
1054 [137; 143) 'return': !
1055 [159; 162) '_x3': i32
1056 [165; 247) 'match ... }': i32
1057 [171; 175) 'true': bool
1058 [186; 190) 'true': bool
1059 [194; 195) '3': i32
1060 [205; 206) '_': bool
1061 [210; 241) '{ ... }': !
1062 [224; 230) 'return': !
1063 [257; 260) '_x4': i32
1064 [263; 320) 'match ... }': i32
1065 [269; 273) 'true': bool
1066 [284; 288) 'true': bool
1067 [292; 293) '4': i32
1068 [303; 304) '_': bool
1069 [308; 314) 'return': !
1070 "###
1071 )
1072}
1073
1074#[test]
1075fn infer_inherent_method() {
1076 assert_snapshot!(
1077 infer(r#"
1078struct A;
1079
1080impl A {
1081 fn foo(self, x: u32) -> i32 {}
1082}
1083
1084mod b {
1085 impl super::A {
1086 fn bar(&self, x: u64) -> i64 {}
1087 }
1088}
1089
1090fn test(a: A) {
1091 a.foo(1);
1092 (&a).bar(1);
1093 a.bar(1);
1094}
1095"#),
1096 @r###"
1097 [32; 36) 'self': A
1098 [38; 39) 'x': u32
1099 [53; 55) '{}': ()
1100 [103; 107) 'self': &A
1101 [109; 110) 'x': u64
1102 [124; 126) '{}': ()
1103 [144; 145) 'a': A
1104 [150; 198) '{ ...(1); }': ()
1105 [156; 157) 'a': A
1106 [156; 164) 'a.foo(1)': i32
1107 [162; 163) '1': u32
1108 [170; 181) '(&a).bar(1)': i64
1109 [171; 173) '&a': &A
1110 [172; 173) 'a': A
1111 [179; 180) '1': u64
1112 [187; 188) 'a': A
1113 [187; 195) 'a.bar(1)': i64
1114 [193; 194) '1': u64
1115 "###
1116 );
1117}
1118
1119#[test]
1120fn infer_inherent_method_str() {
1121 assert_snapshot!(
1122 infer(r#"
1123#[lang = "str"]
1124impl str {
1125 fn foo(&self) -> i32 {}
1126}
1127
1128fn test() {
1129 "foo".foo();
1130}
1131"#),
1132 @r###"
1133 [40; 44) 'self': &str
1134 [53; 55) '{}': ()
1135 [69; 89) '{ ...o(); }': ()
1136 [75; 80) '"foo"': &str
1137 [75; 86) '"foo".foo()': i32
1138 "###
1139 );
1140}
1141
1142#[test]
1143fn infer_tuple() {
1144 assert_snapshot!(
1145 infer(r#"
1146fn test(x: &str, y: isize) {
1147 let a: (u32, &str) = (1, "a");
1148 let b = (a, x);
1149 let c = (y, x);
1150 let d = (c, x);
1151 let e = (1, "e");
1152 let f = (e, "d");
1153}
1154"#),
1155 @r###"
1156 [9; 10) 'x': &str
1157 [18; 19) 'y': isize
1158 [28; 170) '{ ...d"); }': ()
1159 [38; 39) 'a': (u32, &str)
1160 [55; 63) '(1, "a")': (u32, &str)
1161 [56; 57) '1': u32
1162 [59; 62) '"a"': &str
1163 [73; 74) 'b': ((u32, &str), &str)
1164 [77; 83) '(a, x)': ((u32, &str), &str)
1165 [78; 79) 'a': (u32, &str)
1166 [81; 82) 'x': &str
1167 [93; 94) 'c': (isize, &str)
1168 [97; 103) '(y, x)': (isize, &str)
1169 [98; 99) 'y': isize
1170 [101; 102) 'x': &str
1171 [113; 114) 'd': ((isize, &str), &str)
1172 [117; 123) '(c, x)': ((isize, &str), &str)
1173 [118; 119) 'c': (isize, &str)
1174 [121; 122) 'x': &str
1175 [133; 134) 'e': (i32, &str)
1176 [137; 145) '(1, "e")': (i32, &str)
1177 [138; 139) '1': i32
1178 [141; 144) '"e"': &str
1179 [155; 156) 'f': ((i32, &str), &str)
1180 [159; 167) '(e, "d")': ((i32, &str), &str)
1181 [160; 161) 'e': (i32, &str)
1182 [163; 166) '"d"': &str
1183 "###
1184 );
1185}
1186
1187#[test]
1188fn infer_array() {
1189 assert_snapshot!(
1190 infer(r#"
1191fn test(x: &str, y: isize) {
1192 let a = [x];
1193 let b = [a, a];
1194 let c = [b, b];
1195
1196 let d = [y, 1, 2, 3];
1197 let d = [1, y, 2, 3];
1198 let e = [y];
1199 let f = [d, d];
1200 let g = [e, e];
1201
1202 let h = [1, 2];
1203 let i = ["a", "b"];
1204
1205 let b = [a, ["b"]];
1206 let x: [u8; 0] = [];
1207}
1208"#),
1209 @r###"
1210 [9; 10) 'x': &str
1211 [18; 19) 'y': isize
1212 [28; 293) '{ ... []; }': ()
1213 [38; 39) 'a': [&str;_]
1214 [42; 45) '[x]': [&str;_]
1215 [43; 44) 'x': &str
1216 [55; 56) 'b': [[&str;_];_]
1217 [59; 65) '[a, a]': [[&str;_];_]
1218 [60; 61) 'a': [&str;_]
1219 [63; 64) 'a': [&str;_]
1220 [75; 76) 'c': [[[&str;_];_];_]
1221 [79; 85) '[b, b]': [[[&str;_];_];_]
1222 [80; 81) 'b': [[&str;_];_]
1223 [83; 84) 'b': [[&str;_];_]
1224 [96; 97) 'd': [isize;_]
1225 [100; 112) '[y, 1, 2, 3]': [isize;_]
1226 [101; 102) 'y': isize
1227 [104; 105) '1': isize
1228 [107; 108) '2': isize
1229 [110; 111) '3': isize
1230 [122; 123) 'd': [isize;_]
1231 [126; 138) '[1, y, 2, 3]': [isize;_]
1232 [127; 128) '1': isize
1233 [130; 131) 'y': isize
1234 [133; 134) '2': isize
1235 [136; 137) '3': isize
1236 [148; 149) 'e': [isize;_]
1237 [152; 155) '[y]': [isize;_]
1238 [153; 154) 'y': isize
1239 [165; 166) 'f': [[isize;_];_]
1240 [169; 175) '[d, d]': [[isize;_];_]
1241 [170; 171) 'd': [isize;_]
1242 [173; 174) 'd': [isize;_]
1243 [185; 186) 'g': [[isize;_];_]
1244 [189; 195) '[e, e]': [[isize;_];_]
1245 [190; 191) 'e': [isize;_]
1246 [193; 194) 'e': [isize;_]
1247 [206; 207) 'h': [i32;_]
1248 [210; 216) '[1, 2]': [i32;_]
1249 [211; 212) '1': i32
1250 [214; 215) '2': i32
1251 [226; 227) 'i': [&str;_]
1252 [230; 240) '["a", "b"]': [&str;_]
1253 [231; 234) '"a"': &str
1254 [236; 239) '"b"': &str
1255 [251; 252) 'b': [[&str;_];_]
1256 [255; 265) '[a, ["b"]]': [[&str;_];_]
1257 [256; 257) 'a': [&str;_]
1258 [259; 264) '["b"]': [&str;_]
1259 [260; 263) '"b"': &str
1260 [275; 276) 'x': [u8;_]
1261 [288; 290) '[]': [u8;_]
1262 "###
1263 );
1264}
1265
1266#[test]
1267fn infer_pattern() {
1268 assert_snapshot!(
1269 infer(r#"
1270fn test(x: &i32) {
1271 let y = x;
1272 let &z = x;
1273 let a = z;
1274 let (c, d) = (1, "hello");
1275
1276 for (e, f) in some_iter {
1277 let g = e;
1278 }
1279
1280 if let [val] = opt {
1281 let h = val;
1282 }
1283
1284 let lambda = |a: u64, b, c: i32| { a + b; c };
1285
1286 let ref ref_to_x = x;
1287 let mut mut_x = x;
1288 let ref mut mut_ref_to_x = x;
1289 let k = mut_ref_to_x;
1290}
1291"#),
1292 @r###"
1293 [9; 10) 'x': &i32
1294 [18; 369) '{ ...o_x; }': ()
1295 [28; 29) 'y': &i32
1296 [32; 33) 'x': &i32
1297 [43; 45) '&z': &i32
1298 [44; 45) 'z': i32
1299 [48; 49) 'x': &i32
1300 [59; 60) 'a': i32
1301 [63; 64) 'z': i32
1302 [74; 80) '(c, d)': (i32, &str)
1303 [75; 76) 'c': i32
1304 [78; 79) 'd': &str
1305 [83; 95) '(1, "hello")': (i32, &str)
1306 [84; 85) '1': i32
1307 [87; 94) '"hello"': &str
1308 [102; 152) 'for (e... }': ()
1309 [106; 112) '(e, f)': ({unknown}, {unknown})
1310 [107; 108) 'e': {unknown}
1311 [110; 111) 'f': {unknown}
1312 [116; 125) 'some_iter': {unknown}
1313 [126; 152) '{ ... }': ()
1314 [140; 141) 'g': {unknown}
1315 [144; 145) 'e': {unknown}
1316 [158; 205) 'if let... }': ()
1317 [165; 170) '[val]': {unknown}
1318 [173; 176) 'opt': {unknown}
1319 [177; 205) '{ ... }': ()
1320 [191; 192) 'h': {unknown}
1321 [195; 198) 'val': {unknown}
1322 [215; 221) 'lambda': |u64, u64, i32| -> i32
1323 [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
1324 [225; 226) 'a': u64
1325 [233; 234) 'b': u64
1326 [236; 237) 'c': i32
1327 [244; 256) '{ a + b; c }': i32
1328 [246; 247) 'a': u64
1329 [246; 251) 'a + b': u64
1330 [250; 251) 'b': u64
1331 [253; 254) 'c': i32
1332 [267; 279) 'ref ref_to_x': &&i32
1333 [282; 283) 'x': &i32
1334 [293; 302) 'mut mut_x': &i32
1335 [305; 306) 'x': &i32
1336 [316; 336) 'ref mu...f_to_x': &mut &i32
1337 [339; 340) 'x': &i32
1338 [350; 351) 'k': &mut &i32
1339 [354; 366) 'mut_ref_to_x': &mut &i32
1340 "###
1341 );
1342}
1343
1344#[test]
1345fn infer_pattern_match_ergonomics() {
1346 assert_snapshot!(
1347 infer(r#"
1348struct A<T>(T);
1349
1350fn test() {
1351 let A(n) = &A(1);
1352 let A(n) = &mut A(1);
1353}
1354"#),
1355 @r###"
1356 [28; 79) '{ ...(1); }': ()
1357 [38; 42) 'A(n)': A<i32>
1358 [40; 41) 'n': &i32
1359 [45; 50) '&A(1)': &A<i32>
1360 [46; 47) 'A': A<i32>(T) -> A<T>
1361 [46; 50) 'A(1)': A<i32>
1362 [48; 49) '1': i32
1363 [60; 64) 'A(n)': A<i32>
1364 [62; 63) 'n': &mut i32
1365 [67; 76) '&mut A(1)': &mut A<i32>
1366 [72; 73) 'A': A<i32>(T) -> A<T>
1367 [72; 76) 'A(1)': A<i32>
1368 [74; 75) '1': i32
1369 "###
1370 );
1371}
1372
1373#[test]
1374fn infer_pattern_match_ergonomics_ref() {
1375 covers!(match_ergonomics_ref);
1376 assert_snapshot!(
1377 infer(r#"
1378fn test() {
1379 let v = &(1, &2);
1380 let (_, &w) = v;
1381}
1382"#),
1383 @r###"
1384 [11; 57) '{ ...= v; }': ()
1385 [21; 22) 'v': &(i32, &i32)
1386 [25; 33) '&(1, &2)': &(i32, &i32)
1387 [26; 33) '(1, &2)': (i32, &i32)
1388 [27; 28) '1': i32
1389 [30; 32) '&2': &i32
1390 [31; 32) '2': i32
1391 [43; 50) '(_, &w)': (i32, &i32)
1392 [44; 45) '_': i32
1393 [47; 49) '&w': &i32
1394 [48; 49) 'w': i32
1395 [53; 54) 'v': &(i32, &i32)
1396 "###
1397 );
1398}
1399
1400#[test]
1401fn infer_adt_pattern() {
1402 assert_snapshot!(
1403 infer(r#"
1404enum E {
1405 A { x: usize },
1406 B
1407}
1408
1409struct S(u32, E);
1410
1411fn test() {
1412 let e = E::A { x: 3 };
1413
1414 let S(y, z) = foo;
1415 let E::A { x: new_var } = e;
1416
1417 match e {
1418 E::A { x } => x,
1419 E::B if foo => 1,
1420 E::B => 10,
1421 };
1422
1423 let ref d @ E::A { .. } = e;
1424 d;
1425}
1426"#),
1427 @r###"
1428 [68; 289) '{ ... d; }': ()
1429 [78; 79) 'e': E
1430 [82; 95) 'E::A { x: 3 }': E
1431 [92; 93) '3': usize
1432 [106; 113) 'S(y, z)': S
1433 [108; 109) 'y': u32
1434 [111; 112) 'z': E
1435 [116; 119) 'foo': S
1436 [129; 148) 'E::A {..._var }': E
1437 [139; 146) 'new_var': usize
1438 [151; 152) 'e': E
1439 [159; 245) 'match ... }': usize
1440 [165; 166) 'e': E
1441 [177; 187) 'E::A { x }': E
1442 [184; 185) 'x': usize
1443 [191; 192) 'x': usize
1444 [202; 206) 'E::B': E
1445 [210; 213) 'foo': bool
1446 [217; 218) '1': usize
1447 [228; 232) 'E::B': E
1448 [236; 238) '10': usize
1449 [256; 275) 'ref d ...{ .. }': &E
1450 [264; 275) 'E::A { .. }': E
1451 [278; 279) 'e': E
1452 [285; 286) 'd': &E
1453 "###
1454 );
1455}
1456
1457#[test]
1458fn infer_struct_generics() {
1459 assert_snapshot!(
1460 infer(r#"
1461struct A<T> {
1462 x: T,
1463}
1464
1465fn test(a1: A<u32>, i: i32) {
1466 a1.x;
1467 let a2 = A { x: i };
1468 a2.x;
1469 let a3 = A::<i128> { x: 1 };
1470 a3.x;
1471}
1472"#),
1473 @r###"
1474 [36; 38) 'a1': A<u32>
1475 [48; 49) 'i': i32
1476 [56; 147) '{ ...3.x; }': ()
1477 [62; 64) 'a1': A<u32>
1478 [62; 66) 'a1.x': u32
1479 [76; 78) 'a2': A<i32>
1480 [81; 91) 'A { x: i }': A<i32>
1481 [88; 89) 'i': i32
1482 [97; 99) 'a2': A<i32>
1483 [97; 101) 'a2.x': i32
1484 [111; 113) 'a3': A<i128>
1485 [116; 134) 'A::<i1...x: 1 }': A<i128>
1486 [131; 132) '1': i128
1487 [140; 142) 'a3': A<i128>
1488 [140; 144) 'a3.x': i128
1489 "###
1490 );
1491}
1492
1493#[test]
1494fn infer_tuple_struct_generics() {
1495 assert_snapshot!(
1496 infer(r#"
1497struct A<T>(T);
1498enum Option<T> { Some(T), None }
1499use Option::*;
1500
1501fn test() {
1502 A(42);
1503 A(42u128);
1504 Some("x");
1505 Option::Some("x");
1506 None;
1507 let x: Option<i64> = None;
1508}
1509"#),
1510 @r###"
1511 [76; 184) '{ ...one; }': ()
1512 [82; 83) 'A': A<i32>(T) -> A<T>
1513 [82; 87) 'A(42)': A<i32>
1514 [84; 86) '42': i32
1515 [93; 94) 'A': A<u128>(T) -> A<T>
1516 [93; 102) 'A(42u128)': A<u128>
1517 [95; 101) '42u128': u128
1518 [108; 112) 'Some': Some<&str>(T) -> Option<T>
1519 [108; 117) 'Some("x")': Option<&str>
1520 [113; 116) '"x"': &str
1521 [123; 135) 'Option::Some': Some<&str>(T) -> Option<T>
1522 [123; 140) 'Option...e("x")': Option<&str>
1523 [136; 139) '"x"': &str
1524 [146; 150) 'None': Option<{unknown}>
1525 [160; 161) 'x': Option<i64>
1526 [177; 181) 'None': Option<i64>
1527 "###
1528 );
1529}
1530
1531#[test]
1532fn infer_generics_in_patterns() {
1533 assert_snapshot!(
1534 infer(r#"
1535struct A<T> {
1536 x: T,
1537}
1538
1539enum Option<T> {
1540 Some(T),
1541 None,
1542}
1543
1544fn test(a1: A<u32>, o: Option<u64>) {
1545 let A { x: x2 } = a1;
1546 let A::<i64> { x: x3 } = A { x: 1 };
1547 match o {
1548 Option::Some(t) => t,
1549 _ => 1,
1550 };
1551}
1552"#),
1553 @r###"
1554 [79; 81) 'a1': A<u32>
1555 [91; 92) 'o': Option<u64>
1556 [107; 244) '{ ... }; }': ()
1557 [117; 128) 'A { x: x2 }': A<u32>
1558 [124; 126) 'x2': u32
1559 [131; 133) 'a1': A<u32>
1560 [143; 161) 'A::<i6...: x3 }': A<i64>
1561 [157; 159) 'x3': i64
1562 [164; 174) 'A { x: 1 }': A<i64>
1563 [171; 172) '1': i64
1564 [180; 241) 'match ... }': u64
1565 [186; 187) 'o': Option<u64>
1566 [198; 213) 'Option::Some(t)': Option<u64>
1567 [211; 212) 't': u64
1568 [217; 218) 't': u64
1569 [228; 229) '_': Option<u64>
1570 [233; 234) '1': u64
1571 "###
1572 );
1573}
1574
1575#[test]
1576fn infer_function_generics() {
1577 assert_snapshot!(
1578 infer(r#"
1579fn id<T>(t: T) -> T { t }
1580
1581fn test() {
1582 id(1u32);
1583 id::<i128>(1);
1584 let x: u64 = id(1);
1585}
1586"#),
1587 @r###"
1588 [10; 11) 't': T
1589 [21; 26) '{ t }': T
1590 [23; 24) 't': T
1591 [38; 98) '{ ...(1); }': ()
1592 [44; 46) 'id': fn id<u32>(T) -> T
1593 [44; 52) 'id(1u32)': u32
1594 [47; 51) '1u32': u32
1595 [58; 68) 'id::<i128>': fn id<i128>(T) -> T
1596 [58; 71) 'id::<i128>(1)': i128
1597 [69; 70) '1': i128
1598 [81; 82) 'x': u64
1599 [90; 92) 'id': fn id<u64>(T) -> T
1600 [90; 95) 'id(1)': u64
1601 [93; 94) '1': u64
1602 "###
1603 );
1604}
1605
1606#[test]
1607fn infer_impl_generics() {
1608 assert_snapshot!(
1609 infer(r#"
1610struct A<T1, T2> {
1611 x: T1,
1612 y: T2,
1613}
1614impl<Y, X> A<X, Y> {
1615 fn x(self) -> X {
1616 self.x
1617 }
1618 fn y(self) -> Y {
1619 self.y
1620 }
1621 fn z<T>(self, t: T) -> (X, Y, T) {
1622 (self.x, self.y, t)
1623 }
1624}
1625
1626fn test() -> i128 {
1627 let a = A { x: 1u64, y: 1i64 };
1628 a.x();
1629 a.y();
1630 a.z(1i128);
1631 a.z::<u128>(1);
1632}
1633"#),
1634 @r###"
1635 [74; 78) 'self': A<X, Y>
1636 [85; 107) '{ ... }': X
1637 [95; 99) 'self': A<X, Y>
1638 [95; 101) 'self.x': X
1639 [117; 121) 'self': A<X, Y>
1640 [128; 150) '{ ... }': Y
1641 [138; 142) 'self': A<X, Y>
1642 [138; 144) 'self.y': Y
1643 [163; 167) 'self': A<X, Y>
1644 [169; 170) 't': T
1645 [188; 223) '{ ... }': (X, Y, T)
1646 [198; 217) '(self.....y, t)': (X, Y, T)
1647 [199; 203) 'self': A<X, Y>
1648 [199; 205) 'self.x': X
1649 [207; 211) 'self': A<X, Y>
1650 [207; 213) 'self.y': Y
1651 [215; 216) 't': T
1652 [245; 342) '{ ...(1); }': ()
1653 [255; 256) 'a': A<u64, i64>
1654 [259; 281) 'A { x:...1i64 }': A<u64, i64>
1655 [266; 270) '1u64': u64
1656 [275; 279) '1i64': i64
1657 [287; 288) 'a': A<u64, i64>
1658 [287; 292) 'a.x()': u64
1659 [298; 299) 'a': A<u64, i64>
1660 [298; 303) 'a.y()': i64
1661 [309; 310) 'a': A<u64, i64>
1662 [309; 319) 'a.z(1i128)': (u64, i64, i128)
1663 [313; 318) '1i128': i128
1664 [325; 326) 'a': A<u64, i64>
1665 [325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
1666 [337; 338) '1': u128
1667 "###
1668 );
1669}
1670
1671#[test]
1672fn infer_impl_generics_with_autoderef() {
1673 assert_snapshot!(
1674 infer(r#"
1675enum Option<T> {
1676 Some(T),
1677 None,
1678}
1679impl<T> Option<T> {
1680 fn as_ref(&self) -> Option<&T> {}
1681}
1682fn test(o: Option<u32>) {
1683 (&o).as_ref();
1684 o.as_ref();
1685}
1686"#),
1687 @r###"
1688 [78; 82) 'self': &Option<T>
1689 [98; 100) '{}': ()
1690 [111; 112) 'o': Option<u32>
1691 [127; 165) '{ ...f(); }': ()
1692 [133; 146) '(&o).as_ref()': Option<&u32>
1693 [134; 136) '&o': &Option<u32>
1694 [135; 136) 'o': Option<u32>
1695 [152; 153) 'o': Option<u32>
1696 [152; 162) 'o.as_ref()': Option<&u32>
1697 "###
1698 );
1699}
1700
1701#[test]
1702fn infer_generic_chain() {
1703 assert_snapshot!(
1704 infer(r#"
1705struct A<T> {
1706 x: T,
1707}
1708impl<T2> A<T2> {
1709 fn x(self) -> T2 {
1710 self.x
1711 }
1712}
1713fn id<T>(t: T) -> T { t }
1714
1715fn test() -> i128 {
1716 let x = 1;
1717 let y = id(x);
1718 let a = A { x: id(y) };
1719 let z = id(a.x);
1720 let b = A { x: z };
1721 b.x()
1722}
1723"#),
1724 @r###"
1725 [53; 57) 'self': A<T2>
1726 [65; 87) '{ ... }': T2
1727 [75; 79) 'self': A<T2>
1728 [75; 81) 'self.x': T2
1729 [99; 100) 't': T
1730 [110; 115) '{ t }': T
1731 [112; 113) 't': T
1732 [135; 261) '{ ....x() }': i128
1733 [146; 147) 'x': i128
1734 [150; 151) '1': i128
1735 [162; 163) 'y': i128
1736 [166; 168) 'id': fn id<i128>(T) -> T
1737 [166; 171) 'id(x)': i128
1738 [169; 170) 'x': i128
1739 [182; 183) 'a': A<i128>
1740 [186; 200) 'A { x: id(y) }': A<i128>
1741 [193; 195) 'id': fn id<i128>(T) -> T
1742 [193; 198) 'id(y)': i128
1743 [196; 197) 'y': i128
1744 [211; 212) 'z': i128
1745 [215; 217) 'id': fn id<i128>(T) -> T
1746 [215; 222) 'id(a.x)': i128
1747 [218; 219) 'a': A<i128>
1748 [218; 221) 'a.x': i128
1749 [233; 234) 'b': A<i128>
1750 [237; 247) 'A { x: z }': A<i128>
1751 [244; 245) 'z': i128
1752 [254; 255) 'b': A<i128>
1753 [254; 259) 'b.x()': i128
1754 "###
1755 );
1756}
1757
1758#[test]
1759fn infer_associated_const() {
1760 assert_snapshot!(
1761 infer(r#"
1762struct Struct;
1763
1764impl Struct {
1765 const FOO: u32 = 1;
1766}
1767
1768enum Enum {}
1769
1770impl Enum {
1771 const BAR: u32 = 2;
1772}
1773
1774trait Trait {
1775 const ID: u32;
1776}
1777
1778struct TraitTest;
1779
1780impl Trait for TraitTest {
1781 const ID: u32 = 5;
1782}
1783
1784fn test() {
1785 let x = Struct::FOO;
1786 let y = Enum::BAR;
1787 let z = TraitTest::ID;
1788}
1789"#),
1790 @r###"
1791 [52; 53) '1': u32
1792 [105; 106) '2': u32
1793 [213; 214) '5': u32
1794 [229; 307) '{ ...:ID; }': ()
1795 [239; 240) 'x': u32
1796 [243; 254) 'Struct::FOO': u32
1797 [264; 265) 'y': u32
1798 [268; 277) 'Enum::BAR': u32
1799 [287; 288) 'z': u32
1800 [291; 304) 'TraitTest::ID': u32
1801 "###
1802 );
1803}
1804
1805#[test]
1806fn infer_associated_method_struct() {
1807 assert_snapshot!(
1808 infer(r#"
1809struct A { x: u32 }
1810
1811impl A {
1812 fn new() -> A {
1813 A { x: 0 }
1814 }
1815}
1816fn test() {
1817 let a = A::new();
1818 a.x;
1819}
1820"#),
1821 @r###"
1822 [49; 75) '{ ... }': A
1823 [59; 69) 'A { x: 0 }': A
1824 [66; 67) '0': u32
1825 [88; 122) '{ ...a.x; }': ()
1826 [98; 99) 'a': A
1827 [102; 108) 'A::new': fn new() -> A
1828 [102; 110) 'A::new()': A
1829 [116; 117) 'a': A
1830 [116; 119) 'a.x': u32
1831 "###
1832 );
1833}
1834
1835#[test]
1836fn infer_associated_method_enum() {
1837 assert_snapshot!(
1838 infer(r#"
1839enum A { B, C }
1840
1841impl A {
1842 pub fn b() -> A {
1843 A::B
1844 }
1845 pub fn c() -> A {
1846 A::C
1847 }
1848}
1849fn test() {
1850 let a = A::b();
1851 a;
1852 let c = A::c();
1853 c;
1854}
1855"#),
1856 @r###"
1857 [47; 67) '{ ... }': A
1858 [57; 61) 'A::B': A
1859 [88; 108) '{ ... }': A
1860 [98; 102) 'A::C': A
1861 [121; 178) '{ ... c; }': ()
1862 [131; 132) 'a': A
1863 [135; 139) 'A::b': fn b() -> A
1864 [135; 141) 'A::b()': A
1865 [147; 148) 'a': A
1866 [158; 159) 'c': A
1867 [162; 166) 'A::c': fn c() -> A
1868 [162; 168) 'A::c()': A
1869 [174; 175) 'c': A
1870 "###
1871 );
1872}
1873
1874#[test]
1875fn infer_associated_method_with_modules() {
1876 assert_snapshot!(
1877 infer(r#"
1878mod a {
1879 struct A;
1880 impl A { pub fn thing() -> A { A {} }}
1881}
1882
1883mod b {
1884 struct B;
1885 impl B { pub fn thing() -> u32 { 99 }}
1886
1887 mod c {
1888 struct C;
1889 impl C { pub fn thing() -> C { C {} }}
1890 }
1891}
1892use b::c;
1893
1894fn test() {
1895 let x = a::A::thing();
1896 let y = b::B::thing();
1897 let z = c::C::thing();
1898}
1899"#),
1900 @r###"
1901 [56; 64) '{ A {} }': A
1902 [58; 62) 'A {}': A
1903 [126; 132) '{ 99 }': u32
1904 [128; 130) '99': u32
1905 [202; 210) '{ C {} }': C
1906 [204; 208) 'C {}': C
1907 [241; 325) '{ ...g(); }': ()
1908 [251; 252) 'x': A
1909 [255; 266) 'a::A::thing': fn thing() -> A
1910 [255; 268) 'a::A::thing()': A
1911 [278; 279) 'y': u32
1912 [282; 293) 'b::B::thing': fn thing() -> u32
1913 [282; 295) 'b::B::thing()': u32
1914 [305; 306) 'z': C
1915 [309; 320) 'c::C::thing': fn thing() -> C
1916 [309; 322) 'c::C::thing()': C
1917 "###
1918 );
1919}
1920
1921#[test]
1922fn infer_associated_method_generics() {
1923 assert_snapshot!(
1924 infer(r#"
1925struct Gen<T> {
1926 val: T
1927}
1928
1929impl<T> Gen<T> {
1930 pub fn make(val: T) -> Gen<T> {
1931 Gen { val }
1932 }
1933}
1934
1935fn test() {
1936 let a = Gen::make(0u32);
1937}
1938"#),
1939 @r###"
1940 [64; 67) 'val': T
1941 [82; 109) '{ ... }': Gen<T>
1942 [92; 103) 'Gen { val }': Gen<T>
1943 [98; 101) 'val': T
1944 [123; 155) '{ ...32); }': ()
1945 [133; 134) 'a': Gen<u32>
1946 [137; 146) 'Gen::make': fn make<u32>(T) -> Gen<T>
1947 [137; 152) 'Gen::make(0u32)': Gen<u32>
1948 [147; 151) '0u32': u32
1949 "###
1950 );
1951}
1952
1953#[test]
1954fn infer_associated_method_generics_with_default_param() {
1955 assert_snapshot!(
1956 infer(r#"
1957struct Gen<T=u32> {
1958 val: T
1959}
1960
1961impl<T> Gen<T> {
1962 pub fn make() -> Gen<T> {
1963 loop { }
1964 }
1965}
1966
1967fn test() {
1968 let a = Gen::make();
1969}
1970"#),
1971 @r###"
1972 [80; 104) '{ ... }': Gen<T>
1973 [90; 98) 'loop { }': !
1974 [95; 98) '{ }': ()
1975 [118; 146) '{ ...e(); }': ()
1976 [128; 129) 'a': Gen<u32>
1977 [132; 141) 'Gen::make': fn make<u32>() -> Gen<T>
1978 [132; 143) 'Gen::make()': Gen<u32>
1979 "###
1980 );
1981}
1982
1983#[test]
1984fn infer_associated_method_generics_with_default_tuple_param() {
1985 let t = type_at(
1986 r#"
1987//- /main.rs
1988struct Gen<T=()> {
1989 val: T
1990}
1991
1992impl<T> Gen<T> {
1993 pub fn make() -> Gen<T> {
1994 loop { }
1995 }
1996}
1997
1998fn test() {
1999 let a = Gen::make();
2000 a.val<|>;
2001}
2002"#,
2003 );
2004 assert_eq!(t, "()");
2005}
2006
2007#[test]
2008fn infer_associated_method_generics_without_args() {
2009 assert_snapshot!(
2010 infer(r#"
2011struct Gen<T> {
2012 val: T
2013}
2014
2015impl<T> Gen<T> {
2016 pub fn make() -> Gen<T> {
2017 loop { }
2018 }
2019}
2020
2021fn test() {
2022 let a = Gen::<u32>::make();
2023}
2024"#),
2025 @r###"
2026 [76; 100) '{ ... }': Gen<T>
2027 [86; 94) 'loop { }': !
2028 [91; 94) '{ }': ()
2029 [114; 149) '{ ...e(); }': ()
2030 [124; 125) 'a': Gen<u32>
2031 [128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T>
2032 [128; 146) 'Gen::<...make()': Gen<u32>
2033 "###
2034 );
2035}
2036
2037#[test]
2038fn infer_associated_method_generics_2_type_params_without_args() {
2039 assert_snapshot!(
2040 infer(r#"
2041struct Gen<T, U> {
2042 val: T,
2043 val2: U,
2044}
2045
2046impl<T> Gen<u32, T> {
2047 pub fn make() -> Gen<u32,T> {
2048 loop { }
2049 }
2050}
2051
2052fn test() {
2053 let a = Gen::<u32, u64>::make();
2054}
2055"#),
2056 @r###"
2057 [102; 126) '{ ... }': Gen<u32, T>
2058 [112; 120) 'loop { }': !
2059 [117; 120) '{ }': ()
2060 [140; 180) '{ ...e(); }': ()
2061 [150; 151) 'a': Gen<u32, u64>
2062 [154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T>
2063 [154; 177) 'Gen::<...make()': Gen<u32, u64>
2064 "###
2065 );
2066}
2067
2068#[test]
2069fn infer_type_alias() {
2070 assert_snapshot!(
2071 infer(r#"
2072struct A<X, Y> { x: X, y: Y }
2073type Foo = A<u32, i128>;
2074type Bar<T> = A<T, u128>;
2075type Baz<U, V> = A<V, U>;
2076fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
2077 x.x;
2078 x.y;
2079 y.x;
2080 y.y;
2081 z.x;
2082 z.y;
2083}
2084"#),
2085 @r###"
2086 [116; 117) 'x': A<u32, i128>
2087 [124; 125) 'y': A<&str, u128>
2088 [138; 139) 'z': A<u8, i8>
2089 [154; 211) '{ ...z.y; }': ()
2090 [160; 161) 'x': A<u32, i128>
2091 [160; 163) 'x.x': u32
2092 [169; 170) 'x': A<u32, i128>
2093 [169; 172) 'x.y': i128
2094 [178; 179) 'y': A<&str, u128>
2095 [178; 181) 'y.x': &str
2096 [187; 188) 'y': A<&str, u128>
2097 [187; 190) 'y.y': u128
2098 [196; 197) 'z': A<u8, i8>
2099 [196; 199) 'z.x': u8
2100 [205; 206) 'z': A<u8, i8>
2101 [205; 208) 'z.y': i8
2102 "###
2103 )
2104}
2105
2106#[test]
2107#[should_panic] // we currently can't handle this
2108fn recursive_type_alias() {
2109 assert_snapshot!(
2110 infer(r#"
2111struct A<X> {}
2112type Foo = Foo;
2113type Bar = A<Bar>;
2114fn test(x: Foo) {}
2115"#),
2116 @""
2117 )
2118}
2119
2120#[test]
2121fn no_panic_on_field_of_enum() {
2122 assert_snapshot!(
2123 infer(r#"
2124enum X {}
2125
2126fn test(x: X) {
2127 x.some_field;
2128}
2129"#),
2130 @r###"
2131 [20; 21) 'x': X
2132 [26; 47) '{ ...eld; }': ()
2133 [32; 33) 'x': X
2134 [32; 44) 'x.some_field': {unknown}
2135 "###
2136 );
2137}
2138
2139#[test]
2140fn bug_585() {
2141 assert_snapshot!(
2142 infer(r#"
2143fn test() {
2144 X {};
2145 match x {
2146 A::B {} => (),
2147 A::Y() => (),
2148 }
2149}
2150"#),
2151 @r###"
2152 [11; 89) '{ ... } }': ()
2153 [17; 21) 'X {}': {unknown}
2154 [27; 87) 'match ... }': ()
2155 [33; 34) 'x': {unknown}
2156 [45; 52) 'A::B {}': {unknown}
2157 [56; 58) '()': ()
2158 [68; 74) 'A::Y()': {unknown}
2159 [78; 80) '()': ()
2160 "###
2161 );
2162}
2163
2164#[test]
2165fn bug_651() {
2166 assert_snapshot!(
2167 infer(r#"
2168fn quux() {
2169 let y = 92;
2170 1 + y;
2171}
2172"#),
2173 @r###"
2174 [11; 41) '{ ...+ y; }': ()
2175 [21; 22) 'y': i32
2176 [25; 27) '92': i32
2177 [33; 34) '1': i32
2178 [33; 38) '1 + y': i32
2179 [37; 38) 'y': i32
2180 "###
2181 );
2182}
2183
2184#[test]
2185fn recursive_vars() {
2186 covers!(type_var_cycles_resolve_completely);
2187 covers!(type_var_cycles_resolve_as_possible);
2188 assert_snapshot!(
2189 infer(r#"
2190fn test() {
2191 let y = unknown;
2192 [y, &y];
2193}
2194"#),
2195 @r###"
2196 [11; 48) '{ ...&y]; }': ()
2197 [21; 22) 'y': &{unknown}
2198 [25; 32) 'unknown': &{unknown}
2199 [38; 45) '[y, &y]': [&&{unknown};_]
2200 [39; 40) 'y': &{unknown}
2201 [42; 44) '&y': &&{unknown}
2202 [43; 44) 'y': &{unknown}
2203 "###
2204 );
2205}
2206
2207#[test]
2208fn recursive_vars_2() {
2209 covers!(type_var_cycles_resolve_completely);
2210 covers!(type_var_cycles_resolve_as_possible);
2211 assert_snapshot!(
2212 infer(r#"
2213fn test() {
2214 let x = unknown;
2215 let y = unknown;
2216 [(x, y), (&y, &x)];
2217}
2218"#),
2219 @r###"
2220 [11; 80) '{ ...x)]; }': ()
2221 [21; 22) 'x': &&{unknown}
2222 [25; 32) 'unknown': &&{unknown}
2223 [42; 43) 'y': &&{unknown}
2224 [46; 53) 'unknown': &&{unknown}
2225 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_]
2226 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown})
2227 [61; 62) 'x': &&{unknown}
2228 [64; 65) 'y': &&{unknown}
2229 [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown})
2230 [69; 71) '&y': &&&{unknown}
2231 [70; 71) 'y': &&{unknown}
2232 [73; 75) '&x': &&&{unknown}
2233 [74; 75) 'x': &&{unknown}
2234 "###
2235 );
2236}
2237
2238#[test]
2239fn infer_type_param() {
2240 assert_snapshot!(
2241 infer(r#"
2242fn id<T>(x: T) -> T {
2243 x
2244}
2245
2246fn clone<T>(x: &T) -> T {
2247 *x
2248}
2249
2250fn test() {
2251 let y = 10u32;
2252 id(y);
2253 let x: bool = clone(z);
2254 id::<i128>(1);
2255}
2256"#),
2257 @r###"
2258 [10; 11) 'x': T
2259 [21; 30) '{ x }': T
2260 [27; 28) 'x': T
2261 [44; 45) 'x': &T
2262 [56; 66) '{ *x }': T
2263 [62; 64) '*x': T
2264 [63; 64) 'x': &T
2265 [78; 158) '{ ...(1); }': ()
2266 [88; 89) 'y': u32
2267 [92; 97) '10u32': u32
2268 [103; 105) 'id': fn id<u32>(T) -> T
2269 [103; 108) 'id(y)': u32
2270 [106; 107) 'y': u32
2271 [118; 119) 'x': bool
2272 [128; 133) 'clone': fn clone<bool>(&T) -> T
2273 [128; 136) 'clone(z)': bool
2274 [134; 135) 'z': &bool
2275 [142; 152) 'id::<i128>': fn id<i128>(T) -> T
2276 [142; 155) 'id::<i128>(1)': i128
2277 [153; 154) '1': i128
2278 "###
2279 );
2280}
2281
2282#[test]
2283fn infer_std_crash_1() {
2284 // caused stack overflow, taken from std
2285 assert_snapshot!(
2286 infer(r#"
2287enum Maybe<T> {
2288 Real(T),
2289 Fake,
2290}
2291
2292fn write() {
2293 match something_unknown {
2294 Maybe::Real(ref mut something) => (),
2295 }
2296}
2297"#),
2298 @r###"
2299 [54; 139) '{ ... } }': ()
2300 [60; 137) 'match ... }': ()
2301 [66; 83) 'someth...nknown': Maybe<{unknown}>
2302 [94; 124) 'Maybe:...thing)': Maybe<{unknown}>
2303 [106; 123) 'ref mu...ething': &mut {unknown}
2304 [128; 130) '()': ()
2305 "###
2306 );
2307}
2308
2309#[test]
2310fn infer_std_crash_2() {
2311 covers!(type_var_resolves_to_int_var);
2312 // caused "equating two type variables, ...", taken from std
2313 assert_snapshot!(
2314 infer(r#"
2315fn test_line_buffer() {
2316 &[0, b'\n', 1, b'\n'];
2317}
2318"#),
2319 @r###"
2320 [23; 53) '{ ...n']; }': ()
2321 [29; 50) '&[0, b...b'\n']': &[u8;_]
2322 [30; 50) '[0, b'...b'\n']': [u8;_]
2323 [31; 32) '0': u8
2324 [34; 39) 'b'\n'': u8
2325 [41; 42) '1': u8
2326 [44; 49) 'b'\n'': u8
2327 "###
2328 );
2329}
2330
2331#[test]
2332fn infer_std_crash_3() {
2333 // taken from rustc
2334 assert_snapshot!(
2335 infer(r#"
2336pub fn compute() {
2337 match nope!() {
2338 SizeSkeleton::Pointer { non_zero: true, tail } => {}
2339 }
2340}
2341"#),
2342 @r###"
2343 [18; 108) '{ ... } }': ()
2344 [24; 106) 'match ... }': ()
2345 [30; 37) 'nope!()': {unknown}
2346 [48; 94) 'SizeSk...tail }': {unknown}
2347 [82; 86) 'true': {unknown}
2348 [88; 92) 'tail': {unknown}
2349 [98; 100) '{}': ()
2350 "###
2351 );
2352}
2353
2354#[test]
2355fn infer_std_crash_4() {
2356 // taken from rustc
2357 assert_snapshot!(
2358 infer(r#"
2359pub fn primitive_type() {
2360 match *self {
2361 BorrowedRef { type_: Primitive(p), ..} => {},
2362 }
2363}
2364"#),
2365 @r###"
2366 [25; 106) '{ ... } }': ()
2367 [31; 104) 'match ... }': ()
2368 [37; 42) '*self': {unknown}
2369 [38; 42) 'self': {unknown}
2370 [53; 91) 'Borrow...), ..}': {unknown}
2371 [74; 86) 'Primitive(p)': {unknown}
2372 [84; 85) 'p': {unknown}
2373 [95; 97) '{}': ()
2374 "###
2375 );
2376}
2377
2378#[test]
2379fn infer_std_crash_5() {
2380 // taken from rustc
2381 assert_snapshot!(
2382 infer(r#"
2383fn extra_compiler_flags() {
2384 for content in doesnt_matter {
2385 let name = if doesnt_matter {
2386 first
2387 } else {
2388 &content
2389 };
2390
2391 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
2392 name
2393 } else {
2394 content
2395 };
2396 }
2397}
2398"#),
2399 @r###"
2400 [27; 323) '{ ... } }': ()
2401 [33; 321) 'for co... }': ()
2402 [37; 44) 'content': &{unknown}
2403 [48; 61) 'doesnt_matter': {unknown}
2404 [62; 321) '{ ... }': ()
2405 [76; 80) 'name': &&{unknown}
2406 [83; 167) 'if doe... }': &&{unknown}
2407 [86; 99) 'doesnt_matter': bool
2408 [100; 129) '{ ... }': &&{unknown}
2409 [114; 119) 'first': &&{unknown}
2410 [135; 167) '{ ... }': &&{unknown}
2411 [149; 157) '&content': &&{unknown}
2412 [150; 157) 'content': &{unknown}
2413 [182; 189) 'content': &{unknown}
2414 [192; 314) 'if ICE... }': &{unknown}
2415 [195; 232) 'ICE_RE..._VALUE': {unknown}
2416 [195; 248) 'ICE_RE...&name)': bool
2417 [242; 247) '&name': &&&{unknown}
2418 [243; 247) 'name': &&{unknown}
2419 [249; 277) '{ ... }': &&{unknown}
2420 [263; 267) 'name': &&{unknown}
2421 [283; 314) '{ ... }': &{unknown}
2422 [297; 304) 'content': &{unknown}
2423 "###
2424 );
2425}
2426
2427#[test]
2428fn infer_nested_generics_crash() {
2429 // another crash found typechecking rustc
2430 assert_snapshot!(
2431 infer(r#"
2432struct Canonical<V> {
2433 value: V,
2434}
2435struct QueryResponse<V> {
2436 value: V,
2437}
2438fn test<R>(query_response: Canonical<QueryResponse<R>>) {
2439 &query_response.value;
2440}
2441"#),
2442 @r###"
2443 [92; 106) 'query_response': Canonical<QueryResponse<R>>
2444 [137; 167) '{ ...lue; }': ()
2445 [143; 164) '&query....value': &QueryResponse<R>
2446 [144; 158) 'query_response': Canonical<QueryResponse<R>>
2447 [144; 164) 'query_....value': QueryResponse<R>
2448 "###
2449 );
2450}
2451
2452#[test]
2453fn bug_1030() {
2454 assert_snapshot!(infer(r#"
2455struct HashSet<T, H>;
2456struct FxHasher;
2457type FxHashSet<T> = HashSet<T, FxHasher>;
2458
2459impl<T, H> HashSet<T, H> {
2460 fn default() -> HashSet<T, H> {}
2461}
2462
2463pub fn main_loop() {
2464 FxHashSet::default();
2465}
2466"#),
2467 @r###"
2468 [144; 146) '{}': ()
2469 [169; 198) '{ ...t(); }': ()
2470 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
2471 [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>
2472 "###
2473 );
2474}
2475
2476#[test]
2477fn cross_crate_associated_method_call() {
2478 let (db, pos) = TestDB::with_position(
2479 r#"
2480//- /main.rs crate:main deps:other_crate
2481fn test() {
2482 let x = other_crate::foo::S::thing();
2483 x<|>;
2484}
2485
2486//- /lib.rs crate:other_crate
2487mod foo {
2488 struct S;
2489 impl S {
2490 fn thing() -> i128 {}
2491 }
2492}
2493"#,
2494 );
2495 assert_eq!("i128", type_at_pos(&db, pos));
2496}
2497
2498#[test]
2499fn infer_const() {
2500 assert_snapshot!(
2501 infer(r#"
2502struct Foo;
2503impl Foo { const ASSOC_CONST: u32 = 0; }
2504const GLOBAL_CONST: u32 = 101;
2505fn test() {
2506 const LOCAL_CONST: u32 = 99;
2507 let x = LOCAL_CONST;
2508 let z = GLOBAL_CONST;
2509 let id = Foo::ASSOC_CONST;
2510}
2511"#),
2512 @r###"
2513 [49; 50) '0': u32
2514 [80; 83) '101': u32
2515 [95; 213) '{ ...NST; }': ()
2516 [138; 139) 'x': {unknown}
2517 [142; 153) 'LOCAL_CONST': {unknown}
2518 [163; 164) 'z': u32
2519 [167; 179) 'GLOBAL_CONST': u32
2520 [189; 191) 'id': u32
2521 [194; 210) 'Foo::A..._CONST': u32
2522 "###
2523 );
2524}
2525
2526#[test]
2527fn infer_static() {
2528 assert_snapshot!(
2529 infer(r#"
2530static GLOBAL_STATIC: u32 = 101;
2531static mut GLOBAL_STATIC_MUT: u32 = 101;
2532fn test() {
2533 static LOCAL_STATIC: u32 = 99;
2534 static mut LOCAL_STATIC_MUT: u32 = 99;
2535 let x = LOCAL_STATIC;
2536 let y = LOCAL_STATIC_MUT;
2537 let z = GLOBAL_STATIC;
2538 let w = GLOBAL_STATIC_MUT;
2539}
2540"#),
2541 @r###"
2542 [29; 32) '101': u32
2543 [70; 73) '101': u32
2544 [85; 280) '{ ...MUT; }': ()
2545 [173; 174) 'x': {unknown}
2546 [177; 189) 'LOCAL_STATIC': {unknown}
2547 [199; 200) 'y': {unknown}
2548 [203; 219) 'LOCAL_...IC_MUT': {unknown}
2549 [229; 230) 'z': u32
2550 [233; 246) 'GLOBAL_STATIC': u32
2551 [256; 257) 'w': u32
2552 [260; 277) 'GLOBAL...IC_MUT': u32
2553 "###
2554 );
2555}
2556
2557#[test]
2558fn infer_trait_method_simple() {
2559 // the trait implementation is intentionally incomplete -- it shouldn't matter
2560 assert_snapshot!(
2561 infer(r#"
2562trait Trait1 {
2563 fn method(&self) -> u32;
2564}
2565struct S1;
2566impl Trait1 for S1 {}
2567trait Trait2 {
2568 fn method(&self) -> i128;
2569}
2570struct S2;
2571impl Trait2 for S2 {}
2572fn test() {
2573 S1.method(); // -> u32
2574 S2.method(); // -> i128
2575}
2576"#),
2577 @r###"
2578 [31; 35) 'self': &Self
2579 [110; 114) 'self': &Self
2580 [170; 228) '{ ...i128 }': ()
2581 [176; 178) 'S1': S1
2582 [176; 187) 'S1.method()': u32
2583 [203; 205) 'S2': S2
2584 [203; 214) 'S2.method()': i128
2585 "###
2586 );
2587}
2588
2589#[test]
2590fn infer_trait_method_scoped() {
2591 // the trait implementation is intentionally incomplete -- it shouldn't matter
2592 assert_snapshot!(
2593 infer(r#"
2594struct S;
2595mod foo {
2596 pub trait Trait1 {
2597 fn method(&self) -> u32;
2598 }
2599 impl Trait1 for super::S {}
2600}
2601mod bar {
2602 pub trait Trait2 {
2603 fn method(&self) -> i128;
2604 }
2605 impl Trait2 for super::S {}
2606}
2607
2608mod foo_test {
2609 use super::S;
2610 use super::foo::Trait1;
2611 fn test() {
2612 S.method(); // -> u32
2613 }
2614}
2615
2616mod bar_test {
2617 use super::S;
2618 use super::bar::Trait2;
2619 fn test() {
2620 S.method(); // -> i128
2621 }
2622}
2623"#),
2624 @r###"
2625 [63; 67) 'self': &Self
2626 [169; 173) 'self': &Self
2627 [300; 337) '{ ... }': ()
2628 [310; 311) 'S': S
2629 [310; 320) 'S.method()': u32
2630 [416; 454) '{ ... }': ()
2631 [426; 427) 'S': S
2632 [426; 436) 'S.method()': i128
2633 "###
2634 );
2635}
2636
2637#[test]
2638fn infer_trait_method_generic_1() {
2639 // the trait implementation is intentionally incomplete -- it shouldn't matter
2640 assert_snapshot!(
2641 infer(r#"
2642trait Trait<T> {
2643 fn method(&self) -> T;
2644}
2645struct S;
2646impl Trait<u32> for S {}
2647fn test() {
2648 S.method();
2649}
2650"#),
2651 @r###"
2652 [33; 37) 'self': &Self
2653 [92; 111) '{ ...d(); }': ()
2654 [98; 99) 'S': S
2655 [98; 108) 'S.method()': u32
2656 "###
2657 );
2658}
2659
2660#[test]
2661fn infer_trait_method_generic_more_params() {
2662 // the trait implementation is intentionally incomplete -- it shouldn't matter
2663 assert_snapshot!(
2664 infer(r#"
2665trait Trait<T1, T2, T3> {
2666 fn method1(&self) -> (T1, T2, T3);
2667 fn method2(&self) -> (T3, T2, T1);
2668}
2669struct S1;
2670impl Trait<u8, u16, u32> for S1 {}
2671struct S2;
2672impl<T> Trait<i8, i16, T> for S2 {}
2673fn test() {
2674 S1.method1(); // u8, u16, u32
2675 S1.method2(); // u32, u16, u8
2676 S2.method1(); // i8, i16, {unknown}
2677 S2.method2(); // {unknown}, i16, i8
2678}
2679"#),
2680 @r###"
2681 [43; 47) 'self': &Self
2682 [82; 86) 'self': &Self
2683 [210; 361) '{ ..., i8 }': ()
2684 [216; 218) 'S1': S1
2685 [216; 228) 'S1.method1()': (u8, u16, u32)
2686 [250; 252) 'S1': S1
2687 [250; 262) 'S1.method2()': (u32, u16, u8)
2688 [284; 286) 'S2': S2
2689 [284; 296) 'S2.method1()': (i8, i16, {unknown})
2690 [324; 326) 'S2': S2
2691 [324; 336) 'S2.method2()': ({unknown}, i16, i8)
2692 "###
2693 );
2694}
2695
2696#[test]
2697fn infer_trait_method_generic_2() {
2698 // the trait implementation is intentionally incomplete -- it shouldn't matter
2699 assert_snapshot!(
2700 infer(r#"
2701trait Trait<T> {
2702 fn method(&self) -> T;
2703}
2704struct S<T>(T);
2705impl<U> Trait<U> for S<U> {}
2706fn test() {
2707 S(1u32).method();
2708}
2709"#),
2710 @r###"
2711 [33; 37) 'self': &Self
2712 [102; 127) '{ ...d(); }': ()
2713 [108; 109) 'S': S<u32>(T) -> S<T>
2714 [108; 115) 'S(1u32)': S<u32>
2715 [108; 124) 'S(1u32...thod()': u32
2716 [110; 114) '1u32': u32
2717 "###
2718 );
2719}
2720
2721#[test]
2722fn infer_trait_assoc_method() {
2723 assert_snapshot!(
2724 infer(r#"
2725trait Default {
2726 fn default() -> Self;
2727}
2728struct S;
2729impl Default for S {}
2730fn test() {
2731 let s1: S = Default::default();
2732 let s2 = S::default();
2733 let s3 = <S as Default>::default();
2734}
2735"#),
2736 @r###"
2737 [87; 193) '{ ...t(); }': ()
2738 [97; 99) 's1': S
2739 [105; 121) 'Defaul...efault': fn default<S>() -> Self
2740 [105; 123) 'Defaul...ault()': S
2741 [133; 135) 's2': S
2742 [138; 148) 'S::default': fn default<S>() -> Self
2743 [138; 150) 'S::default()': S
2744 [160; 162) 's3': S
2745 [165; 188) '<S as ...efault': fn default<S>() -> Self
2746 [165; 190) '<S as ...ault()': S
2747 "###
2748 );
2749}
2750
2751#[test]
2752fn infer_trait_assoc_method_generics_1() {
2753 assert_snapshot!(
2754 infer(r#"
2755trait Trait<T> {
2756 fn make() -> T;
2757}
2758struct S;
2759impl Trait<u32> for S {}
2760struct G<T>;
2761impl<T> Trait<T> for G<T> {}
2762fn test() {
2763 let a = S::make();
2764 let b = G::<u64>::make();
2765 let c: f64 = G::make();
2766}
2767"#),
2768 @r###"
2769 [127; 211) '{ ...e(); }': ()
2770 [137; 138) 'a': u32
2771 [141; 148) 'S::make': fn make<S, u32>() -> T
2772 [141; 150) 'S::make()': u32
2773 [160; 161) 'b': u64
2774 [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
2775 [164; 180) 'G::<u6...make()': u64
2776 [190; 191) 'c': f64
2777 [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
2778 [199; 208) 'G::make()': f64
2779 "###
2780 );
2781}
2782
2783#[test]
2784fn infer_trait_assoc_method_generics_2() {
2785 assert_snapshot!(
2786 infer(r#"
2787trait Trait<T> {
2788 fn make<U>() -> (T, U);
2789}
2790struct S;
2791impl Trait<u32> for S {}
2792struct G<T>;
2793impl<T> Trait<T> for G<T> {}
2794fn test() {
2795 let a = S::make::<i64>();
2796 let b: (_, i64) = S::make();
2797 let c = G::<u32>::make::<i64>();
2798 let d: (u32, _) = G::make::<i64>();
2799 let e: (u32, i64) = G::make();
2800}
2801"#),
2802 @r###"
2803 [135; 313) '{ ...e(); }': ()
2804 [145; 146) 'a': (u32, i64)
2805 [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
2806 [149; 165) 'S::mak...i64>()': (u32, i64)
2807 [175; 176) 'b': (u32, i64)
2808 [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
2809 [189; 198) 'S::make()': (u32, i64)
2810 [208; 209) 'c': (u32, i64)
2811 [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2812 [212; 235) 'G::<u3...i64>()': (u32, i64)
2813 [245; 246) 'd': (u32, i64)
2814 [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2815 [259; 275) 'G::mak...i64>()': (u32, i64)
2816 [285; 286) 'e': (u32, i64)
2817 [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
2818 [301; 310) 'G::make()': (u32, i64)
2819 "###
2820 );
2821}
2822
2823#[test]
2824fn infer_trait_assoc_method_generics_3() {
2825 assert_snapshot!(
2826 infer(r#"
2827trait Trait<T> {
2828 fn make() -> (Self, T);
2829}
2830struct S<T>;
2831impl Trait<i64> for S<i32> {}
2832fn test() {
2833 let a = S::make();
2834}
2835"#),
2836 @r###"
2837 [101; 127) '{ ...e(); }': ()
2838 [111; 112) 'a': (S<i32>, i64)
2839 [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T)
2840 [115; 124) 'S::make()': (S<i32>, i64)
2841 "###
2842 );
2843}
2844
2845#[test]
2846fn infer_trait_assoc_method_generics_4() {
2847 assert_snapshot!(
2848 infer(r#"
2849trait Trait<T> {
2850 fn make() -> (Self, T);
2851}
2852struct S<T>;
2853impl Trait<i64> for S<u64> {}
2854impl Trait<i32> for S<u32> {}
2855fn test() {
2856 let a: (S<u64>, _) = S::make();
2857 let b: (_, i32) = S::make();
2858}
2859"#),
2860 @r###"
2861 [131; 203) '{ ...e(); }': ()
2862 [141; 142) 'a': (S<u64>, i64)
2863 [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T)
2864 [158; 167) 'S::make()': (S<u64>, i64)
2865 [177; 178) 'b': (S<u32>, i32)
2866 [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T)
2867 [191; 200) 'S::make()': (S<u32>, i32)
2868 "###
2869 );
2870}
2871
2872#[test]
2873fn infer_trait_assoc_method_generics_5() {
2874 assert_snapshot!(
2875 infer(r#"
2876trait Trait<T> {
2877 fn make<U>() -> (Self, T, U);
2878}
2879struct S<T>;
2880impl Trait<i64> for S<u64> {}
2881fn test() {
2882 let a = <S as Trait<i64>>::make::<u8>();
2883 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
2884}
2885"#),
2886 @r###"
2887 [107; 211) '{ ...>(); }': ()
2888 [117; 118) 'a': (S<u64>, i64, u8)
2889 [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2890 [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
2891 [162; 163) 'b': (S<u64>, i64, u8)
2892 [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2893 [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
2894 "###
2895 );
2896}
2897
2898#[test]
2899fn infer_from_bound_1() {
2900 assert_snapshot!(
2901 infer(r#"
2902trait Trait<T> {}
2903struct S<T>(T);
2904impl<U> Trait<U> for S<U> {}
2905fn foo<T: Trait<u32>>(t: T) {}
2906fn test() {
2907 let s = S(unknown);
2908 foo(s);
2909}
2910"#),
2911 @r###"
2912 [86; 87) 't': T
2913 [92; 94) '{}': ()
2914 [105; 144) '{ ...(s); }': ()
2915 [115; 116) 's': S<u32>
2916 [119; 120) 'S': S<u32>(T) -> S<T>
2917 [119; 129) 'S(unknown)': S<u32>
2918 [121; 128) 'unknown': u32
2919 [135; 138) 'foo': fn foo<S<u32>>(T) -> ()
2920 [135; 141) 'foo(s)': ()
2921 [139; 140) 's': S<u32>
2922 "###
2923 );
2924}
2925
2926#[test]
2927fn infer_from_bound_2() {
2928 assert_snapshot!(
2929 infer(r#"
2930trait Trait<T> {}
2931struct S<T>(T);
2932impl<U> Trait<U> for S<U> {}
2933fn foo<U, T: Trait<U>>(t: T) -> U {}
2934fn test() {
2935 let s = S(unknown);
2936 let x: u32 = foo(s);
2937}
2938"#),
2939 @r###"
2940 [87; 88) 't': T
2941 [98; 100) '{}': ()
2942 [111; 163) '{ ...(s); }': ()
2943 [121; 122) 's': S<u32>
2944 [125; 126) 'S': S<u32>(T) -> S<T>
2945 [125; 135) 'S(unknown)': S<u32>
2946 [127; 134) 'unknown': u32
2947 [145; 146) 'x': u32
2948 [154; 157) 'foo': fn foo<u32, S<u32>>(T) -> U
2949 [154; 160) 'foo(s)': u32
2950 [158; 159) 's': S<u32>
2951 "###
2952 );
2953}
2954
2955#[test]
2956fn infer_call_trait_method_on_generic_param_1() {
2957 assert_snapshot!(
2958 infer(r#"
2959trait Trait {
2960 fn method(&self) -> u32;
2961}
2962fn test<T: Trait>(t: T) {
2963 t.method();
2964}
2965"#),
2966 @r###"
2967 [30; 34) 'self': &Self
2968 [64; 65) 't': T
2969 [70; 89) '{ ...d(); }': ()
2970 [76; 77) 't': T
2971 [76; 86) 't.method()': u32
2972 "###
2973 );
2974}
2975
2976#[test]
2977fn infer_call_trait_method_on_generic_param_2() {
2978 assert_snapshot!(
2979 infer(r#"
2980trait Trait<T> {
2981 fn method(&self) -> T;
2982}
2983fn test<U, T: Trait<U>>(t: T) {
2984 t.method();
2985}
2986"#),
2987 @r###"
2988 [33; 37) 'self': &Self
2989 [71; 72) 't': T
2990 [77; 96) '{ ...d(); }': ()
2991 [83; 84) 't': T
2992 [83; 93) 't.method()': [missing name]
2993 "###
2994 );
2995}
2996
2997#[test]
2998fn infer_with_multiple_trait_impls() {
2999 assert_snapshot!(
3000 infer(r#"
3001trait Into<T> {
3002 fn into(self) -> T;
3003}
3004struct S;
3005impl Into<u32> for S {}
3006impl Into<u64> for S {}
3007fn test() {
3008 let x: u32 = S.into();
3009 let y: u64 = S.into();
3010 let z = Into::<u64>::into(S);
3011}
3012"#),
3013 @r###"
3014 [29; 33) 'self': Self
3015 [111; 202) '{ ...(S); }': ()
3016 [121; 122) 'x': u32
3017 [130; 131) 'S': S
3018 [130; 138) 'S.into()': u32
3019 [148; 149) 'y': u64
3020 [157; 158) 'S': S
3021 [157; 165) 'S.into()': u64
3022 [175; 176) 'z': u64
3023 [179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
3024 [179; 199) 'Into::...nto(S)': u64
3025 [197; 198) 'S': S
3026 "###
3027 );
3028}
3029
3030#[test]
3031fn infer_project_associated_type() {
3032 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
3033 assert_snapshot!(
3034 infer(r#"
3035trait Iterable {
3036 type Item;
3037}
3038struct S;
3039impl Iterable for S { type Item = u32; }
3040fn test<T: Iterable>() {
3041 let x: <S as Iterable>::Item = 1;
3042 let y: <T as Iterable>::Item = no_matter;
3043 let z: T::Item = no_matter;
3044 let a: <T>::Item = no_matter;
3045}
3046"#),
3047 @r###"
3048 [108; 261) '{ ...ter; }': ()
3049 [118; 119) 'x': u32
3050 [145; 146) '1': u32
3051 [156; 157) 'y': {unknown}
3052 [183; 192) 'no_matter': {unknown}
3053 [202; 203) 'z': {unknown}
3054 [215; 224) 'no_matter': {unknown}
3055 [234; 235) 'a': {unknown}
3056 [249; 258) 'no_matter': {unknown}
3057 "###
3058 );
3059}
3060
3061#[test]
3062fn infer_return_associated_type() {
3063 assert_snapshot!(
3064 infer(r#"
3065trait Iterable {
3066 type Item;
3067}
3068struct S;
3069impl Iterable for S { type Item = u32; }
3070fn foo1<T: Iterable>(t: T) -> T::Item {}
3071fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
3072fn foo3<T: Iterable>(t: T) -> <T>::Item {}
3073fn test() {
3074 let x = foo1(S);
3075 let y = foo2(S);
3076 let z = foo3(S);
3077}
3078"#),
3079 @r###"
3080 [106; 107) 't': T
3081 [123; 125) '{}': ()
3082 [147; 148) 't': T
3083 [178; 180) '{}': ()
3084 [202; 203) 't': T
3085 [221; 223) '{}': ()
3086 [234; 300) '{ ...(S); }': ()
3087 [244; 245) 'x': u32
3088 [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item
3089 [248; 255) 'foo1(S)': u32
3090 [253; 254) 'S': S
3091 [265; 266) 'y': u32
3092 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
3093 [269; 276) 'foo2(S)': u32
3094 [274; 275) 'S': S
3095 [286; 287) 'z': u32
3096 [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item
3097 [290; 297) 'foo3(S)': u32
3098 [295; 296) 'S': S
3099 "###
3100 );
3101}
3102
3103#[test]
3104fn infer_associated_type_bound() {
3105 assert_snapshot!(
3106 infer(r#"
3107trait Iterable {
3108 type Item;
3109}
3110fn test<T: Iterable<Item=u32>>() {
3111 let y: T::Item = unknown;
3112}
3113"#),
3114 @r###"
3115 [67; 100) '{ ...own; }': ()
3116 [77; 78) 'y': {unknown}
3117 [90; 97) 'unknown': {unknown}
3118 "###
3119 );
3120}
3121
3122#[test]
3123fn infer_const_body() {
3124 assert_snapshot!(
3125 infer(r#"
3126const A: u32 = 1 + 1;
3127static B: u64 = { let x = 1; x };
3128"#),
3129 @r###"
3130 [16; 17) '1': u32
3131 [16; 21) '1 + 1': u32
3132 [20; 21) '1': u32
3133 [39; 55) '{ let ...1; x }': u64
3134 [45; 46) 'x': u64
3135 [49; 50) '1': u64
3136 [52; 53) 'x': u64
3137 "###
3138 );
3139}
3140
3141#[test]
3142fn tuple_struct_fields() {
3143 assert_snapshot!(
3144 infer(r#"
3145struct S(i32, u64);
3146fn test() -> u64 {
3147 let a = S(4, 6);
3148 let b = a.0;
3149 a.1
3150}
3151"#),
3152 @r###"
3153 [38; 87) '{ ... a.1 }': u64
3154 [48; 49) 'a': S
3155 [52; 53) 'S': S(i32, u64) -> S
3156 [52; 59) 'S(4, 6)': S
3157 [54; 55) '4': i32
3158 [57; 58) '6': u64
3159 [69; 70) 'b': i32
3160 [73; 74) 'a': S
3161 [73; 76) 'a.0': i32
3162 [82; 83) 'a': S
3163 [82; 85) 'a.1': u64
3164 "###
3165 );
3166}
3167
3168#[test]
3169fn tuple_struct_with_fn() {
3170 assert_snapshot!(
3171 infer(r#"
3172struct S(fn(u32) -> u64);
3173fn test() -> u64 {
3174 let a = S(|i| 2*i);
3175 let b = a.0(4);
3176 a.0(2)
3177}
3178"#),
3179 @r###"
3180 [44; 102) '{ ...0(2) }': u64
3181 [54; 55) 'a': S
3182 [58; 59) 'S': S(fn(u32) -> u64) -> S
3183 [58; 68) 'S(|i| 2*i)': S
3184 [60; 67) '|i| 2*i': |i32| -> i32
3185 [61; 62) 'i': i32
3186 [64; 65) '2': i32
3187 [64; 67) '2*i': i32
3188 [66; 67) 'i': i32
3189 [78; 79) 'b': u64
3190 [82; 83) 'a': S
3191 [82; 85) 'a.0': fn(u32) -> u64
3192 [82; 88) 'a.0(4)': u64
3193 [86; 87) '4': u32
3194 [94; 95) 'a': S
3195 [94; 97) 'a.0': fn(u32) -> u64
3196 [94; 100) 'a.0(2)': u64
3197 [98; 99) '2': u32
3198 "###
3199 );
3200}
3201
3202#[test]
3203fn indexing_arrays() {
3204 assert_snapshot!(
3205 infer("fn main() { &mut [9][2]; }"),
3206 @r###"
3207 [10; 26) '{ &mut...[2]; }': ()
3208 [12; 23) '&mut [9][2]': &mut {unknown}
3209 [17; 20) '[9]': [i32;_]
3210 [17; 23) '[9][2]': {unknown}
3211 [18; 19) '9': i32
3212 [21; 22) '2': i32
3213 "###
3214 )
3215}
3216
3217#[test]
3218fn infer_macros_expanded() {
3219 assert_snapshot!(
3220 infer(r#"
3221struct Foo(Vec<i32>);
3222
3223macro_rules! foo {
3224 ($($item:expr),*) => {
3225 {
3226 Foo(vec![$($item,)*])
3227 }
3228 };
3229}
3230
3231fn main() {
3232 let x = foo!(1,2);
3233}
3234"#),
3235 @r###"
3236 ![0; 17) '{Foo(v...,2,])}': Foo
3237 ![1; 4) 'Foo': Foo({unknown}) -> Foo
3238 ![1; 16) 'Foo(vec![1,2,])': Foo
3239 ![5; 15) 'vec![1,2,]': {unknown}
3240 [156; 182) '{ ...,2); }': ()
3241 [166; 167) 'x': Foo
3242 "###
3243 );
3244}
3245
3246#[test]
3247fn infer_legacy_textual_scoped_macros_expanded() {
3248 assert_snapshot!(
3249 infer(r#"
3250struct Foo(Vec<i32>);
3251
3252#[macro_use]
3253mod m {
3254 macro_rules! foo {
3255 ($($item:expr),*) => {
3256 {
3257 Foo(vec![$($item,)*])
3258 }
3259 };
3260 }
3261}
3262
3263fn main() {
3264 let x = foo!(1,2);
3265 let y = crate::foo!(1,2);
3266}
3267"#),
3268 @r###"
3269 ![0; 17) '{Foo(v...,2,])}': Foo
3270 ![1; 4) 'Foo': Foo({unknown}) -> Foo
3271 ![1; 16) 'Foo(vec![1,2,])': Foo
3272 ![5; 15) 'vec![1,2,]': {unknown}
3273 [195; 251) '{ ...,2); }': ()
3274 [205; 206) 'x': Foo
3275 [228; 229) 'y': {unknown}
3276 [232; 248) 'crate:...!(1,2)': {unknown}
3277 "###
3278 );
3279}
3280
3281#[test]
3282fn infer_path_qualified_macros_expanded() {
3283 assert_snapshot!(
3284 infer(r#"
3285#[macro_export]
3286macro_rules! foo {
3287 () => { 42i32 }
3288}
3289
3290mod m {
3291 pub use super::foo as bar;
3292}
3293
3294fn main() {
3295 let x = crate::foo!();
3296 let y = m::bar!();
3297}
3298"#),
3299 @r###"
3300 ![0; 5) '42i32': i32
3301 ![0; 5) '42i32': i32
3302 [111; 164) '{ ...!(); }': ()
3303 [121; 122) 'x': i32
3304 [148; 149) 'y': i32
3305 "###
3306 );
3307}
3308
3309#[test]
3310fn infer_type_value_macro_having_same_name() {
3311 assert_snapshot!(
3312 infer(r#"
3313#[macro_export]
3314macro_rules! foo {
3315 () => {
3316 mod foo {
3317 pub use super::foo;
3318 }
3319 };
3320 ($x:tt) => {
3321 $x
3322 };
3323}
3324
3325foo!();
3326
3327fn foo() {
3328 let foo = foo::foo!(42i32);
3329}
3330"#),
3331 @r###"
3332 ![0; 5) '42i32': i32
3333 [171; 206) '{ ...32); }': ()
3334 [181; 184) 'foo': i32
3335 "###
3336 );
3337}
3338
3339#[test]
3340fn processes_impls_generated_by_macros() {
3341 let t = type_at(
3342 r#"
3343//- /main.rs
3344macro_rules! m {
3345 ($ident:ident) => (impl Trait for $ident {})
3346}
3347trait Trait { fn foo(self) -> u128 {} }
3348struct S;
3349m!(S);
3350fn test() { S.foo()<|>; }
3351"#,
3352 );
3353 assert_eq!(t, "u128");
3354}
3355
3356#[test]
3357fn infer_macro_with_dollar_crate_is_correct_in_expr() {
3358 let (db, pos) = TestDB::with_position(
3359 r#"
3360//- /main.rs crate:main deps:foo
3361fn test() {
3362 let x = (foo::foo!(1), foo::foo!(2));
3363 x<|>;
3364}
3365
3366//- /lib.rs crate:foo
3367#[macro_export]
3368macro_rules! foo {
3369 (1) => { $crate::bar!() };
3370 (2) => { 1 + $crate::baz() };
3371}
3372
3373#[macro_export]
3374macro_rules! bar {
3375 () => { 42 }
3376}
3377
3378pub fn baz() -> usize { 31usize }
3379"#,
3380 );
3381 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
3382}
3383
3384#[ignore]
3385#[test]
3386fn method_resolution_trait_before_autoref() {
3387 let t = type_at(
3388 r#"
3389//- /main.rs
3390trait Trait { fn foo(self) -> u128; }
3391struct S;
3392impl S { fn foo(&self) -> i8 { 0 } }
3393impl Trait for S { fn foo(self) -> u128 { 0 } }
3394fn test() { S.foo()<|>; }
3395"#,
3396 );
3397 assert_eq!(t, "u128");
3398}
3399
3400#[ignore]
3401#[test]
3402fn method_resolution_by_value_before_autoref() {
3403 let t = type_at(
3404 r#"
3405//- /main.rs
3406trait Clone { fn clone(&self) -> Self; }
3407struct S;
3408impl Clone for S {}
3409impl Clone for &S {}
3410fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
3411"#,
3412 );
3413 assert_eq!(t, "(S, S, &S)");
3414}
3415
3416#[test]
3417fn method_resolution_trait_before_autoderef() {
3418 let t = type_at(
3419 r#"
3420//- /main.rs
3421trait Trait { fn foo(self) -> u128; }
3422struct S;
3423impl S { fn foo(self) -> i8 { 0 } }
3424impl Trait for &S { fn foo(self) -> u128 { 0 } }
3425fn test() { (&S).foo()<|>; }
3426"#,
3427 );
3428 assert_eq!(t, "u128");
3429}
3430
3431#[test]
3432fn method_resolution_impl_before_trait() {
3433 let t = type_at(
3434 r#"
3435//- /main.rs
3436trait Trait { fn foo(self) -> u128; }
3437struct S;
3438impl S { fn foo(self) -> i8 { 0 } }
3439impl Trait for S { fn foo(self) -> u128 { 0 } }
3440fn test() { S.foo()<|>; }
3441"#,
3442 );
3443 assert_eq!(t, "i8");
3444}
3445
3446#[test]
3447fn method_resolution_trait_autoderef() {
3448 let t = type_at(
3449 r#"
3450//- /main.rs
3451trait Trait { fn foo(self) -> u128; }
3452struct S;
3453impl Trait for S { fn foo(self) -> u128 { 0 } }
3454fn test() { (&S).foo()<|>; }
3455"#,
3456 );
3457 assert_eq!(t, "u128");
3458}
3459
3460#[test]
3461fn method_resolution_trait_from_prelude() {
3462 let (db, pos) = TestDB::with_position(
3463 r#"
3464//- /main.rs crate:main deps:other_crate
3465struct S;
3466impl Clone for S {}
3467
3468fn test() {
3469 S.clone()<|>;
3470}
3471
3472//- /lib.rs crate:other_crate
3473#[prelude_import] use foo::*;
3474
3475mod foo {
3476 trait Clone {
3477 fn clone(&self) -> Self;
3478 }
3479}
3480"#,
3481 );
3482 assert_eq!("S", type_at_pos(&db, pos));
3483}
3484
3485#[test]
3486fn method_resolution_where_clause_for_unknown_trait() {
3487 // The blanket impl shouldn't apply because we can't even resolve UnknownTrait
3488 let t = type_at(
3489 r#"
3490//- /main.rs
3491trait Trait { fn foo(self) -> u128; }
3492struct S;
3493impl<T> Trait for T where T: UnknownTrait {}
3494fn test() { (&S).foo()<|>; }
3495"#,
3496 );
3497 assert_eq!(t, "{unknown}");
3498}
3499
3500#[test]
3501fn method_resolution_where_clause_not_met() {
3502 // The blanket impl shouldn't apply because we can't prove S: Clone
3503 let t = type_at(
3504 r#"
3505//- /main.rs
3506trait Clone {}
3507trait Trait { fn foo(self) -> u128; }
3508struct S;
3509impl<T> Trait for T where T: Clone {}
3510fn test() { (&S).foo()<|>; }
3511"#,
3512 );
3513 // This is also to make sure that we don't resolve to the foo method just
3514 // because that's the only method named foo we can find, which would make
3515 // the below tests not work
3516 assert_eq!(t, "{unknown}");
3517}
3518
3519#[test]
3520fn method_resolution_where_clause_inline_not_met() {
3521 // The blanket impl shouldn't apply because we can't prove S: Clone
3522 let t = type_at(
3523 r#"
3524//- /main.rs
3525trait Clone {}
3526trait Trait { fn foo(self) -> u128; }
3527struct S;
3528impl<T: Clone> Trait for T {}
3529fn test() { (&S).foo()<|>; }
3530"#,
3531 );
3532 assert_eq!(t, "{unknown}");
3533}
3534
3535#[test]
3536fn method_resolution_where_clause_1() {
3537 let t = type_at(
3538 r#"
3539//- /main.rs
3540trait Clone {}
3541trait Trait { fn foo(self) -> u128; }
3542struct S;
3543impl Clone for S {}
3544impl<T> Trait for T where T: Clone {}
3545fn test() { S.foo()<|>; }
3546"#,
3547 );
3548 assert_eq!(t, "u128");
3549}
3550
3551#[test]
3552fn method_resolution_where_clause_2() {
3553 let t = type_at(
3554 r#"
3555//- /main.rs
3556trait Into<T> { fn into(self) -> T; }
3557trait From<T> { fn from(other: T) -> Self; }
3558struct S1;
3559struct S2;
3560impl From<S2> for S1 {}
3561impl<T, U> Into<U> for T where U: From<T> {}
3562fn test() { S2.into()<|>; }
3563"#,
3564 );
3565 assert_eq!(t, "{unknown}");
3566}
3567
3568#[test]
3569fn method_resolution_where_clause_inline() {
3570 let t = type_at(
3571 r#"
3572//- /main.rs
3573trait Into<T> { fn into(self) -> T; }
3574trait From<T> { fn from(other: T) -> Self; }
3575struct S1;
3576struct S2;
3577impl From<S2> for S1 {}
3578impl<T, U: From<T>> Into<U> for T {}
3579fn test() { S2.into()<|>; }
3580"#,
3581 );
3582 assert_eq!(t, "{unknown}");
3583}
3584
3585#[test]
3586fn method_resolution_encountering_fn_type() {
3587 type_at(
3588 r#"
3589//- /main.rs
3590fn foo() {}
3591trait FnOnce { fn call(self); }
3592fn test() { foo.call()<|>; }
3593"#,
3594 );
3595}
3596
3597#[test]
3598fn method_resolution_slow() {
3599 // this can get quite slow if we set the solver size limit too high
3600 let t = type_at(
3601 r#"
3602//- /main.rs
3603trait SendX {}
3604
3605struct S1; impl SendX for S1 {}
3606struct S2; impl SendX for S2 {}
3607struct U1;
3608
3609trait Trait { fn method(self); }
3610
3611struct X1<A, B> {}
3612impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
3613
3614struct S<B, C> {}
3615
3616trait FnX {}
3617
3618impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
3619
3620fn test() { (S {}).method()<|>; }
3621"#,
3622 );
3623 assert_eq!(t, "()");
3624}
3625
3626#[test]
3627fn shadowing_primitive() {
3628 let t = type_at(
3629 r#"
3630//- /main.rs
3631struct i32;
3632struct Foo;
3633
3634impl i32 { fn foo(&self) -> Foo { Foo } }
3635
3636fn main() {
3637 let x: i32 = i32;
3638 x.foo()<|>;
3639}"#,
3640 );
3641 assert_eq!(t, "Foo");
3642}
3643
3644#[test]
3645fn deref_trait() {
3646 let t = type_at(
3647 r#"
3648//- /main.rs
3649#[lang = "deref"]
3650trait Deref {
3651 type Target;
3652 fn deref(&self) -> &Self::Target;
3653}
3654
3655struct Arc<T>;
3656impl<T> Deref for Arc<T> {
3657 type Target = T;
3658}
3659
3660struct S;
3661impl S {
3662 fn foo(&self) -> u128 {}
3663}
3664
3665fn test(s: Arc<S>) {
3666 (*s, s.foo())<|>;
3667}
3668"#,
3669 );
3670 assert_eq!(t, "(S, u128)");
3671}
3672
3673#[test]
3674fn deref_trait_with_inference_var() {
3675 let t = type_at(
3676 r#"
3677//- /main.rs
3678#[lang = "deref"]
3679trait Deref {
3680 type Target;
3681 fn deref(&self) -> &Self::Target;
3682}
3683
3684struct Arc<T>;
3685fn new_arc<T>() -> Arc<T> {}
3686impl<T> Deref for Arc<T> {
3687 type Target = T;
3688}
3689
3690struct S;
3691fn foo(a: Arc<S>) {}
3692
3693fn test() {
3694 let a = new_arc();
3695 let b = (*a)<|>;
3696 foo(a);
3697}
3698"#,
3699 );
3700 assert_eq!(t, "S");
3701}
3702
3703#[test]
3704fn deref_trait_infinite_recursion() {
3705 let t = type_at(
3706 r#"
3707//- /main.rs
3708#[lang = "deref"]
3709trait Deref {
3710 type Target;
3711 fn deref(&self) -> &Self::Target;
3712}
3713
3714struct S;
3715
3716impl Deref for S {
3717 type Target = S;
3718}
3719
3720fn test(s: S) {
3721 s.foo()<|>;
3722}
3723"#,
3724 );
3725 assert_eq!(t, "{unknown}");
3726}
3727
3728#[test]
3729fn deref_trait_with_question_mark_size() {
3730 let t = type_at(
3731 r#"
3732//- /main.rs
3733#[lang = "deref"]
3734trait Deref {
3735 type Target;
3736 fn deref(&self) -> &Self::Target;
3737}
3738
3739struct Arc<T>;
3740impl<T> Deref for Arc<T> {
3741 type Target = T;
3742}
3743
3744struct S;
3745impl S {
3746 fn foo(&self) -> u128 {}
3747}
3748
3749fn test(s: Arc<S>) {
3750 (*s, s.foo())<|>;
3751}
3752"#,
3753 );
3754 assert_eq!(t, "(S, u128)");
3755}
3756
3757#[test]
3758fn obligation_from_function_clause() {
3759 let t = type_at(
3760 r#"
3761//- /main.rs
3762struct S;
3763
3764trait Trait<T> {}
3765impl Trait<u32> for S {}
3766
3767fn foo<T: Trait<U>, U>(t: T) -> U {}
3768
3769fn test(s: S) {
3770 foo(s)<|>;
3771}
3772"#,
3773 );
3774 assert_eq!(t, "u32");
3775}
3776
3777#[test]
3778fn obligation_from_method_clause() {
3779 let t = type_at(
3780 r#"
3781//- /main.rs
3782struct S;
3783
3784trait Trait<T> {}
3785impl Trait<isize> for S {}
3786
3787struct O;
3788impl O {
3789 fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
3790}
3791
3792fn test() {
3793 O.foo(S)<|>;
3794}
3795"#,
3796 );
3797 assert_eq!(t, "isize");
3798}
3799
3800#[test]
3801fn obligation_from_self_method_clause() {
3802 let t = type_at(
3803 r#"
3804//- /main.rs
3805struct S;
3806
3807trait Trait<T> {}
3808impl Trait<i64> for S {}
3809
3810impl S {
3811 fn foo<U>(&self) -> U where Self: Trait<U> {}
3812}
3813
3814fn test() {
3815 S.foo()<|>;
3816}
3817"#,
3818 );
3819 assert_eq!(t, "i64");
3820}
3821
3822#[test]
3823fn obligation_from_impl_clause() {
3824 let t = type_at(
3825 r#"
3826//- /main.rs
3827struct S;
3828
3829trait Trait<T> {}
3830impl Trait<&str> for S {}
3831
3832struct O<T>;
3833impl<U, T: Trait<U>> O<T> {
3834 fn foo(&self) -> U {}
3835}
3836
3837fn test(o: O<S>) {
3838 o.foo()<|>;
3839}
3840"#,
3841 );
3842 assert_eq!(t, "&str");
3843}
3844
3845#[test]
3846fn generic_param_env_1() {
3847 let t = type_at(
3848 r#"
3849//- /main.rs
3850trait Clone {}
3851trait Trait { fn foo(self) -> u128; }
3852struct S;
3853impl Clone for S {}
3854impl<T> Trait for T where T: Clone {}
3855fn test<T: Clone>(t: T) { t.foo()<|>; }
3856"#,
3857 );
3858 assert_eq!(t, "u128");
3859}
3860
3861#[test]
3862fn generic_param_env_1_not_met() {
3863 let t = type_at(
3864 r#"
3865//- /main.rs
3866trait Clone {}
3867trait Trait { fn foo(self) -> u128; }
3868struct S;
3869impl Clone for S {}
3870impl<T> Trait for T where T: Clone {}
3871fn test<T>(t: T) { t.foo()<|>; }
3872"#,
3873 );
3874 assert_eq!(t, "{unknown}");
3875}
3876
3877#[test]
3878fn generic_param_env_2() {
3879 let t = type_at(
3880 r#"
3881//- /main.rs
3882trait Trait { fn foo(self) -> u128; }
3883struct S;
3884impl Trait for S {}
3885fn test<T: Trait>(t: T) { t.foo()<|>; }
3886"#,
3887 );
3888 assert_eq!(t, "u128");
3889}
3890
3891#[test]
3892fn generic_param_env_2_not_met() {
3893 let t = type_at(
3894 r#"
3895//- /main.rs
3896trait Trait { fn foo(self) -> u128; }
3897struct S;
3898impl Trait for S {}
3899fn test<T>(t: T) { t.foo()<|>; }
3900"#,
3901 );
3902 assert_eq!(t, "{unknown}");
3903}
3904
3905#[test]
3906fn generic_param_env_deref() {
3907 let t = type_at(
3908 r#"
3909//- /main.rs
3910#[lang = "deref"]
3911trait Deref {
3912 type Target;
3913}
3914trait Trait {}
3915impl<T> Deref for T where T: Trait {
3916 type Target = i128;
3917}
3918fn test<T: Trait>(t: T) { (*t)<|>; }
3919"#,
3920 );
3921 assert_eq!(t, "i128");
3922}
3923
3924#[test]
3925fn associated_type_placeholder() {
3926 let t = type_at(
3927 r#"
3928//- /main.rs
3929pub trait ApplyL {
3930 type Out;
3931}
3932
3933pub struct RefMutL<T>;
3934
3935impl<T> ApplyL for RefMutL<T> {
3936 type Out = <T as ApplyL>::Out;
3937}
3938
3939fn test<T: ApplyL>() {
3940 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
3941 y<|>;
3942}
3943"#,
3944 );
3945 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
3946 // FIXME: fix type parameter names going missing when going through Chalk
3947 assert_eq!(t, "ApplyL::Out<[missing name]>");
3948}
3949
3950#[test]
3951fn associated_type_placeholder_2() {
3952 let t = type_at(
3953 r#"
3954//- /main.rs
3955pub trait ApplyL {
3956 type Out;
3957}
3958fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
3959
3960fn test<T: ApplyL>(t: T) {
3961 let y = foo(t);
3962 y<|>;
3963}
3964"#,
3965 );
3966 // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
3967 // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
3968 // to the trait env ourselves here; probably Chalk can't do this by itself.
3969 // assert_eq!(t, "ApplyL::Out<[missing name]>");
3970 assert_eq!(t, "{unknown}");
3971}
3972
3973#[test]
3974fn impl_trait() {
3975 assert_snapshot!(
3976 infer(r#"
3977trait Trait<T> {
3978 fn foo(&self) -> T;
3979 fn foo2(&self) -> i64;
3980}
3981fn bar() -> impl Trait<u64> {}
3982
3983fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
3984 x;
3985 y;
3986 let z = bar();
3987 x.foo();
3988 y.foo();
3989 z.foo();
3990 x.foo2();
3991 y.foo2();
3992 z.foo2();
3993}
3994"#),
3995 @r###"
3996 [30; 34) 'self': &Self
3997 [55; 59) 'self': &Self
3998 [99; 101) '{}': ()
3999 [111; 112) 'x': impl Trait<u64>
4000 [131; 132) 'y': &impl Trait<u64>
4001 [152; 269) '{ ...2(); }': ()
4002 [158; 159) 'x': impl Trait<u64>
4003 [165; 166) 'y': &impl Trait<u64>
4004 [176; 177) 'z': impl Trait<u64>
4005 [180; 183) 'bar': fn bar() -> impl Trait<u64>
4006 [180; 185) 'bar()': impl Trait<u64>
4007 [191; 192) 'x': impl Trait<u64>
4008 [191; 198) 'x.foo()': u64
4009 [204; 205) 'y': &impl Trait<u64>
4010 [204; 211) 'y.foo()': u64
4011 [217; 218) 'z': impl Trait<u64>
4012 [217; 224) 'z.foo()': u64
4013 [230; 231) 'x': impl Trait<u64>
4014 [230; 238) 'x.foo2()': i64
4015 [244; 245) 'y': &impl Trait<u64>
4016 [244; 252) 'y.foo2()': i64
4017 [258; 259) 'z': impl Trait<u64>
4018 [258; 266) 'z.foo2()': i64
4019 "###
4020 );
4021}
4022
4023#[test]
4024fn dyn_trait() {
4025 assert_snapshot!(
4026 infer(r#"
4027trait Trait<T> {
4028 fn foo(&self) -> T;
4029 fn foo2(&self) -> i64;
4030}
4031fn bar() -> dyn Trait<u64> {}
4032
4033fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
4034 x;
4035 y;
4036 let z = bar();
4037 x.foo();
4038 y.foo();
4039 z.foo();
4040 x.foo2();
4041 y.foo2();
4042 z.foo2();
4043}
4044"#),
4045 @r###"
4046 [30; 34) 'self': &Self
4047 [55; 59) 'self': &Self
4048 [98; 100) '{}': ()
4049 [110; 111) 'x': dyn Trait<u64>
4050 [129; 130) 'y': &dyn Trait<u64>
4051 [149; 266) '{ ...2(); }': ()
4052 [155; 156) 'x': dyn Trait<u64>
4053 [162; 163) 'y': &dyn Trait<u64>
4054 [173; 174) 'z': dyn Trait<u64>
4055 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
4056 [177; 182) 'bar()': dyn Trait<u64>
4057 [188; 189) 'x': dyn Trait<u64>
4058 [188; 195) 'x.foo()': u64
4059 [201; 202) 'y': &dyn Trait<u64>
4060 [201; 208) 'y.foo()': u64
4061 [214; 215) 'z': dyn Trait<u64>
4062 [214; 221) 'z.foo()': u64
4063 [227; 228) 'x': dyn Trait<u64>
4064 [227; 235) 'x.foo2()': i64
4065 [241; 242) 'y': &dyn Trait<u64>
4066 [241; 249) 'y.foo2()': i64
4067 [255; 256) 'z': dyn Trait<u64>
4068 [255; 263) 'z.foo2()': i64
4069 "###
4070 );
4071}
4072
4073#[test]
4074fn dyn_trait_bare() {
4075 assert_snapshot!(
4076 infer(r#"
4077trait Trait {
4078 fn foo(&self) -> u64;
4079}
4080fn bar() -> Trait {}
4081
4082fn test(x: Trait, y: &Trait) -> u64 {
4083 x;
4084 y;
4085 let z = bar();
4086 x.foo();
4087 y.foo();
4088 z.foo();
4089}
4090"#),
4091 @r###"
4092 [27; 31) 'self': &Self
4093 [61; 63) '{}': ()
4094 [73; 74) 'x': dyn Trait
4095 [83; 84) 'y': &dyn Trait
4096 [101; 176) '{ ...o(); }': ()
4097 [107; 108) 'x': dyn Trait
4098 [114; 115) 'y': &dyn Trait
4099 [125; 126) 'z': dyn Trait
4100 [129; 132) 'bar': fn bar() -> dyn Trait
4101 [129; 134) 'bar()': dyn Trait
4102 [140; 141) 'x': dyn Trait
4103 [140; 147) 'x.foo()': u64
4104 [153; 154) 'y': &dyn Trait
4105 [153; 160) 'y.foo()': u64
4106 [166; 167) 'z': dyn Trait
4107 [166; 173) 'z.foo()': u64
4108 "###
4109 );
4110}
4111
4112#[test]
4113fn weird_bounds() {
4114 assert_snapshot!(
4115 infer(r#"
4116trait Trait {}
4117fn test() {
4118 let a: impl Trait + 'lifetime = foo;
4119 let b: impl 'lifetime = foo;
4120 let b: impl (Trait) = foo;
4121 let b: impl ('lifetime) = foo;
4122 let d: impl ?Sized = foo;
4123 let e: impl Trait + ?Sized = foo;
4124}
4125"#),
4126 @r###"
4127 [26; 237) '{ ...foo; }': ()
4128 [36; 37) 'a': impl Trait + {error}
4129 [64; 67) 'foo': impl Trait + {error}
4130 [77; 78) 'b': impl {error}
4131 [97; 100) 'foo': impl {error}
4132 [110; 111) 'b': impl Trait
4133 [128; 131) 'foo': impl Trait
4134 [141; 142) 'b': impl {error}
4135 [163; 166) 'foo': impl {error}
4136 [176; 177) 'd': impl {error}
4137 [193; 196) 'foo': impl {error}
4138 [206; 207) 'e': impl Trait + {error}
4139 [231; 234) 'foo': impl Trait + {error}
4140 "###
4141 );
4142}
4143
4144#[test]
4145fn assoc_type_bindings() {
4146 assert_snapshot!(
4147 infer(r#"
4148trait Trait {
4149 type Type;
4150}
4151
4152fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
4153fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
4154fn set<T: Trait<Type = u64>>(t: T) -> T {t}
4155
4156struct S<T>;
4157impl<T> Trait for S<T> { type Type = T; }
4158
4159fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
4160 get(x);
4161 get2(x);
4162 get(y);
4163 get2(y);
4164 get(set(S));
4165 get2(set(S));
4166 get2(S::<str>);
4167}
4168"#),
4169 @r###"
4170 [50; 51) 't': T
4171 [78; 80) '{}': ()
4172 [112; 113) 't': T
4173 [123; 125) '{}': ()
4174 [155; 156) 't': T
4175 [166; 169) '{t}': T
4176 [167; 168) 't': T
4177 [257; 258) 'x': T
4178 [263; 264) 'y': impl Trait<Type = i64>
4179 [290; 398) '{ ...r>); }': ()
4180 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
4181 [296; 302) 'get(x)': {unknown}
4182 [300; 301) 'x': T
4183 [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
4184 [308; 315) 'get2(x)': {unknown}
4185 [313; 314) 'x': T
4186 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
4187 [321; 327) 'get(y)': {unknown}
4188 [325; 326) 'y': impl Trait<Type = i64>
4189 [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
4190 [333; 340) 'get2(y)': {unknown}
4191 [338; 339) 'y': impl Trait<Type = i64>
4192 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
4193 [346; 357) 'get(set(S))': u64
4194 [350; 353) 'set': fn set<S<u64>>(T) -> T
4195 [350; 356) 'set(S)': S<u64>
4196 [354; 355) 'S': S<u64>
4197 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
4198 [363; 375) 'get2(set(S))': u64
4199 [368; 371) 'set': fn set<S<u64>>(T) -> T
4200 [368; 374) 'set(S)': S<u64>
4201 [372; 373) 'S': S<u64>
4202 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
4203 [381; 395) 'get2(S::<str>)': str
4204 [386; 394) 'S::<str>': S<str>
4205 "###
4206 );
4207}
4208
4209#[test]
4210fn impl_trait_assoc_binding_projection_bug() {
4211 let (db, pos) = TestDB::with_position(
4212 r#"
4213//- /main.rs crate:main deps:std
4214pub trait Language {
4215 type Kind;
4216}
4217pub enum RustLanguage {}
4218impl Language for RustLanguage {
4219 type Kind = SyntaxKind;
4220}
4221struct SyntaxNode<L> {}
4222fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
4223
4224trait Clone {
4225 fn clone(&self) -> Self;
4226}
4227
4228fn api_walkthrough() {
4229 for node in foo() {
4230 node.clone()<|>;
4231 }
4232}
4233
4234//- /std.rs crate:std
4235#[prelude_import] use iter::*;
4236mod iter {
4237 trait IntoIterator {
4238 type Item;
4239 }
4240 trait Iterator {
4241 type Item;
4242 }
4243 impl<T: Iterator> IntoIterator for T {
4244 type Item = <T as Iterator>::Item;
4245 }
4246}
4247"#,
4248 );
4249 assert_eq!("{unknown}", type_at_pos(&db, pos));
4250}
4251
4252#[test]
4253fn projection_eq_within_chalk() {
4254 // std::env::set_var("CHALK_DEBUG", "1");
4255 assert_snapshot!(
4256 infer(r#"
4257trait Trait1 {
4258 type Type;
4259}
4260trait Trait2<T> {
4261 fn foo(self) -> T;
4262}
4263impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
4264
4265fn test<T: Trait1<Type = u32>>(x: T) {
4266 x.foo();
4267}
4268"#),
4269 @r###"
4270 [62; 66) 'self': Self
4271 [164; 165) 'x': T
4272 [170; 186) '{ ...o(); }': ()
4273 [176; 177) 'x': T
4274 [176; 183) 'x.foo()': {unknown}
4275 "###
4276 );
4277}
4278
4279#[test]
4280fn where_clause_trait_in_scope_for_method_resolution() {
4281 let t = type_at(
4282 r#"
4283//- /main.rs
4284mod foo {
4285 trait Trait {
4286 fn foo(&self) -> u32 {}
4287 }
4288}
4289
4290fn test<T: foo::Trait>(x: T) {
4291 x.foo()<|>;
4292}
4293"#,
4294 );
4295 assert_eq!(t, "u32");
4296}
4297
4298#[test]
4299fn super_trait_method_resolution() {
4300 assert_snapshot!(
4301 infer(r#"
4302mod foo {
4303 trait SuperTrait {
4304 fn foo(&self) -> u32 {}
4305 }
4306}
4307trait Trait1: foo::SuperTrait {}
4308trait Trait2 where Self: foo::SuperTrait {}
4309
4310fn test<T: Trait1, U: Trait2>(x: T, y: U) {
4311 x.foo();
4312 y.foo();
4313}
4314"#),
4315 @r###"
4316 [50; 54) 'self': &Self
4317 [63; 65) '{}': ()
4318 [182; 183) 'x': T
4319 [188; 189) 'y': U
4320 [194; 223) '{ ...o(); }': ()
4321 [200; 201) 'x': T
4322 [200; 207) 'x.foo()': u32
4323 [213; 214) 'y': U
4324 [213; 220) 'y.foo()': u32
4325 "###
4326 );
4327}
4328
4329#[test]
4330fn super_trait_cycle() {
4331 // This just needs to not crash
4332 assert_snapshot!(
4333 infer(r#"
4334trait A: B {}
4335trait B: A {}
4336
4337fn test<T: A>(x: T) {
4338 x.foo();
4339}
4340"#),
4341 @r###"
4342 [44; 45) 'x': T
4343 [50; 66) '{ ...o(); }': ()
4344 [56; 57) 'x': T
4345 [56; 63) 'x.foo()': {unknown}
4346 "###
4347 );
4348}
4349
4350#[test]
4351fn super_trait_assoc_type_bounds() {
4352 assert_snapshot!(
4353 infer(r#"
4354trait SuperTrait { type Type; }
4355trait Trait where Self: SuperTrait {}
4356
4357fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
4358fn set<T: Trait<Type = u64>>(t: T) -> T {t}
4359
4360struct S<T>;
4361impl<T> SuperTrait for S<T> { type Type = T; }
4362impl<T> Trait for S<T> {}
4363
4364fn test() {
4365 get2(set(S));
4366}
4367"#),
4368 @r###"
4369 [103; 104) 't': T
4370 [114; 116) '{}': ()
4371 [146; 147) 't': T
4372 [157; 160) '{t}': T
4373 [158; 159) 't': T
4374 [259; 280) '{ ...S)); }': ()
4375 [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
4376 [265; 277) 'get2(set(S))': u64
4377 [270; 273) 'set': fn set<S<u64>>(T) -> T
4378 [270; 276) 'set(S)': S<u64>
4379 [274; 275) 'S': S<u64>
4380 "###
4381 );
4382}
4383
4384#[test]
4385fn fn_trait() {
4386 assert_snapshot!(
4387 infer(r#"
4388trait FnOnce<Args> {
4389 type Output;
4390
4391 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
4392}
4393
4394fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
4395 f.call_once((1, 2));
4396}
4397"#),
4398 @r###"
4399 [57; 61) 'self': Self
4400 [63; 67) 'args': Args
4401 [150; 151) 'f': F
4402 [156; 184) '{ ...2)); }': ()
4403 [162; 163) 'f': F
4404 [162; 181) 'f.call...1, 2))': {unknown}
4405 [174; 180) '(1, 2)': (u32, u64)
4406 [175; 176) '1': u32
4407 [178; 179) '2': u64
4408 "###
4409 );
4410}
4411
4412#[test]
4413fn closure_1() {
4414 assert_snapshot!(
4415 infer(r#"
4416#[lang = "fn_once"]
4417trait FnOnce<Args> {
4418 type Output;
4419}
4420
4421enum Option<T> { Some(T), None }
4422impl<T> Option<T> {
4423 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
4424}
4425
4426fn test() {
4427 let x = Option::Some(1u32);
4428 x.map(|v| v + 1);
4429 x.map(|_v| 1u64);
4430 let y: Option<i64> = x.map(|_v| 1);
4431}
4432"#),
4433 @r###"
4434 [148; 152) 'self': Option<T>
4435 [154; 155) 'f': F
4436 [173; 175) '{}': ()
4437 [189; 308) '{ ... 1); }': ()
4438 [199; 200) 'x': Option<u32>
4439 [203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
4440 [203; 221) 'Option...(1u32)': Option<u32>
4441 [216; 220) '1u32': u32
4442 [227; 228) 'x': Option<u32>
4443 [227; 243) 'x.map(...v + 1)': Option<u32>
4444 [233; 242) '|v| v + 1': |u32| -> u32
4445 [234; 235) 'v': u32
4446 [237; 238) 'v': u32
4447 [237; 242) 'v + 1': u32
4448 [241; 242) '1': u32
4449 [249; 250) 'x': Option<u32>
4450 [249; 265) 'x.map(... 1u64)': Option<u64>
4451 [255; 264) '|_v| 1u64': |u32| -> u64
4452 [256; 258) '_v': u32
4453 [260; 264) '1u64': u64
4454 [275; 276) 'y': Option<i64>
4455 [292; 293) 'x': Option<u32>
4456 [292; 305) 'x.map(|_v| 1)': Option<i64>
4457 [298; 304) '|_v| 1': |u32| -> i64
4458 [299; 301) '_v': u32
4459 [303; 304) '1': i64
4460 "###
4461 );
4462}
4463
4464#[test]
4465fn closure_2() {
4466 assert_snapshot!(
4467 infer(r#"
4468trait FnOnce<Args> {
4469 type Output;
4470}
4471
4472fn test<F: FnOnce(u32) -> u64>(f: F) {
4473 f(1);
4474 let g = |v| v + 1;
4475 g(1u64);
4476 let h = |v| 1u128 + v;
4477}
4478"#),
4479 @r###"
4480 [73; 74) 'f': F
4481 [79; 155) '{ ...+ v; }': ()
4482 [85; 86) 'f': F
4483 [85; 89) 'f(1)': {unknown}
4484 [87; 88) '1': i32
4485 [99; 100) 'g': |u64| -> i32
4486 [103; 112) '|v| v + 1': |u64| -> i32
4487 [104; 105) 'v': u64
4488 [107; 108) 'v': u64
4489 [107; 112) 'v + 1': i32
4490 [111; 112) '1': i32
4491 [118; 119) 'g': |u64| -> i32
4492 [118; 125) 'g(1u64)': i32
4493 [120; 124) '1u64': u64
4494 [135; 136) 'h': |u128| -> u128
4495 [139; 152) '|v| 1u128 + v': |u128| -> u128
4496 [140; 141) 'v': u128
4497 [143; 148) '1u128': u128
4498 [143; 152) '1u128 + v': u128
4499 [151; 152) 'v': u128
4500 "###
4501 );
4502}
4503
4504#[test]
4505fn closure_as_argument_inference_order() {
4506 assert_snapshot!(
4507 infer(r#"
4508#[lang = "fn_once"]
4509trait FnOnce<Args> {
4510 type Output;
4511}
4512
4513fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
4514fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
4515
4516struct S;
4517impl S {
4518 fn method(self) -> u64;
4519
4520 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
4521 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
4522}
4523
4524fn test() {
4525 let x1 = foo1(S, |s| s.method());
4526 let x2 = foo2(|s| s.method(), S);
4527 let x3 = S.foo1(S, |s| s.method());
4528 let x4 = S.foo2(|s| s.method(), S);
4529}
4530"#),
4531 @r###"
4532 [95; 96) 'x': T
4533 [101; 102) 'f': F
4534 [112; 114) '{}': ()
4535 [148; 149) 'f': F
4536 [154; 155) 'x': T
4537 [165; 167) '{}': ()
4538 [202; 206) 'self': S
4539 [254; 258) 'self': S
4540 [260; 261) 'x': T
4541 [266; 267) 'f': F
4542 [277; 279) '{}': ()
4543 [317; 321) 'self': S
4544 [323; 324) 'f': F
4545 [329; 330) 'x': T
4546 [340; 342) '{}': ()
4547 [356; 515) '{ ... S); }': ()
4548 [366; 368) 'x1': u64
4549 [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
4550 [371; 394) 'foo1(S...hod())': u64
4551 [376; 377) 'S': S
4552 [379; 393) '|s| s.method()': |S| -> u64
4553 [380; 381) 's': S
4554 [383; 384) 's': S
4555 [383; 393) 's.method()': u64
4556 [404; 406) 'x2': u64
4557 [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
4558 [409; 432) 'foo2(|...(), S)': u64
4559 [414; 428) '|s| s.method()': |S| -> u64
4560 [415; 416) 's': S
4561 [418; 419) 's': S
4562 [418; 428) 's.method()': u64
4563 [430; 431) 'S': S
4564 [442; 444) 'x3': u64
4565 [447; 448) 'S': S
4566 [447; 472) 'S.foo1...hod())': u64
4567 [454; 455) 'S': S
4568 [457; 471) '|s| s.method()': |S| -> u64
4569 [458; 459) 's': S
4570 [461; 462) 's': S
4571 [461; 471) 's.method()': u64
4572 [482; 484) 'x4': u64
4573 [487; 488) 'S': S
4574 [487; 512) 'S.foo2...(), S)': u64
4575 [494; 508) '|s| s.method()': |S| -> u64
4576 [495; 496) 's': S
4577 [498; 499) 's': S
4578 [498; 508) 's.method()': u64
4579 [510; 511) 'S': S
4580 "###
4581 );
4582}
4583
4584#[test]
4585fn unselected_projection_in_trait_env_1() {
4586 let t = type_at(
4587 r#"
4588//- /main.rs
4589trait Trait {
4590 type Item;
4591}
4592
4593trait Trait2 {
4594 fn foo(&self) -> u32;
4595}
4596
4597fn test<T: Trait>() where T::Item: Trait2 {
4598 let x: T::Item = no_matter;
4599 x.foo()<|>;
4600}
4601"#,
4602 );
4603 assert_eq!(t, "u32");
4604}
4605
4606#[test]
4607fn unselected_projection_in_trait_env_2() {
4608 let t = type_at(
4609 r#"
4610//- /main.rs
4611trait Trait<T> {
4612 type Item;
4613}
4614
4615trait Trait2 {
4616 fn foo(&self) -> u32;
4617}
4618
4619fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
4620 let x: T::Item = no_matter;
4621 x.foo()<|>;
4622}
4623"#,
4624 );
4625 assert_eq!(t, "u32");
4626}
4627
4628#[test]
4629// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4630// in Unknown, and we should be able to do that once Salsa allows us to handle
4631// the cycle. But at least it doesn't overflow for now.
4632#[should_panic]
4633fn unselected_projection_in_trait_env_cycle_1() {
4634 let t = type_at(
4635 r#"
4636//- /main.rs
4637trait Trait {
4638 type Item;
4639}
4640
4641trait Trait2<T> {}
4642
4643fn test<T: Trait>() where T: Trait2<T::Item> {
4644 let x: T::Item = no_matter<|>;
4645}
4646"#,
4647 );
4648 // this is a legitimate cycle
4649 assert_eq!(t, "{unknown}");
4650}
4651
4652#[test]
4653// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4654// in Unknown, and we should be able to do that once Salsa allows us to handle
4655// the cycle. But at least it doesn't overflow for now.
4656#[should_panic]
4657fn unselected_projection_in_trait_env_cycle_2() {
4658 let t = type_at(
4659 r#"
4660//- /main.rs
4661trait Trait<T> {
4662 type Item;
4663}
4664
4665fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
4666 let x: T::Item = no_matter<|>;
4667}
4668"#,
4669 );
4670 // this is a legitimate cycle
4671 assert_eq!(t, "{unknown}");
4672}
4673
4674fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 31fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
4675 let file = db.parse(pos.file_id).ok().unwrap(); 32 let file = db.parse(pos.file_id).ok().unwrap();
4676 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 33 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
4677 34 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
4678 let module = db.module_for_file(pos.file_id); 35 let module = db.module_for_file(pos.file_id);
4679 let crate_def_map = db.crate_def_map(module.krate); 36 let func = *module.child_by_source(db)[keys::FUNCTION]
4680 for decl in crate_def_map[module.local_id].scope.declarations() { 37 .get(&InFile::new(pos.file_id.into(), fn_def))
4681 if let ModuleDefId::FunctionId(func) = decl { 38 .unwrap();
4682 let (_body, source_map) = db.body_with_source_map(func.into()); 39
4683 if let Some(expr_id) = source_map.node_expr(Source::new(pos.file_id.into(), &expr)) { 40 let (_body, source_map) = db.body_with_source_map(func.into());
4684 let infer = db.infer(func.into()); 41 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
4685 let ty = &infer[expr_id]; 42 let infer = db.infer(func.into());
4686 return ty.display(db).to_string(); 43 let ty = &infer[expr_id];
4687 } 44 return ty.display(db).to_string();
4688 }
4689 } 45 }
4690 panic!("Can't find expression") 46 panic!("Can't find expression")
4691} 47}
@@ -4696,6 +52,10 @@ fn type_at(content: &str) -> String {
4696} 52}
4697 53
4698fn infer(content: &str) -> String { 54fn infer(content: &str) -> String {
55 infer_with_mismatches(content, false)
56}
57
58fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
4699 let (db, file_id) = TestDB::with_single_file(content); 59 let (db, file_id) = TestDB::with_single_file(content);
4700 60
4701 let mut acc = String::new(); 61 let mut acc = String::new();
@@ -4703,6 +63,7 @@ fn infer(content: &str) -> String {
4703 let mut infer_def = |inference_result: Arc<InferenceResult>, 63 let mut infer_def = |inference_result: Arc<InferenceResult>,
4704 body_source_map: Arc<BodySourceMap>| { 64 body_source_map: Arc<BodySourceMap>| {
4705 let mut types = Vec::new(); 65 let mut types = Vec::new();
66 let mut mismatches = Vec::new();
4706 67
4707 for (pat, ty) in inference_result.type_of_pat.iter() { 68 for (pat, ty) in inference_result.type_of_pat.iter() {
4708 let syntax_ptr = match body_source_map.pat_syntax(pat) { 69 let syntax_ptr = match body_source_map.pat_syntax(pat) {
@@ -4722,6 +83,9 @@ fn infer(content: &str) -> String {
4722 None => continue, 83 None => continue,
4723 }; 84 };
4724 types.push((syntax_ptr, ty)); 85 types.push((syntax_ptr, ty));
86 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
87 mismatches.push((syntax_ptr, mismatch));
88 }
4725 } 89 }
4726 90
4727 // sort ranges for consistency 91 // sort ranges for consistency
@@ -4747,6 +111,24 @@ fn infer(content: &str) -> String {
4747 ) 111 )
4748 .unwrap(); 112 .unwrap();
4749 } 113 }
114 if include_mismatches {
115 mismatches.sort_by_key(|(src_ptr, _)| {
116 (src_ptr.value.range().start(), src_ptr.value.range().end())
117 });
118 for (src_ptr, mismatch) in &mismatches {
119 let range = src_ptr.value.range();
120 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
121 write!(
122 acc,
123 "{}{}: expected {}, got {}\n",
124 macro_prefix,
125 range,
126 mismatch.expected.display(&db),
127 mismatch.actual.display(&db),
128 )
129 .unwrap();
130 }
131 }
4750 }; 132 };
4751 133
4752 let module = db.module_for_file(file_id); 134 let module = db.module_for_file(file_id);
@@ -4800,7 +182,7 @@ fn visit_module(
4800 _ => (), 182 _ => (),
4801 } 183 }
4802 } 184 }
4803 for &impl_id in crate_def_map[module_id].impls.iter() { 185 for impl_id in crate_def_map[module_id].scope.impls() {
4804 let impl_data = db.impl_data(impl_id); 186 let impl_data = db.impl_data(impl_id);
4805 for &item in impl_data.items.iter() { 187 for &item in impl_data.items.iter() {
4806 match item { 188 match item {
@@ -4899,60 +281,3 @@ fn no_such_field_diagnostics() {
4899 "### 281 "###
4900 ); 282 );
4901} 283}
4902
4903#[test]
4904fn infer_builtin_macros_line() {
4905 assert_snapshot!(
4906 infer(r#"
4907#[rustc_builtin_macro]
4908macro_rules! line {() => {}}
4909
4910fn main() {
4911 let x = line!();
4912}
4913"#),
4914 @r###"
4915 ![0; 1) '6': i32
4916 [64; 88) '{ ...!(); }': ()
4917 [74; 75) 'x': i32
4918 "###
4919 );
4920}
4921
4922#[test]
4923fn infer_builtin_macros_file() {
4924 assert_snapshot!(
4925 infer(r#"
4926#[rustc_builtin_macro]
4927macro_rules! file {() => {}}
4928
4929fn main() {
4930 let x = file!();
4931}
4932"#),
4933 @r###"
4934 ![0; 2) '""': &str
4935 [64; 88) '{ ...!(); }': ()
4936 [74; 75) 'x': &str
4937 "###
4938 );
4939}
4940
4941#[test]
4942fn infer_builtin_macros_column() {
4943 assert_snapshot!(
4944 infer(r#"
4945#[rustc_builtin_macro]
4946macro_rules! column {() => {}}
4947
4948fn main() {
4949 let x = column!();
4950}
4951"#),
4952 @r###"
4953 ![0; 2) '13': i32
4954 [66; 92) '{ ...!(); }': ()
4955 [76; 77) 'x': i32
4956 "###
4957 );
4958}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 1530fcc63..7e99a42ed 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,3 +1,4 @@
1use super::infer_with_mismatches;
1use insta::assert_snapshot; 2use insta::assert_snapshot;
2use test_utils::covers; 3use test_utils::covers;
3 4
@@ -367,3 +368,161 @@ fn test() {
367 "### 368 "###
368 ); 369 );
369} 370}
371
372#[test]
373fn return_coerce_unknown() {
374 assert_snapshot!(
375 infer_with_mismatches(r#"
376fn foo() -> u32 {
377 return unknown;
378}
379"#, true),
380 @r###"
381 [17; 40) '{ ...own; }': !
382 [23; 37) 'return unknown': !
383 [30; 37) 'unknown': u32
384 "###
385 );
386}
387
388#[test]
389fn coerce_autoderef() {
390 assert_snapshot!(
391 infer_with_mismatches(r#"
392struct Foo;
393fn takes_ref_foo(x: &Foo) {}
394fn test() {
395 takes_ref_foo(&Foo);
396 takes_ref_foo(&&Foo);
397 takes_ref_foo(&&&Foo);
398}
399"#, true),
400 @r###"
401 [30; 31) 'x': &Foo
402 [39; 41) '{}': ()
403 [52; 133) '{ ...oo); }': ()
404 [58; 71) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
405 [58; 77) 'takes_...(&Foo)': ()
406 [72; 76) '&Foo': &Foo
407 [73; 76) 'Foo': Foo
408 [83; 96) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
409 [83; 103) 'takes_...&&Foo)': ()
410 [97; 102) '&&Foo': &&Foo
411 [98; 102) '&Foo': &Foo
412 [99; 102) 'Foo': Foo
413 [109; 122) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
414 [109; 130) 'takes_...&&Foo)': ()
415 [123; 129) '&&&Foo': &&&Foo
416 [124; 129) '&&Foo': &&Foo
417 [125; 129) '&Foo': &Foo
418 [126; 129) 'Foo': Foo
419 "###
420 );
421}
422
423#[test]
424fn coerce_autoderef_generic() {
425 assert_snapshot!(
426 infer_with_mismatches(r#"
427struct Foo;
428fn takes_ref<T>(x: &T) -> T { *x }
429fn test() {
430 takes_ref(&Foo);
431 takes_ref(&&Foo);
432 takes_ref(&&&Foo);
433}
434"#, true),
435 @r###"
436 [29; 30) 'x': &T
437 [41; 47) '{ *x }': T
438 [43; 45) '*x': T
439 [44; 45) 'x': &T
440 [58; 127) '{ ...oo); }': ()
441 [64; 73) 'takes_ref': fn takes_ref<Foo>(&T) -> T
442 [64; 79) 'takes_ref(&Foo)': Foo
443 [74; 78) '&Foo': &Foo
444 [75; 78) 'Foo': Foo
445 [85; 94) 'takes_ref': fn takes_ref<&Foo>(&T) -> T
446 [85; 101) 'takes_...&&Foo)': &Foo
447 [95; 100) '&&Foo': &&Foo
448 [96; 100) '&Foo': &Foo
449 [97; 100) 'Foo': Foo
450 [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&T) -> T
451 [107; 124) 'takes_...&&Foo)': &&Foo
452 [117; 123) '&&&Foo': &&&Foo
453 [118; 123) '&&Foo': &&Foo
454 [119; 123) '&Foo': &Foo
455 [120; 123) 'Foo': Foo
456 "###
457 );
458}
459
460#[test]
461fn closure_return_coerce() {
462 assert_snapshot!(
463 infer_with_mismatches(r#"
464fn foo() {
465 let x = || {
466 if true {
467 return &1u32;
468 }
469 &&1u32
470 };
471}
472"#, true),
473 @r###"
474 [10; 106) '{ ... }; }': ()
475 [20; 21) 'x': || -> &u32
476 [24; 103) '|| { ... }': || -> &u32
477 [27; 103) '{ ... }': &u32
478 [37; 82) 'if tru... }': ()
479 [40; 44) 'true': bool
480 [45; 82) '{ ... }': !
481 [59; 71) 'return &1u32': !
482 [66; 71) '&1u32': &u32
483 [67; 71) '1u32': u32
484 [91; 97) '&&1u32': &&u32
485 [92; 97) '&1u32': &u32
486 [93; 97) '1u32': u32
487 "###
488 );
489}
490
491#[test]
492fn coerce_fn_item_to_fn_ptr() {
493 assert_snapshot!(
494 infer_with_mismatches(r#"
495fn foo(x: u32) -> isize { 1 }
496fn test() {
497 let f: fn(u32) -> isize = foo;
498}
499"#, true),
500 @r###"
501 [8; 9) 'x': u32
502 [25; 30) '{ 1 }': isize
503 [27; 28) '1': isize
504 [41; 79) '{ ...foo; }': ()
505 [51; 52) 'f': fn(u32) -> isize
506 [73; 76) 'foo': fn foo(u32) -> isize
507 "###
508 );
509}
510
511#[test]
512fn coerce_closure_to_fn_ptr() {
513 assert_snapshot!(
514 infer_with_mismatches(r#"
515fn test() {
516 let f: fn(u32) -> isize = |x| { 1 };
517}
518"#, true),
519 @r###"
520 [11; 55) '{ ...1 }; }': ()
521 [21; 22) 'f': fn(u32) -> isize
522 [43; 52) '|x| { 1 }': |u32| -> isize
523 [44; 45) 'x': u32
524 [47; 52) '{ 1 }': isize
525 [49; 50) '1': isize
526 "###
527 );
528}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
new file mode 100644
index 000000000..69c695cc8
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -0,0 +1,390 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn cfg_impl_block() {
8 let (db, pos) = TestDB::with_position(
9 r#"
10//- /main.rs crate:main deps:foo cfg:test
11use foo::S as T;
12struct S;
13
14#[cfg(test)]
15impl S {
16 fn foo1(&self) -> i32 { 0 }
17}
18
19#[cfg(not(test))]
20impl S {
21 fn foo2(&self) -> i32 { 0 }
22}
23
24fn test() {
25 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
26 t<|>;
27}
28
29//- /foo.rs crate:foo
30struct S;
31
32#[cfg(not(test))]
33impl S {
34 fn foo3(&self) -> i32 { 0 }
35}
36
37#[cfg(test)]
38impl S {
39 fn foo4(&self) -> i32 { 0 }
40}
41"#,
42 );
43 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
44}
45
46#[test]
47fn infer_macros_expanded() {
48 assert_snapshot!(
49 infer(r#"
50struct Foo(Vec<i32>);
51
52macro_rules! foo {
53 ($($item:expr),*) => {
54 {
55 Foo(vec![$($item,)*])
56 }
57 };
58}
59
60fn main() {
61 let x = foo!(1,2);
62}
63"#),
64 @r###"
65 ![0; 17) '{Foo(v...,2,])}': Foo
66 ![1; 4) 'Foo': Foo({unknown}) -> Foo
67 ![1; 16) 'Foo(vec![1,2,])': Foo
68 ![5; 15) 'vec![1,2,]': {unknown}
69 [156; 182) '{ ...,2); }': ()
70 [166; 167) 'x': Foo
71 "###
72 );
73}
74
75#[test]
76fn infer_legacy_textual_scoped_macros_expanded() {
77 assert_snapshot!(
78 infer(r#"
79struct Foo(Vec<i32>);
80
81#[macro_use]
82mod m {
83 macro_rules! foo {
84 ($($item:expr),*) => {
85 {
86 Foo(vec![$($item,)*])
87 }
88 };
89 }
90}
91
92fn main() {
93 let x = foo!(1,2);
94 let y = crate::foo!(1,2);
95}
96"#),
97 @r###"
98 ![0; 17) '{Foo(v...,2,])}': Foo
99 ![1; 4) 'Foo': Foo({unknown}) -> Foo
100 ![1; 16) 'Foo(vec![1,2,])': Foo
101 ![5; 15) 'vec![1,2,]': {unknown}
102 [195; 251) '{ ...,2); }': ()
103 [205; 206) 'x': Foo
104 [228; 229) 'y': {unknown}
105 [232; 248) 'crate:...!(1,2)': {unknown}
106 "###
107 );
108}
109
110#[test]
111fn infer_path_qualified_macros_expanded() {
112 assert_snapshot!(
113 infer(r#"
114#[macro_export]
115macro_rules! foo {
116 () => { 42i32 }
117}
118
119mod m {
120 pub use super::foo as bar;
121}
122
123fn main() {
124 let x = crate::foo!();
125 let y = m::bar!();
126}
127"#),
128 @r###"
129 ![0; 5) '42i32': i32
130 ![0; 5) '42i32': i32
131 [111; 164) '{ ...!(); }': ()
132 [121; 122) 'x': i32
133 [148; 149) 'y': i32
134 "###
135 );
136}
137
138#[test]
139fn infer_type_value_macro_having_same_name() {
140 assert_snapshot!(
141 infer(r#"
142#[macro_export]
143macro_rules! foo {
144 () => {
145 mod foo {
146 pub use super::foo;
147 }
148 };
149 ($x:tt) => {
150 $x
151 };
152}
153
154foo!();
155
156fn foo() {
157 let foo = foo::foo!(42i32);
158}
159"#),
160 @r###"
161 ![0; 5) '42i32': i32
162 [171; 206) '{ ...32); }': ()
163 [181; 184) 'foo': i32
164 "###
165 );
166}
167
168#[test]
169fn processes_impls_generated_by_macros() {
170 let t = type_at(
171 r#"
172//- /main.rs
173macro_rules! m {
174 ($ident:ident) => (impl Trait for $ident {})
175}
176trait Trait { fn foo(self) -> u128 {} }
177struct S;
178m!(S);
179fn test() { S.foo()<|>; }
180"#,
181 );
182 assert_eq!(t, "u128");
183}
184
185#[test]
186fn infer_impl_items_generated_by_macros() {
187 let t = type_at(
188 r#"
189//- /main.rs
190macro_rules! m {
191 () => (fn foo(&self) -> u128 {0})
192}
193struct S;
194impl S {
195 m!();
196}
197
198fn test() { S.foo()<|>; }
199"#,
200 );
201 assert_eq!(t, "u128");
202}
203
204#[test]
205fn infer_impl_items_generated_by_macros_chain() {
206 let t = type_at(
207 r#"
208//- /main.rs
209macro_rules! m_inner {
210 () => {fn foo(&self) -> u128 {0}}
211}
212macro_rules! m {
213 () => {m_inner!();}
214}
215
216struct S;
217impl S {
218 m!();
219}
220
221fn test() { S.foo()<|>; }
222"#,
223 );
224 assert_eq!(t, "u128");
225}
226
227#[test]
228fn infer_macro_with_dollar_crate_is_correct_in_expr() {
229 let (db, pos) = TestDB::with_position(
230 r#"
231//- /main.rs crate:main deps:foo
232fn test() {
233 let x = (foo::foo!(1), foo::foo!(2));
234 x<|>;
235}
236
237//- /lib.rs crate:foo
238#[macro_export]
239macro_rules! foo {
240 (1) => { $crate::bar!() };
241 (2) => { 1 + $crate::baz() };
242}
243
244#[macro_export]
245macro_rules! bar {
246 () => { 42 }
247}
248
249pub fn baz() -> usize { 31usize }
250"#,
251 );
252 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
253}
254
255#[test]
256fn infer_type_value_non_legacy_macro_use_as() {
257 assert_snapshot!(
258 infer(r#"
259mod m {
260 macro_rules! _foo {
261 ($x:ident) => { type $x = u64; }
262 }
263 pub(crate) use _foo as foo;
264}
265
266m::foo!(foo);
267use foo as bar;
268fn f() -> bar { 0 }
269fn main() {
270 let _a = f();
271}
272"#),
273 @r###"
274 [159; 164) '{ 0 }': u64
275 [161; 162) '0': u64
276 [175; 199) '{ ...f(); }': ()
277 [187; 189) '_a': u64
278 [193; 194) 'f': fn f() -> u64
279 [193; 196) 'f()': u64
280 "###
281 );
282}
283
284#[test]
285fn infer_builtin_macros_line() {
286 assert_snapshot!(
287 infer(r#"
288#[rustc_builtin_macro]
289macro_rules! line {() => {}}
290
291fn main() {
292 let x = line!();
293}
294"#),
295 @r###"
296 ![0; 1) '6': i32
297 [64; 88) '{ ...!(); }': ()
298 [74; 75) 'x': i32
299 "###
300 );
301}
302
303#[test]
304fn infer_builtin_macros_file() {
305 assert_snapshot!(
306 infer(r#"
307#[rustc_builtin_macro]
308macro_rules! file {() => {}}
309
310fn main() {
311 let x = file!();
312}
313"#),
314 @r###"
315 ![0; 2) '""': &str
316 [64; 88) '{ ...!(); }': ()
317 [74; 75) 'x': &str
318 "###
319 );
320}
321
322#[test]
323fn infer_builtin_macros_column() {
324 assert_snapshot!(
325 infer(r#"
326#[rustc_builtin_macro]
327macro_rules! column {() => {}}
328
329fn main() {
330 let x = column!();
331}
332"#),
333 @r###"
334 ![0; 2) '13': i32
335 [66; 92) '{ ...!(); }': ()
336 [76; 77) 'x': i32
337 "###
338 );
339}
340
341#[test]
342fn infer_derive_clone_simple() {
343 let (db, pos) = TestDB::with_position(
344 r#"
345//- /main.rs crate:main deps:std
346#[derive(Clone)]
347struct S;
348fn test() {
349 S.clone()<|>;
350}
351
352//- /lib.rs crate:std
353#[prelude_import]
354use clone::*;
355mod clone {
356 trait Clone {
357 fn clone(&self) -> Self;
358 }
359}
360"#,
361 );
362 assert_eq!("S", type_at_pos(&db, pos));
363}
364
365#[test]
366fn infer_derive_clone_with_params() {
367 let (db, pos) = TestDB::with_position(
368 r#"
369//- /main.rs crate:main deps:std
370#[derive(Clone)]
371struct S;
372#[derive(Clone)]
373struct Wrapper<T>(T);
374struct NonClone;
375fn test() {
376 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
377}
378
379//- /lib.rs crate:std
380#[prelude_import]
381use clone::*;
382mod clone {
383 trait Clone {
384 fn clone(&self) -> Self;
385 }
386}
387"#,
388 );
389 assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
390}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
new file mode 100644
index 000000000..ce9a06fde
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -0,0 +1,1005 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn infer_slice_method() {
8 assert_snapshot!(
9 infer(r#"
10#[lang = "slice"]
11impl<T> [T] {
12 fn foo(&self) -> T {
13 loop {}
14 }
15}
16
17#[lang = "slice_alloc"]
18impl<T> [T] {}
19
20fn test() {
21 <[_]>::foo(b"foo");
22}
23"#),
24 @r###"
25 [45; 49) 'self': &[T]
26 [56; 79) '{ ... }': T
27 [66; 73) 'loop {}': !
28 [71; 73) '{}': ()
29 [133; 160) '{ ...o"); }': ()
30 [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T
31 [139; 157) '<[_]>:..."foo")': u8
32 [150; 156) 'b"foo"': &[u8]
33 "###
34 );
35}
36
37#[test]
38fn infer_associated_method_struct() {
39 assert_snapshot!(
40 infer(r#"
41struct A { x: u32 }
42
43impl A {
44 fn new() -> A {
45 A { x: 0 }
46 }
47}
48fn test() {
49 let a = A::new();
50 a.x;
51}
52"#),
53 @r###"
54 [49; 75) '{ ... }': A
55 [59; 69) 'A { x: 0 }': A
56 [66; 67) '0': u32
57 [88; 122) '{ ...a.x; }': ()
58 [98; 99) 'a': A
59 [102; 108) 'A::new': fn new() -> A
60 [102; 110) 'A::new()': A
61 [116; 117) 'a': A
62 [116; 119) 'a.x': u32
63 "###
64 );
65}
66
67#[test]
68fn infer_associated_method_enum() {
69 assert_snapshot!(
70 infer(r#"
71enum A { B, C }
72
73impl A {
74 pub fn b() -> A {
75 A::B
76 }
77 pub fn c() -> A {
78 A::C
79 }
80}
81fn test() {
82 let a = A::b();
83 a;
84 let c = A::c();
85 c;
86}
87"#),
88 @r###"
89 [47; 67) '{ ... }': A
90 [57; 61) 'A::B': A
91 [88; 108) '{ ... }': A
92 [98; 102) 'A::C': A
93 [121; 178) '{ ... c; }': ()
94 [131; 132) 'a': A
95 [135; 139) 'A::b': fn b() -> A
96 [135; 141) 'A::b()': A
97 [147; 148) 'a': A
98 [158; 159) 'c': A
99 [162; 166) 'A::c': fn c() -> A
100 [162; 168) 'A::c()': A
101 [174; 175) 'c': A
102 "###
103 );
104}
105
106#[test]
107fn infer_associated_method_with_modules() {
108 assert_snapshot!(
109 infer(r#"
110mod a {
111 struct A;
112 impl A { pub fn thing() -> A { A {} }}
113}
114
115mod b {
116 struct B;
117 impl B { pub fn thing() -> u32 { 99 }}
118
119 mod c {
120 struct C;
121 impl C { pub fn thing() -> C { C {} }}
122 }
123}
124use b::c;
125
126fn test() {
127 let x = a::A::thing();
128 let y = b::B::thing();
129 let z = c::C::thing();
130}
131"#),
132 @r###"
133 [56; 64) '{ A {} }': A
134 [58; 62) 'A {}': A
135 [126; 132) '{ 99 }': u32
136 [128; 130) '99': u32
137 [202; 210) '{ C {} }': C
138 [204; 208) 'C {}': C
139 [241; 325) '{ ...g(); }': ()
140 [251; 252) 'x': A
141 [255; 266) 'a::A::thing': fn thing() -> A
142 [255; 268) 'a::A::thing()': A
143 [278; 279) 'y': u32
144 [282; 293) 'b::B::thing': fn thing() -> u32
145 [282; 295) 'b::B::thing()': u32
146 [305; 306) 'z': C
147 [309; 320) 'c::C::thing': fn thing() -> C
148 [309; 322) 'c::C::thing()': C
149 "###
150 );
151}
152
153#[test]
154fn infer_associated_method_generics() {
155 assert_snapshot!(
156 infer(r#"
157struct Gen<T> {
158 val: T
159}
160
161impl<T> Gen<T> {
162 pub fn make(val: T) -> Gen<T> {
163 Gen { val }
164 }
165}
166
167fn test() {
168 let a = Gen::make(0u32);
169}
170"#),
171 @r###"
172 [64; 67) 'val': T
173 [82; 109) '{ ... }': Gen<T>
174 [92; 103) 'Gen { val }': Gen<T>
175 [98; 101) 'val': T
176 [123; 155) '{ ...32); }': ()
177 [133; 134) 'a': Gen<u32>
178 [137; 146) 'Gen::make': fn make<u32>(T) -> Gen<T>
179 [137; 152) 'Gen::make(0u32)': Gen<u32>
180 [147; 151) '0u32': u32
181 "###
182 );
183}
184
185#[test]
186fn infer_associated_method_generics_with_default_param() {
187 assert_snapshot!(
188 infer(r#"
189struct Gen<T=u32> {
190 val: T
191}
192
193impl<T> Gen<T> {
194 pub fn make() -> Gen<T> {
195 loop { }
196 }
197}
198
199fn test() {
200 let a = Gen::make();
201}
202"#),
203 @r###"
204 [80; 104) '{ ... }': Gen<T>
205 [90; 98) 'loop { }': !
206 [95; 98) '{ }': ()
207 [118; 146) '{ ...e(); }': ()
208 [128; 129) 'a': Gen<u32>
209 [132; 141) 'Gen::make': fn make<u32>() -> Gen<T>
210 [132; 143) 'Gen::make()': Gen<u32>
211 "###
212 );
213}
214
215#[test]
216fn infer_associated_method_generics_with_default_tuple_param() {
217 let t = type_at(
218 r#"
219//- /main.rs
220struct Gen<T=()> {
221 val: T
222}
223
224impl<T> Gen<T> {
225 pub fn make() -> Gen<T> {
226 loop { }
227 }
228}
229
230fn test() {
231 let a = Gen::make();
232 a.val<|>;
233}
234"#,
235 );
236 assert_eq!(t, "()");
237}
238
239#[test]
240fn infer_associated_method_generics_without_args() {
241 assert_snapshot!(
242 infer(r#"
243struct Gen<T> {
244 val: T
245}
246
247impl<T> Gen<T> {
248 pub fn make() -> Gen<T> {
249 loop { }
250 }
251}
252
253fn test() {
254 let a = Gen::<u32>::make();
255}
256"#),
257 @r###"
258 [76; 100) '{ ... }': Gen<T>
259 [86; 94) 'loop { }': !
260 [91; 94) '{ }': ()
261 [114; 149) '{ ...e(); }': ()
262 [124; 125) 'a': Gen<u32>
263 [128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T>
264 [128; 146) 'Gen::<...make()': Gen<u32>
265 "###
266 );
267}
268
269#[test]
270fn infer_associated_method_generics_2_type_params_without_args() {
271 assert_snapshot!(
272 infer(r#"
273struct Gen<T, U> {
274 val: T,
275 val2: U,
276}
277
278impl<T> Gen<u32, T> {
279 pub fn make() -> Gen<u32,T> {
280 loop { }
281 }
282}
283
284fn test() {
285 let a = Gen::<u32, u64>::make();
286}
287"#),
288 @r###"
289 [102; 126) '{ ... }': Gen<u32, T>
290 [112; 120) 'loop { }': !
291 [117; 120) '{ }': ()
292 [140; 180) '{ ...e(); }': ()
293 [150; 151) 'a': Gen<u32, u64>
294 [154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T>
295 [154; 177) 'Gen::<...make()': Gen<u32, u64>
296 "###
297 );
298}
299
300#[test]
301fn cross_crate_associated_method_call() {
302 let (db, pos) = TestDB::with_position(
303 r#"
304//- /main.rs crate:main deps:other_crate
305fn test() {
306 let x = other_crate::foo::S::thing();
307 x<|>;
308}
309
310//- /lib.rs crate:other_crate
311mod foo {
312 struct S;
313 impl S {
314 fn thing() -> i128 {}
315 }
316}
317"#,
318 );
319 assert_eq!("i128", type_at_pos(&db, pos));
320}
321
322#[test]
323fn infer_trait_method_simple() {
324 // the trait implementation is intentionally incomplete -- it shouldn't matter
325 assert_snapshot!(
326 infer(r#"
327trait Trait1 {
328 fn method(&self) -> u32;
329}
330struct S1;
331impl Trait1 for S1 {}
332trait Trait2 {
333 fn method(&self) -> i128;
334}
335struct S2;
336impl Trait2 for S2 {}
337fn test() {
338 S1.method(); // -> u32
339 S2.method(); // -> i128
340}
341"#),
342 @r###"
343 [31; 35) 'self': &Self
344 [110; 114) 'self': &Self
345 [170; 228) '{ ...i128 }': ()
346 [176; 178) 'S1': S1
347 [176; 187) 'S1.method()': u32
348 [203; 205) 'S2': S2
349 [203; 214) 'S2.method()': i128
350 "###
351 );
352}
353
354#[test]
355fn infer_trait_method_scoped() {
356 // the trait implementation is intentionally incomplete -- it shouldn't matter
357 assert_snapshot!(
358 infer(r#"
359struct S;
360mod foo {
361 pub trait Trait1 {
362 fn method(&self) -> u32;
363 }
364 impl Trait1 for super::S {}
365}
366mod bar {
367 pub trait Trait2 {
368 fn method(&self) -> i128;
369 }
370 impl Trait2 for super::S {}
371}
372
373mod foo_test {
374 use super::S;
375 use super::foo::Trait1;
376 fn test() {
377 S.method(); // -> u32
378 }
379}
380
381mod bar_test {
382 use super::S;
383 use super::bar::Trait2;
384 fn test() {
385 S.method(); // -> i128
386 }
387}
388"#),
389 @r###"
390 [63; 67) 'self': &Self
391 [169; 173) 'self': &Self
392 [300; 337) '{ ... }': ()
393 [310; 311) 'S': S
394 [310; 320) 'S.method()': u32
395 [416; 454) '{ ... }': ()
396 [426; 427) 'S': S
397 [426; 436) 'S.method()': i128
398 "###
399 );
400}
401
402#[test]
403fn infer_trait_method_generic_1() {
404 // the trait implementation is intentionally incomplete -- it shouldn't matter
405 assert_snapshot!(
406 infer(r#"
407trait Trait<T> {
408 fn method(&self) -> T;
409}
410struct S;
411impl Trait<u32> for S {}
412fn test() {
413 S.method();
414}
415"#),
416 @r###"
417 [33; 37) 'self': &Self
418 [92; 111) '{ ...d(); }': ()
419 [98; 99) 'S': S
420 [98; 108) 'S.method()': u32
421 "###
422 );
423}
424
425#[test]
426fn infer_trait_method_generic_more_params() {
427 // the trait implementation is intentionally incomplete -- it shouldn't matter
428 assert_snapshot!(
429 infer(r#"
430trait Trait<T1, T2, T3> {
431 fn method1(&self) -> (T1, T2, T3);
432 fn method2(&self) -> (T3, T2, T1);
433}
434struct S1;
435impl Trait<u8, u16, u32> for S1 {}
436struct S2;
437impl<T> Trait<i8, i16, T> for S2 {}
438fn test() {
439 S1.method1(); // u8, u16, u32
440 S1.method2(); // u32, u16, u8
441 S2.method1(); // i8, i16, {unknown}
442 S2.method2(); // {unknown}, i16, i8
443}
444"#),
445 @r###"
446 [43; 47) 'self': &Self
447 [82; 86) 'self': &Self
448 [210; 361) '{ ..., i8 }': ()
449 [216; 218) 'S1': S1
450 [216; 228) 'S1.method1()': (u8, u16, u32)
451 [250; 252) 'S1': S1
452 [250; 262) 'S1.method2()': (u32, u16, u8)
453 [284; 286) 'S2': S2
454 [284; 296) 'S2.method1()': (i8, i16, {unknown})
455 [324; 326) 'S2': S2
456 [324; 336) 'S2.method2()': ({unknown}, i16, i8)
457 "###
458 );
459}
460
461#[test]
462fn infer_trait_method_generic_2() {
463 // the trait implementation is intentionally incomplete -- it shouldn't matter
464 assert_snapshot!(
465 infer(r#"
466trait Trait<T> {
467 fn method(&self) -> T;
468}
469struct S<T>(T);
470impl<U> Trait<U> for S<U> {}
471fn test() {
472 S(1u32).method();
473}
474"#),
475 @r###"
476 [33; 37) 'self': &Self
477 [102; 127) '{ ...d(); }': ()
478 [108; 109) 'S': S<u32>(T) -> S<T>
479 [108; 115) 'S(1u32)': S<u32>
480 [108; 124) 'S(1u32...thod()': u32
481 [110; 114) '1u32': u32
482 "###
483 );
484}
485
486#[test]
487fn infer_trait_assoc_method() {
488 assert_snapshot!(
489 infer(r#"
490trait Default {
491 fn default() -> Self;
492}
493struct S;
494impl Default for S {}
495fn test() {
496 let s1: S = Default::default();
497 let s2 = S::default();
498 let s3 = <S as Default>::default();
499}
500"#),
501 @r###"
502 [87; 193) '{ ...t(); }': ()
503 [97; 99) 's1': S
504 [105; 121) 'Defaul...efault': fn default<S>() -> Self
505 [105; 123) 'Defaul...ault()': S
506 [133; 135) 's2': S
507 [138; 148) 'S::default': fn default<S>() -> Self
508 [138; 150) 'S::default()': S
509 [160; 162) 's3': S
510 [165; 188) '<S as ...efault': fn default<S>() -> Self
511 [165; 190) '<S as ...ault()': S
512 "###
513 );
514}
515
516#[test]
517fn infer_trait_assoc_method_generics_1() {
518 assert_snapshot!(
519 infer(r#"
520trait Trait<T> {
521 fn make() -> T;
522}
523struct S;
524impl Trait<u32> for S {}
525struct G<T>;
526impl<T> Trait<T> for G<T> {}
527fn test() {
528 let a = S::make();
529 let b = G::<u64>::make();
530 let c: f64 = G::make();
531}
532"#),
533 @r###"
534 [127; 211) '{ ...e(); }': ()
535 [137; 138) 'a': u32
536 [141; 148) 'S::make': fn make<S, u32>() -> T
537 [141; 150) 'S::make()': u32
538 [160; 161) 'b': u64
539 [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
540 [164; 180) 'G::<u6...make()': u64
541 [190; 191) 'c': f64
542 [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
543 [199; 208) 'G::make()': f64
544 "###
545 );
546}
547
548#[test]
549fn infer_trait_assoc_method_generics_2() {
550 assert_snapshot!(
551 infer(r#"
552trait Trait<T> {
553 fn make<U>() -> (T, U);
554}
555struct S;
556impl Trait<u32> for S {}
557struct G<T>;
558impl<T> Trait<T> for G<T> {}
559fn test() {
560 let a = S::make::<i64>();
561 let b: (_, i64) = S::make();
562 let c = G::<u32>::make::<i64>();
563 let d: (u32, _) = G::make::<i64>();
564 let e: (u32, i64) = G::make();
565}
566"#),
567 @r###"
568 [135; 313) '{ ...e(); }': ()
569 [145; 146) 'a': (u32, i64)
570 [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
571 [149; 165) 'S::mak...i64>()': (u32, i64)
572 [175; 176) 'b': (u32, i64)
573 [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
574 [189; 198) 'S::make()': (u32, i64)
575 [208; 209) 'c': (u32, i64)
576 [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
577 [212; 235) 'G::<u3...i64>()': (u32, i64)
578 [245; 246) 'd': (u32, i64)
579 [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
580 [259; 275) 'G::mak...i64>()': (u32, i64)
581 [285; 286) 'e': (u32, i64)
582 [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
583 [301; 310) 'G::make()': (u32, i64)
584 "###
585 );
586}
587
588#[test]
589fn infer_trait_assoc_method_generics_3() {
590 assert_snapshot!(
591 infer(r#"
592trait Trait<T> {
593 fn make() -> (Self, T);
594}
595struct S<T>;
596impl Trait<i64> for S<i32> {}
597fn test() {
598 let a = S::make();
599}
600"#),
601 @r###"
602 [101; 127) '{ ...e(); }': ()
603 [111; 112) 'a': (S<i32>, i64)
604 [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T)
605 [115; 124) 'S::make()': (S<i32>, i64)
606 "###
607 );
608}
609
610#[test]
611fn infer_trait_assoc_method_generics_4() {
612 assert_snapshot!(
613 infer(r#"
614trait Trait<T> {
615 fn make() -> (Self, T);
616}
617struct S<T>;
618impl Trait<i64> for S<u64> {}
619impl Trait<i32> for S<u32> {}
620fn test() {
621 let a: (S<u64>, _) = S::make();
622 let b: (_, i32) = S::make();
623}
624"#),
625 @r###"
626 [131; 203) '{ ...e(); }': ()
627 [141; 142) 'a': (S<u64>, i64)
628 [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T)
629 [158; 167) 'S::make()': (S<u64>, i64)
630 [177; 178) 'b': (S<u32>, i32)
631 [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T)
632 [191; 200) 'S::make()': (S<u32>, i32)
633 "###
634 );
635}
636
637#[test]
638fn infer_trait_assoc_method_generics_5() {
639 assert_snapshot!(
640 infer(r#"
641trait Trait<T> {
642 fn make<U>() -> (Self, T, U);
643}
644struct S<T>;
645impl Trait<i64> for S<u64> {}
646fn test() {
647 let a = <S as Trait<i64>>::make::<u8>();
648 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
649}
650"#),
651 @r###"
652 [107; 211) '{ ...>(); }': ()
653 [117; 118) 'a': (S<u64>, i64, u8)
654 [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
655 [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
656 [162; 163) 'b': (S<u64>, i64, u8)
657 [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
658 [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
659 "###
660 );
661}
662
663#[test]
664fn infer_call_trait_method_on_generic_param_1() {
665 assert_snapshot!(
666 infer(r#"
667trait Trait {
668 fn method(&self) -> u32;
669}
670fn test<T: Trait>(t: T) {
671 t.method();
672}
673"#),
674 @r###"
675 [30; 34) 'self': &Self
676 [64; 65) 't': T
677 [70; 89) '{ ...d(); }': ()
678 [76; 77) 't': T
679 [76; 86) 't.method()': u32
680 "###
681 );
682}
683
684#[test]
685fn infer_call_trait_method_on_generic_param_2() {
686 assert_snapshot!(
687 infer(r#"
688trait Trait<T> {
689 fn method(&self) -> T;
690}
691fn test<U, T: Trait<U>>(t: T) {
692 t.method();
693}
694"#),
695 @r###"
696 [33; 37) 'self': &Self
697 [71; 72) 't': T
698 [77; 96) '{ ...d(); }': ()
699 [83; 84) 't': T
700 [83; 93) 't.method()': [missing name]
701 "###
702 );
703}
704
705#[test]
706fn infer_with_multiple_trait_impls() {
707 assert_snapshot!(
708 infer(r#"
709trait Into<T> {
710 fn into(self) -> T;
711}
712struct S;
713impl Into<u32> for S {}
714impl Into<u64> for S {}
715fn test() {
716 let x: u32 = S.into();
717 let y: u64 = S.into();
718 let z = Into::<u64>::into(S);
719}
720"#),
721 @r###"
722 [29; 33) 'self': Self
723 [111; 202) '{ ...(S); }': ()
724 [121; 122) 'x': u32
725 [130; 131) 'S': S
726 [130; 138) 'S.into()': u32
727 [148; 149) 'y': u64
728 [157; 158) 'S': S
729 [157; 165) 'S.into()': u64
730 [175; 176) 'z': u64
731 [179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
732 [179; 199) 'Into::...nto(S)': u64
733 [197; 198) 'S': S
734 "###
735 );
736}
737
738#[test]
739fn method_resolution_unify_impl_self_type() {
740 let t = type_at(
741 r#"
742//- /main.rs
743struct S<T>;
744impl S<u32> { fn foo(&self) -> u8 {} }
745impl S<i32> { fn foo(&self) -> i8 {} }
746fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; }
747"#,
748 );
749 assert_eq!(t, "(u8, i8)");
750}
751
752#[test]
753fn method_resolution_trait_before_autoref() {
754 let t = type_at(
755 r#"
756//- /main.rs
757trait Trait { fn foo(self) -> u128; }
758struct S;
759impl S { fn foo(&self) -> i8 { 0 } }
760impl Trait for S { fn foo(self) -> u128 { 0 } }
761fn test() { S.foo()<|>; }
762"#,
763 );
764 assert_eq!(t, "u128");
765}
766
767#[test]
768fn method_resolution_by_value_before_autoref() {
769 let t = type_at(
770 r#"
771//- /main.rs
772trait Clone { fn clone(&self) -> Self; }
773struct S;
774impl Clone for S {}
775impl Clone for &S {}
776fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
777"#,
778 );
779 assert_eq!(t, "(S, S, &S)");
780}
781
782#[test]
783fn method_resolution_trait_before_autoderef() {
784 let t = type_at(
785 r#"
786//- /main.rs
787trait Trait { fn foo(self) -> u128; }
788struct S;
789impl S { fn foo(self) -> i8 { 0 } }
790impl Trait for &S { fn foo(self) -> u128 { 0 } }
791fn test() { (&S).foo()<|>; }
792"#,
793 );
794 assert_eq!(t, "u128");
795}
796
797#[test]
798fn method_resolution_impl_before_trait() {
799 let t = type_at(
800 r#"
801//- /main.rs
802trait Trait { fn foo(self) -> u128; }
803struct S;
804impl S { fn foo(self) -> i8 { 0 } }
805impl Trait for S { fn foo(self) -> u128 { 0 } }
806fn test() { S.foo()<|>; }
807"#,
808 );
809 assert_eq!(t, "i8");
810}
811
812#[test]
813fn method_resolution_impl_ref_before_trait() {
814 let t = type_at(
815 r#"
816//- /main.rs
817trait Trait { fn foo(self) -> u128; }
818struct S;
819impl S { fn foo(&self) -> i8 { 0 } }
820impl Trait for &S { fn foo(self) -> u128 { 0 } }
821fn test() { S.foo()<|>; }
822"#,
823 );
824 assert_eq!(t, "i8");
825}
826
827#[test]
828fn method_resolution_trait_autoderef() {
829 let t = type_at(
830 r#"
831//- /main.rs
832trait Trait { fn foo(self) -> u128; }
833struct S;
834impl Trait for S { fn foo(self) -> u128 { 0 } }
835fn test() { (&S).foo()<|>; }
836"#,
837 );
838 assert_eq!(t, "u128");
839}
840
841#[test]
842fn method_resolution_trait_from_prelude() {
843 let (db, pos) = TestDB::with_position(
844 r#"
845//- /main.rs crate:main deps:other_crate
846struct S;
847impl Clone for S {}
848
849fn test() {
850 S.clone()<|>;
851}
852
853//- /lib.rs crate:other_crate
854#[prelude_import] use foo::*;
855
856mod foo {
857 trait Clone {
858 fn clone(&self) -> Self;
859 }
860}
861"#,
862 );
863 assert_eq!("S", type_at_pos(&db, pos));
864}
865
866#[test]
867fn method_resolution_where_clause_for_unknown_trait() {
868 // The blanket impl currently applies because we ignore the unresolved where clause
869 let t = type_at(
870 r#"
871//- /main.rs
872trait Trait { fn foo(self) -> u128; }
873struct S;
874impl<T> Trait for T where T: UnknownTrait {}
875fn test() { (&S).foo()<|>; }
876"#,
877 );
878 assert_eq!(t, "u128");
879}
880
881#[test]
882fn method_resolution_where_clause_not_met() {
883 // The blanket impl shouldn't apply because we can't prove S: Clone
884 let t = type_at(
885 r#"
886//- /main.rs
887trait Clone {}
888trait Trait { fn foo(self) -> u128; }
889struct S;
890impl<T> Trait for T where T: Clone {}
891fn test() { (&S).foo()<|>; }
892"#,
893 );
894 // This is also to make sure that we don't resolve to the foo method just
895 // because that's the only method named foo we can find, which would make
896 // the below tests not work
897 assert_eq!(t, "{unknown}");
898}
899
900#[test]
901fn method_resolution_where_clause_inline_not_met() {
902 // The blanket impl shouldn't apply because we can't prove S: Clone
903 let t = type_at(
904 r#"
905//- /main.rs
906trait Clone {}
907trait Trait { fn foo(self) -> u128; }
908struct S;
909impl<T: Clone> Trait for T {}
910fn test() { (&S).foo()<|>; }
911"#,
912 );
913 assert_eq!(t, "{unknown}");
914}
915
916#[test]
917fn method_resolution_where_clause_1() {
918 let t = type_at(
919 r#"
920//- /main.rs
921trait Clone {}
922trait Trait { fn foo(self) -> u128; }
923struct S;
924impl Clone for S {}
925impl<T> Trait for T where T: Clone {}
926fn test() { S.foo()<|>; }
927"#,
928 );
929 assert_eq!(t, "u128");
930}
931
932#[test]
933fn method_resolution_where_clause_2() {
934 let t = type_at(
935 r#"
936//- /main.rs
937trait Into<T> { fn into(self) -> T; }
938trait From<T> { fn from(other: T) -> Self; }
939struct S1;
940struct S2;
941impl From<S2> for S1 {}
942impl<T, U> Into<U> for T where U: From<T> {}
943fn test() { S2.into()<|>; }
944"#,
945 );
946 assert_eq!(t, "{unknown}");
947}
948
949#[test]
950fn method_resolution_where_clause_inline() {
951 let t = type_at(
952 r#"
953//- /main.rs
954trait Into<T> { fn into(self) -> T; }
955trait From<T> { fn from(other: T) -> Self; }
956struct S1;
957struct S2;
958impl From<S2> for S1 {}
959impl<T, U: From<T>> Into<U> for T {}
960fn test() { S2.into()<|>; }
961"#,
962 );
963 assert_eq!(t, "{unknown}");
964}
965
966#[test]
967fn method_resolution_encountering_fn_type() {
968 type_at(
969 r#"
970//- /main.rs
971fn foo() {}
972trait FnOnce { fn call(self); }
973fn test() { foo.call()<|>; }
974"#,
975 );
976}
977
978#[test]
979fn method_resolution_slow() {
980 // this can get quite slow if we set the solver size limit too high
981 let t = type_at(
982 r#"
983//- /main.rs
984trait SendX {}
985
986struct S1; impl SendX for S1 {}
987struct S2; impl SendX for S2 {}
988struct U1;
989
990trait Trait { fn method(self); }
991
992struct X1<A, B> {}
993impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
994
995struct S<B, C> {}
996
997trait FnX {}
998
999impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
1000
1001fn test() { (S {}).method()<|>; }
1002"#,
1003 );
1004 assert_eq!(t, "()");
1005}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
new file mode 100644
index 000000000..cb3890b42
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -0,0 +1,238 @@
1use super::infer;
2use insta::assert_snapshot;
3use test_utils::covers;
4
5#[test]
6fn infer_pattern() {
7 assert_snapshot!(
8 infer(r#"
9fn test(x: &i32) {
10 let y = x;
11 let &z = x;
12 let a = z;
13 let (c, d) = (1, "hello");
14
15 for (e, f) in some_iter {
16 let g = e;
17 }
18
19 if let [val] = opt {
20 let h = val;
21 }
22
23 let lambda = |a: u64, b, c: i32| { a + b; c };
24
25 let ref ref_to_x = x;
26 let mut mut_x = x;
27 let ref mut mut_ref_to_x = x;
28 let k = mut_ref_to_x;
29}
30"#),
31 @r###"
32 [9; 10) 'x': &i32
33 [18; 369) '{ ...o_x; }': ()
34 [28; 29) 'y': &i32
35 [32; 33) 'x': &i32
36 [43; 45) '&z': &i32
37 [44; 45) 'z': i32
38 [48; 49) 'x': &i32
39 [59; 60) 'a': i32
40 [63; 64) 'z': i32
41 [74; 80) '(c, d)': (i32, &str)
42 [75; 76) 'c': i32
43 [78; 79) 'd': &str
44 [83; 95) '(1, "hello")': (i32, &str)
45 [84; 85) '1': i32
46 [87; 94) '"hello"': &str
47 [102; 152) 'for (e... }': ()
48 [106; 112) '(e, f)': ({unknown}, {unknown})
49 [107; 108) 'e': {unknown}
50 [110; 111) 'f': {unknown}
51 [116; 125) 'some_iter': {unknown}
52 [126; 152) '{ ... }': ()
53 [140; 141) 'g': {unknown}
54 [144; 145) 'e': {unknown}
55 [158; 205) 'if let... }': ()
56 [165; 170) '[val]': {unknown}
57 [173; 176) 'opt': {unknown}
58 [177; 205) '{ ... }': ()
59 [191; 192) 'h': {unknown}
60 [195; 198) 'val': {unknown}
61 [215; 221) 'lambda': |u64, u64, i32| -> i32
62 [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
63 [225; 226) 'a': u64
64 [233; 234) 'b': u64
65 [236; 237) 'c': i32
66 [244; 256) '{ a + b; c }': i32
67 [246; 247) 'a': u64
68 [246; 251) 'a + b': u64
69 [250; 251) 'b': u64
70 [253; 254) 'c': i32
71 [267; 279) 'ref ref_to_x': &&i32
72 [282; 283) 'x': &i32
73 [293; 302) 'mut mut_x': &i32
74 [305; 306) 'x': &i32
75 [316; 336) 'ref mu...f_to_x': &mut &i32
76 [339; 340) 'x': &i32
77 [350; 351) 'k': &mut &i32
78 [354; 366) 'mut_ref_to_x': &mut &i32
79 "###
80 );
81}
82
83#[test]
84fn infer_pattern_match_ergonomics() {
85 assert_snapshot!(
86 infer(r#"
87struct A<T>(T);
88
89fn test() {
90 let A(n) = &A(1);
91 let A(n) = &mut A(1);
92}
93"#),
94 @r###"
95 [28; 79) '{ ...(1); }': ()
96 [38; 42) 'A(n)': A<i32>
97 [40; 41) 'n': &i32
98 [45; 50) '&A(1)': &A<i32>
99 [46; 47) 'A': A<i32>(T) -> A<T>
100 [46; 50) 'A(1)': A<i32>
101 [48; 49) '1': i32
102 [60; 64) 'A(n)': A<i32>
103 [62; 63) 'n': &mut i32
104 [67; 76) '&mut A(1)': &mut A<i32>
105 [72; 73) 'A': A<i32>(T) -> A<T>
106 [72; 76) 'A(1)': A<i32>
107 [74; 75) '1': i32
108 "###
109 );
110}
111
112#[test]
113fn infer_pattern_match_ergonomics_ref() {
114 covers!(match_ergonomics_ref);
115 assert_snapshot!(
116 infer(r#"
117fn test() {
118 let v = &(1, &2);
119 let (_, &w) = v;
120}
121"#),
122 @r###"
123 [11; 57) '{ ...= v; }': ()
124 [21; 22) 'v': &(i32, &i32)
125 [25; 33) '&(1, &2)': &(i32, &i32)
126 [26; 33) '(1, &2)': (i32, &i32)
127 [27; 28) '1': i32
128 [30; 32) '&2': &i32
129 [31; 32) '2': i32
130 [43; 50) '(_, &w)': (i32, &i32)
131 [44; 45) '_': i32
132 [47; 49) '&w': &i32
133 [48; 49) 'w': i32
134 [53; 54) 'v': &(i32, &i32)
135 "###
136 );
137}
138
139#[test]
140fn infer_adt_pattern() {
141 assert_snapshot!(
142 infer(r#"
143enum E {
144 A { x: usize },
145 B
146}
147
148struct S(u32, E);
149
150fn test() {
151 let e = E::A { x: 3 };
152
153 let S(y, z) = foo;
154 let E::A { x: new_var } = e;
155
156 match e {
157 E::A { x } => x,
158 E::B if foo => 1,
159 E::B => 10,
160 };
161
162 let ref d @ E::A { .. } = e;
163 d;
164}
165"#),
166 @r###"
167 [68; 289) '{ ... d; }': ()
168 [78; 79) 'e': E
169 [82; 95) 'E::A { x: 3 }': E
170 [92; 93) '3': usize
171 [106; 113) 'S(y, z)': S
172 [108; 109) 'y': u32
173 [111; 112) 'z': E
174 [116; 119) 'foo': S
175 [129; 148) 'E::A {..._var }': E
176 [139; 146) 'new_var': usize
177 [151; 152) 'e': E
178 [159; 245) 'match ... }': usize
179 [165; 166) 'e': E
180 [177; 187) 'E::A { x }': E
181 [184; 185) 'x': usize
182 [191; 192) 'x': usize
183 [202; 206) 'E::B': E
184 [210; 213) 'foo': bool
185 [217; 218) '1': usize
186 [228; 232) 'E::B': E
187 [236; 238) '10': usize
188 [256; 275) 'ref d ...{ .. }': &E
189 [264; 275) 'E::A { .. }': E
190 [278; 279) 'e': E
191 [285; 286) 'd': &E
192 "###
193 );
194}
195
196#[test]
197fn infer_generics_in_patterns() {
198 assert_snapshot!(
199 infer(r#"
200struct A<T> {
201 x: T,
202}
203
204enum Option<T> {
205 Some(T),
206 None,
207}
208
209fn test(a1: A<u32>, o: Option<u64>) {
210 let A { x: x2 } = a1;
211 let A::<i64> { x: x3 } = A { x: 1 };
212 match o {
213 Option::Some(t) => t,
214 _ => 1,
215 };
216}
217"#),
218 @r###"
219 [79; 81) 'a1': A<u32>
220 [91; 92) 'o': Option<u64>
221 [107; 244) '{ ... }; }': ()
222 [117; 128) 'A { x: x2 }': A<u32>
223 [124; 126) 'x2': u32
224 [131; 133) 'a1': A<u32>
225 [143; 161) 'A::<i6...: x3 }': A<i64>
226 [157; 159) 'x3': i64
227 [164; 174) 'A { x: 1 }': A<i64>
228 [171; 172) '1': i64
229 [180; 241) 'match ... }': u64
230 [186; 187) 'o': Option<u64>
231 [198; 213) 'Option::Some(t)': Option<u64>
232 [211; 212) 't': u64
233 [217; 218) 't': u64
234 [228; 229) '_': Option<u64>
235 [233; 234) '1': u64
236 "###
237 );
238}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
new file mode 100644
index 000000000..09d684ac2
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -0,0 +1,333 @@
1use super::infer;
2use insta::assert_snapshot;
3use test_utils::covers;
4
5#[test]
6fn bug_484() {
7 assert_snapshot!(
8 infer(r#"
9fn test() {
10 let x = if true {};
11}
12"#),
13 @r###"
14 [11; 37) '{ l... {}; }': ()
15 [20; 21) 'x': ()
16 [24; 34) 'if true {}': ()
17 [27; 31) 'true': bool
18 [32; 34) '{}': ()
19 "###
20 );
21}
22
23#[test]
24fn no_panic_on_field_of_enum() {
25 assert_snapshot!(
26 infer(r#"
27enum X {}
28
29fn test(x: X) {
30 x.some_field;
31}
32"#),
33 @r###"
34 [20; 21) 'x': X
35 [26; 47) '{ ...eld; }': ()
36 [32; 33) 'x': X
37 [32; 44) 'x.some_field': {unknown}
38 "###
39 );
40}
41
42#[test]
43fn bug_585() {
44 assert_snapshot!(
45 infer(r#"
46fn test() {
47 X {};
48 match x {
49 A::B {} => (),
50 A::Y() => (),
51 }
52}
53"#),
54 @r###"
55 [11; 89) '{ ... } }': ()
56 [17; 21) 'X {}': {unknown}
57 [27; 87) 'match ... }': ()
58 [33; 34) 'x': {unknown}
59 [45; 52) 'A::B {}': {unknown}
60 [56; 58) '()': ()
61 [68; 74) 'A::Y()': {unknown}
62 [78; 80) '()': ()
63 "###
64 );
65}
66
67#[test]
68fn bug_651() {
69 assert_snapshot!(
70 infer(r#"
71fn quux() {
72 let y = 92;
73 1 + y;
74}
75"#),
76 @r###"
77 [11; 41) '{ ...+ y; }': ()
78 [21; 22) 'y': i32
79 [25; 27) '92': i32
80 [33; 34) '1': i32
81 [33; 38) '1 + y': i32
82 [37; 38) 'y': i32
83 "###
84 );
85}
86
87#[test]
88fn recursive_vars() {
89 covers!(type_var_cycles_resolve_completely);
90 covers!(type_var_cycles_resolve_as_possible);
91 assert_snapshot!(
92 infer(r#"
93fn test() {
94 let y = unknown;
95 [y, &y];
96}
97"#),
98 @r###"
99 [11; 48) '{ ...&y]; }': ()
100 [21; 22) 'y': &{unknown}
101 [25; 32) 'unknown': &{unknown}
102 [38; 45) '[y, &y]': [&&{unknown};_]
103 [39; 40) 'y': &{unknown}
104 [42; 44) '&y': &&{unknown}
105 [43; 44) 'y': &{unknown}
106 "###
107 );
108}
109
110#[test]
111fn recursive_vars_2() {
112 covers!(type_var_cycles_resolve_completely);
113 covers!(type_var_cycles_resolve_as_possible);
114 assert_snapshot!(
115 infer(r#"
116fn test() {
117 let x = unknown;
118 let y = unknown;
119 [(x, y), (&y, &x)];
120}
121"#),
122 @r###"
123 [11; 80) '{ ...x)]; }': ()
124 [21; 22) 'x': &&{unknown}
125 [25; 32) 'unknown': &&{unknown}
126 [42; 43) 'y': &&{unknown}
127 [46; 53) 'unknown': &&{unknown}
128 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_]
129 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown})
130 [61; 62) 'x': &&{unknown}
131 [64; 65) 'y': &&{unknown}
132 [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown})
133 [69; 71) '&y': &&&{unknown}
134 [70; 71) 'y': &&{unknown}
135 [73; 75) '&x': &&&{unknown}
136 [74; 75) 'x': &&{unknown}
137 "###
138 );
139}
140
141#[test]
142fn infer_std_crash_1() {
143 // caused stack overflow, taken from std
144 assert_snapshot!(
145 infer(r#"
146enum Maybe<T> {
147 Real(T),
148 Fake,
149}
150
151fn write() {
152 match something_unknown {
153 Maybe::Real(ref mut something) => (),
154 }
155}
156"#),
157 @r###"
158 [54; 139) '{ ... } }': ()
159 [60; 137) 'match ... }': ()
160 [66; 83) 'someth...nknown': Maybe<{unknown}>
161 [94; 124) 'Maybe:...thing)': Maybe<{unknown}>
162 [106; 123) 'ref mu...ething': &mut {unknown}
163 [128; 130) '()': ()
164 "###
165 );
166}
167
168#[test]
169fn infer_std_crash_2() {
170 covers!(type_var_resolves_to_int_var);
171 // caused "equating two type variables, ...", taken from std
172 assert_snapshot!(
173 infer(r#"
174fn test_line_buffer() {
175 &[0, b'\n', 1, b'\n'];
176}
177"#),
178 @r###"
179 [23; 53) '{ ...n']; }': ()
180 [29; 50) '&[0, b...b'\n']': &[u8;_]
181 [30; 50) '[0, b'...b'\n']': [u8;_]
182 [31; 32) '0': u8
183 [34; 39) 'b'\n'': u8
184 [41; 42) '1': u8
185 [44; 49) 'b'\n'': u8
186 "###
187 );
188}
189
190#[test]
191fn infer_std_crash_3() {
192 // taken from rustc
193 assert_snapshot!(
194 infer(r#"
195pub fn compute() {
196 match nope!() {
197 SizeSkeleton::Pointer { non_zero: true, tail } => {}
198 }
199}
200"#),
201 @r###"
202 [18; 108) '{ ... } }': ()
203 [24; 106) 'match ... }': ()
204 [30; 37) 'nope!()': {unknown}
205 [48; 94) 'SizeSk...tail }': {unknown}
206 [82; 86) 'true': {unknown}
207 [88; 92) 'tail': {unknown}
208 [98; 100) '{}': ()
209 "###
210 );
211}
212
213#[test]
214fn infer_std_crash_4() {
215 // taken from rustc
216 assert_snapshot!(
217 infer(r#"
218pub fn primitive_type() {
219 match *self {
220 BorrowedRef { type_: Primitive(p), ..} => {},
221 }
222}
223"#),
224 @r###"
225 [25; 106) '{ ... } }': ()
226 [31; 104) 'match ... }': ()
227 [37; 42) '*self': {unknown}
228 [38; 42) 'self': {unknown}
229 [53; 91) 'Borrow...), ..}': {unknown}
230 [74; 86) 'Primitive(p)': {unknown}
231 [84; 85) 'p': {unknown}
232 [95; 97) '{}': ()
233 "###
234 );
235}
236
237#[test]
238fn infer_std_crash_5() {
239 // taken from rustc
240 assert_snapshot!(
241 infer(r#"
242fn extra_compiler_flags() {
243 for content in doesnt_matter {
244 let name = if doesnt_matter {
245 first
246 } else {
247 &content
248 };
249
250 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
251 name
252 } else {
253 content
254 };
255 }
256}
257"#),
258 @r###"
259 [27; 323) '{ ... } }': ()
260 [33; 321) 'for co... }': ()
261 [37; 44) 'content': &{unknown}
262 [48; 61) 'doesnt_matter': {unknown}
263 [62; 321) '{ ... }': ()
264 [76; 80) 'name': &&{unknown}
265 [83; 167) 'if doe... }': &&{unknown}
266 [86; 99) 'doesnt_matter': bool
267 [100; 129) '{ ... }': &&{unknown}
268 [114; 119) 'first': &&{unknown}
269 [135; 167) '{ ... }': &&{unknown}
270 [149; 157) '&content': &&{unknown}
271 [150; 157) 'content': &{unknown}
272 [182; 189) 'content': &{unknown}
273 [192; 314) 'if ICE... }': &{unknown}
274 [195; 232) 'ICE_RE..._VALUE': {unknown}
275 [195; 248) 'ICE_RE...&name)': bool
276 [242; 247) '&name': &&&{unknown}
277 [243; 247) 'name': &&{unknown}
278 [249; 277) '{ ... }': &&{unknown}
279 [263; 267) 'name': &&{unknown}
280 [283; 314) '{ ... }': &{unknown}
281 [297; 304) 'content': &{unknown}
282 "###
283 );
284}
285
286#[test]
287fn infer_nested_generics_crash() {
288 // another crash found typechecking rustc
289 assert_snapshot!(
290 infer(r#"
291struct Canonical<V> {
292 value: V,
293}
294struct QueryResponse<V> {
295 value: V,
296}
297fn test<R>(query_response: Canonical<QueryResponse<R>>) {
298 &query_response.value;
299}
300"#),
301 @r###"
302 [92; 106) 'query_response': Canonical<QueryResponse<R>>
303 [137; 167) '{ ...lue; }': ()
304 [143; 164) '&query....value': &QueryResponse<R>
305 [144; 158) 'query_response': Canonical<QueryResponse<R>>
306 [144; 164) 'query_....value': QueryResponse<R>
307 "###
308 );
309}
310
311#[test]
312fn bug_1030() {
313 assert_snapshot!(infer(r#"
314struct HashSet<T, H>;
315struct FxHasher;
316type FxHashSet<T> = HashSet<T, FxHasher>;
317
318impl<T, H> HashSet<T, H> {
319 fn default() -> HashSet<T, H> {}
320}
321
322pub fn main_loop() {
323 FxHashSet::default();
324}
325"#),
326 @r###"
327 [144; 146) '{}': ()
328 [169; 198) '{ ...t(); }': ()
329 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
330 [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>
331 "###
332 );
333}
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
new file mode 100644
index 000000000..3e5e163e3
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -0,0 +1,1663 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn infer_box() {
8 let (db, pos) = TestDB::with_position(
9 r#"
10//- /main.rs crate:main deps:std
11
12fn test() {
13 let x = box 1;
14 let t = (x, box x, box &1, box [1]);
15 t<|>;
16}
17
18//- /std.rs crate:std
19#[prelude_import] use prelude::*;
20mod prelude {}
21
22mod boxed {
23 pub struct Box<T: ?Sized> {
24 inner: *mut T,
25 }
26}
27
28"#,
29 );
30 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
31}
32
33#[test]
34fn infer_adt_self() {
35 let (db, pos) = TestDB::with_position(
36 r#"
37//- /main.rs
38enum Nat { Succ(Self), Demo(Nat), Zero }
39
40fn test() {
41 let foo: Nat = Nat::Zero;
42 if let Nat::Succ(x) = foo {
43 x<|>
44 }
45}
46
47"#,
48 );
49 assert_eq!("Nat", type_at_pos(&db, pos));
50}
51
52#[test]
53fn infer_ranges() {
54 let (db, pos) = TestDB::with_position(
55 r#"
56//- /main.rs crate:main deps:std
57fn test() {
58 let a = ..;
59 let b = 1..;
60 let c = ..2u32;
61 let d = 1..2usize;
62 let e = ..=10;
63 let f = 'a'..='z';
64
65 let t = (a, b, c, d, e, f);
66 t<|>;
67}
68
69//- /std.rs crate:std
70#[prelude_import] use prelude::*;
71mod prelude {}
72
73pub mod ops {
74 pub struct Range<Idx> {
75 pub start: Idx,
76 pub end: Idx,
77 }
78 pub struct RangeFrom<Idx> {
79 pub start: Idx,
80 }
81 struct RangeFull;
82 pub struct RangeInclusive<Idx> {
83 start: Idx,
84 end: Idx,
85 is_empty: u8,
86 }
87 pub struct RangeTo<Idx> {
88 pub end: Idx,
89 }
90 pub struct RangeToInclusive<Idx> {
91 pub end: Idx,
92 }
93}
94"#,
95 );
96 assert_eq!(
97 "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
98 type_at_pos(&db, pos),
99 );
100}
101
102#[test]
103fn infer_while_let() {
104 let (db, pos) = TestDB::with_position(
105 r#"
106//- /main.rs
107enum Option<T> { Some(T), None }
108
109fn test() {
110 let foo: Option<f32> = None;
111 while let Option::Some(x) = foo {
112 <|>x
113 }
114}
115
116"#,
117 );
118 assert_eq!("f32", type_at_pos(&db, pos));
119}
120
121#[test]
122fn infer_basics() {
123 assert_snapshot!(
124 infer(r#"
125fn test(a: u32, b: isize, c: !, d: &str) {
126 a;
127 b;
128 c;
129 d;
130 1usize;
131 1isize;
132 "test";
133 1.0f32;
134}"#),
135 @r###"
136 [9; 10) 'a': u32
137 [17; 18) 'b': isize
138 [27; 28) 'c': !
139 [33; 34) 'd': &str
140 [42; 121) '{ ...f32; }': !
141 [48; 49) 'a': u32
142 [55; 56) 'b': isize
143 [62; 63) 'c': !
144 [69; 70) 'd': &str
145 [76; 82) '1usize': usize
146 [88; 94) '1isize': isize
147 [100; 106) '"test"': &str
148 [112; 118) '1.0f32': f32
149 "###
150 );
151}
152
153#[test]
154fn infer_let() {
155 assert_snapshot!(
156 infer(r#"
157fn test() {
158 let a = 1isize;
159 let b: usize = 1;
160 let c = b;
161 let d: u32;
162 let e;
163 let f: i32 = e;
164}
165"#),
166 @r###"
167 [11; 118) '{ ...= e; }': ()
168 [21; 22) 'a': isize
169 [25; 31) '1isize': isize
170 [41; 42) 'b': usize
171 [52; 53) '1': usize
172 [63; 64) 'c': usize
173 [67; 68) 'b': usize
174 [78; 79) 'd': u32
175 [94; 95) 'e': i32
176 [105; 106) 'f': i32
177 [114; 115) 'e': i32
178 "###
179 );
180}
181
182#[test]
183fn infer_paths() {
184 assert_snapshot!(
185 infer(r#"
186fn a() -> u32 { 1 }
187
188mod b {
189 fn c() -> u32 { 1 }
190}
191
192fn test() {
193 a();
194 b::c();
195}
196"#),
197 @r###"
198 [15; 20) '{ 1 }': u32
199 [17; 18) '1': u32
200 [48; 53) '{ 1 }': u32
201 [50; 51) '1': u32
202 [67; 91) '{ ...c(); }': ()
203 [73; 74) 'a': fn a() -> u32
204 [73; 76) 'a()': u32
205 [82; 86) 'b::c': fn c() -> u32
206 [82; 88) 'b::c()': u32
207 "###
208 );
209}
210
211#[test]
212fn infer_path_type() {
213 assert_snapshot!(
214 infer(r#"
215struct S;
216
217impl S {
218 fn foo() -> i32 { 1 }
219}
220
221fn test() {
222 S::foo();
223 <S>::foo();
224}
225"#),
226 @r###"
227 [41; 46) '{ 1 }': i32
228 [43; 44) '1': i32
229 [60; 93) '{ ...o(); }': ()
230 [66; 72) 'S::foo': fn foo() -> i32
231 [66; 74) 'S::foo()': i32
232 [80; 88) '<S>::foo': fn foo() -> i32
233 [80; 90) '<S>::foo()': i32
234 "###
235 );
236}
237
238#[test]
239fn infer_struct() {
240 assert_snapshot!(
241 infer(r#"
242struct A {
243 b: B,
244 c: C,
245}
246struct B;
247struct C(usize);
248
249fn test() {
250 let c = C(1);
251 B;
252 let a: A = A { b: B, c: C(1) };
253 a.b;
254 a.c;
255}
256"#),
257 @r###"
258 [72; 154) '{ ...a.c; }': ()
259 [82; 83) 'c': C
260 [86; 87) 'C': C(usize) -> C
261 [86; 90) 'C(1)': C
262 [88; 89) '1': usize
263 [96; 97) 'B': B
264 [107; 108) 'a': A
265 [114; 133) 'A { b:...C(1) }': A
266 [121; 122) 'B': B
267 [127; 128) 'C': C(usize) -> C
268 [127; 131) 'C(1)': C
269 [129; 130) '1': usize
270 [139; 140) 'a': A
271 [139; 142) 'a.b': B
272 [148; 149) 'a': A
273 [148; 151) 'a.c': C
274 "###
275 );
276}
277
278#[test]
279fn infer_enum() {
280 assert_snapshot!(
281 infer(r#"
282enum E {
283 V1 { field: u32 },
284 V2
285}
286fn test() {
287 E::V1 { field: 1 };
288 E::V2;
289}"#),
290 @r###"
291 [48; 82) '{ E:...:V2; }': ()
292 [52; 70) 'E::V1 ...d: 1 }': E
293 [67; 68) '1': u32
294 [74; 79) 'E::V2': E
295 "###
296 );
297}
298
299#[test]
300fn infer_refs() {
301 assert_snapshot!(
302 infer(r#"
303fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
304 a;
305 *a;
306 &a;
307 &mut a;
308 b;
309 *b;
310 &b;
311 c;
312 *c;
313 d;
314 *d;
315}
316"#),
317 @r###"
318 [9; 10) 'a': &u32
319 [18; 19) 'b': &mut u32
320 [31; 32) 'c': *const u32
321 [46; 47) 'd': *mut u32
322 [59; 150) '{ ... *d; }': ()
323 [65; 66) 'a': &u32
324 [72; 74) '*a': u32
325 [73; 74) 'a': &u32
326 [80; 82) '&a': &&u32
327 [81; 82) 'a': &u32
328 [88; 94) '&mut a': &mut &u32
329 [93; 94) 'a': &u32
330 [100; 101) 'b': &mut u32
331 [107; 109) '*b': u32
332 [108; 109) 'b': &mut u32
333 [115; 117) '&b': &&mut u32
334 [116; 117) 'b': &mut u32
335 [123; 124) 'c': *const u32
336 [130; 132) '*c': u32
337 [131; 132) 'c': *const u32
338 [138; 139) 'd': *mut u32
339 [145; 147) '*d': u32
340 [146; 147) 'd': *mut u32
341 "###
342 );
343}
344
345#[test]
346fn infer_literals() {
347 assert_snapshot!(
348 infer(r##"
349fn test() {
350 5i32;
351 5f32;
352 5f64;
353 "hello";
354 b"bytes";
355 'c';
356 b'b';
357 3.14;
358 5000;
359 false;
360 true;
361 r#"
362 //! doc
363 // non-doc
364 mod foo {}
365 "#;
366 br#"yolo"#;
367}
368"##),
369 @r###"
370 [11; 221) '{ ...o"#; }': ()
371 [17; 21) '5i32': i32
372 [27; 31) '5f32': f32
373 [37; 41) '5f64': f64
374 [47; 54) '"hello"': &str
375 [60; 68) 'b"bytes"': &[u8]
376 [74; 77) ''c'': char
377 [83; 87) 'b'b'': u8
378 [93; 97) '3.14': f64
379 [103; 107) '5000': i32
380 [113; 118) 'false': bool
381 [124; 128) 'true': bool
382 [134; 202) 'r#" ... "#': &str
383 [208; 218) 'br#"yolo"#': &[u8]
384 "###
385 );
386}
387
388#[test]
389fn infer_unary_op() {
390 assert_snapshot!(
391 infer(r#"
392enum SomeType {}
393
394fn test(x: SomeType) {
395 let b = false;
396 let c = !b;
397 let a = 100;
398 let d: i128 = -a;
399 let e = -100;
400 let f = !!!true;
401 let g = !42;
402 let h = !10u32;
403 let j = !a;
404 -3.14;
405 !3;
406 -x;
407 !x;
408 -"hello";
409 !"hello";
410}
411"#),
412 @r###"
413 [27; 28) 'x': SomeType
414 [40; 272) '{ ...lo"; }': ()
415 [50; 51) 'b': bool
416 [54; 59) 'false': bool
417 [69; 70) 'c': bool
418 [73; 75) '!b': bool
419 [74; 75) 'b': bool
420 [85; 86) 'a': i128
421 [89; 92) '100': i128
422 [102; 103) 'd': i128
423 [112; 114) '-a': i128
424 [113; 114) 'a': i128
425 [124; 125) 'e': i32
426 [128; 132) '-100': i32
427 [129; 132) '100': i32
428 [142; 143) 'f': bool
429 [146; 153) '!!!true': bool
430 [147; 153) '!!true': bool
431 [148; 153) '!true': bool
432 [149; 153) 'true': bool
433 [163; 164) 'g': i32
434 [167; 170) '!42': i32
435 [168; 170) '42': i32
436 [180; 181) 'h': u32
437 [184; 190) '!10u32': u32
438 [185; 190) '10u32': u32
439 [200; 201) 'j': i128
440 [204; 206) '!a': i128
441 [205; 206) 'a': i128
442 [212; 217) '-3.14': f64
443 [213; 217) '3.14': f64
444 [223; 225) '!3': i32
445 [224; 225) '3': i32
446 [231; 233) '-x': {unknown}
447 [232; 233) 'x': SomeType
448 [239; 241) '!x': {unknown}
449 [240; 241) 'x': SomeType
450 [247; 255) '-"hello"': {unknown}
451 [248; 255) '"hello"': &str
452 [261; 269) '!"hello"': {unknown}
453 [262; 269) '"hello"': &str
454 "###
455 );
456}
457
458#[test]
459fn infer_backwards() {
460 assert_snapshot!(
461 infer(r#"
462fn takes_u32(x: u32) {}
463
464struct S { i32_field: i32 }
465
466fn test() -> &mut &f64 {
467 let a = unknown_function();
468 takes_u32(a);
469 let b = unknown_function();
470 S { i32_field: b };
471 let c = unknown_function();
472 &mut &c
473}
474"#),
475 @r###"
476 [14; 15) 'x': u32
477 [22; 24) '{}': ()
478 [78; 231) '{ ...t &c }': &mut &f64
479 [88; 89) 'a': u32
480 [92; 108) 'unknow...nction': {unknown}
481 [92; 110) 'unknow...tion()': u32
482 [116; 125) 'takes_u32': fn takes_u32(u32) -> ()
483 [116; 128) 'takes_u32(a)': ()
484 [126; 127) 'a': u32
485 [138; 139) 'b': i32
486 [142; 158) 'unknow...nction': {unknown}
487 [142; 160) 'unknow...tion()': i32
488 [166; 184) 'S { i3...d: b }': S
489 [181; 182) 'b': i32
490 [194; 195) 'c': f64
491 [198; 214) 'unknow...nction': {unknown}
492 [198; 216) 'unknow...tion()': f64
493 [222; 229) '&mut &c': &mut &f64
494 [227; 229) '&c': &f64
495 [228; 229) 'c': f64
496 "###
497 );
498}
499
500#[test]
501fn infer_self() {
502 assert_snapshot!(
503 infer(r#"
504struct S;
505
506impl S {
507 fn test(&self) {
508 self;
509 }
510 fn test2(self: &Self) {
511 self;
512 }
513 fn test3() -> Self {
514 S {}
515 }
516 fn test4() -> Self {
517 Self {}
518 }
519}
520"#),
521 @r###"
522 [34; 38) 'self': &S
523 [40; 61) '{ ... }': ()
524 [50; 54) 'self': &S
525 [75; 79) 'self': &S
526 [88; 109) '{ ... }': ()
527 [98; 102) 'self': &S
528 [133; 153) '{ ... }': S
529 [143; 147) 'S {}': S
530 [177; 200) '{ ... }': S
531 [187; 194) 'Self {}': S
532 "###
533 );
534}
535
536#[test]
537fn infer_binary_op() {
538 assert_snapshot!(
539 infer(r#"
540fn f(x: bool) -> i32 {
541 0i32
542}
543
544fn test() -> bool {
545 let x = a && b;
546 let y = true || false;
547 let z = x == y;
548 let t = x != y;
549 let minus_forty: isize = -40isize;
550 let h = minus_forty <= CONST_2;
551 let c = f(z || y) + 5;
552 let d = b;
553 let g = minus_forty ^= i;
554 let ten: usize = 10;
555 let ten_is_eleven = ten == some_num;
556
557 ten < 3
558}
559"#),
560 @r###"
561 [6; 7) 'x': bool
562 [22; 34) '{ 0i32 }': i32
563 [28; 32) '0i32': i32
564 [54; 370) '{ ... < 3 }': bool
565 [64; 65) 'x': bool
566 [68; 69) 'a': bool
567 [68; 74) 'a && b': bool
568 [73; 74) 'b': bool
569 [84; 85) 'y': bool
570 [88; 92) 'true': bool
571 [88; 101) 'true || false': bool
572 [96; 101) 'false': bool
573 [111; 112) 'z': bool
574 [115; 116) 'x': bool
575 [115; 121) 'x == y': bool
576 [120; 121) 'y': bool
577 [131; 132) 't': bool
578 [135; 136) 'x': bool
579 [135; 141) 'x != y': bool
580 [140; 141) 'y': bool
581 [151; 162) 'minus_forty': isize
582 [172; 180) '-40isize': isize
583 [173; 180) '40isize': isize
584 [190; 191) 'h': bool
585 [194; 205) 'minus_forty': isize
586 [194; 216) 'minus_...ONST_2': bool
587 [209; 216) 'CONST_2': isize
588 [226; 227) 'c': i32
589 [230; 231) 'f': fn f(bool) -> i32
590 [230; 239) 'f(z || y)': i32
591 [230; 243) 'f(z || y) + 5': i32
592 [232; 233) 'z': bool
593 [232; 238) 'z || y': bool
594 [237; 238) 'y': bool
595 [242; 243) '5': i32
596 [253; 254) 'd': {unknown}
597 [257; 258) 'b': {unknown}
598 [268; 269) 'g': ()
599 [272; 283) 'minus_forty': isize
600 [272; 288) 'minus_...y ^= i': ()
601 [287; 288) 'i': isize
602 [298; 301) 'ten': usize
603 [311; 313) '10': usize
604 [323; 336) 'ten_is_eleven': bool
605 [339; 342) 'ten': usize
606 [339; 354) 'ten == some_num': bool
607 [346; 354) 'some_num': usize
608 [361; 364) 'ten': usize
609 [361; 368) 'ten < 3': bool
610 [367; 368) '3': usize
611 "###
612 );
613}
614
615#[test]
616fn infer_field_autoderef() {
617 assert_snapshot!(
618 infer(r#"
619struct A {
620 b: B,
621}
622struct B;
623
624fn test1(a: A) {
625 let a1 = a;
626 a1.b;
627 let a2 = &a;
628 a2.b;
629 let a3 = &mut a;
630 a3.b;
631 let a4 = &&&&&&&a;
632 a4.b;
633 let a5 = &mut &&mut &&mut a;
634 a5.b;
635}
636
637fn test2(a1: *const A, a2: *mut A) {
638 a1.b;
639 a2.b;
640}
641"#),
642 @r###"
643 [44; 45) 'a': A
644 [50; 213) '{ ...5.b; }': ()
645 [60; 62) 'a1': A
646 [65; 66) 'a': A
647 [72; 74) 'a1': A
648 [72; 76) 'a1.b': B
649 [86; 88) 'a2': &A
650 [91; 93) '&a': &A
651 [92; 93) 'a': A
652 [99; 101) 'a2': &A
653 [99; 103) 'a2.b': B
654 [113; 115) 'a3': &mut A
655 [118; 124) '&mut a': &mut A
656 [123; 124) 'a': A
657 [130; 132) 'a3': &mut A
658 [130; 134) 'a3.b': B
659 [144; 146) 'a4': &&&&&&&A
660 [149; 157) '&&&&&&&a': &&&&&&&A
661 [150; 157) '&&&&&&a': &&&&&&A
662 [151; 157) '&&&&&a': &&&&&A
663 [152; 157) '&&&&a': &&&&A
664 [153; 157) '&&&a': &&&A
665 [154; 157) '&&a': &&A
666 [155; 157) '&a': &A
667 [156; 157) 'a': A
668 [163; 165) 'a4': &&&&&&&A
669 [163; 167) 'a4.b': B
670 [177; 179) 'a5': &mut &&mut &&mut A
671 [182; 200) '&mut &...&mut a': &mut &&mut &&mut A
672 [187; 200) '&&mut &&mut a': &&mut &&mut A
673 [188; 200) '&mut &&mut a': &mut &&mut A
674 [193; 200) '&&mut a': &&mut A
675 [194; 200) '&mut a': &mut A
676 [199; 200) 'a': A
677 [206; 208) 'a5': &mut &&mut &&mut A
678 [206; 210) 'a5.b': B
679 [224; 226) 'a1': *const A
680 [238; 240) 'a2': *mut A
681 [250; 273) '{ ...2.b; }': ()
682 [256; 258) 'a1': *const A
683 [256; 260) 'a1.b': B
684 [266; 268) 'a2': *mut A
685 [266; 270) 'a2.b': B
686 "###
687 );
688}
689
690#[test]
691fn infer_argument_autoderef() {
692 assert_snapshot!(
693 infer(r#"
694#[lang = "deref"]
695pub trait Deref {
696 type Target;
697 fn deref(&self) -> &Self::Target;
698}
699
700struct A<T>(T);
701
702impl<T> A<T> {
703 fn foo(&self) -> &T {
704 &self.0
705 }
706}
707
708struct B<T>(T);
709
710impl<T> Deref for B<T> {
711 type Target = T;
712 fn deref(&self) -> &Self::Target {
713 &self.0
714 }
715}
716
717fn test() {
718 let t = A::foo(&&B(B(A(42))));
719}
720"#),
721 @r###"
722 [68; 72) 'self': &Self
723 [139; 143) 'self': &A<T>
724 [151; 174) '{ ... }': &T
725 [161; 168) '&self.0': &T
726 [162; 166) 'self': &A<T>
727 [162; 168) 'self.0': T
728 [255; 259) 'self': &B<T>
729 [278; 301) '{ ... }': &T
730 [288; 295) '&self.0': &T
731 [289; 293) 'self': &B<T>
732 [289; 295) 'self.0': T
733 [315; 353) '{ ...))); }': ()
734 [325; 326) 't': &i32
735 [329; 335) 'A::foo': fn foo<i32>(&A<T>) -> &T
736 [329; 350) 'A::foo...42))))': &i32
737 [336; 349) '&&B(B(A(42)))': &&B<B<A<i32>>>
738 [337; 349) '&B(B(A(42)))': &B<B<A<i32>>>
739 [338; 339) 'B': B<B<A<i32>>>(T) -> B<T>
740 [338; 349) 'B(B(A(42)))': B<B<A<i32>>>
741 [340; 341) 'B': B<A<i32>>(T) -> B<T>
742 [340; 348) 'B(A(42))': B<A<i32>>
743 [342; 343) 'A': A<i32>(T) -> A<T>
744 [342; 347) 'A(42)': A<i32>
745 [344; 346) '42': i32
746 "###
747 );
748}
749
750#[test]
751fn infer_method_argument_autoderef() {
752 assert_snapshot!(
753 infer(r#"
754#[lang = "deref"]
755pub trait Deref {
756 type Target;
757 fn deref(&self) -> &Self::Target;
758}
759
760struct A<T>(*mut T);
761
762impl<T> A<T> {
763 fn foo(&self, x: &A<T>) -> &T {
764 &*x.0
765 }
766}
767
768struct B<T>(T);
769
770impl<T> Deref for B<T> {
771 type Target = T;
772 fn deref(&self) -> &Self::Target {
773 &self.0
774 }
775}
776
777fn test(a: A<i32>) {
778 let t = A(0 as *mut _).foo(&&B(B(a)));
779}
780"#),
781 @r###"
782 [68; 72) 'self': &Self
783 [144; 148) 'self': &A<T>
784 [150; 151) 'x': &A<T>
785 [166; 187) '{ ... }': &T
786 [176; 181) '&*x.0': &T
787 [177; 181) '*x.0': T
788 [178; 179) 'x': &A<T>
789 [178; 181) 'x.0': *mut T
790 [268; 272) 'self': &B<T>
791 [291; 314) '{ ... }': &T
792 [301; 308) '&self.0': &T
793 [302; 306) 'self': &B<T>
794 [302; 308) 'self.0': T
795 [326; 327) 'a': A<i32>
796 [337; 383) '{ ...))); }': ()
797 [347; 348) 't': &i32
798 [351; 352) 'A': A<i32>(*mut T) -> A<T>
799 [351; 365) 'A(0 as *mut _)': A<i32>
800 [351; 380) 'A(0 as...B(a)))': &i32
801 [353; 354) '0': i32
802 [353; 364) '0 as *mut _': *mut i32
803 [370; 379) '&&B(B(a))': &&B<B<A<i32>>>
804 [371; 379) '&B(B(a))': &B<B<A<i32>>>
805 [372; 373) 'B': B<B<A<i32>>>(T) -> B<T>
806 [372; 379) 'B(B(a))': B<B<A<i32>>>
807 [374; 375) 'B': B<A<i32>>(T) -> B<T>
808 [374; 378) 'B(a)': B<A<i32>>
809 [376; 377) 'a': A<i32>
810 "###
811 );
812}
813
814#[test]
815fn infer_in_elseif() {
816 assert_snapshot!(
817 infer(r#"
818struct Foo { field: i32 }
819fn main(foo: Foo) {
820 if true {
821
822 } else if false {
823 foo.field
824 }
825}
826"#),
827 @r###"
828 [35; 38) 'foo': Foo
829 [45; 109) '{ ... } }': ()
830 [51; 107) 'if tru... }': ()
831 [54; 58) 'true': bool
832 [59; 67) '{ }': ()
833 [73; 107) 'if fal... }': ()
834 [76; 81) 'false': bool
835 [82; 107) '{ ... }': i32
836 [92; 95) 'foo': Foo
837 [92; 101) 'foo.field': i32
838 "###
839 )
840}
841
842#[test]
843fn infer_if_match_with_return() {
844 assert_snapshot!(
845 infer(r#"
846fn foo() {
847 let _x1 = if true {
848 1
849 } else {
850 return;
851 };
852 let _x2 = if true {
853 2
854 } else {
855 return
856 };
857 let _x3 = match true {
858 true => 3,
859 _ => {
860 return;
861 }
862 };
863 let _x4 = match true {
864 true => 4,
865 _ => return
866 };
867}"#),
868 @r###"
869 [10; 323) '{ ... }; }': ()
870 [20; 23) '_x1': i32
871 [26; 80) 'if tru... }': i32
872 [29; 33) 'true': bool
873 [34; 51) '{ ... }': i32
874 [44; 45) '1': i32
875 [57; 80) '{ ... }': !
876 [67; 73) 'return': !
877 [90; 93) '_x2': i32
878 [96; 149) 'if tru... }': i32
879 [99; 103) 'true': bool
880 [104; 121) '{ ... }': i32
881 [114; 115) '2': i32
882 [127; 149) '{ ... }': !
883 [137; 143) 'return': !
884 [159; 162) '_x3': i32
885 [165; 247) 'match ... }': i32
886 [171; 175) 'true': bool
887 [186; 190) 'true': bool
888 [194; 195) '3': i32
889 [205; 206) '_': bool
890 [210; 241) '{ ... }': !
891 [224; 230) 'return': !
892 [257; 260) '_x4': i32
893 [263; 320) 'match ... }': i32
894 [269; 273) 'true': bool
895 [284; 288) 'true': bool
896 [292; 293) '4': i32
897 [303; 304) '_': bool
898 [308; 314) 'return': !
899 "###
900 )
901}
902
903#[test]
904fn infer_inherent_method() {
905 assert_snapshot!(
906 infer(r#"
907struct A;
908
909impl A {
910 fn foo(self, x: u32) -> i32 {}
911}
912
913mod b {
914 impl super::A {
915 fn bar(&self, x: u64) -> i64 {}
916 }
917}
918
919fn test(a: A) {
920 a.foo(1);
921 (&a).bar(1);
922 a.bar(1);
923}
924"#),
925 @r###"
926 [32; 36) 'self': A
927 [38; 39) 'x': u32
928 [53; 55) '{}': ()
929 [103; 107) 'self': &A
930 [109; 110) 'x': u64
931 [124; 126) '{}': ()
932 [144; 145) 'a': A
933 [150; 198) '{ ...(1); }': ()
934 [156; 157) 'a': A
935 [156; 164) 'a.foo(1)': i32
936 [162; 163) '1': u32
937 [170; 181) '(&a).bar(1)': i64
938 [171; 173) '&a': &A
939 [172; 173) 'a': A
940 [179; 180) '1': u64
941 [187; 188) 'a': A
942 [187; 195) 'a.bar(1)': i64
943 [193; 194) '1': u64
944 "###
945 );
946}
947
948#[test]
949fn infer_inherent_method_str() {
950 assert_snapshot!(
951 infer(r#"
952#[lang = "str"]
953impl str {
954 fn foo(&self) -> i32 {}
955}
956
957fn test() {
958 "foo".foo();
959}
960"#),
961 @r###"
962 [40; 44) 'self': &str
963 [53; 55) '{}': ()
964 [69; 89) '{ ...o(); }': ()
965 [75; 80) '"foo"': &str
966 [75; 86) '"foo".foo()': i32
967 "###
968 );
969}
970
971#[test]
972fn infer_tuple() {
973 assert_snapshot!(
974 infer(r#"
975fn test(x: &str, y: isize) {
976 let a: (u32, &str) = (1, "a");
977 let b = (a, x);
978 let c = (y, x);
979 let d = (c, x);
980 let e = (1, "e");
981 let f = (e, "d");
982}
983"#),
984 @r###"
985 [9; 10) 'x': &str
986 [18; 19) 'y': isize
987 [28; 170) '{ ...d"); }': ()
988 [38; 39) 'a': (u32, &str)
989 [55; 63) '(1, "a")': (u32, &str)
990 [56; 57) '1': u32
991 [59; 62) '"a"': &str
992 [73; 74) 'b': ((u32, &str), &str)
993 [77; 83) '(a, x)': ((u32, &str), &str)
994 [78; 79) 'a': (u32, &str)
995 [81; 82) 'x': &str
996 [93; 94) 'c': (isize, &str)
997 [97; 103) '(y, x)': (isize, &str)
998 [98; 99) 'y': isize
999 [101; 102) 'x': &str
1000 [113; 114) 'd': ((isize, &str), &str)
1001 [117; 123) '(c, x)': ((isize, &str), &str)
1002 [118; 119) 'c': (isize, &str)
1003 [121; 122) 'x': &str
1004 [133; 134) 'e': (i32, &str)
1005 [137; 145) '(1, "e")': (i32, &str)
1006 [138; 139) '1': i32
1007 [141; 144) '"e"': &str
1008 [155; 156) 'f': ((i32, &str), &str)
1009 [159; 167) '(e, "d")': ((i32, &str), &str)
1010 [160; 161) 'e': (i32, &str)
1011 [163; 166) '"d"': &str
1012 "###
1013 );
1014}
1015
1016#[test]
1017fn infer_array() {
1018 assert_snapshot!(
1019 infer(r#"
1020fn test(x: &str, y: isize) {
1021 let a = [x];
1022 let b = [a, a];
1023 let c = [b, b];
1024
1025 let d = [y, 1, 2, 3];
1026 let d = [1, y, 2, 3];
1027 let e = [y];
1028 let f = [d, d];
1029 let g = [e, e];
1030
1031 let h = [1, 2];
1032 let i = ["a", "b"];
1033
1034 let b = [a, ["b"]];
1035 let x: [u8; 0] = [];
1036}
1037"#),
1038 @r###"
1039 [9; 10) 'x': &str
1040 [18; 19) 'y': isize
1041 [28; 293) '{ ... []; }': ()
1042 [38; 39) 'a': [&str;_]
1043 [42; 45) '[x]': [&str;_]
1044 [43; 44) 'x': &str
1045 [55; 56) 'b': [[&str;_];_]
1046 [59; 65) '[a, a]': [[&str;_];_]
1047 [60; 61) 'a': [&str;_]
1048 [63; 64) 'a': [&str;_]
1049 [75; 76) 'c': [[[&str;_];_];_]
1050 [79; 85) '[b, b]': [[[&str;_];_];_]
1051 [80; 81) 'b': [[&str;_];_]
1052 [83; 84) 'b': [[&str;_];_]
1053 [96; 97) 'd': [isize;_]
1054 [100; 112) '[y, 1, 2, 3]': [isize;_]
1055 [101; 102) 'y': isize
1056 [104; 105) '1': isize
1057 [107; 108) '2': isize
1058 [110; 111) '3': isize
1059 [122; 123) 'd': [isize;_]
1060 [126; 138) '[1, y, 2, 3]': [isize;_]
1061 [127; 128) '1': isize
1062 [130; 131) 'y': isize
1063 [133; 134) '2': isize
1064 [136; 137) '3': isize
1065 [148; 149) 'e': [isize;_]
1066 [152; 155) '[y]': [isize;_]
1067 [153; 154) 'y': isize
1068 [165; 166) 'f': [[isize;_];_]
1069 [169; 175) '[d, d]': [[isize;_];_]
1070 [170; 171) 'd': [isize;_]
1071 [173; 174) 'd': [isize;_]
1072 [185; 186) 'g': [[isize;_];_]
1073 [189; 195) '[e, e]': [[isize;_];_]
1074 [190; 191) 'e': [isize;_]
1075 [193; 194) 'e': [isize;_]
1076 [206; 207) 'h': [i32;_]
1077 [210; 216) '[1, 2]': [i32;_]
1078 [211; 212) '1': i32
1079 [214; 215) '2': i32
1080 [226; 227) 'i': [&str;_]
1081 [230; 240) '["a", "b"]': [&str;_]
1082 [231; 234) '"a"': &str
1083 [236; 239) '"b"': &str
1084 [251; 252) 'b': [[&str;_];_]
1085 [255; 265) '[a, ["b"]]': [[&str;_];_]
1086 [256; 257) 'a': [&str;_]
1087 [259; 264) '["b"]': [&str;_]
1088 [260; 263) '"b"': &str
1089 [275; 276) 'x': [u8;_]
1090 [288; 290) '[]': [u8;_]
1091 "###
1092 );
1093}
1094
1095#[test]
1096fn infer_struct_generics() {
1097 assert_snapshot!(
1098 infer(r#"
1099struct A<T> {
1100 x: T,
1101}
1102
1103fn test(a1: A<u32>, i: i32) {
1104 a1.x;
1105 let a2 = A { x: i };
1106 a2.x;
1107 let a3 = A::<i128> { x: 1 };
1108 a3.x;
1109}
1110"#),
1111 @r###"
1112 [36; 38) 'a1': A<u32>
1113 [48; 49) 'i': i32
1114 [56; 147) '{ ...3.x; }': ()
1115 [62; 64) 'a1': A<u32>
1116 [62; 66) 'a1.x': u32
1117 [76; 78) 'a2': A<i32>
1118 [81; 91) 'A { x: i }': A<i32>
1119 [88; 89) 'i': i32
1120 [97; 99) 'a2': A<i32>
1121 [97; 101) 'a2.x': i32
1122 [111; 113) 'a3': A<i128>
1123 [116; 134) 'A::<i1...x: 1 }': A<i128>
1124 [131; 132) '1': i128
1125 [140; 142) 'a3': A<i128>
1126 [140; 144) 'a3.x': i128
1127 "###
1128 );
1129}
1130
1131#[test]
1132fn infer_tuple_struct_generics() {
1133 assert_snapshot!(
1134 infer(r#"
1135struct A<T>(T);
1136enum Option<T> { Some(T), None }
1137use Option::*;
1138
1139fn test() {
1140 A(42);
1141 A(42u128);
1142 Some("x");
1143 Option::Some("x");
1144 None;
1145 let x: Option<i64> = None;
1146}
1147"#),
1148 @r###"
1149 [76; 184) '{ ...one; }': ()
1150 [82; 83) 'A': A<i32>(T) -> A<T>
1151 [82; 87) 'A(42)': A<i32>
1152 [84; 86) '42': i32
1153 [93; 94) 'A': A<u128>(T) -> A<T>
1154 [93; 102) 'A(42u128)': A<u128>
1155 [95; 101) '42u128': u128
1156 [108; 112) 'Some': Some<&str>(T) -> Option<T>
1157 [108; 117) 'Some("x")': Option<&str>
1158 [113; 116) '"x"': &str
1159 [123; 135) 'Option::Some': Some<&str>(T) -> Option<T>
1160 [123; 140) 'Option...e("x")': Option<&str>
1161 [136; 139) '"x"': &str
1162 [146; 150) 'None': Option<{unknown}>
1163 [160; 161) 'x': Option<i64>
1164 [177; 181) 'None': Option<i64>
1165 "###
1166 );
1167}
1168
1169#[test]
1170fn infer_function_generics() {
1171 assert_snapshot!(
1172 infer(r#"
1173fn id<T>(t: T) -> T { t }
1174
1175fn test() {
1176 id(1u32);
1177 id::<i128>(1);
1178 let x: u64 = id(1);
1179}
1180"#),
1181 @r###"
1182 [10; 11) 't': T
1183 [21; 26) '{ t }': T
1184 [23; 24) 't': T
1185 [38; 98) '{ ...(1); }': ()
1186 [44; 46) 'id': fn id<u32>(T) -> T
1187 [44; 52) 'id(1u32)': u32
1188 [47; 51) '1u32': u32
1189 [58; 68) 'id::<i128>': fn id<i128>(T) -> T
1190 [58; 71) 'id::<i128>(1)': i128
1191 [69; 70) '1': i128
1192 [81; 82) 'x': u64
1193 [90; 92) 'id': fn id<u64>(T) -> T
1194 [90; 95) 'id(1)': u64
1195 [93; 94) '1': u64
1196 "###
1197 );
1198}
1199
1200#[test]
1201fn infer_impl_generics() {
1202 assert_snapshot!(
1203 infer(r#"
1204struct A<T1, T2> {
1205 x: T1,
1206 y: T2,
1207}
1208impl<Y, X> A<X, Y> {
1209 fn x(self) -> X {
1210 self.x
1211 }
1212 fn y(self) -> Y {
1213 self.y
1214 }
1215 fn z<T>(self, t: T) -> (X, Y, T) {
1216 (self.x, self.y, t)
1217 }
1218}
1219
1220fn test() -> i128 {
1221 let a = A { x: 1u64, y: 1i64 };
1222 a.x();
1223 a.y();
1224 a.z(1i128);
1225 a.z::<u128>(1);
1226}
1227"#),
1228 @r###"
1229 [74; 78) 'self': A<X, Y>
1230 [85; 107) '{ ... }': X
1231 [95; 99) 'self': A<X, Y>
1232 [95; 101) 'self.x': X
1233 [117; 121) 'self': A<X, Y>
1234 [128; 150) '{ ... }': Y
1235 [138; 142) 'self': A<X, Y>
1236 [138; 144) 'self.y': Y
1237 [163; 167) 'self': A<X, Y>
1238 [169; 170) 't': T
1239 [188; 223) '{ ... }': (X, Y, T)
1240 [198; 217) '(self.....y, t)': (X, Y, T)
1241 [199; 203) 'self': A<X, Y>
1242 [199; 205) 'self.x': X
1243 [207; 211) 'self': A<X, Y>
1244 [207; 213) 'self.y': Y
1245 [215; 216) 't': T
1246 [245; 342) '{ ...(1); }': ()
1247 [255; 256) 'a': A<u64, i64>
1248 [259; 281) 'A { x:...1i64 }': A<u64, i64>
1249 [266; 270) '1u64': u64
1250 [275; 279) '1i64': i64
1251 [287; 288) 'a': A<u64, i64>
1252 [287; 292) 'a.x()': u64
1253 [298; 299) 'a': A<u64, i64>
1254 [298; 303) 'a.y()': i64
1255 [309; 310) 'a': A<u64, i64>
1256 [309; 319) 'a.z(1i128)': (u64, i64, i128)
1257 [313; 318) '1i128': i128
1258 [325; 326) 'a': A<u64, i64>
1259 [325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
1260 [337; 338) '1': u128
1261 "###
1262 );
1263}
1264
1265#[test]
1266fn infer_impl_generics_with_autoderef() {
1267 assert_snapshot!(
1268 infer(r#"
1269enum Option<T> {
1270 Some(T),
1271 None,
1272}
1273impl<T> Option<T> {
1274 fn as_ref(&self) -> Option<&T> {}
1275}
1276fn test(o: Option<u32>) {
1277 (&o).as_ref();
1278 o.as_ref();
1279}
1280"#),
1281 @r###"
1282 [78; 82) 'self': &Option<T>
1283 [98; 100) '{}': ()
1284 [111; 112) 'o': Option<u32>
1285 [127; 165) '{ ...f(); }': ()
1286 [133; 146) '(&o).as_ref()': Option<&u32>
1287 [134; 136) '&o': &Option<u32>
1288 [135; 136) 'o': Option<u32>
1289 [152; 153) 'o': Option<u32>
1290 [152; 162) 'o.as_ref()': Option<&u32>
1291 "###
1292 );
1293}
1294
1295#[test]
1296fn infer_generic_chain() {
1297 assert_snapshot!(
1298 infer(r#"
1299struct A<T> {
1300 x: T,
1301}
1302impl<T2> A<T2> {
1303 fn x(self) -> T2 {
1304 self.x
1305 }
1306}
1307fn id<T>(t: T) -> T { t }
1308
1309fn test() -> i128 {
1310 let x = 1;
1311 let y = id(x);
1312 let a = A { x: id(y) };
1313 let z = id(a.x);
1314 let b = A { x: z };
1315 b.x()
1316}
1317"#),
1318 @r###"
1319 [53; 57) 'self': A<T2>
1320 [65; 87) '{ ... }': T2
1321 [75; 79) 'self': A<T2>
1322 [75; 81) 'self.x': T2
1323 [99; 100) 't': T
1324 [110; 115) '{ t }': T
1325 [112; 113) 't': T
1326 [135; 261) '{ ....x() }': i128
1327 [146; 147) 'x': i128
1328 [150; 151) '1': i128
1329 [162; 163) 'y': i128
1330 [166; 168) 'id': fn id<i128>(T) -> T
1331 [166; 171) 'id(x)': i128
1332 [169; 170) 'x': i128
1333 [182; 183) 'a': A<i128>
1334 [186; 200) 'A { x: id(y) }': A<i128>
1335 [193; 195) 'id': fn id<i128>(T) -> T
1336 [193; 198) 'id(y)': i128
1337 [196; 197) 'y': i128
1338 [211; 212) 'z': i128
1339 [215; 217) 'id': fn id<i128>(T) -> T
1340 [215; 222) 'id(a.x)': i128
1341 [218; 219) 'a': A<i128>
1342 [218; 221) 'a.x': i128
1343 [233; 234) 'b': A<i128>
1344 [237; 247) 'A { x: z }': A<i128>
1345 [244; 245) 'z': i128
1346 [254; 255) 'b': A<i128>
1347 [254; 259) 'b.x()': i128
1348 "###
1349 );
1350}
1351
1352#[test]
1353fn infer_associated_const() {
1354 assert_snapshot!(
1355 infer(r#"
1356struct Struct;
1357
1358impl Struct {
1359 const FOO: u32 = 1;
1360}
1361
1362enum Enum {}
1363
1364impl Enum {
1365 const BAR: u32 = 2;
1366}
1367
1368trait Trait {
1369 const ID: u32;
1370}
1371
1372struct TraitTest;
1373
1374impl Trait for TraitTest {
1375 const ID: u32 = 5;
1376}
1377
1378fn test() {
1379 let x = Struct::FOO;
1380 let y = Enum::BAR;
1381 let z = TraitTest::ID;
1382}
1383"#),
1384 @r###"
1385 [52; 53) '1': u32
1386 [105; 106) '2': u32
1387 [213; 214) '5': u32
1388 [229; 307) '{ ...:ID; }': ()
1389 [239; 240) 'x': u32
1390 [243; 254) 'Struct::FOO': u32
1391 [264; 265) 'y': u32
1392 [268; 277) 'Enum::BAR': u32
1393 [287; 288) 'z': u32
1394 [291; 304) 'TraitTest::ID': u32
1395 "###
1396 );
1397}
1398
1399#[test]
1400fn infer_type_alias() {
1401 assert_snapshot!(
1402 infer(r#"
1403struct A<X, Y> { x: X, y: Y }
1404type Foo = A<u32, i128>;
1405type Bar<T> = A<T, u128>;
1406type Baz<U, V> = A<V, U>;
1407fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
1408 x.x;
1409 x.y;
1410 y.x;
1411 y.y;
1412 z.x;
1413 z.y;
1414}
1415"#),
1416 @r###"
1417 [116; 117) 'x': A<u32, i128>
1418 [124; 125) 'y': A<&str, u128>
1419 [138; 139) 'z': A<u8, i8>
1420 [154; 211) '{ ...z.y; }': ()
1421 [160; 161) 'x': A<u32, i128>
1422 [160; 163) 'x.x': u32
1423 [169; 170) 'x': A<u32, i128>
1424 [169; 172) 'x.y': i128
1425 [178; 179) 'y': A<&str, u128>
1426 [178; 181) 'y.x': &str
1427 [187; 188) 'y': A<&str, u128>
1428 [187; 190) 'y.y': u128
1429 [196; 197) 'z': A<u8, i8>
1430 [196; 199) 'z.x': u8
1431 [205; 206) 'z': A<u8, i8>
1432 [205; 208) 'z.y': i8
1433 "###
1434 )
1435}
1436
1437#[test]
1438fn recursive_type_alias() {
1439 assert_snapshot!(
1440 infer(r#"
1441struct A<X> {}
1442type Foo = Foo;
1443type Bar = A<Bar>;
1444fn test(x: Foo) {}
1445"#),
1446 @r###"
1447 [59; 60) 'x': {unknown}
1448 [67; 69) '{}': ()
1449 "###
1450 )
1451}
1452
1453#[test]
1454fn infer_type_param() {
1455 assert_snapshot!(
1456 infer(r#"
1457fn id<T>(x: T) -> T {
1458 x
1459}
1460
1461fn clone<T>(x: &T) -> T {
1462 *x
1463}
1464
1465fn test() {
1466 let y = 10u32;
1467 id(y);
1468 let x: bool = clone(z);
1469 id::<i128>(1);
1470}
1471"#),
1472 @r###"
1473 [10; 11) 'x': T
1474 [21; 30) '{ x }': T
1475 [27; 28) 'x': T
1476 [44; 45) 'x': &T
1477 [56; 66) '{ *x }': T
1478 [62; 64) '*x': T
1479 [63; 64) 'x': &T
1480 [78; 158) '{ ...(1); }': ()
1481 [88; 89) 'y': u32
1482 [92; 97) '10u32': u32
1483 [103; 105) 'id': fn id<u32>(T) -> T
1484 [103; 108) 'id(y)': u32
1485 [106; 107) 'y': u32
1486 [118; 119) 'x': bool
1487 [128; 133) 'clone': fn clone<bool>(&T) -> T
1488 [128; 136) 'clone(z)': bool
1489 [134; 135) 'z': &bool
1490 [142; 152) 'id::<i128>': fn id<i128>(T) -> T
1491 [142; 155) 'id::<i128>(1)': i128
1492 [153; 154) '1': i128
1493 "###
1494 );
1495}
1496
1497#[test]
1498fn infer_const() {
1499 assert_snapshot!(
1500 infer(r#"
1501struct Foo;
1502impl Foo { const ASSOC_CONST: u32 = 0; }
1503const GLOBAL_CONST: u32 = 101;
1504fn test() {
1505 const LOCAL_CONST: u32 = 99;
1506 let x = LOCAL_CONST;
1507 let z = GLOBAL_CONST;
1508 let id = Foo::ASSOC_CONST;
1509}
1510"#),
1511 @r###"
1512 [49; 50) '0': u32
1513 [80; 83) '101': u32
1514 [95; 213) '{ ...NST; }': ()
1515 [138; 139) 'x': u32
1516 [142; 153) 'LOCAL_CONST': u32
1517 [163; 164) 'z': u32
1518 [167; 179) 'GLOBAL_CONST': u32
1519 [189; 191) 'id': u32
1520 [194; 210) 'Foo::A..._CONST': u32
1521 "###
1522 );
1523}
1524
1525#[test]
1526fn infer_static() {
1527 assert_snapshot!(
1528 infer(r#"
1529static GLOBAL_STATIC: u32 = 101;
1530static mut GLOBAL_STATIC_MUT: u32 = 101;
1531fn test() {
1532 static LOCAL_STATIC: u32 = 99;
1533 static mut LOCAL_STATIC_MUT: u32 = 99;
1534 let x = LOCAL_STATIC;
1535 let y = LOCAL_STATIC_MUT;
1536 let z = GLOBAL_STATIC;
1537 let w = GLOBAL_STATIC_MUT;
1538}
1539"#),
1540 @r###"
1541 [29; 32) '101': u32
1542 [70; 73) '101': u32
1543 [85; 280) '{ ...MUT; }': ()
1544 [173; 174) 'x': u32
1545 [177; 189) 'LOCAL_STATIC': u32
1546 [199; 200) 'y': u32
1547 [203; 219) 'LOCAL_...IC_MUT': u32
1548 [229; 230) 'z': u32
1549 [233; 246) 'GLOBAL_STATIC': u32
1550 [256; 257) 'w': u32
1551 [260; 277) 'GLOBAL...IC_MUT': u32
1552 "###
1553 );
1554}
1555
1556#[test]
1557fn shadowing_primitive() {
1558 let t = type_at(
1559 r#"
1560//- /main.rs
1561struct i32;
1562struct Foo;
1563
1564impl i32 { fn foo(&self) -> Foo { Foo } }
1565
1566fn main() {
1567 let x: i32 = i32;
1568 x.foo()<|>;
1569}"#,
1570 );
1571 assert_eq!(t, "Foo");
1572}
1573
1574#[test]
1575fn not_shadowing_primitive_by_module() {
1576 let t = type_at(
1577 r#"
1578//- /str.rs
1579fn foo() {}
1580
1581//- /main.rs
1582mod str;
1583fn foo() -> &'static str { "" }
1584
1585fn main() {
1586 foo()<|>;
1587}"#,
1588 );
1589 assert_eq!(t, "&str");
1590}
1591
1592#[test]
1593fn not_shadowing_module_by_primitive() {
1594 let t = type_at(
1595 r#"
1596//- /str.rs
1597fn foo() -> u32 {0}
1598
1599//- /main.rs
1600mod str;
1601fn foo() -> &'static str { "" }
1602
1603fn main() {
1604 str::foo()<|>;
1605}"#,
1606 );
1607 assert_eq!(t, "u32");
1608}
1609
1610#[test]
1611fn closure_return() {
1612 assert_snapshot!(
1613 infer(r#"
1614fn foo() -> u32 {
1615 let x = || -> usize { return 1; };
1616}
1617"#),
1618 @r###"
1619 [17; 59) '{ ...; }; }': ()
1620 [27; 28) 'x': || -> usize
1621 [31; 56) '|| -> ...n 1; }': || -> usize
1622 [43; 56) '{ return 1; }': !
1623 [45; 53) 'return 1': !
1624 [52; 53) '1': usize
1625 "###
1626 );
1627}
1628
1629#[test]
1630fn closure_return_unit() {
1631 assert_snapshot!(
1632 infer(r#"
1633fn foo() -> u32 {
1634 let x = || { return; };
1635}
1636"#),
1637 @r###"
1638 [17; 48) '{ ...; }; }': ()
1639 [27; 28) 'x': || -> ()
1640 [31; 45) '|| { return; }': || -> ()
1641 [34; 45) '{ return; }': !
1642 [36; 42) 'return': !
1643 "###
1644 );
1645}
1646
1647#[test]
1648fn closure_return_inferred() {
1649 assert_snapshot!(
1650 infer(r#"
1651fn foo() -> u32 {
1652 let x = || { "test" };
1653}
1654"#),
1655 @r###"
1656 [17; 47) '{ ..." }; }': ()
1657 [27; 28) 'x': || -> &str
1658 [31; 44) '|| { "test" }': || -> &str
1659 [34; 44) '{ "test" }': &str
1660 [36; 42) '"test"': &str
1661 "###
1662 );
1663}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
new file mode 100644
index 000000000..ae316922b
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -0,0 +1,1598 @@
1use insta::assert_snapshot;
2
3use ra_db::fixture::WithFixture;
4use test_utils::covers;
5
6use super::{infer, infer_with_mismatches, type_at, type_at_pos};
7use crate::test_db::TestDB;
8
9#[test]
10fn infer_await() {
11 let (db, pos) = TestDB::with_position(
12 r#"
13//- /main.rs crate:main deps:std
14
15struct IntFuture;
16
17impl Future for IntFuture {
18 type Output = u64;
19}
20
21fn test() {
22 let r = IntFuture;
23 let v = r.await;
24 v<|>;
25}
26
27//- /std.rs crate:std
28#[prelude_import] use future::*;
29mod future {
30 trait Future {
31 type Output;
32 }
33}
34
35"#,
36 );
37 assert_eq!("u64", type_at_pos(&db, pos));
38}
39
40#[test]
41fn infer_try() {
42 let (db, pos) = TestDB::with_position(
43 r#"
44//- /main.rs crate:main deps:std
45
46fn test() {
47 let r: Result<i32, u64> = Result::Ok(1);
48 let v = r?;
49 v<|>;
50}
51
52//- /std.rs crate:std
53
54#[prelude_import] use ops::*;
55mod ops {
56 trait Try {
57 type Ok;
58 type Error;
59 }
60}
61
62#[prelude_import] use result::*;
63mod result {
64 enum Result<O, E> {
65 Ok(O),
66 Err(E)
67 }
68
69 impl<O, E> crate::ops::Try for Result<O, E> {
70 type Ok = O;
71 type Error = E;
72 }
73}
74
75"#,
76 );
77 assert_eq!("i32", type_at_pos(&db, pos));
78}
79
80#[test]
81fn infer_for_loop() {
82 let (db, pos) = TestDB::with_position(
83 r#"
84//- /main.rs crate:main deps:std
85
86use std::collections::Vec;
87
88fn test() {
89 let v = Vec::new();
90 v.push("foo");
91 for x in v {
92 x<|>;
93 }
94}
95
96//- /std.rs crate:std
97
98#[prelude_import] use iter::*;
99mod iter {
100 trait IntoIterator {
101 type Item;
102 }
103}
104
105mod collections {
106 struct Vec<T> {}
107 impl<T> Vec<T> {
108 fn new() -> Self { Vec {} }
109 fn push(&mut self, t: T) { }
110 }
111
112 impl<T> crate::iter::IntoIterator for Vec<T> {
113 type Item=T;
114 }
115}
116"#,
117 );
118 assert_eq!("&str", type_at_pos(&db, pos));
119}
120
121#[test]
122fn infer_ops_neg() {
123 let (db, pos) = TestDB::with_position(
124 r#"
125//- /main.rs crate:main deps:std
126
127struct Bar;
128struct Foo;
129
130impl std::ops::Neg for Bar {
131 type Output = Foo;
132}
133
134fn test() {
135 let a = Bar;
136 let b = -a;
137 b<|>;
138}
139
140//- /std.rs crate:std
141
142#[prelude_import] use ops::*;
143mod ops {
144 pub trait Neg {
145 type Output;
146 }
147}
148"#,
149 );
150 assert_eq!("Foo", type_at_pos(&db, pos));
151}
152
153#[test]
154fn infer_ops_not() {
155 let (db, pos) = TestDB::with_position(
156 r#"
157//- /main.rs crate:main deps:std
158
159struct Bar;
160struct Foo;
161
162impl std::ops::Not for Bar {
163 type Output = Foo;
164}
165
166fn test() {
167 let a = Bar;
168 let b = !a;
169 b<|>;
170}
171
172//- /std.rs crate:std
173
174#[prelude_import] use ops::*;
175mod ops {
176 pub trait Not {
177 type Output;
178 }
179}
180"#,
181 );
182 assert_eq!("Foo", type_at_pos(&db, pos));
183}
184
185#[test]
186fn infer_from_bound_1() {
187 assert_snapshot!(
188 infer(r#"
189trait Trait<T> {}
190struct S<T>(T);
191impl<U> Trait<U> for S<U> {}
192fn foo<T: Trait<u32>>(t: T) {}
193fn test() {
194 let s = S(unknown);
195 foo(s);
196}
197"#),
198 @r###"
199 [86; 87) 't': T
200 [92; 94) '{}': ()
201 [105; 144) '{ ...(s); }': ()
202 [115; 116) 's': S<u32>
203 [119; 120) 'S': S<u32>(T) -> S<T>
204 [119; 129) 'S(unknown)': S<u32>
205 [121; 128) 'unknown': u32
206 [135; 138) 'foo': fn foo<S<u32>>(T) -> ()
207 [135; 141) 'foo(s)': ()
208 [139; 140) 's': S<u32>
209 "###
210 );
211}
212
213#[test]
214fn infer_from_bound_2() {
215 assert_snapshot!(
216 infer(r#"
217trait Trait<T> {}
218struct S<T>(T);
219impl<U> Trait<U> for S<U> {}
220fn foo<U, T: Trait<U>>(t: T) -> U {}
221fn test() {
222 let s = S(unknown);
223 let x: u32 = foo(s);
224}
225"#),
226 @r###"
227 [87; 88) 't': T
228 [98; 100) '{}': ()
229 [111; 163) '{ ...(s); }': ()
230 [121; 122) 's': S<u32>
231 [125; 126) 'S': S<u32>(T) -> S<T>
232 [125; 135) 'S(unknown)': S<u32>
233 [127; 134) 'unknown': u32
234 [145; 146) 'x': u32
235 [154; 157) 'foo': fn foo<u32, S<u32>>(T) -> U
236 [154; 160) 'foo(s)': u32
237 [158; 159) 's': S<u32>
238 "###
239 );
240}
241
242#[test]
243fn infer_project_associated_type() {
244 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
245 assert_snapshot!(
246 infer(r#"
247trait Iterable {
248 type Item;
249}
250struct S;
251impl Iterable for S { type Item = u32; }
252fn test<T: Iterable>() {
253 let x: <S as Iterable>::Item = 1;
254 let y: <T as Iterable>::Item = no_matter;
255 let z: T::Item = no_matter;
256 let a: <T>::Item = no_matter;
257}
258"#),
259 @r###"
260 [108; 261) '{ ...ter; }': ()
261 [118; 119) 'x': u32
262 [145; 146) '1': u32
263 [156; 157) 'y': {unknown}
264 [183; 192) 'no_matter': {unknown}
265 [202; 203) 'z': {unknown}
266 [215; 224) 'no_matter': {unknown}
267 [234; 235) 'a': {unknown}
268 [249; 258) 'no_matter': {unknown}
269 "###
270 );
271}
272
273#[test]
274fn infer_return_associated_type() {
275 assert_snapshot!(
276 infer(r#"
277trait Iterable {
278 type Item;
279}
280struct S;
281impl Iterable for S { type Item = u32; }
282fn foo1<T: Iterable>(t: T) -> T::Item {}
283fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
284fn foo3<T: Iterable>(t: T) -> <T>::Item {}
285fn test() {
286 let x = foo1(S);
287 let y = foo2(S);
288 let z = foo3(S);
289}
290"#),
291 @r###"
292 [106; 107) 't': T
293 [123; 125) '{}': ()
294 [147; 148) 't': T
295 [178; 180) '{}': ()
296 [202; 203) 't': T
297 [221; 223) '{}': ()
298 [234; 300) '{ ...(S); }': ()
299 [244; 245) 'x': u32
300 [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item
301 [248; 255) 'foo1(S)': u32
302 [253; 254) 'S': S
303 [265; 266) 'y': u32
304 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
305 [269; 276) 'foo2(S)': u32
306 [274; 275) 'S': S
307 [286; 287) 'z': u32
308 [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item
309 [290; 297) 'foo3(S)': u32
310 [295; 296) 'S': S
311 "###
312 );
313}
314
315#[test]
316fn infer_associated_type_bound() {
317 assert_snapshot!(
318 infer(r#"
319trait Iterable {
320 type Item;
321}
322fn test<T: Iterable<Item=u32>>() {
323 let y: T::Item = unknown;
324}
325"#),
326 @r###"
327 [67; 100) '{ ...own; }': ()
328 [77; 78) 'y': {unknown}
329 [90; 97) 'unknown': {unknown}
330 "###
331 );
332}
333
334#[test]
335fn infer_const_body() {
336 assert_snapshot!(
337 infer(r#"
338const A: u32 = 1 + 1;
339static B: u64 = { let x = 1; x };
340"#),
341 @r###"
342 [16; 17) '1': u32
343 [16; 21) '1 + 1': u32
344 [20; 21) '1': u32
345 [39; 55) '{ let ...1; x }': u64
346 [45; 46) 'x': u64
347 [49; 50) '1': u64
348 [52; 53) 'x': u64
349 "###
350 );
351}
352
353#[test]
354fn tuple_struct_fields() {
355 assert_snapshot!(
356 infer(r#"
357struct S(i32, u64);
358fn test() -> u64 {
359 let a = S(4, 6);
360 let b = a.0;
361 a.1
362}
363"#),
364 @r###"
365 [38; 87) '{ ... a.1 }': u64
366 [48; 49) 'a': S
367 [52; 53) 'S': S(i32, u64) -> S
368 [52; 59) 'S(4, 6)': S
369 [54; 55) '4': i32
370 [57; 58) '6': u64
371 [69; 70) 'b': i32
372 [73; 74) 'a': S
373 [73; 76) 'a.0': i32
374 [82; 83) 'a': S
375 [82; 85) 'a.1': u64
376 "###
377 );
378}
379
380#[test]
381fn tuple_struct_with_fn() {
382 assert_snapshot!(
383 infer(r#"
384struct S(fn(u32) -> u64);
385fn test() -> u64 {
386 let a = S(|i| 2*i);
387 let b = a.0(4);
388 a.0(2)
389}
390"#),
391 @r###"
392 [44; 102) '{ ...0(2) }': u64
393 [54; 55) 'a': S
394 [58; 59) 'S': S(fn(u32) -> u64) -> S
395 [58; 68) 'S(|i| 2*i)': S
396 [60; 67) '|i| 2*i': |u32| -> u64
397 [61; 62) 'i': u32
398 [64; 65) '2': u32
399 [64; 67) '2*i': u32
400 [66; 67) 'i': u32
401 [78; 79) 'b': u64
402 [82; 83) 'a': S
403 [82; 85) 'a.0': fn(u32) -> u64
404 [82; 88) 'a.0(4)': u64
405 [86; 87) '4': u32
406 [94; 95) 'a': S
407 [94; 97) 'a.0': fn(u32) -> u64
408 [94; 100) 'a.0(2)': u64
409 [98; 99) '2': u32
410 "###
411 );
412}
413
414#[test]
415fn indexing_arrays() {
416 assert_snapshot!(
417 infer("fn main() { &mut [9][2]; }"),
418 @r###"
419 [10; 26) '{ &mut...[2]; }': ()
420 [12; 23) '&mut [9][2]': &mut {unknown}
421 [17; 20) '[9]': [i32;_]
422 [17; 23) '[9][2]': {unknown}
423 [18; 19) '9': i32
424 [21; 22) '2': i32
425 "###
426 )
427}
428
429#[test]
430fn infer_ops_index() {
431 let (db, pos) = TestDB::with_position(
432 r#"
433//- /main.rs crate:main deps:std
434
435struct Bar;
436struct Foo;
437
438impl std::ops::Index<u32> for Bar {
439 type Output = Foo;
440}
441
442fn test() {
443 let a = Bar;
444 let b = a[1];
445 b<|>;
446}
447
448//- /std.rs crate:std
449
450#[prelude_import] use ops::*;
451mod ops {
452 pub trait Index<Idx> {
453 type Output;
454 }
455}
456"#,
457 );
458 assert_eq!("Foo", type_at_pos(&db, pos));
459}
460
461#[test]
462fn deref_trait() {
463 let t = type_at(
464 r#"
465//- /main.rs
466#[lang = "deref"]
467trait Deref {
468 type Target;
469 fn deref(&self) -> &Self::Target;
470}
471
472struct Arc<T>;
473impl<T> Deref for Arc<T> {
474 type Target = T;
475}
476
477struct S;
478impl S {
479 fn foo(&self) -> u128 {}
480}
481
482fn test(s: Arc<S>) {
483 (*s, s.foo())<|>;
484}
485"#,
486 );
487 assert_eq!(t, "(S, u128)");
488}
489
490#[test]
491fn deref_trait_with_inference_var() {
492 let t = type_at(
493 r#"
494//- /main.rs
495#[lang = "deref"]
496trait Deref {
497 type Target;
498 fn deref(&self) -> &Self::Target;
499}
500
501struct Arc<T>;
502fn new_arc<T>() -> Arc<T> {}
503impl<T> Deref for Arc<T> {
504 type Target = T;
505}
506
507struct S;
508fn foo(a: Arc<S>) {}
509
510fn test() {
511 let a = new_arc();
512 let b = (*a)<|>;
513 foo(a);
514}
515"#,
516 );
517 assert_eq!(t, "S");
518}
519
520#[test]
521fn deref_trait_infinite_recursion() {
522 let t = type_at(
523 r#"
524//- /main.rs
525#[lang = "deref"]
526trait Deref {
527 type Target;
528 fn deref(&self) -> &Self::Target;
529}
530
531struct S;
532
533impl Deref for S {
534 type Target = S;
535}
536
537fn test(s: S) {
538 s.foo()<|>;
539}
540"#,
541 );
542 assert_eq!(t, "{unknown}");
543}
544
545#[test]
546fn deref_trait_with_question_mark_size() {
547 let t = type_at(
548 r#"
549//- /main.rs
550#[lang = "deref"]
551trait Deref {
552 type Target;
553 fn deref(&self) -> &Self::Target;
554}
555
556struct Arc<T>;
557impl<T> Deref for Arc<T> {
558 type Target = T;
559}
560
561struct S;
562impl S {
563 fn foo(&self) -> u128 {}
564}
565
566fn test(s: Arc<S>) {
567 (*s, s.foo())<|>;
568}
569"#,
570 );
571 assert_eq!(t, "(S, u128)");
572}
573
574#[test]
575fn obligation_from_function_clause() {
576 let t = type_at(
577 r#"
578//- /main.rs
579struct S;
580
581trait Trait<T> {}
582impl Trait<u32> for S {}
583
584fn foo<T: Trait<U>, U>(t: T) -> U {}
585
586fn test(s: S) {
587 foo(s)<|>;
588}
589"#,
590 );
591 assert_eq!(t, "u32");
592}
593
594#[test]
595fn obligation_from_method_clause() {
596 let t = type_at(
597 r#"
598//- /main.rs
599struct S;
600
601trait Trait<T> {}
602impl Trait<isize> for S {}
603
604struct O;
605impl O {
606 fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
607}
608
609fn test() {
610 O.foo(S)<|>;
611}
612"#,
613 );
614 assert_eq!(t, "isize");
615}
616
617#[test]
618fn obligation_from_self_method_clause() {
619 let t = type_at(
620 r#"
621//- /main.rs
622struct S;
623
624trait Trait<T> {}
625impl Trait<i64> for S {}
626
627impl S {
628 fn foo<U>(&self) -> U where Self: Trait<U> {}
629}
630
631fn test() {
632 S.foo()<|>;
633}
634"#,
635 );
636 assert_eq!(t, "i64");
637}
638
639#[test]
640fn obligation_from_impl_clause() {
641 let t = type_at(
642 r#"
643//- /main.rs
644struct S;
645
646trait Trait<T> {}
647impl Trait<&str> for S {}
648
649struct O<T>;
650impl<U, T: Trait<U>> O<T> {
651 fn foo(&self) -> U {}
652}
653
654fn test(o: O<S>) {
655 o.foo()<|>;
656}
657"#,
658 );
659 assert_eq!(t, "&str");
660}
661
662#[test]
663fn generic_param_env_1() {
664 let t = type_at(
665 r#"
666//- /main.rs
667trait Clone {}
668trait Trait { fn foo(self) -> u128; }
669struct S;
670impl Clone for S {}
671impl<T> Trait for T where T: Clone {}
672fn test<T: Clone>(t: T) { t.foo()<|>; }
673"#,
674 );
675 assert_eq!(t, "u128");
676}
677
678#[test]
679fn generic_param_env_1_not_met() {
680 let t = type_at(
681 r#"
682//- /main.rs
683trait Clone {}
684trait Trait { fn foo(self) -> u128; }
685struct S;
686impl Clone for S {}
687impl<T> Trait for T where T: Clone {}
688fn test<T>(t: T) { t.foo()<|>; }
689"#,
690 );
691 assert_eq!(t, "{unknown}");
692}
693
694#[test]
695fn generic_param_env_2() {
696 let t = type_at(
697 r#"
698//- /main.rs
699trait Trait { fn foo(self) -> u128; }
700struct S;
701impl Trait for S {}
702fn test<T: Trait>(t: T) { t.foo()<|>; }
703"#,
704 );
705 assert_eq!(t, "u128");
706}
707
708#[test]
709fn generic_param_env_2_not_met() {
710 let t = type_at(
711 r#"
712//- /main.rs
713trait Trait { fn foo(self) -> u128; }
714struct S;
715impl Trait for S {}
716fn test<T>(t: T) { t.foo()<|>; }
717"#,
718 );
719 assert_eq!(t, "{unknown}");
720}
721
722#[test]
723fn generic_param_env_deref() {
724 let t = type_at(
725 r#"
726//- /main.rs
727#[lang = "deref"]
728trait Deref {
729 type Target;
730}
731trait Trait {}
732impl<T> Deref for T where T: Trait {
733 type Target = i128;
734}
735fn test<T: Trait>(t: T) { (*t)<|>; }
736"#,
737 );
738 assert_eq!(t, "i128");
739}
740
741#[test]
742fn associated_type_placeholder() {
743 let t = type_at(
744 r#"
745//- /main.rs
746pub trait ApplyL {
747 type Out;
748}
749
750pub struct RefMutL<T>;
751
752impl<T> ApplyL for RefMutL<T> {
753 type Out = <T as ApplyL>::Out;
754}
755
756fn test<T: ApplyL>() {
757 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
758 y<|>;
759}
760"#,
761 );
762 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
763 // FIXME: fix type parameter names going missing when going through Chalk
764 assert_eq!(t, "ApplyL::Out<[missing name]>");
765}
766
767#[test]
768fn associated_type_placeholder_2() {
769 let t = type_at(
770 r#"
771//- /main.rs
772pub trait ApplyL {
773 type Out;
774}
775fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
776
777fn test<T: ApplyL>(t: T) {
778 let y = foo(t);
779 y<|>;
780}
781"#,
782 );
783 // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
784 // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
785 // to the trait env ourselves here; probably Chalk can't do this by itself.
786 // assert_eq!(t, "ApplyL::Out<[missing name]>");
787 assert_eq!(t, "{unknown}");
788}
789
790#[test]
791fn impl_trait() {
792 assert_snapshot!(
793 infer(r#"
794trait Trait<T> {
795 fn foo(&self) -> T;
796 fn foo2(&self) -> i64;
797}
798fn bar() -> impl Trait<u64> {}
799
800fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
801 x;
802 y;
803 let z = bar();
804 x.foo();
805 y.foo();
806 z.foo();
807 x.foo2();
808 y.foo2();
809 z.foo2();
810}
811"#),
812 @r###"
813 [30; 34) 'self': &Self
814 [55; 59) 'self': &Self
815 [99; 101) '{}': ()
816 [111; 112) 'x': impl Trait<u64>
817 [131; 132) 'y': &impl Trait<u64>
818 [152; 269) '{ ...2(); }': ()
819 [158; 159) 'x': impl Trait<u64>
820 [165; 166) 'y': &impl Trait<u64>
821 [176; 177) 'z': impl Trait<u64>
822 [180; 183) 'bar': fn bar() -> impl Trait<u64>
823 [180; 185) 'bar()': impl Trait<u64>
824 [191; 192) 'x': impl Trait<u64>
825 [191; 198) 'x.foo()': u64
826 [204; 205) 'y': &impl Trait<u64>
827 [204; 211) 'y.foo()': u64
828 [217; 218) 'z': impl Trait<u64>
829 [217; 224) 'z.foo()': u64
830 [230; 231) 'x': impl Trait<u64>
831 [230; 238) 'x.foo2()': i64
832 [244; 245) 'y': &impl Trait<u64>
833 [244; 252) 'y.foo2()': i64
834 [258; 259) 'z': impl Trait<u64>
835 [258; 266) 'z.foo2()': i64
836 "###
837 );
838}
839
840#[test]
841fn dyn_trait() {
842 assert_snapshot!(
843 infer(r#"
844trait Trait<T> {
845 fn foo(&self) -> T;
846 fn foo2(&self) -> i64;
847}
848fn bar() -> dyn Trait<u64> {}
849
850fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
851 x;
852 y;
853 let z = bar();
854 x.foo();
855 y.foo();
856 z.foo();
857 x.foo2();
858 y.foo2();
859 z.foo2();
860}
861"#),
862 @r###"
863 [30; 34) 'self': &Self
864 [55; 59) 'self': &Self
865 [98; 100) '{}': ()
866 [110; 111) 'x': dyn Trait<u64>
867 [129; 130) 'y': &dyn Trait<u64>
868 [149; 266) '{ ...2(); }': ()
869 [155; 156) 'x': dyn Trait<u64>
870 [162; 163) 'y': &dyn Trait<u64>
871 [173; 174) 'z': dyn Trait<u64>
872 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
873 [177; 182) 'bar()': dyn Trait<u64>
874 [188; 189) 'x': dyn Trait<u64>
875 [188; 195) 'x.foo()': u64
876 [201; 202) 'y': &dyn Trait<u64>
877 [201; 208) 'y.foo()': u64
878 [214; 215) 'z': dyn Trait<u64>
879 [214; 221) 'z.foo()': u64
880 [227; 228) 'x': dyn Trait<u64>
881 [227; 235) 'x.foo2()': i64
882 [241; 242) 'y': &dyn Trait<u64>
883 [241; 249) 'y.foo2()': i64
884 [255; 256) 'z': dyn Trait<u64>
885 [255; 263) 'z.foo2()': i64
886 "###
887 );
888}
889
890#[test]
891fn dyn_trait_bare() {
892 assert_snapshot!(
893 infer(r#"
894trait Trait {
895 fn foo(&self) -> u64;
896}
897fn bar() -> Trait {}
898
899fn test(x: Trait, y: &Trait) -> u64 {
900 x;
901 y;
902 let z = bar();
903 x.foo();
904 y.foo();
905 z.foo();
906}
907"#),
908 @r###"
909 [27; 31) 'self': &Self
910 [61; 63) '{}': ()
911 [73; 74) 'x': dyn Trait
912 [83; 84) 'y': &dyn Trait
913 [101; 176) '{ ...o(); }': ()
914 [107; 108) 'x': dyn Trait
915 [114; 115) 'y': &dyn Trait
916 [125; 126) 'z': dyn Trait
917 [129; 132) 'bar': fn bar() -> dyn Trait
918 [129; 134) 'bar()': dyn Trait
919 [140; 141) 'x': dyn Trait
920 [140; 147) 'x.foo()': u64
921 [153; 154) 'y': &dyn Trait
922 [153; 160) 'y.foo()': u64
923 [166; 167) 'z': dyn Trait
924 [166; 173) 'z.foo()': u64
925 "###
926 );
927}
928
929#[test]
930fn weird_bounds() {
931 assert_snapshot!(
932 infer(r#"
933trait Trait {}
934fn test() {
935 let a: impl Trait + 'lifetime = foo;
936 let b: impl 'lifetime = foo;
937 let b: impl (Trait) = foo;
938 let b: impl ('lifetime) = foo;
939 let d: impl ?Sized = foo;
940 let e: impl Trait + ?Sized = foo;
941}
942"#),
943 @r###"
944 [26; 237) '{ ...foo; }': ()
945 [36; 37) 'a': impl Trait + {error}
946 [64; 67) 'foo': impl Trait + {error}
947 [77; 78) 'b': impl {error}
948 [97; 100) 'foo': impl {error}
949 [110; 111) 'b': impl Trait
950 [128; 131) 'foo': impl Trait
951 [141; 142) 'b': impl {error}
952 [163; 166) 'foo': impl {error}
953 [176; 177) 'd': impl {error}
954 [193; 196) 'foo': impl {error}
955 [206; 207) 'e': impl Trait + {error}
956 [231; 234) 'foo': impl Trait + {error}
957 "###
958 );
959}
960
961#[test]
962fn error_bound_chalk() {
963 let t = type_at(
964 r#"
965//- /main.rs
966trait Trait {
967 fn foo(&self) -> u32 {}
968}
969
970fn test(x: (impl Trait + UnknownTrait)) {
971 x.foo()<|>;
972}
973"#,
974 );
975 assert_eq!(t, "u32");
976}
977
978#[test]
979fn assoc_type_bindings() {
980 assert_snapshot!(
981 infer(r#"
982trait Trait {
983 type Type;
984}
985
986fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
987fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
988fn set<T: Trait<Type = u64>>(t: T) -> T {t}
989
990struct S<T>;
991impl<T> Trait for S<T> { type Type = T; }
992
993fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
994 get(x);
995 get2(x);
996 get(y);
997 get2(y);
998 get(set(S));
999 get2(set(S));
1000 get2(S::<str>);
1001}
1002"#),
1003 @r###"
1004 [50; 51) 't': T
1005 [78; 80) '{}': ()
1006 [112; 113) 't': T
1007 [123; 125) '{}': ()
1008 [155; 156) 't': T
1009 [166; 169) '{t}': T
1010 [167; 168) 't': T
1011 [257; 258) 'x': T
1012 [263; 264) 'y': impl Trait<Type = i64>
1013 [290; 398) '{ ...r>); }': ()
1014 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
1015 [296; 302) 'get(x)': {unknown}
1016 [300; 301) 'x': T
1017 [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
1018 [308; 315) 'get2(x)': {unknown}
1019 [313; 314) 'x': T
1020 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
1021 [321; 327) 'get(y)': {unknown}
1022 [325; 326) 'y': impl Trait<Type = i64>
1023 [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
1024 [333; 340) 'get2(y)': {unknown}
1025 [338; 339) 'y': impl Trait<Type = i64>
1026 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
1027 [346; 357) 'get(set(S))': u64
1028 [350; 353) 'set': fn set<S<u64>>(T) -> T
1029 [350; 356) 'set(S)': S<u64>
1030 [354; 355) 'S': S<u64>
1031 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
1032 [363; 375) 'get2(set(S))': u64
1033 [368; 371) 'set': fn set<S<u64>>(T) -> T
1034 [368; 374) 'set(S)': S<u64>
1035 [372; 373) 'S': S<u64>
1036 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
1037 [381; 395) 'get2(S::<str>)': str
1038 [386; 394) 'S::<str>': S<str>
1039 "###
1040 );
1041}
1042
1043#[test]
1044fn impl_trait_assoc_binding_projection_bug() {
1045 let (db, pos) = TestDB::with_position(
1046 r#"
1047//- /main.rs crate:main deps:std
1048pub trait Language {
1049 type Kind;
1050}
1051pub enum RustLanguage {}
1052impl Language for RustLanguage {
1053 type Kind = SyntaxKind;
1054}
1055struct SyntaxNode<L> {}
1056fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
1057
1058trait Clone {
1059 fn clone(&self) -> Self;
1060}
1061
1062fn api_walkthrough() {
1063 for node in foo() {
1064 node.clone()<|>;
1065 }
1066}
1067
1068//- /std.rs crate:std
1069#[prelude_import] use iter::*;
1070mod iter {
1071 trait IntoIterator {
1072 type Item;
1073 }
1074 trait Iterator {
1075 type Item;
1076 }
1077 impl<T: Iterator> IntoIterator for T {
1078 type Item = <T as Iterator>::Item;
1079 }
1080}
1081"#,
1082 );
1083 assert_eq!("{unknown}", type_at_pos(&db, pos));
1084}
1085
1086#[test]
1087fn projection_eq_within_chalk() {
1088 // std::env::set_var("CHALK_DEBUG", "1");
1089 assert_snapshot!(
1090 infer(r#"
1091trait Trait1 {
1092 type Type;
1093}
1094trait Trait2<T> {
1095 fn foo(self) -> T;
1096}
1097impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
1098
1099fn test<T: Trait1<Type = u32>>(x: T) {
1100 x.foo();
1101}
1102"#),
1103 @r###"
1104 [62; 66) 'self': Self
1105 [164; 165) 'x': T
1106 [170; 186) '{ ...o(); }': ()
1107 [176; 177) 'x': T
1108 [176; 183) 'x.foo()': {unknown}
1109 "###
1110 );
1111}
1112
1113#[test]
1114fn where_clause_trait_in_scope_for_method_resolution() {
1115 let t = type_at(
1116 r#"
1117//- /main.rs
1118mod foo {
1119 trait Trait {
1120 fn foo(&self) -> u32 {}
1121 }
1122}
1123
1124fn test<T: foo::Trait>(x: T) {
1125 x.foo()<|>;
1126}
1127"#,
1128 );
1129 assert_eq!(t, "u32");
1130}
1131
1132#[test]
1133fn super_trait_method_resolution() {
1134 assert_snapshot!(
1135 infer(r#"
1136mod foo {
1137 trait SuperTrait {
1138 fn foo(&self) -> u32 {}
1139 }
1140}
1141trait Trait1: foo::SuperTrait {}
1142trait Trait2 where Self: foo::SuperTrait {}
1143
1144fn test<T: Trait1, U: Trait2>(x: T, y: U) {
1145 x.foo();
1146 y.foo();
1147}
1148"#),
1149 @r###"
1150 [50; 54) 'self': &Self
1151 [63; 65) '{}': ()
1152 [182; 183) 'x': T
1153 [188; 189) 'y': U
1154 [194; 223) '{ ...o(); }': ()
1155 [200; 201) 'x': T
1156 [200; 207) 'x.foo()': u32
1157 [213; 214) 'y': U
1158 [213; 220) 'y.foo()': u32
1159 "###
1160 );
1161}
1162
1163#[test]
1164fn super_trait_cycle() {
1165 // This just needs to not crash
1166 assert_snapshot!(
1167 infer(r#"
1168trait A: B {}
1169trait B: A {}
1170
1171fn test<T: A>(x: T) {
1172 x.foo();
1173}
1174"#),
1175 @r###"
1176 [44; 45) 'x': T
1177 [50; 66) '{ ...o(); }': ()
1178 [56; 57) 'x': T
1179 [56; 63) 'x.foo()': {unknown}
1180 "###
1181 );
1182}
1183
1184#[test]
1185fn super_trait_assoc_type_bounds() {
1186 assert_snapshot!(
1187 infer(r#"
1188trait SuperTrait { type Type; }
1189trait Trait where Self: SuperTrait {}
1190
1191fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1192fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1193
1194struct S<T>;
1195impl<T> SuperTrait for S<T> { type Type = T; }
1196impl<T> Trait for S<T> {}
1197
1198fn test() {
1199 get2(set(S));
1200}
1201"#),
1202 @r###"
1203 [103; 104) 't': T
1204 [114; 116) '{}': ()
1205 [146; 147) 't': T
1206 [157; 160) '{t}': T
1207 [158; 159) 't': T
1208 [259; 280) '{ ...S)); }': ()
1209 [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
1210 [265; 277) 'get2(set(S))': u64
1211 [270; 273) 'set': fn set<S<u64>>(T) -> T
1212 [270; 276) 'set(S)': S<u64>
1213 [274; 275) 'S': S<u64>
1214 "###
1215 );
1216}
1217
1218#[test]
1219fn fn_trait() {
1220 assert_snapshot!(
1221 infer(r#"
1222trait FnOnce<Args> {
1223 type Output;
1224
1225 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
1226}
1227
1228fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1229 f.call_once((1, 2));
1230}
1231"#),
1232 @r###"
1233 [57; 61) 'self': Self
1234 [63; 67) 'args': Args
1235 [150; 151) 'f': F
1236 [156; 184) '{ ...2)); }': ()
1237 [162; 163) 'f': F
1238 [162; 181) 'f.call...1, 2))': {unknown}
1239 [174; 180) '(1, 2)': (u32, u64)
1240 [175; 176) '1': u32
1241 [178; 179) '2': u64
1242 "###
1243 );
1244}
1245
1246#[test]
1247fn closure_1() {
1248 assert_snapshot!(
1249 infer(r#"
1250#[lang = "fn_once"]
1251trait FnOnce<Args> {
1252 type Output;
1253}
1254
1255enum Option<T> { Some(T), None }
1256impl<T> Option<T> {
1257 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
1258}
1259
1260fn test() {
1261 let x = Option::Some(1u32);
1262 x.map(|v| v + 1);
1263 x.map(|_v| 1u64);
1264 let y: Option<i64> = x.map(|_v| 1);
1265}
1266"#),
1267 @r###"
1268 [148; 152) 'self': Option<T>
1269 [154; 155) 'f': F
1270 [173; 175) '{}': ()
1271 [189; 308) '{ ... 1); }': ()
1272 [199; 200) 'x': Option<u32>
1273 [203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
1274 [203; 221) 'Option...(1u32)': Option<u32>
1275 [216; 220) '1u32': u32
1276 [227; 228) 'x': Option<u32>
1277 [227; 243) 'x.map(...v + 1)': Option<u32>
1278 [233; 242) '|v| v + 1': |u32| -> u32
1279 [234; 235) 'v': u32
1280 [237; 238) 'v': u32
1281 [237; 242) 'v + 1': u32
1282 [241; 242) '1': u32
1283 [249; 250) 'x': Option<u32>
1284 [249; 265) 'x.map(... 1u64)': Option<u64>
1285 [255; 264) '|_v| 1u64': |u32| -> u64
1286 [256; 258) '_v': u32
1287 [260; 264) '1u64': u64
1288 [275; 276) 'y': Option<i64>
1289 [292; 293) 'x': Option<u32>
1290 [292; 305) 'x.map(|_v| 1)': Option<i64>
1291 [298; 304) '|_v| 1': |u32| -> i64
1292 [299; 301) '_v': u32
1293 [303; 304) '1': i64
1294 "###
1295 );
1296}
1297
1298#[test]
1299fn closure_2() {
1300 assert_snapshot!(
1301 infer(r#"
1302trait FnOnce<Args> {
1303 type Output;
1304}
1305
1306fn test<F: FnOnce(u32) -> u64>(f: F) {
1307 f(1);
1308 let g = |v| v + 1;
1309 g(1u64);
1310 let h = |v| 1u128 + v;
1311}
1312"#),
1313 @r###"
1314 [73; 74) 'f': F
1315 [79; 155) '{ ...+ v; }': ()
1316 [85; 86) 'f': F
1317 [85; 89) 'f(1)': {unknown}
1318 [87; 88) '1': i32
1319 [99; 100) 'g': |u64| -> i32
1320 [103; 112) '|v| v + 1': |u64| -> i32
1321 [104; 105) 'v': u64
1322 [107; 108) 'v': u64
1323 [107; 112) 'v + 1': i32
1324 [111; 112) '1': i32
1325 [118; 119) 'g': |u64| -> i32
1326 [118; 125) 'g(1u64)': i32
1327 [120; 124) '1u64': u64
1328 [135; 136) 'h': |u128| -> u128
1329 [139; 152) '|v| 1u128 + v': |u128| -> u128
1330 [140; 141) 'v': u128
1331 [143; 148) '1u128': u128
1332 [143; 152) '1u128 + v': u128
1333 [151; 152) 'v': u128
1334 "###
1335 );
1336}
1337
1338#[test]
1339fn closure_as_argument_inference_order() {
1340 assert_snapshot!(
1341 infer(r#"
1342#[lang = "fn_once"]
1343trait FnOnce<Args> {
1344 type Output;
1345}
1346
1347fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
1348fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
1349
1350struct S;
1351impl S {
1352 fn method(self) -> u64;
1353
1354 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
1355 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
1356}
1357
1358fn test() {
1359 let x1 = foo1(S, |s| s.method());
1360 let x2 = foo2(|s| s.method(), S);
1361 let x3 = S.foo1(S, |s| s.method());
1362 let x4 = S.foo2(|s| s.method(), S);
1363}
1364"#),
1365 @r###"
1366 [95; 96) 'x': T
1367 [101; 102) 'f': F
1368 [112; 114) '{}': ()
1369 [148; 149) 'f': F
1370 [154; 155) 'x': T
1371 [165; 167) '{}': ()
1372 [202; 206) 'self': S
1373 [254; 258) 'self': S
1374 [260; 261) 'x': T
1375 [266; 267) 'f': F
1376 [277; 279) '{}': ()
1377 [317; 321) 'self': S
1378 [323; 324) 'f': F
1379 [329; 330) 'x': T
1380 [340; 342) '{}': ()
1381 [356; 515) '{ ... S); }': ()
1382 [366; 368) 'x1': u64
1383 [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
1384 [371; 394) 'foo1(S...hod())': u64
1385 [376; 377) 'S': S
1386 [379; 393) '|s| s.method()': |S| -> u64
1387 [380; 381) 's': S
1388 [383; 384) 's': S
1389 [383; 393) 's.method()': u64
1390 [404; 406) 'x2': u64
1391 [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
1392 [409; 432) 'foo2(|...(), S)': u64
1393 [414; 428) '|s| s.method()': |S| -> u64
1394 [415; 416) 's': S
1395 [418; 419) 's': S
1396 [418; 428) 's.method()': u64
1397 [430; 431) 'S': S
1398 [442; 444) 'x3': u64
1399 [447; 448) 'S': S
1400 [447; 472) 'S.foo1...hod())': u64
1401 [454; 455) 'S': S
1402 [457; 471) '|s| s.method()': |S| -> u64
1403 [458; 459) 's': S
1404 [461; 462) 's': S
1405 [461; 471) 's.method()': u64
1406 [482; 484) 'x4': u64
1407 [487; 488) 'S': S
1408 [487; 512) 'S.foo2...(), S)': u64
1409 [494; 508) '|s| s.method()': |S| -> u64
1410 [495; 496) 's': S
1411 [498; 499) 's': S
1412 [498; 508) 's.method()': u64
1413 [510; 511) 'S': S
1414 "###
1415 );
1416}
1417
1418#[test]
1419fn unselected_projection_in_trait_env_1() {
1420 let t = type_at(
1421 r#"
1422//- /main.rs
1423trait Trait {
1424 type Item;
1425}
1426
1427trait Trait2 {
1428 fn foo(&self) -> u32;
1429}
1430
1431fn test<T: Trait>() where T::Item: Trait2 {
1432 let x: T::Item = no_matter;
1433 x.foo()<|>;
1434}
1435"#,
1436 );
1437 assert_eq!(t, "u32");
1438}
1439
1440#[test]
1441fn unselected_projection_in_trait_env_2() {
1442 let t = type_at(
1443 r#"
1444//- /main.rs
1445trait Trait<T> {
1446 type Item;
1447}
1448
1449trait Trait2 {
1450 fn foo(&self) -> u32;
1451}
1452
1453fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1454 let x: T::Item = no_matter;
1455 x.foo()<|>;
1456}
1457"#,
1458 );
1459 assert_eq!(t, "u32");
1460}
1461
1462#[test]
1463fn trait_impl_self_ty() {
1464 let t = type_at(
1465 r#"
1466//- /main.rs
1467trait Trait<T> {
1468 fn foo(&self);
1469}
1470
1471struct S;
1472
1473impl Trait<Self> for S {}
1474
1475fn test() {
1476 S.foo()<|>;
1477}
1478"#,
1479 );
1480 assert_eq!(t, "()");
1481}
1482
1483#[test]
1484fn trait_impl_self_ty_cycle() {
1485 let t = type_at(
1486 r#"
1487//- /main.rs
1488trait Trait {
1489 fn foo(&self);
1490}
1491
1492struct S<T>;
1493
1494impl Trait for S<Self> {}
1495
1496fn test() {
1497 S.foo()<|>;
1498}
1499"#,
1500 );
1501 assert_eq!(t, "{unknown}");
1502}
1503
1504#[test]
1505fn unselected_projection_in_trait_env_cycle_1() {
1506 let t = type_at(
1507 r#"
1508//- /main.rs
1509trait Trait {
1510 type Item;
1511}
1512
1513trait Trait2<T> {}
1514
1515fn test<T: Trait>() where T: Trait2<T::Item> {
1516 let x: T::Item = no_matter<|>;
1517}
1518"#,
1519 );
1520 // this is a legitimate cycle
1521 assert_eq!(t, "{unknown}");
1522}
1523
1524#[test]
1525fn unselected_projection_in_trait_env_cycle_2() {
1526 let t = type_at(
1527 r#"
1528//- /main.rs
1529trait Trait<T> {
1530 type Item;
1531}
1532
1533fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1534 let x: T::Item = no_matter<|>;
1535}
1536"#,
1537 );
1538 // this is a legitimate cycle
1539 assert_eq!(t, "{unknown}");
1540}
1541
1542#[test]
1543fn unify_impl_trait() {
1544 covers!(insert_vars_for_impl_trait);
1545 assert_snapshot!(
1546 infer_with_mismatches(r#"
1547trait Trait<T> {}
1548
1549fn foo(x: impl Trait<u32>) { loop {} }
1550fn bar<T>(x: impl Trait<T>) -> T { loop {} }
1551
1552struct S<T>(T);
1553impl<T> Trait<T> for S<T> {}
1554
1555fn default<T>() -> T { loop {} }
1556
1557fn test() -> impl Trait<i32> {
1558 let s1 = S(default());
1559 foo(s1);
1560 let x: i32 = bar(S(default()));
1561 S(default())
1562}
1563"#, true),
1564 @r###"
1565 [27; 28) 'x': impl Trait<u32>
1566 [47; 58) '{ loop {} }': ()
1567 [49; 56) 'loop {}': !
1568 [54; 56) '{}': ()
1569 [69; 70) 'x': impl Trait<T>
1570 [92; 103) '{ loop {} }': T
1571 [94; 101) 'loop {}': !
1572 [99; 101) '{}': ()
1573 [172; 183) '{ loop {} }': T
1574 [174; 181) 'loop {}': !
1575 [179; 181) '{}': ()
1576 [214; 310) '{ ...t()) }': S<i32>
1577 [224; 226) 's1': S<u32>
1578 [229; 230) 'S': S<u32>(T) -> S<T>
1579 [229; 241) 'S(default())': S<u32>
1580 [231; 238) 'default': fn default<u32>() -> T
1581 [231; 240) 'default()': u32
1582 [247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
1583 [247; 254) 'foo(s1)': ()
1584 [251; 253) 's1': S<u32>
1585 [264; 265) 'x': i32
1586 [273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
1587 [273; 290) 'bar(S(...lt()))': i32
1588 [277; 278) 'S': S<i32>(T) -> S<T>
1589 [277; 289) 'S(default())': S<i32>
1590 [279; 286) 'default': fn default<i32>() -> T
1591 [279; 288) 'default()': i32
1592 [296; 297) 'S': S<i32>(T) -> S<T>
1593 [296; 308) 'S(default())': S<i32>
1594 [298; 305) 'default': fn default<i32>() -> T
1595 [298; 307) 'default()': i32
1596 "###
1597 );
1598}
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 76189a60b..c4dc857bc 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,7 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use chalk_ir::{cast::Cast, family::ChalkIr}; 4use chalk_ir::cast::Cast;
5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
6use log::debug; 6use log::debug;
7use ra_db::{impl_intern_key, salsa, CrateId}; 7use ra_db::{impl_intern_key, salsa, CrateId};
@@ -12,14 +12,15 @@ use crate::db::HirDatabase;
12 12
13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
14 14
15use self::chalk::{from_chalk, ToChalk}; 15use self::chalk::{from_chalk, ToChalk, TypeFamily};
16 16
17pub(crate) mod chalk; 17pub(crate) mod chalk;
18mod builtin;
18 19
19#[derive(Debug, Clone)] 20#[derive(Debug, Clone)]
20pub struct TraitSolver { 21pub struct TraitSolver {
21 krate: CrateId, 22 krate: CrateId,
22 inner: Arc<Mutex<chalk_solve::Solver<ChalkIr>>>, 23 inner: Arc<Mutex<chalk_solve::Solver<TypeFamily>>>,
23} 24}
24 25
25/// We need eq for salsa 26/// We need eq for salsa
@@ -35,8 +36,8 @@ impl TraitSolver {
35 fn solve( 36 fn solve(
36 &self, 37 &self,
37 db: &impl HirDatabase, 38 db: &impl HirDatabase,
38 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>, 39 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>,
39 ) -> Option<chalk_solve::Solution<ChalkIr>> { 40 ) -> Option<chalk_solve::Solution<TypeFamily>> {
40 let context = ChalkContext { db, krate: self.krate }; 41 let context = ChalkContext { db, krate: self.krate };
41 debug!("solve goal: {:?}", goal); 42 debug!("solve goal: {:?}", goal);
42 let mut solver = match self.inner.lock() { 43 let mut solver = match self.inner.lock() {
@@ -200,17 +201,17 @@ pub(crate) fn trait_solve_query(
200 201
201fn solution_from_chalk( 202fn solution_from_chalk(
202 db: &impl HirDatabase, 203 db: &impl HirDatabase,
203 solution: chalk_solve::Solution<ChalkIr>, 204 solution: chalk_solve::Solution<TypeFamily>,
204) -> Solution { 205) -> Solution {
205 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| { 206 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<TypeFamily>>| {
206 let value = subst 207 let value = subst
207 .value 208 .value
208 .parameters 209 .parameters
209 .into_iter() 210 .into_iter()
210 .map(|p| { 211 .map(|p| {
211 let ty = match p { 212 let ty = match p.ty() {
212 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 213 Some(ty) => from_chalk(db, ty.clone()),
213 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 214 None => unimplemented!(),
214 }; 215 };
215 ty 216 ty
216 }) 217 })
@@ -290,7 +291,7 @@ impl FnTrait {
290 } 291 }
291} 292}
292 293
293#[derive(Debug, Clone, PartialEq, Eq, Hash)] 294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct ClosureFnTraitImplData { 295pub struct ClosureFnTraitImplData {
295 def: DefWithBodyId, 296 def: DefWithBodyId,
296 expr: ExprId, 297 expr: ExprId,
@@ -299,7 +300,7 @@ pub struct ClosureFnTraitImplData {
299 300
300/// An impl. Usually this comes from an impl block, but some built-in types get 301/// An impl. Usually this comes from an impl block, but some built-in types get
301/// synthetic impls. 302/// synthetic impls.
302#[derive(Debug, Clone, PartialEq, Eq, Hash)] 303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
303pub enum Impl { 304pub enum Impl {
304 /// A normal impl from an impl block. 305 /// A normal impl from an impl block.
305 ImplBlock(ImplId), 306 ImplBlock(ImplId),
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
new file mode 100644
index 000000000..dd41176f0
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -0,0 +1,178 @@
1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name::name;
5use ra_db::CrateId;
6
7use super::{AssocTyValue, Impl};
8use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor};
9
10pub(super) struct BuiltinImplData {
11 pub num_vars: usize,
12 pub trait_ref: TraitRef,
13 pub where_clauses: Vec<super::GenericPredicate>,
14 pub assoc_ty_values: Vec<AssocTyValue>,
15}
16
17pub(super) struct BuiltinImplAssocTyValueData {
18 pub impl_: Impl,
19 pub assoc_ty_id: TypeAliasId,
20 pub num_vars: usize,
21 pub value: Ty,
22}
23
24pub(super) fn get_builtin_impls(
25 db: &impl HirDatabase,
26 krate: CrateId,
27 ty: &Ty,
28 trait_: TraitId,
29 mut callback: impl FnMut(Impl),
30) {
31 // Note: since impl_datum needs to be infallible, we need to make sure here
32 // that we have all prerequisites to build the respective impls.
33 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
34 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
35 {
36 if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) {
37 if trait_ == actual_trait {
38 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait };
39 if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) {
40 callback(Impl::ClosureFnTraitImpl(impl_));
41 }
42 }
43 }
44 }
45 }
46}
47
48pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
49 match impl_ {
50 Impl::ImplBlock(_) => unreachable!(),
51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
52 }
53}
54
55pub(super) fn associated_ty_value(
56 db: &impl HirDatabase,
57 krate: CrateId,
58 data: AssocTyValue,
59) -> BuiltinImplAssocTyValueData {
60 match data {
61 AssocTyValue::TypeAlias(_) => unreachable!(),
62 AssocTyValue::ClosureFnTraitImplOutput(data) => {
63 closure_fn_trait_output_assoc_ty_value(db, krate, data)
64 }
65 }
66}
67
68fn check_closure_fn_trait_impl_prerequisites(
69 db: &impl HirDatabase,
70 krate: CrateId,
71 data: super::ClosureFnTraitImplData,
72) -> bool {
73 // the respective Fn/FnOnce/FnMut trait needs to exist
74 if get_fn_trait(db, krate, data.fn_trait).is_none() {
75 return false;
76 }
77
78 // FIXME: there are more assumptions that we should probably check here:
79 // the traits having no type params, FnOnce being a supertrait
80
81 // the FnOnce trait needs to exist and have an assoc type named Output
82 let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) {
83 Some(t) => t,
84 None => return false,
85 };
86 db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some()
87}
88
89fn closure_fn_trait_impl_datum(
90 db: &impl HirDatabase,
91 krate: CrateId,
92 data: super::ClosureFnTraitImplData,
93) -> BuiltinImplData {
94 // for some closure |X, Y| -> Z:
95 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
96
97 let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait
98 // the existence of the Fn trait has been checked before
99 .expect("fn trait for closure impl missing");
100
101 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
102 Expr::Lambda { args, .. } => args.len() as u16,
103 _ => {
104 log::warn!("closure for closure type {:?} not found", data);
105 0
106 }
107 };
108
109 let arg_ty = Ty::apply(
110 TypeCtor::Tuple { cardinality: num_args },
111 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
112 );
113 let sig_ty = Ty::apply(
114 TypeCtor::FnPtr { num_args },
115 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
116 );
117
118 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
119
120 let trait_ref = TraitRef {
121 trait_: trait_.into(),
122 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
123 };
124
125 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone());
126
127 BuiltinImplData {
128 num_vars: num_args as usize + 1,
129 trait_ref,
130 where_clauses: Vec::new(),
131 assoc_ty_values: vec![output_ty_id],
132 }
133}
134
135fn closure_fn_trait_output_assoc_ty_value(
136 db: &impl HirDatabase,
137 krate: CrateId,
138 data: super::ClosureFnTraitImplData,
139) -> BuiltinImplAssocTyValueData {
140 let impl_ = Impl::ClosureFnTraitImpl(data.clone());
141
142 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
143 Expr::Lambda { args, .. } => args.len() as u16,
144 _ => {
145 log::warn!("closure for closure type {:?} not found", data);
146 0
147 }
148 };
149
150 let output_ty = Ty::Bound(num_args.into());
151
152 let fn_once_trait =
153 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
154
155 let output_ty_id = db
156 .trait_data(fn_once_trait)
157 .associated_type_by_name(&name![Output])
158 .expect("assoc ty value should not exist");
159
160 BuiltinImplAssocTyValueData {
161 impl_,
162 assoc_ty_id: output_ty_id,
163 num_vars: num_args as usize + 1,
164 value: output_ty,
165 }
166}
167
168fn get_fn_trait(
169 db: &impl HirDatabase,
170 krate: CrateId,
171 fn_trait: super::FnTrait,
172) -> Option<TraitId> {
173 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
174 match target {
175 LangItemTarget::TraitId(t) => Some(t),
176 _ => None,
177 }
178}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 35de37e6b..555930c9b 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -1,32 +1,99 @@
1//! Conversion code from/to Chalk. 1//! Conversion code from/to Chalk.
2use std::sync::Arc; 2use std::{fmt, sync::Arc};
3 3
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{cast::Cast, Parameter, PlaceholderIndex, TypeName, UniverseIndex};
7 cast::Cast, family::ChalkIr, Identifier, Parameter, PlaceholderIndex, TypeId, TypeKindId,
8 TypeName, UniverseIndex,
9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11use ra_db::CrateId;
12 7
13use hir_def::{ 8use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId};
14 expr::Expr, lang_item::LangItemTarget, AssocItemId, AstItemDef, ContainerId, GenericDefId, 9use ra_db::{
15 ImplId, Lookup, TraitId, TypeAliasId, 10 salsa::{InternId, InternKey},
11 CrateId,
16}; 12};
17use hir_expand::name;
18
19use ra_db::salsa::{InternId, InternKey};
20 13
21use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 14use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
22use crate::{ 15use crate::{
23 db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ImplTy, ProjectionTy, 16 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate,
24 Substs, TraitRef, Ty, TypeCtor, TypeWalk, 17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
25}; 18};
26 19
27/// This represents a trait whose name we could not resolve. 20#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
28const UNKNOWN_TRAIT: chalk_ir::TraitId = 21pub struct TypeFamily {}
29 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); 22
23impl chalk_ir::family::TypeFamily for TypeFamily {
24 type InternedType = Box<chalk_ir::TyData<Self>>;
25 type InternedLifetime = chalk_ir::LifetimeData<Self>;
26 type InternedParameter = chalk_ir::ParameterData<Self>;
27 type DefId = InternId;
28
29 // FIXME: implement these
30 fn debug_struct_id(
31 _type_kind_id: chalk_ir::StructId<Self>,
32 _fmt: &mut fmt::Formatter<'_>,
33 ) -> Option<fmt::Result> {
34 None
35 }
36
37 fn debug_trait_id(
38 _type_kind_id: chalk_ir::TraitId<Self>,
39 _fmt: &mut fmt::Formatter<'_>,
40 ) -> Option<fmt::Result> {
41 None
42 }
43
44 fn debug_assoc_type_id(
45 _id: chalk_ir::AssocTypeId<Self>,
46 _fmt: &mut fmt::Formatter<'_>,
47 ) -> Option<fmt::Result> {
48 None
49 }
50
51 fn debug_projection(
52 _projection: &chalk_ir::ProjectionTy<Self>,
53 _fmt: &mut fmt::Formatter<'_>,
54 ) -> Option<fmt::Result> {
55 None
56 }
57
58 fn intern_ty(ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
59 Box::new(ty)
60 }
61
62 fn ty_data(ty: &Box<chalk_ir::TyData<Self>>) -> &chalk_ir::TyData<Self> {
63 ty
64 }
65
66 fn intern_lifetime(lifetime: chalk_ir::LifetimeData<Self>) -> chalk_ir::LifetimeData<Self> {
67 lifetime
68 }
69
70 fn lifetime_data(lifetime: &chalk_ir::LifetimeData<Self>) -> &chalk_ir::LifetimeData<Self> {
71 lifetime
72 }
73
74 fn intern_parameter(parameter: chalk_ir::ParameterData<Self>) -> chalk_ir::ParameterData<Self> {
75 parameter
76 }
77
78 fn parameter_data(parameter: &chalk_ir::ParameterData<Self>) -> &chalk_ir::ParameterData<Self> {
79 parameter
80 }
81}
82
83impl chalk_ir::family::HasTypeFamily for TypeFamily {
84 type TypeFamily = Self;
85}
86
87pub type AssocTypeId = chalk_ir::AssocTypeId<TypeFamily>;
88pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<TypeFamily>;
89pub type TraitId = chalk_ir::TraitId<TypeFamily>;
90pub type TraitDatum = chalk_rust_ir::TraitDatum<TypeFamily>;
91pub type StructId = chalk_ir::StructId<TypeFamily>;
92pub type StructDatum = chalk_rust_ir::StructDatum<TypeFamily>;
93pub type ImplId = chalk_ir::ImplId<TypeFamily>;
94pub type ImplDatum = chalk_rust_ir::ImplDatum<TypeFamily>;
95pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId;
96pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<TypeFamily>;
30 97
31pub(super) trait ToChalk { 98pub(super) trait ToChalk {
32 type Chalk; 99 type Chalk;
@@ -42,21 +109,11 @@ where
42} 109}
43 110
44impl ToChalk for Ty { 111impl ToChalk for Ty {
45 type Chalk = chalk_ir::Ty<ChalkIr>; 112 type Chalk = chalk_ir::Ty<TypeFamily>;
46 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<ChalkIr> { 113 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<TypeFamily> {
47 match self { 114 match self {
48 Ty::Apply(apply_ty) => { 115 Ty::Apply(apply_ty) => {
49 let name = match apply_ty.ctor { 116 let name = apply_ty.ctor.to_chalk(db);
50 TypeCtor::AssociatedType(type_alias) => {
51 let type_id = type_alias.to_chalk(db);
52 TypeName::AssociatedType(type_id)
53 }
54 _ => {
55 // other TypeCtors get interned and turned into a chalk StructId
56 let struct_id = apply_ty.ctor.to_chalk(db);
57 TypeName::TypeKindId(struct_id.into())
58 }
59 };
60 let parameters = apply_ty.parameters.to_chalk(db); 117 let parameters = apply_ty.parameters.to_chalk(db);
61 chalk_ir::ApplicationTy { name, parameters }.cast().intern() 118 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
62 } 119 }
@@ -66,17 +123,30 @@ impl ToChalk for Ty {
66 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern() 123 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern()
67 } 124 }
68 Ty::Param { idx, .. } => { 125 Ty::Param { idx, .. } => {
69 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>() 126 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }
127 .to_ty::<TypeFamily>()
70 } 128 }
71 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), 129 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(),
72 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 130 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
73 Ty::Dyn(predicates) => { 131 Ty::Dyn(predicates) => {
74 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); 132 let where_clauses = predicates
75 chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern() 133 .iter()
134 .filter(|p| !p.is_error())
135 .cloned()
136 .map(|p| p.to_chalk(db))
137 .collect();
138 let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) };
139 chalk_ir::TyData::Dyn(bounded_ty).intern()
76 } 140 }
77 Ty::Opaque(predicates) => { 141 Ty::Opaque(predicates) => {
78 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); 142 let where_clauses = predicates
79 chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern() 143 .iter()
144 .filter(|p| !p.is_error())
145 .cloned()
146 .map(|p| p.to_chalk(db))
147 .collect();
148 let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) };
149 chalk_ir::TyData::Opaque(bounded_ty).intern()
80 } 150 }
81 Ty::Unknown => { 151 Ty::Unknown => {
82 let parameters = Vec::new(); 152 let parameters = Vec::new();
@@ -85,30 +155,19 @@ impl ToChalk for Ty {
85 } 155 }
86 } 156 }
87 } 157 }
88 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self { 158 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<TypeFamily>) -> Self {
89 match chalk.data().clone() { 159 match chalk.data().clone() {
90 chalk_ir::TyData::Apply(apply_ty) => { 160 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
91 // FIXME this is kind of hacky due to the fact that 161 TypeName::Error => Ty::Unknown,
92 // TypeName::Placeholder is a Ty::Param on our side 162 _ => {
93 match apply_ty.name { 163 let ctor = from_chalk(db, apply_ty.name);
94 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { 164 let parameters = from_chalk(db, apply_ty.parameters);
95 let ctor = from_chalk(db, struct_id); 165 Ty::Apply(ApplicationTy { ctor, parameters })
96 let parameters = from_chalk(db, apply_ty.parameters);
97 Ty::Apply(ApplicationTy { ctor, parameters })
98 }
99 TypeName::AssociatedType(type_id) => {
100 let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id));
101 let parameters = from_chalk(db, apply_ty.parameters);
102 Ty::Apply(ApplicationTy { ctor, parameters })
103 }
104 TypeName::Error => Ty::Unknown,
105 // FIXME handle TypeKindId::Trait/Type here
106 TypeName::TypeKindId(_) => unimplemented!(),
107 TypeName::Placeholder(idx) => {
108 assert_eq!(idx.ui, UniverseIndex::ROOT);
109 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
110 }
111 } 166 }
167 },
168 chalk_ir::TyData::Placeholder(idx) => {
169 assert_eq!(idx.ui, UniverseIndex::ROOT);
170 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
112 } 171 }
113 chalk_ir::TyData::Projection(proj) => { 172 chalk_ir::TyData::Projection(proj) => {
114 let associated_ty = from_chalk(db, proj.associated_ty_id); 173 let associated_ty = from_chalk(db, proj.associated_ty_id);
@@ -119,15 +178,15 @@ impl ToChalk for Ty {
119 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32), 178 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32),
120 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, 179 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
121 chalk_ir::TyData::Dyn(where_clauses) => { 180 chalk_ir::TyData::Dyn(where_clauses) => {
122 assert_eq!(where_clauses.binders.len(), 1); 181 assert_eq!(where_clauses.bounds.binders.len(), 1);
123 let predicates = 182 let predicates =
124 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 183 where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect();
125 Ty::Dyn(predicates) 184 Ty::Dyn(predicates)
126 } 185 }
127 chalk_ir::TyData::Opaque(where_clauses) => { 186 chalk_ir::TyData::Opaque(where_clauses) => {
128 assert_eq!(where_clauses.binders.len(), 1); 187 assert_eq!(where_clauses.bounds.binders.len(), 1);
129 let predicates = 188 let predicates =
130 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 189 where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect();
131 Ty::Opaque(predicates) 190 Ty::Opaque(predicates)
132 } 191 }
133 } 192 }
@@ -135,18 +194,21 @@ impl ToChalk for Ty {
135} 194}
136 195
137impl ToChalk for Substs { 196impl ToChalk for Substs {
138 type Chalk = Vec<chalk_ir::Parameter<ChalkIr>>; 197 type Chalk = Vec<chalk_ir::Parameter<TypeFamily>>;
139 198
140 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<ChalkIr>> { 199 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<TypeFamily>> {
141 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() 200 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
142 } 201 }
143 202
144 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter<ChalkIr>>) -> Substs { 203 fn from_chalk(
204 db: &impl HirDatabase,
205 parameters: Vec<chalk_ir::Parameter<TypeFamily>>,
206 ) -> Substs {
145 let tys = parameters 207 let tys = parameters
146 .into_iter() 208 .into_iter()
147 .map(|p| match p { 209 .map(|p| match p.ty() {
148 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 210 Some(ty) => from_chalk(db, ty.clone()),
149 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 211 None => unimplemented!(),
150 }) 212 })
151 .collect(); 213 .collect();
152 Substs(tys) 214 Substs(tys)
@@ -154,88 +216,102 @@ impl ToChalk for Substs {
154} 216}
155 217
156impl ToChalk for TraitRef { 218impl ToChalk for TraitRef {
157 type Chalk = chalk_ir::TraitRef<ChalkIr>; 219 type Chalk = chalk_ir::TraitRef<TypeFamily>;
158 220
159 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<ChalkIr> { 221 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<TypeFamily> {
160 let trait_id = self.trait_.to_chalk(db); 222 let trait_id = self.trait_.to_chalk(db);
161 let parameters = self.substs.to_chalk(db); 223 let parameters = self.substs.to_chalk(db);
162 chalk_ir::TraitRef { trait_id, parameters } 224 chalk_ir::TraitRef { trait_id, parameters }
163 } 225 }
164 226
165 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<ChalkIr>) -> Self { 227 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<TypeFamily>) -> Self {
166 let trait_ = from_chalk(db, trait_ref.trait_id); 228 let trait_ = from_chalk(db, trait_ref.trait_id);
167 let substs = from_chalk(db, trait_ref.parameters); 229 let substs = from_chalk(db, trait_ref.parameters);
168 TraitRef { trait_, substs } 230 TraitRef { trait_, substs }
169 } 231 }
170} 232}
171 233
172impl ToChalk for TraitId { 234impl ToChalk for hir_def::TraitId {
173 type Chalk = chalk_ir::TraitId; 235 type Chalk = TraitId;
174 236
175 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { 237 fn to_chalk(self, _db: &impl HirDatabase) -> TraitId {
176 chalk_ir::TraitId(id_to_chalk(self)) 238 chalk_ir::TraitId(self.as_intern_id())
177 } 239 }
178 240
179 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> TraitId { 241 fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
180 id_from_chalk(trait_id.0) 242 InternKey::from_intern_id(trait_id.0)
181 } 243 }
182} 244}
183 245
184impl ToChalk for TypeCtor { 246impl ToChalk for TypeCtor {
185 type Chalk = chalk_ir::StructId; 247 type Chalk = TypeName<TypeFamily>;
186 248
187 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId { 249 fn to_chalk(self, db: &impl HirDatabase) -> TypeName<TypeFamily> {
188 db.intern_type_ctor(self).into() 250 match self {
251 TypeCtor::AssociatedType(type_alias) => {
252 let type_id = type_alias.to_chalk(db);
253 TypeName::AssociatedType(type_id)
254 }
255 _ => {
256 // other TypeCtors get interned and turned into a chalk StructId
257 let struct_id = db.intern_type_ctor(self).into();
258 TypeName::Struct(struct_id)
259 }
260 }
189 } 261 }
190 262
191 fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor { 263 fn from_chalk(db: &impl HirDatabase, type_name: TypeName<TypeFamily>) -> TypeCtor {
192 db.lookup_intern_type_ctor(struct_id.into()) 264 match type_name {
265 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
266 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
267 TypeName::Error => {
268 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
269 unreachable!()
270 }
271 }
193 } 272 }
194} 273}
195 274
196impl ToChalk for Impl { 275impl ToChalk for Impl {
197 type Chalk = chalk_ir::ImplId; 276 type Chalk = ImplId;
198 277
199 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { 278 fn to_chalk(self, db: &impl HirDatabase) -> ImplId {
200 db.intern_chalk_impl(self).into() 279 db.intern_chalk_impl(self).into()
201 } 280 }
202 281
203 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { 282 fn from_chalk(db: &impl HirDatabase, impl_id: ImplId) -> Impl {
204 db.lookup_intern_chalk_impl(impl_id.into()) 283 db.lookup_intern_chalk_impl(impl_id.into())
205 } 284 }
206} 285}
207 286
208impl ToChalk for TypeAliasId { 287impl ToChalk for TypeAliasId {
209 type Chalk = chalk_ir::TypeId; 288 type Chalk = AssocTypeId;
210 289
211 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { 290 fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId {
212 chalk_ir::TypeId(id_to_chalk(self)) 291 chalk_ir::AssocTypeId(self.as_intern_id())
213 } 292 }
214 293
215 fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAliasId { 294 fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId {
216 id_from_chalk(type_alias_id.0) 295 InternKey::from_intern_id(type_alias_id.0)
217 } 296 }
218} 297}
219 298
220impl ToChalk for AssocTyValue { 299impl ToChalk for AssocTyValue {
221 type Chalk = chalk_rust_ir::AssociatedTyValueId; 300 type Chalk = AssociatedTyValueId;
222 301
223 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId { 302 fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValueId {
224 db.intern_assoc_ty_value(self).into() 303 db.intern_assoc_ty_value(self).into()
225 } 304 }
226 305
227 fn from_chalk( 306 fn from_chalk(db: &impl HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue {
228 db: &impl HirDatabase,
229 assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId,
230 ) -> AssocTyValue {
231 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) 307 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
232 } 308 }
233} 309}
234 310
235impl ToChalk for GenericPredicate { 311impl ToChalk for GenericPredicate {
236 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>; 312 type Chalk = chalk_ir::QuantifiedWhereClause<TypeFamily>;
237 313
238 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<ChalkIr> { 314 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<TypeFamily> {
239 match self { 315 match self {
240 GenericPredicate::Implemented(trait_ref) => { 316 GenericPredicate::Implemented(trait_ref) => {
241 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 317 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
@@ -247,26 +323,16 @@ impl ToChalk for GenericPredicate {
247 }), 323 }),
248 0, 324 0,
249 ), 325 ),
250 GenericPredicate::Error => { 326 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
251 let impossible_trait_ref = chalk_ir::TraitRef {
252 trait_id: UNKNOWN_TRAIT,
253 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
254 };
255 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
256 }
257 } 327 }
258 } 328 }
259 329
260 fn from_chalk( 330 fn from_chalk(
261 db: &impl HirDatabase, 331 db: &impl HirDatabase,
262 where_clause: chalk_ir::QuantifiedWhereClause<ChalkIr>, 332 where_clause: chalk_ir::QuantifiedWhereClause<TypeFamily>,
263 ) -> GenericPredicate { 333 ) -> GenericPredicate {
264 match where_clause.value { 334 match where_clause.value {
265 chalk_ir::WhereClause::Implemented(tr) => { 335 chalk_ir::WhereClause::Implemented(tr) => {
266 if tr.trait_id == UNKNOWN_TRAIT {
267 // FIXME we need an Error enum on the Chalk side to avoid this
268 return GenericPredicate::Error;
269 }
270 GenericPredicate::Implemented(from_chalk(db, tr)) 336 GenericPredicate::Implemented(from_chalk(db, tr))
271 } 337 }
272 chalk_ir::WhereClause::ProjectionEq(projection_eq) => { 338 chalk_ir::WhereClause::ProjectionEq(projection_eq) => {
@@ -279,9 +345,9 @@ impl ToChalk for GenericPredicate {
279} 345}
280 346
281impl ToChalk for ProjectionTy { 347impl ToChalk for ProjectionTy {
282 type Chalk = chalk_ir::ProjectionTy<ChalkIr>; 348 type Chalk = chalk_ir::ProjectionTy<TypeFamily>;
283 349
284 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<ChalkIr> { 350 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<TypeFamily> {
285 chalk_ir::ProjectionTy { 351 chalk_ir::ProjectionTy {
286 associated_ty_id: self.associated_ty.to_chalk(db), 352 associated_ty_id: self.associated_ty.to_chalk(db),
287 parameters: self.parameters.to_chalk(db), 353 parameters: self.parameters.to_chalk(db),
@@ -290,7 +356,7 @@ impl ToChalk for ProjectionTy {
290 356
291 fn from_chalk( 357 fn from_chalk(
292 db: &impl HirDatabase, 358 db: &impl HirDatabase,
293 projection_ty: chalk_ir::ProjectionTy<ChalkIr>, 359 projection_ty: chalk_ir::ProjectionTy<TypeFamily>,
294 ) -> ProjectionTy { 360 ) -> ProjectionTy {
295 ProjectionTy { 361 ProjectionTy {
296 associated_ty: from_chalk(db, projection_ty.associated_ty_id), 362 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
@@ -300,31 +366,31 @@ impl ToChalk for ProjectionTy {
300} 366}
301 367
302impl ToChalk for super::ProjectionPredicate { 368impl ToChalk for super::ProjectionPredicate {
303 type Chalk = chalk_ir::Normalize<ChalkIr>; 369 type Chalk = chalk_ir::Normalize<TypeFamily>;
304 370
305 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<ChalkIr> { 371 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<TypeFamily> {
306 chalk_ir::Normalize { 372 chalk_ir::Normalize {
307 projection: self.projection_ty.to_chalk(db), 373 projection: self.projection_ty.to_chalk(db),
308 ty: self.ty.to_chalk(db), 374 ty: self.ty.to_chalk(db),
309 } 375 }
310 } 376 }
311 377
312 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<ChalkIr>) -> Self { 378 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<TypeFamily>) -> Self {
313 unimplemented!() 379 unimplemented!()
314 } 380 }
315} 381}
316 382
317impl ToChalk for Obligation { 383impl ToChalk for Obligation {
318 type Chalk = chalk_ir::DomainGoal<ChalkIr>; 384 type Chalk = chalk_ir::DomainGoal<TypeFamily>;
319 385
320 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<ChalkIr> { 386 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<TypeFamily> {
321 match self { 387 match self {
322 Obligation::Trait(tr) => tr.to_chalk(db).cast(), 388 Obligation::Trait(tr) => tr.to_chalk(db).cast(),
323 Obligation::Projection(pr) => pr.to_chalk(db).cast(), 389 Obligation::Projection(pr) => pr.to_chalk(db).cast(),
324 } 390 }
325 } 391 }
326 392
327 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<ChalkIr>) -> Self { 393 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<TypeFamily>) -> Self {
328 unimplemented!() 394 unimplemented!()
329 } 395 }
330} 396}
@@ -348,16 +414,17 @@ where
348} 414}
349 415
350impl ToChalk for Arc<super::TraitEnvironment> { 416impl ToChalk for Arc<super::TraitEnvironment> {
351 type Chalk = chalk_ir::Environment<ChalkIr>; 417 type Chalk = chalk_ir::Environment<TypeFamily>;
352 418
353 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<ChalkIr> { 419 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<TypeFamily> {
354 let mut clauses = Vec::new(); 420 let mut clauses = Vec::new();
355 for pred in &self.predicates { 421 for pred in &self.predicates {
356 if pred.is_error() { 422 if pred.is_error() {
357 // for env, we just ignore errors 423 // for env, we just ignore errors
358 continue; 424 continue;
359 } 425 }
360 let program_clause: chalk_ir::ProgramClause<ChalkIr> = pred.clone().to_chalk(db).cast(); 426 let program_clause: chalk_ir::ProgramClause<TypeFamily> =
427 pred.clone().to_chalk(db).cast();
361 clauses.push(program_clause.into_from_env_clause()); 428 clauses.push(program_clause.into_from_env_clause());
362 } 429 }
363 chalk_ir::Environment::new().add_clauses(clauses) 430 chalk_ir::Environment::new().add_clauses(clauses)
@@ -365,7 +432,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
365 432
366 fn from_chalk( 433 fn from_chalk(
367 _db: &impl HirDatabase, 434 _db: &impl HirDatabase,
368 _env: chalk_ir::Environment<ChalkIr>, 435 _env: chalk_ir::Environment<TypeFamily>,
369 ) -> Arc<super::TraitEnvironment> { 436 ) -> Arc<super::TraitEnvironment> {
370 unimplemented!() 437 unimplemented!()
371 } 438 }
@@ -373,7 +440,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
373 440
374impl<T: ToChalk> ToChalk for super::InEnvironment<T> 441impl<T: ToChalk> ToChalk for super::InEnvironment<T>
375where 442where
376 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = ChalkIr>, 443 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = TypeFamily>,
377{ 444{
378 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 445 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
379 446
@@ -395,6 +462,51 @@ where
395 } 462 }
396} 463}
397 464
465impl ToChalk for builtin::BuiltinImplData {
466 type Chalk = ImplDatum;
467
468 fn to_chalk(self, db: &impl HirDatabase) -> ImplDatum {
469 let impl_type = chalk_rust_ir::ImplType::External;
470 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
471
472 let impl_datum_bound =
473 chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
474 let associated_ty_value_ids =
475 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
476 chalk_rust_ir::ImplDatum {
477 binders: make_binders(impl_datum_bound, self.num_vars),
478 impl_type,
479 polarity: chalk_rust_ir::Polarity::Positive,
480 associated_ty_value_ids,
481 }
482 }
483
484 fn from_chalk(_db: &impl HirDatabase, _data: ImplDatum) -> Self {
485 unimplemented!()
486 }
487}
488
489impl ToChalk for builtin::BuiltinImplAssocTyValueData {
490 type Chalk = AssociatedTyValue;
491
492 fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValue {
493 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) };
494
495 chalk_rust_ir::AssociatedTyValue {
496 associated_ty_id: self.assoc_ty_id.to_chalk(db),
497 impl_id: self.impl_.to_chalk(db),
498 value: make_binders(value_bound, self.num_vars),
499 }
500 }
501
502 fn from_chalk(
503 _db: &impl HirDatabase,
504 _data: AssociatedTyValue,
505 ) -> builtin::BuiltinImplAssocTyValueData {
506 unimplemented!()
507 }
508}
509
398fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 510fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
399 chalk_ir::Binders { 511 chalk_ir::Binders {
400 value, 512 value,
@@ -406,46 +518,46 @@ fn convert_where_clauses(
406 db: &impl HirDatabase, 518 db: &impl HirDatabase,
407 def: GenericDefId, 519 def: GenericDefId,
408 substs: &Substs, 520 substs: &Substs,
409) -> Vec<chalk_ir::QuantifiedWhereClause<ChalkIr>> { 521) -> Vec<chalk_ir::QuantifiedWhereClause<TypeFamily>> {
410 let generic_predicates = db.generic_predicates(def); 522 let generic_predicates = db.generic_predicates(def);
411 let mut result = Vec::with_capacity(generic_predicates.len()); 523 let mut result = Vec::with_capacity(generic_predicates.len());
412 for pred in generic_predicates.iter() { 524 for pred in generic_predicates.iter() {
413 if pred.is_error() { 525 if pred.is_error() {
414 // HACK: Return just the single predicate (which is always false 526 // skip errored predicates completely
415 // anyway), otherwise Chalk can easily get into slow situations 527 continue;
416 return vec![pred.clone().subst(substs).to_chalk(db)];
417 } 528 }
418 result.push(pred.clone().subst(substs).to_chalk(db)); 529 result.push(pred.clone().subst(substs).to_chalk(db));
419 } 530 }
420 result 531 result
421} 532}
422 533
423impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB> 534impl<'a, DB> chalk_solve::RustIrDatabase<TypeFamily> for ChalkContext<'a, DB>
424where 535where
425 DB: HirDatabase, 536 DB: HirDatabase,
426{ 537{
427 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum<ChalkIr>> { 538 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
428 self.db.associated_ty_data(id) 539 self.db.associated_ty_data(id)
429 } 540 }
430 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum<ChalkIr>> { 541 fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> {
431 self.db.trait_datum(self.krate, trait_id) 542 self.db.trait_datum(self.krate, trait_id)
432 } 543 }
433 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum<ChalkIr>> { 544 fn struct_datum(&self, struct_id: StructId) -> Arc<StructDatum> {
434 self.db.struct_datum(self.krate, struct_id) 545 self.db.struct_datum(self.krate, struct_id)
435 } 546 }
436 fn impl_datum(&self, impl_id: chalk_ir::ImplId) -> Arc<ImplDatum<ChalkIr>> { 547 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
437 self.db.impl_datum(self.krate, impl_id) 548 self.db.impl_datum(self.krate, impl_id)
438 } 549 }
439 fn impls_for_trait( 550 fn impls_for_trait(
440 &self, 551 &self,
441 trait_id: chalk_ir::TraitId, 552 trait_id: TraitId,
442 parameters: &[Parameter<ChalkIr>], 553 parameters: &[Parameter<TypeFamily>],
443 ) -> Vec<chalk_ir::ImplId> { 554 ) -> Vec<ImplId> {
444 debug!("impls_for_trait {:?}", trait_id); 555 debug!("impls_for_trait {:?}", trait_id);
445 if trait_id == UNKNOWN_TRAIT { 556 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
446 return Vec::new(); 557
447 } 558 // Note: Since we're using impls_for_trait, only impls where the trait
448 let trait_: TraitId = from_chalk(self.db, trait_id); 559 // can be resolved should ever reach Chalk. `impl_datum` relies on that
560 // and will panic if the trait can't be resolved.
449 let mut result: Vec<_> = self 561 let mut result: Vec<_> = self
450 .db 562 .db
451 .impls_for_trait(self.krate, trait_.into()) 563 .impls_for_trait(self.krate, trait_.into())
@@ -456,62 +568,47 @@ where
456 .collect(); 568 .collect();
457 569
458 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); 570 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
459 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { 571
460 for &fn_trait in 572 builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| {
461 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() 573 result.push(i.to_chalk(self.db))
462 { 574 });
463 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
464 if trait_ == actual_trait {
465 let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
466 result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
467 }
468 }
469 }
470 }
471 575
472 debug!("impls_for_trait returned {} impls", result.len()); 576 debug!("impls_for_trait returned {} impls", result.len());
473 result 577 result
474 } 578 }
475 fn impl_provided_for( 579 fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool {
476 &self,
477 auto_trait_id: chalk_ir::TraitId,
478 struct_id: chalk_ir::StructId,
479 ) -> bool {
480 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); 580 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
481 false // FIXME 581 false // FIXME
482 } 582 }
483 fn type_name(&self, _id: TypeKindId) -> Identifier { 583 fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
484 unimplemented!()
485 }
486 fn associated_ty_value(
487 &self,
488 id: chalk_rust_ir::AssociatedTyValueId,
489 ) -> Arc<AssociatedTyValue<ChalkIr>> {
490 self.db.associated_ty_value(self.krate.into(), id) 584 self.db.associated_ty_value(self.krate.into(), id)
491 } 585 }
492 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> { 586 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<TypeFamily>> {
493 vec![] 587 vec![]
494 } 588 }
495 fn local_impls_to_coherence_check( 589 fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec<ImplId> {
496 &self,
497 _trait_id: chalk_ir::TraitId,
498 ) -> Vec<chalk_ir::ImplId> {
499 // We don't do coherence checking (yet) 590 // We don't do coherence checking (yet)
500 unimplemented!() 591 unimplemented!()
501 } 592 }
593 fn as_struct_id(&self, id: &TypeName<TypeFamily>) -> Option<StructId> {
594 match id {
595 TypeName::Struct(struct_id) => Some(*struct_id),
596 _ => None,
597 }
598 }
502} 599}
503 600
504pub(crate) fn associated_ty_data_query( 601pub(crate) fn associated_ty_data_query(
505 db: &impl HirDatabase, 602 db: &impl HirDatabase,
506 id: TypeId, 603 id: AssocTypeId,
507) -> Arc<AssociatedTyDatum<ChalkIr>> { 604) -> Arc<AssociatedTyDatum> {
508 debug!("associated_ty_data {:?}", id); 605 debug!("associated_ty_data {:?}", id);
509 let type_alias: TypeAliasId = from_chalk(db, id); 606 let type_alias: TypeAliasId = from_chalk(db, id);
510 let trait_ = match type_alias.lookup(db).container { 607 let trait_ = match type_alias.lookup(db).container {
511 ContainerId::TraitId(t) => t, 608 AssocContainerId::TraitId(t) => t,
512 _ => panic!("associated type not in trait"), 609 _ => panic!("associated type not in trait"),
513 }; 610 };
514 let generic_params = db.generic_params(type_alias.into()); 611 let generic_params = generics(db, type_alias.into());
515 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 612 let bound_data = chalk_rust_ir::AssociatedTyDatumBound {
516 // FIXME add bounds and where clauses 613 // FIXME add bounds and where clauses
517 bounds: vec![], 614 bounds: vec![],
@@ -521,7 +618,7 @@ pub(crate) fn associated_ty_data_query(
521 trait_id: trait_.to_chalk(db), 618 trait_id: trait_.to_chalk(db),
522 id, 619 id,
523 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()), 620 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()),
524 binders: make_binders(bound_data, generic_params.count_params_including_parent()), 621 binders: make_binders(bound_data, generic_params.len()),
525 }; 622 };
526 Arc::new(datum) 623 Arc::new(datum)
527} 624}
@@ -529,35 +626,17 @@ pub(crate) fn associated_ty_data_query(
529pub(crate) fn trait_datum_query( 626pub(crate) fn trait_datum_query(
530 db: &impl HirDatabase, 627 db: &impl HirDatabase,
531 krate: CrateId, 628 krate: CrateId,
532 trait_id: chalk_ir::TraitId, 629 trait_id: TraitId,
533) -> Arc<TraitDatum<ChalkIr>> { 630) -> Arc<TraitDatum> {
534 debug!("trait_datum {:?}", trait_id); 631 debug!("trait_datum {:?}", trait_id);
535 if trait_id == UNKNOWN_TRAIT { 632 let trait_: hir_def::TraitId = from_chalk(db, trait_id);
536 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() };
537
538 let flags = chalk_rust_ir::TraitFlags {
539 auto: false,
540 marker: false,
541 upstream: true,
542 fundamental: false,
543 non_enumerable: true,
544 coinductive: false,
545 };
546 return Arc::new(TraitDatum {
547 id: trait_id,
548 binders: make_binders(trait_datum_bound, 1),
549 flags,
550 associated_ty_ids: vec![],
551 });
552 }
553 let trait_: TraitId = from_chalk(db, trait_id);
554 let trait_data = db.trait_data(trait_); 633 let trait_data = db.trait_data(trait_);
555 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 634 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
556 let generic_params = db.generic_params(trait_.into()); 635 let generic_params = generics(db, trait_.into());
557 let bound_vars = Substs::bound_vars(&generic_params); 636 let bound_vars = Substs::bound_vars(&generic_params);
558 let flags = chalk_rust_ir::TraitFlags { 637 let flags = chalk_rust_ir::TraitFlags {
559 auto: trait_data.auto, 638 auto: trait_data.auto,
560 upstream: trait_.module(db).krate != krate, 639 upstream: trait_.lookup(db).container.module(db).krate != krate,
561 non_enumerable: true, 640 non_enumerable: true,
562 coinductive: false, // only relevant for Chalk testing 641 coinductive: false, // only relevant for Chalk testing
563 // FIXME set these flags correctly 642 // FIXME set these flags correctly
@@ -580,17 +659,17 @@ pub(crate) fn trait_datum_query(
580pub(crate) fn struct_datum_query( 659pub(crate) fn struct_datum_query(
581 db: &impl HirDatabase, 660 db: &impl HirDatabase,
582 krate: CrateId, 661 krate: CrateId,
583 struct_id: chalk_ir::StructId, 662 struct_id: StructId,
584) -> Arc<StructDatum<ChalkIr>> { 663) -> Arc<StructDatum> {
585 debug!("struct_datum {:?}", struct_id); 664 debug!("struct_datum {:?}", struct_id);
586 let type_ctor: TypeCtor = from_chalk(db, struct_id); 665 let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id));
587 debug!("struct {:?} = {:?}", struct_id, type_ctor); 666 debug!("struct {:?} = {:?}", struct_id, type_ctor);
588 let num_params = type_ctor.num_ty_params(db); 667 let num_params = type_ctor.num_ty_params(db);
589 let upstream = type_ctor.krate(db) != Some(krate); 668 let upstream = type_ctor.krate(db) != Some(krate);
590 let where_clauses = type_ctor 669 let where_clauses = type_ctor
591 .as_generic_def() 670 .as_generic_def()
592 .map(|generic_def| { 671 .map(|generic_def| {
593 let generic_params = db.generic_params(generic_def.into()); 672 let generic_params = generics(db, generic_def.into());
594 let bound_vars = Substs::bound_vars(&generic_params); 673 let bound_vars = Substs::bound_vars(&generic_params);
595 convert_where_clauses(db, generic_def, &bound_vars) 674 convert_where_clauses(db, generic_def, &bound_vars)
596 }) 675 })
@@ -612,35 +691,34 @@ pub(crate) fn struct_datum_query(
612pub(crate) fn impl_datum_query( 691pub(crate) fn impl_datum_query(
613 db: &impl HirDatabase, 692 db: &impl HirDatabase,
614 krate: CrateId, 693 krate: CrateId,
615 impl_id: chalk_ir::ImplId, 694 impl_id: ImplId,
616) -> Arc<ImplDatum<ChalkIr>> { 695) -> Arc<ImplDatum> {
617 let _p = ra_prof::profile("impl_datum"); 696 let _p = ra_prof::profile("impl_datum");
618 debug!("impl_datum {:?}", impl_id); 697 debug!("impl_datum {:?}", impl_id);
619 let impl_: Impl = from_chalk(db, impl_id); 698 let impl_: Impl = from_chalk(db, impl_id);
620 match impl_ { 699 match impl_ {
621 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 700 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
622 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), 701 _ => Arc::new(builtin::impl_datum(db, krate, impl_).to_chalk(db)),
623 } 702 }
624 .unwrap_or_else(invalid_impl_datum)
625} 703}
626 704
627fn impl_block_datum( 705fn impl_block_datum(
628 db: &impl HirDatabase, 706 db: &impl HirDatabase,
629 krate: CrateId, 707 krate: CrateId,
630 chalk_id: chalk_ir::ImplId, 708 chalk_id: ImplId,
631 impl_id: ImplId, 709 impl_id: hir_def::ImplId,
632) -> Option<Arc<ImplDatum<ChalkIr>>> { 710) -> Arc<ImplDatum> {
633 let trait_ref = match db.impl_ty(impl_id) { 711 let trait_ref = db
634 ImplTy::TraitRef(it) => it, 712 .impl_trait(impl_id)
635 ImplTy::Inherent(_) => return None, 713 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
636 }; 714 .expect("invalid impl passed to Chalk");
637 let impl_data = db.impl_data(impl_id); 715 let impl_data = db.impl_data(impl_id);
638 716
639 let generic_params = db.generic_params(impl_id.into()); 717 let generic_params = generics(db, impl_id.into());
640 let bound_vars = Substs::bound_vars(&generic_params); 718 let bound_vars = Substs::bound_vars(&generic_params);
641 let trait_ref = trait_ref.subst(&bound_vars); 719 let trait_ref = trait_ref.subst(&bound_vars);
642 let trait_ = trait_ref.trait_; 720 let trait_ = trait_ref.trait_;
643 let impl_type = if impl_id.module(db).krate == krate { 721 let impl_type = if impl_id.lookup(db).container.module(db).krate == krate {
644 chalk_rust_ir::ImplType::Local 722 chalk_rust_ir::ImplType::Local
645 } else { 723 } else {
646 chalk_rust_ir::ImplType::External 724 chalk_rust_ir::ImplType::External
@@ -685,94 +763,20 @@ fn impl_block_datum(
685 polarity, 763 polarity,
686 associated_ty_value_ids, 764 associated_ty_value_ids,
687 }; 765 };
688 Some(Arc::new(impl_datum))
689}
690
691fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> {
692 let trait_ref = chalk_ir::TraitRef {
693 trait_id: UNKNOWN_TRAIT,
694 parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()],
695 };
696 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() };
697 let impl_datum = ImplDatum {
698 binders: make_binders(impl_datum_bound, 1),
699 impl_type: chalk_rust_ir::ImplType::External,
700 polarity: chalk_rust_ir::Polarity::Positive,
701 associated_ty_value_ids: Vec::new(),
702 };
703 Arc::new(impl_datum) 766 Arc::new(impl_datum)
704} 767}
705 768
706fn closure_fn_trait_impl_datum(
707 db: &impl HirDatabase,
708 krate: CrateId,
709 data: super::ClosureFnTraitImplData,
710) -> Option<Arc<ImplDatum<ChalkIr>>> {
711 // for some closure |X, Y| -> Z:
712 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
713
714 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
715
716 // validate FnOnce trait, since we need it in the assoc ty value definition
717 // and don't want to return a valid value only to find out later that FnOnce
718 // is broken
719 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
720 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
721
722 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
723 Expr::Lambda { args, .. } => args.len() as u16,
724 _ => {
725 log::warn!("closure for closure type {:?} not found", data);
726 0
727 }
728 };
729
730 let arg_ty = Ty::apply(
731 TypeCtor::Tuple { cardinality: num_args },
732 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
733 );
734 let sig_ty = Ty::apply(
735 TypeCtor::FnPtr { num_args },
736 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
737 );
738
739 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
740
741 let trait_ref = TraitRef {
742 trait_: trait_.into(),
743 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
744 };
745
746 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
747
748 let impl_type = chalk_rust_ir::ImplType::External;
749
750 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
751 trait_ref: trait_ref.to_chalk(db),
752 where_clauses: Vec::new(),
753 };
754 let impl_datum = ImplDatum {
755 binders: make_binders(impl_datum_bound, num_args as usize + 1),
756 impl_type,
757 polarity: chalk_rust_ir::Polarity::Positive,
758 associated_ty_value_ids: vec![output_ty_id],
759 };
760 Some(Arc::new(impl_datum))
761}
762
763pub(crate) fn associated_ty_value_query( 769pub(crate) fn associated_ty_value_query(
764 db: &impl HirDatabase, 770 db: &impl HirDatabase,
765 krate: CrateId, 771 krate: CrateId,
766 id: chalk_rust_ir::AssociatedTyValueId, 772 id: AssociatedTyValueId,
767) -> Arc<chalk_rust_ir::AssociatedTyValue<ChalkIr>> { 773) -> Arc<AssociatedTyValue> {
768 let data: AssocTyValue = from_chalk(db, id); 774 let data: AssocTyValue = from_chalk(db, id);
769 match data { 775 match data {
770 AssocTyValue::TypeAlias(type_alias) => { 776 AssocTyValue::TypeAlias(type_alias) => {
771 type_alias_associated_ty_value(db, krate, type_alias) 777 type_alias_associated_ty_value(db, krate, type_alias)
772 } 778 }
773 AssocTyValue::ClosureFnTraitImplOutput(data) => { 779 _ => Arc::new(builtin::associated_ty_value(db, krate, data).to_chalk(db)),
774 closure_fn_trait_output_assoc_ty_value(db, krate, data)
775 }
776 } 780 }
777} 781}
778 782
@@ -780,24 +784,20 @@ fn type_alias_associated_ty_value(
780 db: &impl HirDatabase, 784 db: &impl HirDatabase,
781 _krate: CrateId, 785 _krate: CrateId,
782 type_alias: TypeAliasId, 786 type_alias: TypeAliasId,
783) -> Arc<AssociatedTyValue<ChalkIr>> { 787) -> Arc<AssociatedTyValue> {
784 let type_alias_data = db.type_alias_data(type_alias); 788 let type_alias_data = db.type_alias_data(type_alias);
785 let impl_id = match type_alias.lookup(db).container { 789 let impl_id = match type_alias.lookup(db).container {
786 ContainerId::ImplId(it) => it, 790 AssocContainerId::ImplId(it) => it,
787 _ => panic!("assoc ty value should be in impl"), 791 _ => panic!("assoc ty value should be in impl"),
788 }; 792 };
789 793
790 let trait_ref = match db.impl_ty(impl_id) { 794 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved
791 ImplTy::TraitRef(it) => it,
792 // we don't return any assoc ty values if the impl'd trait can't be resolved
793 ImplTy::Inherent(_) => panic!("assoc ty value should not exist"),
794 };
795 795
796 let assoc_ty = db 796 let assoc_ty = db
797 .trait_data(trait_ref.trait_) 797 .trait_data(trait_ref.trait_)
798 .associated_type_by_name(&type_alias_data.name) 798 .associated_type_by_name(&type_alias_data.name)
799 .expect("assoc ty value should not exist"); // validated when building the impl data as well 799 .expect("assoc ty value should not exist"); // validated when building the impl data as well
800 let generic_params = db.generic_params(impl_id.into()); 800 let generic_params = generics(db, impl_id.into());
801 let bound_vars = Substs::bound_vars(&generic_params); 801 let bound_vars = Substs::bound_vars(&generic_params);
802 let ty = db.ty(type_alias.into()).subst(&bound_vars); 802 let ty = db.ty(type_alias.into()).subst(&bound_vars);
803 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; 803 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
@@ -809,53 +809,6 @@ fn type_alias_associated_ty_value(
809 Arc::new(value) 809 Arc::new(value)
810} 810}
811 811
812fn closure_fn_trait_output_assoc_ty_value(
813 db: &impl HirDatabase,
814 krate: CrateId,
815 data: super::ClosureFnTraitImplData,
816) -> Arc<AssociatedTyValue<ChalkIr>> {
817 let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db);
818
819 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
820 Expr::Lambda { args, .. } => args.len() as u16,
821 _ => {
822 log::warn!("closure for closure type {:?} not found", data);
823 0
824 }
825 };
826
827 let output_ty = Ty::Bound(num_args.into());
828
829 let fn_once_trait =
830 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
831
832 let output_ty_id = db
833 .trait_data(fn_once_trait)
834 .associated_type_by_name(&name::OUTPUT_TYPE)
835 .expect("assoc ty value should not exist");
836
837 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
838
839 let value = chalk_rust_ir::AssociatedTyValue {
840 associated_ty_id: output_ty_id.to_chalk(db),
841 impl_id,
842 value: make_binders(value_bound, num_args as usize + 1),
843 };
844 Arc::new(value)
845}
846
847fn get_fn_trait(
848 db: &impl HirDatabase,
849 krate: CrateId,
850 fn_trait: super::FnTrait,
851) -> Option<TraitId> {
852 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
853 match target {
854 LangItemTarget::TraitId(t) => Some(t),
855 _ => None,
856 }
857}
858
859fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { 812fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
860 T::from_intern_id(InternId::from(chalk_id.index)) 813 T::from_intern_id(InternId::from(chalk_id.index))
861} 814}
@@ -863,27 +816,27 @@ fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
863 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } 816 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
864} 817}
865 818
866impl From<chalk_ir::StructId> for crate::TypeCtorId { 819impl From<StructId> for crate::TypeCtorId {
867 fn from(struct_id: chalk_ir::StructId) -> Self { 820 fn from(struct_id: StructId) -> Self {
868 id_from_chalk(struct_id.0) 821 InternKey::from_intern_id(struct_id.0)
869 } 822 }
870} 823}
871 824
872impl From<crate::TypeCtorId> for chalk_ir::StructId { 825impl From<crate::TypeCtorId> for StructId {
873 fn from(type_ctor_id: crate::TypeCtorId) -> Self { 826 fn from(type_ctor_id: crate::TypeCtorId) -> Self {
874 chalk_ir::StructId(id_to_chalk(type_ctor_id)) 827 chalk_ir::StructId(type_ctor_id.as_intern_id())
875 } 828 }
876} 829}
877 830
878impl From<chalk_ir::ImplId> for crate::traits::GlobalImplId { 831impl From<ImplId> for crate::traits::GlobalImplId {
879 fn from(impl_id: chalk_ir::ImplId) -> Self { 832 fn from(impl_id: ImplId) -> Self {
880 id_from_chalk(impl_id.0) 833 InternKey::from_intern_id(impl_id.0)
881 } 834 }
882} 835}
883 836
884impl From<crate::traits::GlobalImplId> for chalk_ir::ImplId { 837impl From<crate::traits::GlobalImplId> for ImplId {
885 fn from(impl_id: crate::traits::GlobalImplId) -> Self { 838 fn from(impl_id: crate::traits::GlobalImplId) -> Self {
886 chalk_ir::ImplId(id_to_chalk(impl_id)) 839 chalk_ir::ImplId(impl_id.as_intern_id())
887 } 840 }
888} 841}
889 842
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index e4ba890ef..0b1806a84 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -5,14 +5,14 @@ use std::sync::Arc;
5use hir_def::{ 5use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData},
9 path::Path,
8 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
9 type_ref::TypeRef, 11 type_ref::TypeRef,
10 TraitId, TypeAliasId, VariantId, 12 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
11}; 13};
12use hir_expand::name::{self, Name}; 14use hir_expand::name::{name, Name};
13 15
14// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
15// We should return a `TraitREf` here.
16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { 16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
17 let resolver = trait_.resolver(db); 17 let resolver = trait_.resolver(db);
18 // returning the iterator directly doesn't easily work because of 18 // returning the iterator directly doesn't easily work because of
@@ -23,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
23 .where_predicates 23 .where_predicates
24 .iter() 24 .iter()
25 .filter_map(|pred| match &pred.type_ref { 25 .filter_map(|pred| match &pred.type_ref {
26 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), 26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
27 _ => None, 27 _ => None,
28 }) 28 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
30 Some(TypeNs::TraitId(t)) => Some(t), 30 Some(TypeNs::TraitId(t)) => Some(t),
31 _ => None, 31 _ => None,
32 }) 32 })
@@ -82,3 +82,81 @@ pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
82 } 82 }
83 Arc::get_mut(a).unwrap() 83 Arc::get_mut(a).unwrap()
84} 84}
85
86pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics {
87 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
88 Generics { def, params: db.generic_params(def), parent_generics }
89}
90
91pub(crate) struct Generics {
92 def: GenericDefId,
93 pub(crate) params: Arc<GenericParams>,
94 parent_generics: Option<Box<Generics>>,
95}
96
97impl Generics {
98 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
99 self.parent_generics
100 .as_ref()
101 .into_iter()
102 .flat_map(|it| it.params.types.iter())
103 .chain(self.params.types.iter())
104 .enumerate()
105 .map(|(i, (_local_id, p))| (i as u32, p))
106 }
107
108 pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
109 self.parent_generics
110 .as_ref()
111 .into_iter()
112 .flat_map(|it| it.params.types.iter())
113 .enumerate()
114 .map(|(i, (_local_id, p))| (i as u32, p))
115 }
116
117 pub(crate) fn len(&self) -> usize {
118 self.len_split().0
119 }
120 /// (total, parents, child)
121 pub(crate) fn len_split(&self) -> (usize, usize, usize) {
122 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
123 let child = self.params.types.len();
124 (parent + child, parent, child)
125 }
126 pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 {
127 self.find_param(param).0
128 }
129 pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
130 self.find_param(param).1.name.clone()
131 }
132 fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
133 if param.parent == self.def {
134 let (idx, (_local_id, data)) = self
135 .params
136 .types
137 .iter()
138 .enumerate()
139 .find(|(_, (idx, _))| *idx == param.local_id)
140 .unwrap();
141 let (_total, parent_len, _child) = self.len_split();
142 return ((parent_len + idx) as u32, data);
143 }
144 self.parent_generics.as_ref().unwrap().find_param(param)
145 }
146}
147
148fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
149 let container = match def {
150 GenericDefId::FunctionId(it) => it.lookup(db).container,
151 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
152 GenericDefId::ConstId(it) => it.lookup(db).container,
153 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
154 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None,
155 };
156
157 match container {
158 AssocContainerId::ImplId(it) => Some(it.into()),
159 AssocContainerId::TraitId(it) => Some(it.into()),
160 AssocContainerId::ContainerId(_) => None,
161 }
162}
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index e6383dd35..e3439ae31 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
11wasm = [] 11wasm = []
12 12
13[dependencies] 13[dependencies]
14either = "1.5"
14format-buf = "1.0.0" 15format-buf = "1.0.0"
15itertools = "0.8.0" 16itertools = "0.8.0"
16join_to_string = "0.1.3" 17join_to_string = "0.1.3"
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index d559dc4d0..2c2b6fa48 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,24 +1,26 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::SourceDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 algo::ancestors_at_offset,
6 ast::{self, ArgListOwner}, 5 ast::{self, ArgListOwner},
7 match_ast, AstNode, SyntaxNode, TextUnit, 6 match_ast, AstNode, SyntaxNode,
8}; 7};
9use test_utils::tested_by; 8use test_utils::tested_by;
10 9
11use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature}; 10use crate::{
11 db::RootDatabase, expand::descend_into_macros, CallInfo, FilePosition, FunctionSignature,
12};
12 13
13/// Computes parameter information for the given call expression. 14/// Computes parameter information for the given call expression.
14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 15pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
15 let parse = db.parse(position.file_id); 16 let file = db.parse_or_expand(position.file_id.into())?;
16 let syntax = parse.tree().syntax().clone(); 17 let token = file.token_at_offset(position.offset).next()?;
18 let token = descend_into_macros(db, position.file_id, token);
17 19
18 // Find the calling expression and it's NameRef 20 // Find the calling expression and it's NameRef
19 let calling_node = FnCallNode::with_node(&syntax, position.offset)?; 21 let calling_node = FnCallNode::with_node(&token.value.parent())?;
20 let name_ref = calling_node.name_ref()?; 22 let name_ref = calling_node.name_ref()?;
21 let name_ref = hir::Source::new(position.file_id.into(), name_ref.syntax()); 23 let name_ref = token.with_value(name_ref.syntax());
22 24
23 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None); 25 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);
24 let (mut call_info, has_self) = match &calling_node { 26 let (mut call_info, has_self) = match &calling_node {
@@ -93,8 +95,8 @@ enum FnCallNode {
93} 95}
94 96
95impl FnCallNode { 97impl FnCallNode {
96 fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> { 98 fn with_node(syntax: &SyntaxNode) -> Option<FnCallNode> {
97 ancestors_at_offset(syntax, offset).find_map(|node| { 99 syntax.ancestors().find_map(|node| {
98 match_ast! { 100 match_ast! {
99 match node { 101 match node {
100 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, 102 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
@@ -589,4 +591,25 @@ fn f() {
589 assert_eq!(info.label(), "foo!()"); 591 assert_eq!(info.label(), "foo!()");
590 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 592 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string()));
591 } 593 }
594
595 #[test]
596 fn fn_signature_for_call_in_macro() {
597 let info = call_info(
598 r#"
599 macro_rules! id {
600 ($($tt:tt)*) => { $($tt)* }
601 }
602 fn foo() {
603
604 }
605 id! {
606 fn bar() {
607 foo(<|>);
608 }
609 }
610 "#,
611 );
612
613 assert_eq!(info.label(), "fn foo()");
614 }
592} 615}
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index 4a76d1dd8..387a9cafb 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -270,7 +270,6 @@ impl RootDatabase {
270 270
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);
274 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 273 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
275 274
276 self.query(hir::db::ExprScopesQuery).sweep(sweep); 275 self.query(hir::db::ExprScopesQuery).sweep(sweep);
@@ -309,7 +308,6 @@ impl RootDatabase {
309 hir::db::StructDataQuery 308 hir::db::StructDataQuery
310 hir::db::EnumDataQuery 309 hir::db::EnumDataQuery
311 hir::db::TraitDataQuery 310 hir::db::TraitDataQuery
312 hir::db::RawItemsWithSourceMapQuery
313 hir::db::RawItemsQuery 311 hir::db::RawItemsQuery
314 hir::db::CrateDefMapQuery 312 hir::db::CrateDefMapQuery
315 hir::db::GenericParamsQuery 313 hir::db::GenericParamsQuery
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index b6fe48627..294964887 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -27,7 +27,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
27 complete_methods(acc, ctx, &receiver_ty); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
@@ -217,6 +217,39 @@ mod tests {
217 } 217 }
218 218
219 #[test] 219 #[test]
220 fn test_method_completion_only_fitting_impls() {
221 assert_debug_snapshot!(
222 do_ref_completion(
223 r"
224 struct A<T> {}
225 impl A<u32> {
226 fn the_method(&self) {}
227 }
228 impl A<i32> {
229 fn the_other_method(&self) {}
230 }
231 fn foo(a: A<u32>) {
232 a.<|>
233 }
234 ",
235 ),
236 @r###"
237 [
238 CompletionItem {
239 label: "the_method()",
240 source_range: [243; 243),
241 delete: [243; 243),
242 insert: "the_method()$0",
243 kind: Method,
244 lookup: "the_method",
245 detail: "fn the_method(&self)",
246 },
247 ]
248 "###
249 );
250 }
251
252 #[test]
220 fn test_trait_method_completion() { 253 fn test_trait_method_completion() {
221 assert_debug_snapshot!( 254 assert_debug_snapshot!(
222 do_ref_completion( 255 do_ref_completion(
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 89e0009a1..cc1f7c830 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Either, HasSource, PathResolution}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
@@ -18,17 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
18 match def { 18 match def {
19 hir::ModuleDef::Module(module) => { 19 hir::ModuleDef::Module(module) => {
20 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
21 for (name, def, import) in module_scope { 21 for (name, def) in module_scope {
22 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { 22 if ctx.use_item_syntax.is_some() {
23 if ctx.use_item_syntax.is_some() { 23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
24 tested_by!(dont_complete_primitive_in_use); 24 tested_by!(dont_complete_primitive_in_use);
25 continue; 25 continue;
26 } 26 }
27 } 27 if let ScopeDef::Unknown = def {
28 if Some(module) == ctx.module { 28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
29 if let Some(import) = import { 29 if &name_ref.syntax().text() == name.to_string().as_str() {
30 if let Either::A(use_tree) = import.source(ctx.db).value {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion 30 // for `use self::foo<|>`, don't suggest `foo` as a completion
33 tested_by!(dont_complete_current_use); 31 tested_by!(dont_complete_current_use);
34 continue; 32 continue;
@@ -36,6 +34,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
36 } 34 }
37 } 35 }
38 } 36 }
37
39 acc.add_resolution(ctx, name.to_string(), &def); 38 acc.add_resolution(ctx, name.to_string(), &def);
40 } 39 }
41 } 40 }
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 646a30c76..5470dc291 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -12,7 +12,7 @@ use crate::{
12}; 12};
13 13
14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
15 if ctx.db.feature_flags.get("completion.enable-postfix") == false { 15 if !ctx.db.feature_flags.get("completion.enable-postfix") {
16 return; 16 return;
17 } 17 }
18 18
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index d5739b58a..458d7525e 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -873,4 +873,41 @@ mod tests {
873 "### 873 "###
874 ); 874 );
875 } 875 }
876
877 #[test]
878 fn completes_local_item() {
879 assert_debug_snapshot!(
880 do_reference_completion(
881 "
882 //- /main.rs
883 fn main() {
884 return f<|>;
885 fn frobnicate() {}
886 }
887 "
888 ),
889 @r###"
890 [
891 CompletionItem {
892 label: "frobnicate()",
893 source_range: [23; 24),
894 delete: [23; 24),
895 insert: "frobnicate()$0",
896 kind: Function,
897 lookup: "frobnicate",
898 detail: "fn frobnicate()",
899 },
900 CompletionItem {
901 label: "main()",
902 source_range: [23; 24),
903 delete: [23; 24),
904 insert: "main()$0",
905 kind: Function,
906 lookup: "main",
907 detail: "fn main()",
908 },
909 ]
910 "###
911 )
912 }
876} 913}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index b8345c91d..48d69f7e5 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -19,6 +19,7 @@ pub(crate) struct CompletionContext<'a> {
19 pub(super) offset: TextUnit, 19 pub(super) offset: TextUnit,
20 pub(super) token: SyntaxToken, 20 pub(super) token: SyntaxToken,
21 pub(super) module: Option<hir::Module>, 21 pub(super) module: Option<hir::Module>,
22 pub(super) name_ref_syntax: Option<ast::NameRef>,
22 pub(super) function_syntax: Option<ast::FnDef>, 23 pub(super) function_syntax: Option<ast::FnDef>,
23 pub(super) use_item_syntax: Option<ast::UseItem>, 24 pub(super) use_item_syntax: Option<ast::UseItem>,
24 pub(super) record_lit_syntax: Option<ast::RecordLit>, 25 pub(super) record_lit_syntax: Option<ast::RecordLit>,
@@ -54,13 +55,13 @@ impl<'a> CompletionContext<'a> {
54 let src = hir::ModuleSource::from_position(db, position); 55 let src = hir::ModuleSource::from_position(db, position);
55 let module = hir::Module::from_definition( 56 let module = hir::Module::from_definition(
56 db, 57 db,
57 hir::Source { file_id: position.file_id.into(), value: src }, 58 hir::InFile { file_id: position.file_id.into(), value: src },
58 ); 59 );
59 let token = 60 let token =
60 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; 61 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?;
61 let analyzer = hir::SourceAnalyzer::new( 62 let analyzer = hir::SourceAnalyzer::new(
62 db, 63 db,
63 hir::Source::new(position.file_id.into(), &token.parent()), 64 hir::InFile::new(position.file_id.into(), &token.parent()),
64 Some(position.offset), 65 Some(position.offset),
65 ); 66 );
66 let mut ctx = CompletionContext { 67 let mut ctx = CompletionContext {
@@ -69,6 +70,7 @@ impl<'a> CompletionContext<'a> {
69 token, 70 token,
70 offset: position.offset, 71 offset: position.offset,
71 module, 72 module,
73 name_ref_syntax: None,
72 function_syntax: None, 74 function_syntax: None,
73 use_item_syntax: None, 75 use_item_syntax: None,
74 record_lit_syntax: None, 76 record_lit_syntax: None,
@@ -142,6 +144,8 @@ impl<'a> CompletionContext<'a> {
142 } 144 }
143 145
144 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 146 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
147 self.name_ref_syntax =
148 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
145 let name_range = name_ref.syntax().text_range(); 149 let name_range = name_ref.syntax().text_range();
146 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 150 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
147 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 151 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset);
@@ -188,10 +192,9 @@ impl<'a> CompletionContext<'a> {
188 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 192 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
189 self.has_type_args = segment.type_arg_list().is_some(); 193 self.has_type_args = segment.type_arg_list().is_some();
190 194
191 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 195 if let Some(path) = hir::Path::from_ast(path.clone()) {
192 if !path.is_ident() { 196 if let Some(path_prefix) = path.qualifier() {
193 path.segments.pop().unwrap(); 197 self.path_prefix = Some(path_prefix);
194 self.path_prefix = Some(path);
195 return; 198 return;
196 } 199 }
197 } 200 }
@@ -240,16 +243,15 @@ impl<'a> CompletionContext<'a> {
240 .expr() 243 .expr()
241 .map(|e| e.syntax().text_range()) 244 .map(|e| e.syntax().text_range())
242 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 245 .and_then(|r| find_node_with_range(original_file.syntax(), r));
243 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = 246 self.dot_receiver_is_ambiguous_float_literal =
244 &self.dot_receiver 247 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
245 { 248 match l.kind() {
246 match l.kind() { 249 ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
247 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'), 250 _ => false,
248 _ => false, 251 }
252 } else {
253 false
249 } 254 }
250 } else {
251 false
252 }
253 } 255 }
254 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 256 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
255 // As above 257 // As above
diff --git a/crates/ra_ide/src/db.rs b/crates/ra_ide/src/db.rs
index f739ebecd..47d0aed6f 100644
--- a/crates/ra_ide/src/db.rs
+++ b/crates/ra_ide/src/db.rs
@@ -5,7 +5,7 @@ use std::sync::Arc;
5use ra_db::{ 5use ra_db::{
6 salsa::{self, Database, Durability}, 6 salsa::{self, Database, Durability},
7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, 7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath,
8 SourceDatabase, SourceDatabaseExt, SourceRootId, 8 SourceDatabase, SourceRootId,
9}; 9};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
@@ -49,18 +49,6 @@ impl FileLoader for RootDatabase {
49 } 49 }
50} 50}
51 51
52impl hir::debug::HirDebugHelper for RootDatabase {
53 fn crate_name(&self, krate: CrateId) -> Option<String> {
54 self.debug_data.crate_names.get(&krate).cloned()
55 }
56 fn file_path(&self, file_id: FileId) -> Option<String> {
57 let source_root_id = self.file_source_root(file_id);
58 let source_root_path = self.debug_data.root_paths.get(&source_root_id)?;
59 let file_path = self.file_relative_path(file_id);
60 Some(format!("{}/{}", source_root_path, file_path))
61 }
62}
63
64impl salsa::Database for RootDatabase { 52impl salsa::Database for RootDatabase {
65 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 53 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
66 &self.runtime 54 &self.runtime
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index cc1ccab4b..c50a70d99 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -96,7 +96,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
96 }); 96 });
97 let source_file = db.parse(file_id).tree(); 97 let source_file = db.parse(file_id).tree();
98 let src = 98 let src =
99 hir::Source { file_id: file_id.into(), value: hir::ModuleSource::SourceFile(source_file) }; 99 hir::InFile { file_id: file_id.into(), value: hir::ModuleSource::SourceFile(source_file) };
100 if let Some(m) = hir::Module::from_definition(db, src) { 100 if let Some(m) = hir::Module::from_definition(db, src) {
101 m.diagnostics(db, &mut sink); 101 m.diagnostics(db, &mut sink);
102 }; 102 };
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 30617412a..fbe89841b 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature;
15pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode}; 16pub use structure::{file_structure, StructureNode};
17 17
18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; 18pub(crate) use navigation_target::ToNav;
19pub(crate) use short_label::ShortLabel; 19pub(crate) use short_label::ShortLabel;
20 20
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 21pub(crate) fn function_label(node: &ast::FnDef) -> String {
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 6ac60722b..b9ae67828 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -1,11 +1,12 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource, Source}; 3use either::Either;
4use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource};
4use ra_db::{FileId, SourceDatabase}; 5use ra_db::{FileId, SourceDatabase};
5use ra_syntax::{ 6use ra_syntax::{
6 ast::{self, DocCommentsOwner, NameOwner}, 7 ast::{self, DocCommentsOwner, NameOwner},
7 match_ast, AstNode, SmolStr, 8 match_ast, AstNode, SmolStr,
8 SyntaxKind::{self, BIND_PAT}, 9 SyntaxKind::{self, BIND_PAT, TYPE_PARAM},
9 TextRange, 10 TextRange,
10}; 11};
11 12
@@ -141,7 +142,7 @@ impl NavigationTarget {
141 /// Allows `NavigationTarget` to be created from a `NameOwner` 142 /// Allows `NavigationTarget` to be created from a `NameOwner`
142 pub(crate) fn from_named( 143 pub(crate) fn from_named(
143 db: &RootDatabase, 144 db: &RootDatabase,
144 node: Source<&dyn ast::NameOwner>, 145 node: InFile<&dyn ast::NameOwner>,
145 docs: Option<String>, 146 docs: Option<String>,
146 description: Option<String>, 147 description: Option<String>,
147 ) -> NavigationTarget { 148 ) -> NavigationTarget {
@@ -230,34 +231,20 @@ impl ToNav for hir::Module {
230 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 231 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
231 let src = self.definition_source(db); 232 let src = self.definition_source(db);
232 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 233 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
233 match &src.value { 234 let syntax = match &src.value {
234 ModuleSource::SourceFile(node) => { 235 ModuleSource::SourceFile(node) => node.syntax(),
235 let frange = original_range(db, src.with_value(node.syntax())); 236 ModuleSource::Module(node) => node.syntax(),
236 237 };
237 NavigationTarget::from_syntax( 238 let frange = original_range(db, src.with_value(syntax));
238 frange.file_id, 239 NavigationTarget::from_syntax(
239 name, 240 frange.file_id,
240 None, 241 name,
241 frange.range, 242 None,
242 node.syntax().kind(), 243 frange.range,
243 None, 244 syntax.kind(),
244 None, 245 None,
245 ) 246 None,
246 } 247 )
247 ModuleSource::Module(node) => {
248 let frange = original_range(db, src.with_value(node.syntax()));
249
250 NavigationTarget::from_syntax(
251 frange.file_id,
252 name,
253 None,
254 frange.range,
255 node.syntax().kind(),
256 node.doc_comment_text(),
257 node.short_label(),
258 )
259 }
260 }
261 } 248 }
262} 249}
263 250
@@ -341,22 +328,43 @@ impl ToNav for hir::AssocItem {
341impl ToNav for hir::Local { 328impl ToNav for hir::Local {
342 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 329 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
343 let src = self.source(db); 330 let src = self.source(db);
344 let (full_range, focus_range) = match src.value { 331 let node = match &src.value {
345 Either::A(it) => { 332 Either::Left(bind_pat) => {
346 (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) 333 bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone())
347 } 334 }
348 Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), 335 Either::Right(it) => it.syntax().clone(),
349 }; 336 };
337 let full_range = original_range(db, src.with_value(&node));
350 let name = match self.name(db) { 338 let name = match self.name(db) {
351 Some(it) => it.to_string().into(), 339 Some(it) => it.to_string().into(),
352 None => "".into(), 340 None => "".into(),
353 }; 341 };
354 NavigationTarget { 342 NavigationTarget {
355 file_id: src.file_id.original_file(db), 343 file_id: full_range.file_id,
356 name, 344 name,
357 kind: BIND_PAT, 345 kind: BIND_PAT,
358 full_range, 346 full_range: full_range.range,
359 focus_range, 347 focus_range: None,
348 container_name: None,
349 description: None,
350 docs: None,
351 }
352 }
353}
354
355impl ToNav for hir::TypeParam {
356 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
357 let src = self.source(db);
358 let range = match src.value {
359 Either::Left(it) => it.syntax().text_range(),
360 Either::Right(it) => it.syntax().text_range(),
361 };
362 NavigationTarget {
363 file_id: src.file_id.original_file(db),
364 name: self.name(db).to_string().into(),
365 kind: TYPE_PARAM,
366 full_range: range,
367 focus_range: None,
360 container_name: None, 368 container_name: None,
361 description: None, 369 description: None,
362 docs: None, 370 docs: None,
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs
index 2f1abf509..7a22bb0a4 100644
--- a/crates/ra_ide/src/expand.rs
+++ b/crates/ra_ide/src/expand.rs
@@ -1,42 +1,71 @@
1//! Utilities to work with files, produced by macros. 1//! Utilities to work with files, produced by macros.
2use std::iter::successors; 2use std::iter::successors;
3 3
4use hir::Source; 4use hir::{InFile, Origin};
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; 6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
7 7
8use crate::{db::RootDatabase, FileRange}; 8use crate::{db::RootDatabase, FileRange};
9 9
10pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { 10pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange {
11 let expansion = match node.file_id.expansion_info(db) { 11 if let Some((range, Origin::Call)) = original_range_and_origin(db, node) {
12 None => { 12 return range;
13 }
14
15 if let Some(expansion) = node.file_id.expansion_info(db) {
16 if let Some(call_node) = expansion.call_node() {
13 return FileRange { 17 return FileRange {
14 file_id: node.file_id.original_file(db), 18 file_id: call_node.file_id.original_file(db),
15 range: node.value.text_range(), 19 range: call_node.value.text_range(),
16 } 20 };
17 } 21 }
18 Some(it) => it, 22 }
19 }; 23
20 // FIXME: the following completely wrong. 24 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() }
21 // 25}
22 // *First*, we should try to map first and last tokens of node, and, if that 26
23 // fails, return the range of the overall macro expansions. 27fn original_range_and_origin(
24 // 28 db: &RootDatabase,
25 // *Second*, we should handle recurside macro expansions 29 node: InFile<&SyntaxNode>,
26 30) -> Option<(FileRange, Origin)> {
27 let token = node 31 let expansion = node.file_id.expansion_info(db)?;
28 .value 32
29 .descendants_with_tokens() 33 // the input node has only one token ?
30 .filter_map(|it| it.into_token()) 34 let single = node.value.first_token()? == node.value.last_token()?;
31 .find_map(|it| expansion.map_token_up(node.with_value(&it))); 35
32 36 // FIXME: We should handle recurside macro expansions
33 match token { 37 let (range, origin) = node.value.descendants().find_map(|it| {
34 Some(it) => { 38 let first = it.first_token()?;
35 FileRange { file_id: it.file_id.original_file(db), range: it.value.text_range() } 39 let last = it.last_token()?;
40
41 if !single && first == last {
42 return None;
36 } 43 }
37 None => { 44
38 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } 45 // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens
46 let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?;
47 let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?;
48
49 if first.file_id != last.file_id || first_origin != last_origin {
50 return None;
39 } 51 }
52
53 // FIXME: Add union method in TextRange
54 Some((
55 first.with_value(union_range(first.value.text_range(), last.value.text_range())),
56 first_origin,
57 ))
58 })?;
59
60 return Some((
61 FileRange { file_id: range.file_id.original_file(db), range: range.value },
62 origin,
63 ));
64
65 fn union_range(a: TextRange, b: TextRange) -> TextRange {
66 let start = a.start().min(b.start());
67 let end = a.end().max(b.end());
68 TextRange::from_to(start, end)
40 } 69 }
41} 70}
42 71
@@ -44,8 +73,8 @@ pub(crate) fn descend_into_macros(
44 db: &RootDatabase, 73 db: &RootDatabase,
45 file_id: FileId, 74 file_id: FileId,
46 token: SyntaxToken, 75 token: SyntaxToken,
47) -> Source<SyntaxToken> { 76) -> InFile<SyntaxToken> {
48 let src = Source::new(file_id.into(), token); 77 let src = InFile::new(file_id.into(), token);
49 78
50 successors(Some(src), |token| { 79 successors(Some(src), |token| {
51 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 80 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index abc602244..bdbc31704 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -22,7 +22,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
22 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?; 22 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
23 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; 23 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;
24 24
25 let source = hir::Source::new(position.file_id.into(), mac.syntax()); 25 let source = hir::InFile::new(position.file_id.into(), mac.syntax());
26 let expanded = expand_macro_recur(db, source, source.with_value(&mac))?; 26 let expanded = expand_macro_recur(db, source, source.with_value(&mac))?;
27 27
28 // FIXME: 28 // FIXME:
@@ -34,8 +34,8 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
34 34
35fn expand_macro_recur( 35fn expand_macro_recur(
36 db: &RootDatabase, 36 db: &RootDatabase,
37 source: hir::Source<&SyntaxNode>, 37 source: hir::InFile<&SyntaxNode>,
38 macro_call: hir::Source<&ast::MacroCall>, 38 macro_call: hir::InFile<&ast::MacroCall>,
39) -> Option<SyntaxNode> { 39) -> Option<SyntaxNode> {
40 let analyzer = hir::SourceAnalyzer::new(db, source, None); 40 let analyzer = hir::SourceAnalyzer::new(db, source, None);
41 let expansion = analyzer.expand(db, macro_call)?; 41 let expansion = analyzer.expand(db, macro_call)?;
@@ -46,7 +46,7 @@ fn expand_macro_recur(
46 let mut replaces = FxHashMap::default(); 46 let mut replaces = FxHashMap::default();
47 47
48 for child in children.into_iter() { 48 for child in children.into_iter() {
49 let node = hir::Source::new(macro_file_id, &child); 49 let node = hir::InFile::new(macro_file_id, &child);
50 if let Some(new_node) = expand_macro_recur(db, source, node) { 50 if let Some(new_node) = expand_macro_recur(db, source, node) {
51 // Replace the whole node if it is root 51 // Replace the whole node if it is root
52 // `replace_descendants` will not replace the parent node 52 // `replace_descendants` will not replace the parent node
@@ -86,21 +86,18 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool { 86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default) 87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
88 }; 88 };
89 let is_last = |f: fn(SyntaxKind) -> bool, default| -> bool { 89 let is_last =
90 last.map(|it| f(it)).unwrap_or(default) 90 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
91 };
92 91
93 res += &match token.kind() { 92 res += &match token.kind() {
94 k @ _ if is_text(k) && is_next(|it| !it.is_punct(), true) => { 93 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ",
95 token.text().to_string() + " "
96 }
97 L_CURLY if is_next(|it| it != R_CURLY, true) => { 94 L_CURLY if is_next(|it| it != R_CURLY, true) => {
98 indent += 1; 95 indent += 1;
99 let leading_space = if is_last(|it| is_text(it), false) { " " } else { "" }; 96 let leading_space = if is_last(is_text, false) { " " } else { "" };
100 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 97 format!("{}{{\n{}", leading_space, " ".repeat(indent))
101 } 98 }
102 R_CURLY if is_last(|it| it != L_CURLY, true) => { 99 R_CURLY if is_last(|it| it != L_CURLY, true) => {
103 indent = indent.checked_sub(1).unwrap_or(0); 100 indent = indent.saturating_sub(1);
104 format!("\n{}}}", " ".repeat(indent)) 101 format!("\n{}}}", " ".repeat(indent))
105 } 102 }
106 R_CURLY => format!("}}\n{}", " ".repeat(indent)), 103 R_CURLY => format!("}}\n{}", " ".repeat(indent)),
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index 4b7bfc0b1..1ec41a117 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -34,6 +34,7 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
34 ARG_LIST, 34 ARG_LIST,
35 ARRAY_EXPR, 35 ARRAY_EXPR,
36 TUPLE_EXPR, 36 TUPLE_EXPR,
37 TUPLE_TYPE,
37 WHERE_CLAUSE, 38 WHERE_CLAUSE,
38 ]; 39 ];
39 40
@@ -137,7 +138,7 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange
137 ws.text_range() 138 ws.text_range()
138} 139}
139 140
140fn pick_best<'a>(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken { 141fn pick_best(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken {
141 return if priority(&r) > priority(&l) { r } else { l }; 142 return if priority(&r) > priority(&l) { r } else { l };
142 fn priority(n: &SyntaxToken) -> usize { 143 fn priority(n: &SyntaxToken) -> usize {
143 match n.kind() { 144 match n.kind() {
@@ -174,12 +175,7 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
174 TYPE_BOUND => T![+], 175 TYPE_BOUND => T![+],
175 _ => T![,], 176 _ => T![,],
176 }; 177 };
177 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) { 178
178 return Some(TextRange::from_to(
179 delimiter_node.text_range().start(),
180 node.text_range().end(),
181 ));
182 }
183 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) { 179 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) {
184 // Include any following whitespace when delimiter is after list item. 180 // Include any following whitespace when delimiter is after list item.
185 let final_node = delimiter_node 181 let final_node = delimiter_node
@@ -190,6 +186,12 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
190 186
191 return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end())); 187 return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end()));
192 } 188 }
189 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) {
190 return Some(TextRange::from_to(
191 delimiter_node.text_range().start(),
192 node.text_range().end(),
193 ));
194 }
193 195
194 None 196 None
195} 197}
@@ -250,14 +252,14 @@ mod tests {
250 fn test_extend_selection_list() { 252 fn test_extend_selection_list() {
251 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); 253 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
252 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); 254 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]);
253 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,"]); 255 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]);
254 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); 256 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]);
255 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", ", y: i32"]); 257 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]);
256 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); 258 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]);
257 259
258 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); 260 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]);
259 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); 261 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
260 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", ", 33"]); 262 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]);
261 263
262 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); 264 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]);
263 265
@@ -276,7 +278,7 @@ const FOO: [usize; 2] = [
276 22 278 22
277 , 33<|>, 279 , 33<|>,
278]"#, 280]"#,
279 &["33", ", 33"], 281 &["33", "33,"],
280 ); 282 );
281 } 283 }
282 284
@@ -424,7 +426,7 @@ fn foo<R>()
424 do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); 426 do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]);
425 do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); 427 do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]);
426 do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]); 428 do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]);
427 do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "+ Display"]); 429 do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "Display + "]);
428 do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]); 430 do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]);
429 } 431 }
430 432
@@ -435,7 +437,7 @@ fn foo<R>()
435 do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]); 437 do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]);
436 do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]); 438 do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]);
437 do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]); 439 do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]);
438 do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "+ Display"]); 440 do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "Display + "]);
439 do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]); 441 do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]);
440 do_check( 442 do_check(
441 r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#, 443 r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#,
@@ -449,4 +451,56 @@ fn foo<R>()
449 ], 451 ],
450 ); 452 );
451 } 453 }
454
455 #[test]
456 fn test_extend_selection_on_tuple_in_type() {
457 do_check(
458 r#"fn main() { let _: (krate, <|>_crate_def_map, module_id) = (); }"#,
459 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
460 );
461 // white space variations
462 do_check(
463 r#"fn main() { let _: (krate,<|>_crate_def_map,module_id) = (); }"#,
464 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
465 );
466 do_check(
467 r#"
468fn main() { let _: (
469 krate,
470 _crate<|>_def_map,
471 module_id
472) = (); }"#,
473 &[
474 "_crate_def_map",
475 "_crate_def_map,",
476 "(\n krate,\n _crate_def_map,\n module_id\n)",
477 ],
478 );
479 }
480
481 #[test]
482 fn test_extend_selection_on_tuple_in_rvalue() {
483 do_check(
484 r#"fn main() { let var = (krate, _crate_def_map<|>, module_id); }"#,
485 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
486 );
487 // white space variations
488 do_check(
489 r#"fn main() { let var = (krate,_crate<|>_def_map,module_id); }"#,
490 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
491 );
492 do_check(
493 r#"
494fn main() { let var = (
495 krate,
496 _crate_def_map<|>,
497 module_id
498); }"#,
499 &[
500 "_crate_def_map",
501 "_crate_def_map,",
502 "(\n krate,\n _crate_def_map,\n module_id\n)",
503 ],
504 );
505 }
452} 506}
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index c10a6c844..79d332e8c 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -1,9 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{db::AstDatabase, Source}; 3use hir::{db::AstDatabase, InFile};
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, DocCommentsOwner}, 5 ast::{self, DocCommentsOwner},
6 match_ast, AstNode, SyntaxNode, 6 match_ast, AstNode,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, TokenAtOffset,
7}; 9};
8 10
9use crate::{ 11use crate::{
@@ -19,25 +21,33 @@ pub(crate) fn goto_definition(
19 position: FilePosition, 21 position: FilePosition,
20) -> Option<RangeInfo<Vec<NavigationTarget>>> { 22) -> Option<RangeInfo<Vec<NavigationTarget>>> {
21 let file = db.parse_or_expand(position.file_id.into())?; 23 let file = db.parse_or_expand(position.file_id.into())?;
22 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 24 let original_token = pick_best(file.token_at_offset(position.offset))?;
23 let token = descend_into_macros(db, position.file_id, token); 25 let token = descend_into_macros(db, position.file_id, original_token.clone());
24 26
25 let res = match_ast! { 27 let nav_targets = match_ast! {
26 match (token.value.parent()) { 28 match (token.value.parent()) {
27 ast::NameRef(name_ref) => { 29 ast::NameRef(name_ref) => {
28 let navs = reference_definition(db, token.with_value(&name_ref)).to_vec(); 30 reference_definition(db, token.with_value(&name_ref)).to_vec()
29 RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())
30 }, 31 },
31 ast::Name(name) => { 32 ast::Name(name) => {
32 let navs = name_definition(db, token.with_value(&name))?; 33 name_definition(db, token.with_value(&name))?
33 RangeInfo::new(name.syntax().text_range(), navs)
34
35 }, 34 },
36 _ => return None, 35 _ => return None,
37 } 36 }
38 }; 37 };
39 38
40 Some(res) 39 Some(RangeInfo::new(original_token.text_range(), nav_targets))
40}
41
42fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
43 return tokens.max_by_key(priority);
44 fn priority(n: &SyntaxToken) -> usize {
45 match n.kind() {
46 IDENT | INT_NUMBER => 2,
47 kind if kind.is_trivia() => 0,
48 _ => 1,
49 }
50 }
41} 51}
42 52
43#[derive(Debug)] 53#[derive(Debug)]
@@ -58,15 +68,17 @@ impl ReferenceResult {
58 68
59pub(crate) fn reference_definition( 69pub(crate) fn reference_definition(
60 db: &RootDatabase, 70 db: &RootDatabase,
61 name_ref: Source<&ast::NameRef>, 71 name_ref: InFile<&ast::NameRef>,
62) -> ReferenceResult { 72) -> ReferenceResult {
63 use self::ReferenceResult::*; 73 use self::ReferenceResult::*;
64 74
65 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); 75 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind);
66 match name_kind { 76 match name_kind {
67 Some(Macro(mac)) => return Exact(mac.to_nav(db)), 77 Some(Macro(it)) => return Exact(it.to_nav(db)),
68 Some(Field(field)) => return Exact(field.to_nav(db)), 78 Some(Field(it)) => return Exact(it.to_nav(db)),
69 Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), 79 Some(TypeParam(it)) => return Exact(it.to_nav(db)),
80 Some(AssocItem(it)) => return Exact(it.to_nav(db)),
81 Some(Local(it)) => return Exact(it.to_nav(db)),
70 Some(Def(def)) => match NavigationTarget::from_def(db, def) { 82 Some(Def(def)) => match NavigationTarget::from_def(db, def) {
71 Some(nav) => return Exact(nav), 83 Some(nav) => return Exact(nav),
72 None => return Approximate(vec![]), 84 None => return Approximate(vec![]),
@@ -77,10 +89,6 @@ pub(crate) fn reference_definition(
77 // us to the actual type 89 // us to the actual type
78 return Exact(imp.to_nav(db)); 90 return Exact(imp.to_nav(db));
79 } 91 }
80 Some(Local(local)) => return Exact(local.to_nav(db)),
81 Some(GenericParam(_)) => {
82 // FIXME: go to the generic param def
83 }
84 None => {} 92 None => {}
85 }; 93 };
86 94
@@ -94,7 +102,7 @@ pub(crate) fn reference_definition(
94 102
95pub(crate) fn name_definition( 103pub(crate) fn name_definition(
96 db: &RootDatabase, 104 db: &RootDatabase,
97 name: Source<&ast::Name>, 105 name: InFile<&ast::Name>,
98) -> Option<Vec<NavigationTarget>> { 106) -> Option<Vec<NavigationTarget>> {
99 let parent = name.value.syntax().parent()?; 107 let parent = name.value.syntax().parent()?;
100 108
@@ -115,7 +123,7 @@ pub(crate) fn name_definition(
115 None 123 None
116} 124}
117 125
118fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<NavigationTarget> { 126fn named_target(db: &RootDatabase, node: InFile<&SyntaxNode>) -> Option<NavigationTarget> {
119 match_ast! { 127 match_ast! {
120 match (node.value) { 128 match (node.value) {
121 ast::StructDef(it) => { 129 ast::StructDef(it) => {
@@ -213,21 +221,44 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati
213 221
214#[cfg(test)] 222#[cfg(test)]
215mod tests { 223mod tests {
216 use test_utils::covers; 224 use test_utils::{assert_eq_text, covers};
217 225
218 use crate::mock_analysis::analysis_and_position; 226 use crate::mock_analysis::analysis_and_position;
219 227
220 fn check_goto(fixture: &str, expected: &str) { 228 fn check_goto(fixture: &str, expected: &str, expected_range: &str) {
221 let (analysis, pos) = analysis_and_position(fixture); 229 let (analysis, pos) = analysis_and_position(fixture);
222 230
223 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
224 assert_eq!(navs.len(), 1); 232 assert_eq!(navs.len(), 1);
233
225 let nav = navs.pop().unwrap(); 234 let nav = navs.pop().unwrap();
235 let file_text = analysis.file_text(nav.file_id()).unwrap();
236
237 let mut actual = file_text[nav.full_range()].to_string();
238 if let Some(focus) = nav.focus_range() {
239 actual += "|";
240 actual += &file_text[focus];
241 }
242
243 if !expected_range.contains("...") {
244 test_utils::assert_eq_text!(&actual, expected_range);
245 } else {
246 let mut parts = expected_range.split("...");
247 let prefix = parts.next().unwrap();
248 let suffix = parts.next().unwrap();
249 assert!(
250 actual.starts_with(prefix) && actual.ends_with(suffix),
251 "\nExpected: {}\n Actual: {}\n",
252 expected_range,
253 actual
254 );
255 }
256
226 nav.assert_match(expected); 257 nav.assert_match(expected);
227 } 258 }
228 259
229 #[test] 260 #[test]
230 fn goto_definition_works_in_items() { 261 fn goto_def_in_items() {
231 check_goto( 262 check_goto(
232 " 263 "
233 //- /lib.rs 264 //- /lib.rs
@@ -235,6 +266,20 @@ mod tests {
235 enum E { X(Foo<|>) } 266 enum E { X(Foo<|>) }
236 ", 267 ",
237 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 268 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
269 "struct Foo;|Foo",
270 );
271 }
272
273 #[test]
274 fn goto_def_at_start_of_item() {
275 check_goto(
276 "
277 //- /lib.rs
278 struct Foo;
279 enum E { X(<|>Foo) }
280 ",
281 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
282 "struct Foo;|Foo",
238 ); 283 );
239 } 284 }
240 285
@@ -247,61 +292,65 @@ mod tests {
247 mod a; 292 mod a;
248 mod b; 293 mod b;
249 enum E { X(Foo<|>) } 294 enum E { X(Foo<|>) }
295
250 //- /a.rs 296 //- /a.rs
251 struct Foo; 297 struct Foo;
298
252 //- /b.rs 299 //- /b.rs
253 struct Foo; 300 struct Foo;
254 ", 301 ",
255 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", 302 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)",
303 "struct Foo;|Foo",
256 ); 304 );
257 } 305 }
258 306
259 #[test] 307 #[test]
260 fn goto_definition_works_for_module_declaration() { 308 fn goto_def_for_module_declaration() {
261 check_goto( 309 check_goto(
262 " 310 "
263 //- /lib.rs 311 //- /lib.rs
264 mod <|>foo; 312 mod <|>foo;
313
265 //- /foo.rs 314 //- /foo.rs
266 // empty 315 // empty
267 ", 316 ",
268 "foo SOURCE_FILE FileId(2) [0; 10)", 317 "foo SOURCE_FILE FileId(2) [0; 10)",
318 "// empty\n\n",
269 ); 319 );
270 320
271 check_goto( 321 check_goto(
272 " 322 "
273 //- /lib.rs 323 //- /lib.rs
274 mod <|>foo; 324 mod <|>foo;
325
275 //- /foo/mod.rs 326 //- /foo/mod.rs
276 // empty 327 // empty
277 ", 328 ",
278 "foo SOURCE_FILE FileId(2) [0; 10)", 329 "foo SOURCE_FILE FileId(2) [0; 10)",
330 "// empty\n\n",
279 ); 331 );
280 } 332 }
281 333
282 #[test] 334 #[test]
283 fn goto_definition_works_for_macros() { 335 fn goto_def_for_macros() {
284 covers!(goto_definition_works_for_macros); 336 covers!(goto_def_for_macros);
285 check_goto( 337 check_goto(
286 " 338 "
287 //- /lib.rs 339 //- /lib.rs
288 macro_rules! foo { 340 macro_rules! foo { () => { () } }
289 () => {
290 {}
291 };
292 }
293 341
294 fn bar() { 342 fn bar() {
295 <|>foo!(); 343 <|>foo!();
296 } 344 }
297 ", 345 ",
298 "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", 346 "foo MACRO_CALL FileId(1) [0; 33) [13; 16)",
347 "macro_rules! foo { () => { () } }|foo",
299 ); 348 );
300 } 349 }
301 350
302 #[test] 351 #[test]
303 fn goto_definition_works_for_macros_from_other_crates() { 352 fn goto_def_for_macros_from_other_crates() {
304 covers!(goto_definition_works_for_macros); 353 covers!(goto_def_for_macros);
305 check_goto( 354 check_goto(
306 " 355 "
307 //- /lib.rs 356 //- /lib.rs
@@ -312,18 +361,15 @@ mod tests {
312 361
313 //- /foo/lib.rs 362 //- /foo/lib.rs
314 #[macro_export] 363 #[macro_export]
315 macro_rules! foo { 364 macro_rules! foo { () => { () } }
316 () => {
317 {}
318 };
319 }
320 ", 365 ",
321 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 366 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
367 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
322 ); 368 );
323 } 369 }
324 370
325 #[test] 371 #[test]
326 fn goto_definition_works_for_macros_in_use_tree() { 372 fn goto_def_for_macros_in_use_tree() {
327 check_goto( 373 check_goto(
328 " 374 "
329 //- /lib.rs 375 //- /lib.rs
@@ -331,18 +377,15 @@ mod tests {
331 377
332 //- /foo/lib.rs 378 //- /foo/lib.rs
333 #[macro_export] 379 #[macro_export]
334 macro_rules! foo { 380 macro_rules! foo { () => { () } }
335 () => {
336 {}
337 };
338 }
339 ", 381 ",
340 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 382 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
383 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
341 ); 384 );
342 } 385 }
343 386
344 #[test] 387 #[test]
345 fn goto_definition_works_for_macro_defined_fn_with_arg() { 388 fn goto_def_for_macro_defined_fn_with_arg() {
346 check_goto( 389 check_goto(
347 " 390 "
348 //- /lib.rs 391 //- /lib.rs
@@ -350,20 +393,19 @@ mod tests {
350 ($name:ident) => (fn $name() {}) 393 ($name:ident) => (fn $name() {})
351 } 394 }
352 395
353 define_fn!( 396 define_fn!(foo);
354 foo
355 )
356 397
357 fn bar() { 398 fn bar() {
358 <|>foo(); 399 <|>foo();
359 } 400 }
360 ", 401 ",
361 "foo FN_DEF FileId(1) [80; 83) [80; 83)", 402 "foo FN_DEF FileId(1) [64; 80) [75; 78)",
403 "define_fn!(foo);|foo",
362 ); 404 );
363 } 405 }
364 406
365 #[test] 407 #[test]
366 fn goto_definition_works_for_macro_defined_fn_no_arg() { 408 fn goto_def_for_macro_defined_fn_no_arg() {
367 check_goto( 409 check_goto(
368 " 410 "
369 //- /lib.rs 411 //- /lib.rs
@@ -377,32 +419,70 @@ mod tests {
377 <|>foo(); 419 <|>foo();
378 } 420 }
379 ", 421 ",
380 "foo FN_DEF FileId(1) [39; 42) [39; 42)", 422 "foo FN_DEF FileId(1) [51; 64) [51; 64)",
423 "define_fn!();|define_fn!();",
381 ); 424 );
382 } 425 }
383 426
384 #[test] 427 #[test]
385 fn goto_definition_works_for_methods() { 428 fn goto_definition_works_for_macro_inside_pattern() {
386 covers!(goto_definition_works_for_methods); 429 check_goto(
430 "
431 //- /lib.rs
432 macro_rules! foo {() => {0}}
433
434 fn bar() {
435 match (0,1) {
436 (<|>foo!(), _) => {}
437 }
438 }
439 ",
440 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
441 "macro_rules! foo {() => {0}}|foo",
442 );
443 }
444
445 #[test]
446 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
447 check_goto(
448 "
449 //- /lib.rs
450 macro_rules! foo {() => {0}}
451
452 fn bar() {
453 match 0 {
454 <|>foo!() => {}
455 }
456 }
457 ",
458 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
459 "macro_rules! foo {() => {0}}|foo",
460 );
461 }
462
463 #[test]
464 fn goto_def_for_methods() {
465 covers!(goto_def_for_methods);
387 check_goto( 466 check_goto(
388 " 467 "
389 //- /lib.rs 468 //- /lib.rs
390 struct Foo; 469 struct Foo;
391 impl Foo { 470 impl Foo {
392 fn frobnicate(&self) { } 471 fn frobnicate(&self) { }
393 } 472 }
394 473
395 fn bar(foo: &Foo) { 474 fn bar(foo: &Foo) {
396 foo.frobnicate<|>(); 475 foo.frobnicate<|>();
397 } 476 }
398 ", 477 ",
399 "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", 478 "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)",
479 "fn frobnicate(&self) { }|frobnicate",
400 ); 480 );
401 } 481 }
402 482
403 #[test] 483 #[test]
404 fn goto_definition_works_for_fields() { 484 fn goto_def_for_fields() {
405 covers!(goto_definition_works_for_fields); 485 covers!(goto_def_for_fields);
406 check_goto( 486 check_goto(
407 " 487 "
408 //- /lib.rs 488 //- /lib.rs
@@ -415,12 +495,13 @@ mod tests {
415 } 495 }
416 ", 496 ",
417 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 497 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
498 "spam: u32|spam",
418 ); 499 );
419 } 500 }
420 501
421 #[test] 502 #[test]
422 fn goto_definition_works_for_record_fields() { 503 fn goto_def_for_record_fields() {
423 covers!(goto_definition_works_for_record_fields); 504 covers!(goto_def_for_record_fields);
424 check_goto( 505 check_goto(
425 " 506 "
426 //- /lib.rs 507 //- /lib.rs
@@ -435,29 +516,48 @@ mod tests {
435 } 516 }
436 ", 517 ",
437 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 518 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
519 "spam: u32|spam",
520 );
521 }
522
523 #[test]
524 fn goto_for_tuple_fields() {
525 check_goto(
526 "
527 //- /lib.rs
528 struct Foo(u32);
529
530 fn bar() {
531 let foo = Foo(0);
532 foo.<|>0;
533 }
534 ",
535 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
536 "u32",
438 ); 537 );
439 } 538 }
440 539
441 #[test] 540 #[test]
442 fn goto_definition_works_for_ufcs_inherent_methods() { 541 fn goto_def_for_ufcs_inherent_methods() {
443 check_goto( 542 check_goto(
444 " 543 "
445 //- /lib.rs 544 //- /lib.rs
446 struct Foo; 545 struct Foo;
447 impl Foo { 546 impl Foo {
448 fn frobnicate() { } 547 fn frobnicate() { }
449 } 548 }
450 549
451 fn bar(foo: &Foo) { 550 fn bar(foo: &Foo) {
452 Foo::frobnicate<|>(); 551 Foo::frobnicate<|>();
453 } 552 }
454 ", 553 ",
455 "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", 554 "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)",
555 "fn frobnicate() { }|frobnicate",
456 ); 556 );
457 } 557 }
458 558
459 #[test] 559 #[test]
460 fn goto_definition_works_for_ufcs_trait_methods_through_traits() { 560 fn goto_def_for_ufcs_trait_methods_through_traits() {
461 check_goto( 561 check_goto(
462 " 562 "
463 //- /lib.rs 563 //- /lib.rs
@@ -470,11 +570,12 @@ mod tests {
470 } 570 }
471 ", 571 ",
472 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", 572 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
573 "fn frobnicate();|frobnicate",
473 ); 574 );
474 } 575 }
475 576
476 #[test] 577 #[test]
477 fn goto_definition_works_for_ufcs_trait_methods_through_self() { 578 fn goto_def_for_ufcs_trait_methods_through_self() {
478 check_goto( 579 check_goto(
479 " 580 "
480 //- /lib.rs 581 //- /lib.rs
@@ -489,6 +590,7 @@ mod tests {
489 } 590 }
490 ", 591 ",
491 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", 592 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
593 "fn frobnicate();|frobnicate",
492 ); 594 );
493 } 595 }
494 596
@@ -505,6 +607,7 @@ mod tests {
505 } 607 }
506 ", 608 ",
507 "impl IMPL_BLOCK FileId(1) [12; 73)", 609 "impl IMPL_BLOCK FileId(1) [12; 73)",
610 "impl Foo {...}",
508 ); 611 );
509 612
510 check_goto( 613 check_goto(
@@ -518,6 +621,7 @@ mod tests {
518 } 621 }
519 ", 622 ",
520 "impl IMPL_BLOCK FileId(1) [12; 73)", 623 "impl IMPL_BLOCK FileId(1) [12; 73)",
624 "impl Foo {...}",
521 ); 625 );
522 626
523 check_goto( 627 check_goto(
@@ -531,6 +635,7 @@ mod tests {
531 } 635 }
532 ", 636 ",
533 "impl IMPL_BLOCK FileId(1) [15; 75)", 637 "impl IMPL_BLOCK FileId(1) [15; 75)",
638 "impl Foo {...}",
534 ); 639 );
535 640
536 check_goto( 641 check_goto(
@@ -543,6 +648,7 @@ mod tests {
543 } 648 }
544 ", 649 ",
545 "impl IMPL_BLOCK FileId(1) [15; 62)", 650 "impl IMPL_BLOCK FileId(1) [15; 62)",
651 "impl Foo {...}",
546 ); 652 );
547 } 653 }
548 654
@@ -562,6 +668,7 @@ mod tests {
562 } 668 }
563 ", 669 ",
564 "impl IMPL_BLOCK FileId(1) [49; 115)", 670 "impl IMPL_BLOCK FileId(1) [49; 115)",
671 "impl Make for Foo {...}",
565 ); 672 );
566 673
567 check_goto( 674 check_goto(
@@ -578,17 +685,19 @@ mod tests {
578 } 685 }
579 ", 686 ",
580 "impl IMPL_BLOCK FileId(1) [49; 115)", 687 "impl IMPL_BLOCK FileId(1) [49; 115)",
688 "impl Make for Foo {...}",
581 ); 689 );
582 } 690 }
583 691
584 #[test] 692 #[test]
585 fn goto_definition_works_when_used_on_definition_name_itself() { 693 fn goto_def_when_used_on_definition_name_itself() {
586 check_goto( 694 check_goto(
587 " 695 "
588 //- /lib.rs 696 //- /lib.rs
589 struct Foo<|> { value: u32 } 697 struct Foo<|> { value: u32 }
590 ", 698 ",
591 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", 699 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)",
700 "struct Foo { value: u32 }|Foo",
592 ); 701 );
593 702
594 check_goto( 703 check_goto(
@@ -599,15 +708,16 @@ mod tests {
599 } 708 }
600 "#, 709 "#,
601 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", 710 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)",
711 "field: string|field",
602 ); 712 );
603 713
604 check_goto( 714 check_goto(
605 " 715 "
606 //- /lib.rs 716 //- /lib.rs
607 fn foo_test<|>() { 717 fn foo_test<|>() { }
608 }
609 ", 718 ",
610 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", 719 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)",
720 "fn foo_test() { }|foo_test",
611 ); 721 );
612 722
613 check_goto( 723 check_goto(
@@ -618,6 +728,7 @@ mod tests {
618 } 728 }
619 ", 729 ",
620 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", 730 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)",
731 "enum Foo {...}|Foo",
621 ); 732 );
622 733
623 check_goto( 734 check_goto(
@@ -630,22 +741,25 @@ mod tests {
630 } 741 }
631 ", 742 ",
632 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", 743 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)",
744 "Variant2|Variant2",
633 ); 745 );
634 746
635 check_goto( 747 check_goto(
636 r#" 748 r#"
637 //- /lib.rs 749 //- /lib.rs
638 static inner<|>: &str = ""; 750 static INNER<|>: &str = "";
639 "#, 751 "#,
640 "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", 752 "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)",
753 "static INNER: &str = \"\";|INNER",
641 ); 754 );
642 755
643 check_goto( 756 check_goto(
644 r#" 757 r#"
645 //- /lib.rs 758 //- /lib.rs
646 const inner<|>: &str = ""; 759 const INNER<|>: &str = "";
647 "#, 760 "#,
648 "inner CONST_DEF FileId(1) [0; 23) [6; 11)", 761 "INNER CONST_DEF FileId(1) [0; 23) [6; 11)",
762 "const INNER: &str = \"\";|INNER",
649 ); 763 );
650 764
651 check_goto( 765 check_goto(
@@ -654,24 +768,25 @@ mod tests {
654 type Thing<|> = Option<()>; 768 type Thing<|> = Option<()>;
655 "#, 769 "#,
656 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", 770 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)",
771 "type Thing = Option<()>;|Thing",
657 ); 772 );
658 773
659 check_goto( 774 check_goto(
660 r#" 775 r#"
661 //- /lib.rs 776 //- /lib.rs
662 trait Foo<|> { 777 trait Foo<|> { }
663 }
664 "#, 778 "#,
665 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", 779 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)",
780 "trait Foo { }|Foo",
666 ); 781 );
667 782
668 check_goto( 783 check_goto(
669 r#" 784 r#"
670 //- /lib.rs 785 //- /lib.rs
671 mod bar<|> { 786 mod bar<|> { }
672 }
673 "#, 787 "#,
674 "bar MODULE FileId(1) [0; 11) [4; 7)", 788 "bar MODULE FileId(1) [0; 11) [4; 7)",
789 "mod bar { }|bar",
675 ); 790 );
676 } 791 }
677 792
@@ -689,8 +804,128 @@ mod tests {
689 fo<|>o(); 804 fo<|>o();
690 } 805 }
691 } 806 }
807 mod confuse_index { fn foo(); }
692 ", 808 ",
693 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 809 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
810 "fn foo() {}|foo",
694 ); 811 );
695 } 812 }
813
814 #[test]
815 fn goto_through_format() {
816 check_goto(
817 "
818 //- /lib.rs
819 #[macro_export]
820 macro_rules! format {
821 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
822 }
823 #[rustc_builtin_macro]
824 #[macro_export]
825 macro_rules! format_args {
826 ($fmt:expr) => ({ /* compiler built-in */ });
827 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
828 }
829 pub mod __export {
830 pub use crate::format_args;
831 fn foo() {} // for index confusion
832 }
833 fn foo() -> i8 {}
834 fn test() {
835 format!(\"{}\", fo<|>o())
836 }
837 ",
838 "foo FN_DEF FileId(1) [398; 415) [401; 404)",
839 "fn foo() -> i8 {}|foo",
840 );
841 }
842
843 #[test]
844 fn goto_for_type_param() {
845 check_goto(
846 "
847 //- /lib.rs
848 struct Foo<T> {
849 t: <|>T,
850 }
851 ",
852 "T TYPE_PARAM FileId(1) [11; 12)",
853 "T",
854 );
855 }
856
857 #[test]
858 fn goto_within_macro() {
859 check_goto(
860 "
861 //- /lib.rs
862 macro_rules! id {
863 ($($tt:tt)*) => ($($tt)*)
864 }
865
866 fn foo() {
867 let x = 1;
868 id!({
869 let y = <|>x;
870 let z = y;
871 });
872 }
873 ",
874 "x BIND_PAT FileId(1) [69; 70)",
875 "x",
876 );
877
878 check_goto(
879 "
880 //- /lib.rs
881 macro_rules! id {
882 ($($tt:tt)*) => ($($tt)*)
883 }
884
885 fn foo() {
886 let x = 1;
887 id!({
888 let y = x;
889 let z = <|>y;
890 });
891 }
892 ",
893 "y BIND_PAT FileId(1) [98; 99)",
894 "y",
895 );
896 }
897
898 #[test]
899 fn goto_def_in_local_fn() {
900 check_goto(
901 "
902 //- /lib.rs
903 fn main() {
904 fn foo() {
905 let x = 92;
906 <|>x;
907 }
908 }
909 ",
910 "x BIND_PAT FileId(1) [39; 40)",
911 "x",
912 );
913 }
914
915 #[test]
916 fn goto_def_for_field_init_shorthand() {
917 covers!(goto_def_for_field_init_shorthand);
918 check_goto(
919 "
920 //- /lib.rs
921 struct Foo { x: i32 }
922 fn main() {
923 let x = 92;
924 Foo { x<|> };
925 }
926 ",
927 "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
928 "x: i32|x",
929 )
930 }
696} 931}
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 992a08809..ce8b6c72a 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::db::AstDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget, 7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget,
@@ -13,7 +13,7 @@ pub(crate) fn goto_type_definition(
13 position: FilePosition, 13 position: FilePosition,
14) -> Option<RangeInfo<Vec<NavigationTarget>>> { 14) -> Option<RangeInfo<Vec<NavigationTarget>>> {
15 let file = db.parse_or_expand(position.file_id.into())?; 15 let file = db.parse_or_expand(position.file_id.into())?;
16 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 16 let token = pick_best(file.token_at_offset(position.offset))?;
17 let token = descend_into_macros(db, position.file_id, token); 17 let token = descend_into_macros(db, position.file_id, token);
18 18
19 let node = token.value.ancestors().find_map(|token| { 19 let node = token.value.ancestors().find_map(|token| {
@@ -41,6 +41,17 @@ pub(crate) fn goto_type_definition(
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
44fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
45 return tokens.max_by_key(priority);
46 fn priority(n: &SyntaxToken) -> usize {
47 match n.kind() {
48 IDENT | INT_NUMBER => 2,
49 kind if kind.is_trivia() => 0,
50 _ => 1,
51 }
52 }
53}
54
44#[cfg(test)] 55#[cfg(test)]
45mod tests { 56mod tests {
46 use crate::mock_analysis::analysis_and_position; 57 use crate::mock_analysis::analysis_and_position;
@@ -102,4 +113,32 @@ mod tests {
102 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)", 113 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)",
103 ); 114 );
104 } 115 }
116
117 #[test]
118 fn goto_type_definition_for_param() {
119 check_goto(
120 "
121 //- /lib.rs
122 struct Foo;
123 fn foo(<|>f: Foo) {}
124 ",
125 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
126 );
127 }
128
129 #[test]
130 fn goto_type_definition_for_tuple_field() {
131 check_goto(
132 "
133 //- /lib.rs
134 struct Foo;
135 struct Bar(Foo);
136 fn foo() {
137 let bar = Bar(Foo);
138 bar.<|>0;
139 }
140 ",
141 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
142 );
143 }
105} 144}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 260a7b869..35e39f965 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -6,14 +6,13 @@ use ra_syntax::{
6 algo::find_covering_element, 6 algo::find_covering_element,
7 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
8 match_ast, AstNode, 8 match_ast, AstNode,
9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset,
9}; 11};
10 12
11use crate::{ 13use crate::{
12 db::RootDatabase, 14 db::RootDatabase,
13 display::{ 15 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
15 rust_code_markup_with_doc, ShortLabel,
16 },
17 expand::descend_into_macros, 16 expand::descend_into_macros,
18 references::{classify_name, classify_name_ref, NameKind, NameKind::*}, 17 references::{classify_name, classify_name_ref, NameKind, NameKind::*},
19 FilePosition, FileRange, RangeInfo, 18 FilePosition, FileRange, RangeInfo,
@@ -93,11 +92,7 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
93 } 92 }
94} 93}
95 94
96fn hover_text_from_name_kind( 95fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<String> {
97 db: &RootDatabase,
98 name_kind: NameKind,
99 no_fallback: &mut bool,
100) -> Option<String> {
101 return match name_kind { 96 return match name_kind {
102 Macro(it) => { 97 Macro(it) => {
103 let src = it.source(db); 98 let src = it.source(db);
@@ -133,12 +128,8 @@ fn hover_text_from_name_kind(
133 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), 128 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
134 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), 129 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
135 }, 130 },
136 Local(_) => { 131 Local(_) => None,
137 // Hover for these shows type names 132 TypeParam(_) | SelfType(_) => {
138 *no_fallback = true;
139 None
140 }
141 GenericParam(_) | SelfType(_) => {
142 // FIXME: Hover for generic param 133 // FIXME: Hover for generic param
143 None 134 None
144 } 135 }
@@ -156,68 +147,55 @@ fn hover_text_from_name_kind(
156 147
157pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 148pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
158 let file = db.parse_or_expand(position.file_id.into())?; 149 let file = db.parse_or_expand(position.file_id.into())?;
159 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 150 let token = pick_best(file.token_at_offset(position.offset))?;
160 let token = descend_into_macros(db, position.file_id, token); 151 let token = descend_into_macros(db, position.file_id, token);
161 152
162 let mut res = HoverResult::new(); 153 let mut res = HoverResult::new();
163 154
164 let mut range = match_ast! { 155 if let Some((range, name_kind)) = match_ast! {
165 match (token.value.parent()) { 156 match (token.value.parent()) {
166 ast::NameRef(name_ref) => { 157 ast::NameRef(name_ref) => {
167 let mut no_fallback = false; 158 classify_name_ref(db, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind))
168 if let Some(name_kind) =
169 classify_name_ref(db, token.with_value(&name_ref)).map(|d| d.kind)
170 {
171 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
172 }
173
174 if res.is_empty() && !no_fallback {
175 // Fallback index based approach:
176 let symbols = crate::symbol_index::index_resolve(db, &name_ref);
177 for sym in symbols {
178 let docs = docs_from_symbol(db, &sym);
179 let desc = description_from_symbol(db, &sym);
180 res.extend(hover_text(docs, desc));
181 }
182 }
183
184 if !res.is_empty() {
185 Some(name_ref.syntax().text_range())
186 } else {
187 None
188 }
189 }, 159 },
190 ast::Name(name) => { 160 ast::Name(name) => {
191 if let Some(name_kind) = classify_name(db, token.with_value(&name)).map(|d| d.kind) { 161 classify_name(db, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind))
192 res.extend(hover_text_from_name_kind(db, name_kind, &mut true));
193 }
194
195 if !res.is_empty() {
196 Some(name.syntax().text_range())
197 } else {
198 None
199 }
200 }, 162 },
201 _ => None, 163 _ => None,
202 } 164 }
203 }; 165 } {
166 res.extend(hover_text_from_name_kind(db, name_kind));
204 167
205 if range.is_none() { 168 if !res.is_empty() {
206 let node = token.value.ancestors().find(|n| { 169 return Some(RangeInfo::new(range, res));
207 ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() 170 }
208 })?; 171 }
209 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
210 res.extend(type_of(db, frange).map(rust_code_markup));
211 range = Some(node.text_range());
212 };
213 172
214 let range = range?; 173 let node = token
174 .value
175 .ancestors()
176 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
177 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
178 res.extend(type_of(db, frange).map(rust_code_markup));
215 if res.is_empty() { 179 if res.is_empty() {
216 return None; 180 return None;
217 } 181 }
182 let range = node.text_range();
183
218 Some(RangeInfo::new(range, res)) 184 Some(RangeInfo::new(range, res))
219} 185}
220 186
187fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
188 return tokens.max_by_key(priority);
189 fn priority(n: &SyntaxToken) -> usize {
190 match n.kind() {
191 IDENT | INT_NUMBER => 3,
192 L_PAREN | R_PAREN => 2,
193 kind if kind.is_trivia() => 0,
194 _ => 1,
195 }
196 }
197}
198
221pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 199pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
222 let parse = db.parse(frange.file_id); 200 let parse = db.parse(frange.file_id);
223 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range); 201 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range);
@@ -227,7 +205,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
227 .take_while(|it| it.text_range() == leaf_node.text_range()) 205 .take_while(|it| it.text_range() == leaf_node.text_range())
228 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; 206 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?;
229 let analyzer = 207 let analyzer =
230 hir::SourceAnalyzer::new(db, hir::Source::new(frange.file_id.into(), &node), None); 208 hir::SourceAnalyzer::new(db, hir::InFile::new(frange.file_id.into(), &node), None);
231 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) 209 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e))
232 { 210 {
233 ty 211 ty
@@ -236,7 +214,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
236 } else { 214 } else {
237 return None; 215 return None;
238 }; 216 };
239 Some(ty.display(db).to_string()) 217 Some(ty.display_truncated(db, None).to_string())
240} 218}
241 219
242#[cfg(test)] 220#[cfg(test)]
@@ -300,7 +278,7 @@ mod tests {
300 &["pub fn foo() -> u32"], 278 &["pub fn foo() -> u32"],
301 ); 279 );
302 280
303 // Multiple results 281 // Multiple candidates but results are ambiguous.
304 check_hover_result( 282 check_hover_result(
305 r#" 283 r#"
306 //- /a.rs 284 //- /a.rs
@@ -321,7 +299,7 @@ mod tests {
321 let foo_test = fo<|>o(); 299 let foo_test = fo<|>o();
322 } 300 }
323 "#, 301 "#,
324 &["pub fn foo() -> &str", "pub fn foo() -> u32", "pub fn foo(a: u32, b: u32)"], 302 &["{unknown}"],
325 ); 303 );
326 } 304 }
327 305
@@ -411,6 +389,23 @@ mod tests {
411 } 389 }
412 390
413 #[test] 391 #[test]
392 fn hover_omits_default_generic_types() {
393 check_hover_result(
394 r#"
395//- /main.rs
396struct Test<K, T = u8> {
397 k: K,
398 t: T,
399}
400
401fn main() {
402 let zz<|> = Test { t: 23, k: 33 };
403}"#,
404 &["Test<i32>"],
405 );
406 }
407
408 #[test]
414 fn hover_some() { 409 fn hover_some() {
415 let (analysis, position) = single_file_with_position( 410 let (analysis, position) = single_file_with_position(
416 " 411 "
@@ -505,6 +500,13 @@ fn func(foo: i32) { if true { <|>foo; }; }
505 } 500 }
506 501
507 #[test] 502 #[test]
503 fn hover_for_param_edge() {
504 let (analysis, position) = single_file_with_position("fn func(<|>foo: i32) {}");
505 let hover = analysis.hover(position).unwrap().unwrap();
506 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
507 }
508
509 #[test]
508 fn test_type_of_for_function() { 510 fn test_type_of_for_function() {
509 let (analysis, range) = single_file_with_range( 511 let (analysis, range) = single_file_with_range(
510 " 512 "
diff --git a/crates/ra_ide/src/impls.rs b/crates/ra_ide/src/impls.rs
index aa480e399..9b165ee2a 100644
--- a/crates/ra_ide/src/impls.rs
+++ b/crates/ra_ide/src/impls.rs
@@ -16,7 +16,7 @@ pub(crate) fn goto_implementation(
16 let src = hir::ModuleSource::from_position(db, position); 16 let src = hir::ModuleSource::from_position(db, position);
17 let module = hir::Module::from_definition( 17 let module = hir::Module::from_definition(
18 db, 18 db,
19 hir::Source { file_id: position.file_id.into(), value: src }, 19 hir::InFile { file_id: position.file_id.into(), value: src },
20 )?; 20 )?;
21 21
22 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) { 22 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) {
@@ -42,15 +42,15 @@ fn impls_for_def(
42) -> Option<Vec<NavigationTarget>> { 42) -> Option<Vec<NavigationTarget>> {
43 let ty = match node { 43 let ty = match node {
44 ast::NominalDef::StructDef(def) => { 44 ast::NominalDef::StructDef(def) => {
45 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 45 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
46 hir::Struct::from_source(db, src)?.ty(db) 46 hir::Struct::from_source(db, src)?.ty(db)
47 } 47 }
48 ast::NominalDef::EnumDef(def) => { 48 ast::NominalDef::EnumDef(def) => {
49 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 49 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
50 hir::Enum::from_source(db, src)?.ty(db) 50 hir::Enum::from_source(db, src)?.ty(db)
51 } 51 }
52 ast::NominalDef::UnionDef(def) => { 52 ast::NominalDef::UnionDef(def) => {
53 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 53 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
54 hir::Union::from_source(db, src)?.ty(db) 54 hir::Union::from_source(db, src)?.ty(db)
55 } 55 }
56 }; 56 };
@@ -73,7 +73,7 @@ fn impls_for_trait(
73 node: &ast::TraitDef, 73 node: &ast::TraitDef,
74 module: hir::Module, 74 module: hir::Module,
75) -> Option<Vec<NavigationTarget>> { 75) -> Option<Vec<NavigationTarget>> {
76 let src = hir::Source { file_id: position.file_id.into(), value: node.clone() }; 76 let src = hir::InFile { file_id: position.file_id.into(), value: node.clone() };
77 let tr = hir::Trait::from_source(db, src)?; 77 let tr = hir::Trait::from_source(db, src)?;
78 78
79 let krate = module.krate(); 79 let krate = module.krate();
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 45149bf0c..c5e406977 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -1,12 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{db::RootDatabase, FileId};
4use hir::{HirDisplay, SourceAnalyzer}; 3use hir::{HirDisplay, SourceAnalyzer};
4use once_cell::unsync::Lazy;
5use ra_prof::profile;
5use ra_syntax::{ 6use ra_syntax::{
6 ast::{self, AstNode, TypeAscriptionOwner}, 7 ast::{self, AstNode, TypeAscriptionOwner},
7 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, 8 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange,
8}; 9};
9 10
11use crate::{db::RootDatabase, FileId};
12
10#[derive(Debug, PartialEq, Eq)] 13#[derive(Debug, PartialEq, Eq)]
11pub enum InlayKind { 14pub enum InlayKind {
12 TypeHint, 15 TypeHint,
@@ -27,7 +30,7 @@ pub(crate) fn inlay_hints(
27) -> Vec<InlayHint> { 30) -> Vec<InlayHint> {
28 file.syntax() 31 file.syntax()
29 .descendants() 32 .descendants()
30 .map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length).unwrap_or_default()) 33 .flat_map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length))
31 .flatten() 34 .flatten()
32 .collect() 35 .collect()
33} 36}
@@ -38,7 +41,9 @@ fn get_inlay_hints(
38 node: &SyntaxNode, 41 node: &SyntaxNode,
39 max_inlay_hint_length: Option<usize>, 42 max_inlay_hint_length: Option<usize>,
40) -> Option<Vec<InlayHint>> { 43) -> Option<Vec<InlayHint>> {
41 let analyzer = SourceAnalyzer::new(db, hir::Source::new(file_id.into(), node), None); 44 let _p = profile("get_inlay_hints");
45 let analyzer =
46 Lazy::new(|| SourceAnalyzer::new(db, hir::InFile::new(file_id.into(), node), None));
42 match_ast! { 47 match_ast! {
43 match node { 48 match node {
44 ast::LetStmt(it) => { 49 ast::LetStmt(it) => {
@@ -122,18 +127,11 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
122 127
123 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() { 128 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() {
124 match &maybe_leaf_pat { 129 match &maybe_leaf_pat {
125 ast::Pat::BindPat(bind_pat) => { 130 ast::Pat::BindPat(bind_pat) => match bind_pat.pat() {
126 if let Some(pat) = bind_pat.pat() { 131 Some(pat) => pats_to_process.push_back(pat),
127 pats_to_process.push_back(pat); 132 _ => leaf_pats.push(maybe_leaf_pat),
128 } else { 133 },
129 leaf_pats.push(maybe_leaf_pat); 134 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
130 }
131 }
132 ast::Pat::TuplePat(tuple_pat) => {
133 for arg_pat in tuple_pat.args() {
134 pats_to_process.push_back(arg_pat);
135 }
136 }
137 ast::Pat::RecordPat(record_pat) => { 135 ast::Pat::RecordPat(record_pat) => {
138 if let Some(pat_list) = record_pat.record_field_pat_list() { 136 if let Some(pat_list) = record_pat.record_field_pat_list() {
139 pats_to_process.extend( 137 pats_to_process.extend(
@@ -151,10 +149,9 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
151 } 149 }
152 } 150 }
153 ast::Pat::TupleStructPat(tuple_struct_pat) => { 151 ast::Pat::TupleStructPat(tuple_struct_pat) => {
154 for arg_pat in tuple_struct_pat.args() { 152 pats_to_process.extend(tuple_struct_pat.args())
155 pats_to_process.push_back(arg_pat);
156 }
157 } 153 }
154 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
158 _ => (), 155 _ => (),
159 } 156 }
160 } 157 }
@@ -163,9 +160,36 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
163 160
164#[cfg(test)] 161#[cfg(test)]
165mod tests { 162mod tests {
166 use crate::mock_analysis::single_file;
167 use insta::assert_debug_snapshot; 163 use insta::assert_debug_snapshot;
168 164
165 use crate::mock_analysis::single_file;
166
167 #[test]
168 fn default_generic_types_should_not_be_displayed() {
169 let (analysis, file_id) = single_file(
170 r#"
171struct Test<K, T = u8> {
172 k: K,
173 t: T,
174}
175
176fn main() {
177 let zz = Test { t: 23, k: 33 };
178}"#,
179 );
180
181 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
182 [
183 InlayHint {
184 range: [69; 71),
185 kind: TypeHint,
186 label: "Test<i32>",
187 },
188 ]
189 "###
190 );
191 }
192
169 #[test] 193 #[test]
170 fn let_statement() { 194 fn let_statement() {
171 let (analysis, file_id) = single_file( 195 let (analysis, file_id) = single_file(
@@ -202,6 +226,7 @@ fn main() {
202 226
203 let test = (42, 'a'); 227 let test = (42, 'a');
204 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); 228 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5));
229 let &x = &92;
205}"#, 230}"#,
206 ); 231 );
207 232
@@ -257,6 +282,11 @@ fn main() {
257 kind: TypeHint, 282 kind: TypeHint,
258 label: "f64", 283 label: "f64",
259 }, 284 },
285 InlayHint {
286 range: [627; 628),
287 kind: TypeHint,
288 label: "i32",
289 },
260 ] 290 ]
261 "### 291 "###
262 ); 292 );
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index d1bff4a76..779a81b2c 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -422,6 +422,11 @@ impl Analysis {
422 self.with_db(|db| parent_module::crate_for(db, file_id)) 422 self.with_db(|db| parent_module::crate_for(db, file_id))
423 } 423 }
424 424
425 /// Returns the edition of the given crate.
426 pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> {
427 self.with_db(|db| db.crate_graph().edition(crate_id))
428 }
429
425 /// Returns the root file of the given crate. 430 /// Returns the root file of the given crate.
426 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { 431 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
427 self.with_db(|db| db.crate_graph().crate_root(crate_id)) 432 self.with_db(|db| db.crate_graph().crate_root(crate_id))
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 848ae4dc7..077a44473 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -3,10 +3,11 @@
3test_utils::marks!( 3test_utils::marks!(
4 inserts_angle_brackets_for_generics 4 inserts_angle_brackets_for_generics
5 inserts_parens_for_function_calls 5 inserts_parens_for_function_calls
6 goto_definition_works_for_macros 6 goto_def_for_macros
7 goto_definition_works_for_methods 7 goto_def_for_methods
8 goto_definition_works_for_fields 8 goto_def_for_fields
9 goto_definition_works_for_record_fields 9 goto_def_for_record_fields
10 goto_def_for_field_init_shorthand
10 call_info_bad_offset 11 call_info_bad_offset
11 dont_complete_current_use 12 dont_complete_current_use
12 dont_complete_primitive_in_use 13 dont_complete_primitive_in_use
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs
index 6027e7d54..f5a788c07 100644
--- a/crates/ra_ide/src/parent_module.rs
+++ b/crates/ra_ide/src/parent_module.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::{CrateId, FileId, FilePosition}; 3use ra_db::{CrateId, FileId, FilePosition, SourceDatabase};
4 4
5use crate::{db::RootDatabase, NavigationTarget}; 5use crate::{db::RootDatabase, NavigationTarget};
6 6
@@ -10,7 +10,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
10 let src = hir::ModuleSource::from_position(db, position); 10 let src = hir::ModuleSource::from_position(db, position);
11 let module = match hir::Module::from_definition( 11 let module = match hir::Module::from_definition(
12 db, 12 db,
13 hir::Source { file_id: position.file_id.into(), value: src }, 13 hir::InFile { file_id: position.file_id.into(), value: src },
14 ) { 14 ) {
15 None => return Vec::new(), 15 None => return Vec::new(),
16 Some(it) => it, 16 Some(it) => it,
@@ -21,15 +21,16 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
21 21
22/// Returns `Vec` for the same reason as `parent_module` 22/// Returns `Vec` for the same reason as `parent_module`
23pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { 23pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
24 let src = hir::ModuleSource::from_file_id(db, file_id); 24 let source_file = db.parse(file_id).tree();
25 let src = hir::ModuleSource::SourceFile(source_file);
25 let module = 26 let module =
26 match hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), value: src }) 27 match hir::Module::from_definition(db, hir::InFile { file_id: file_id.into(), value: src })
27 { 28 {
28 Some(it) => it, 29 Some(it) => it,
29 None => return Vec::new(), 30 None => return Vec::new(),
30 }; 31 };
31 let krate = module.krate(); 32 let krate = module.krate();
32 vec![krate.crate_id()] 33 vec![krate.into()]
33} 34}
34 35
35#[cfg(test)] 36#[cfg(test)]
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 21a1ea69e..e3ecde50d 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -14,7 +14,7 @@ mod name_definition;
14mod rename; 14mod rename;
15mod search_scope; 15mod search_scope;
16 16
17use hir::Source; 17use hir::InFile;
18use once_cell::unsync::Lazy; 18use once_cell::unsync::Lazy;
19use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
20use ra_prof::profile; 20use ra_prof::profile;
@@ -85,7 +85,7 @@ pub(crate) fn find_all_refs(
85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?, 85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
86 NameKind::SelfType(imp) => imp.to_nav(db), 86 NameKind::SelfType(imp) => imp.to_nav(db),
87 NameKind::Local(local) => local.to_nav(db), 87 NameKind::Local(local) => local.to_nav(db),
88 NameKind::GenericParam(_) => return None, 88 NameKind::TypeParam(_) => return None,
89 }; 89 };
90 90
91 let search_scope = { 91 let search_scope = {
@@ -107,12 +107,12 @@ fn find_name<'a>(
107 position: FilePosition, 107 position: FilePosition,
108) -> Option<RangeInfo<(String, NameDefinition)>> { 108) -> Option<RangeInfo<(String, NameDefinition)>> {
109 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { 109 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) {
110 let def = classify_name(db, Source::new(position.file_id.into(), &name))?; 110 let def = classify_name(db, InFile::new(position.file_id.into(), &name))?;
111 let range = name.syntax().text_range(); 111 let range = name.syntax().text_range();
112 return Some(RangeInfo::new(range, (name.text().to_string(), def))); 112 return Some(RangeInfo::new(range, (name.text().to_string(), def)));
113 } 113 }
114 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; 114 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
115 let def = classify_name_ref(db, Source::new(position.file_id.into(), &name_ref))?; 115 let def = classify_name_ref(db, InFile::new(position.file_id.into(), &name_ref))?;
116 let range = name_ref.syntax().text_range(); 116 let range = name_ref.syntax().text_range();
117 Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) 117 Some(RangeInfo::new(range, (name_ref.text().to_string(), def)))
118} 118}
@@ -144,7 +144,7 @@ fn process_definition(
144 continue; 144 continue;
145 } 145 }
146 } 146 }
147 if let Some(d) = classify_name_ref(db, Source::new(file_id.into(), &name_ref)) { 147 if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) {
148 if d == def { 148 if d == def {
149 refs.push(FileRange { file_id, range }); 149 refs.push(FileRange { file_id, range });
150 } 150 }
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs
index 5cea805ec..3483a7176 100644
--- a/crates/ra_ide/src/references/classify.rs
+++ b/crates/ra_ide/src/references/classify.rs
@@ -1,6 +1,6 @@
1//! Functions that are used to classify an element from its definition or reference. 1//! Functions that are used to classify an element from its definition or reference.
2 2
3use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer}; 3use hir::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceAnalyzer};
4use ra_prof::profile; 4use ra_prof::profile;
5use ra_syntax::{ast, match_ast, AstNode}; 5use ra_syntax::{ast, match_ast, AstNode};
6use test_utils::tested_by; 6use test_utils::tested_by;
@@ -11,7 +11,7 @@ use super::{
11}; 11};
12use crate::db::RootDatabase; 12use crate::db::RootDatabase;
13 13
14pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Option<NameDefinition> { 14pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Option<NameDefinition> {
15 let _p = profile("classify_name"); 15 let _p = profile("classify_name");
16 let parent = name.value.syntax().parent()?; 16 let parent = name.value.syntax().parent()?;
17 17
@@ -110,6 +110,15 @@ pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Opti
110 kind: NameKind::Macro(def), 110 kind: NameKind::Macro(def),
111 }) 111 })
112 }, 112 },
113 ast::TypeParam(it) => {
114 let src = name.with_value(it);
115 let def = hir::TypeParam::from_source(db, src)?;
116 Some(NameDefinition {
117 visibility: None,
118 container: def.module(db),
119 kind: NameKind::TypeParam(def),
120 })
121 },
113 _ => None, 122 _ => None,
114 } 123 }
115 } 124 }
@@ -117,7 +126,7 @@ pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Opti
117 126
118pub(crate) fn classify_name_ref( 127pub(crate) fn classify_name_ref(
119 db: &RootDatabase, 128 db: &RootDatabase,
120 name_ref: Source<&ast::NameRef>, 129 name_ref: InFile<&ast::NameRef>,
121) -> Option<NameDefinition> { 130) -> Option<NameDefinition> {
122 let _p = profile("classify_name_ref"); 131 let _p = profile("classify_name_ref");
123 132
@@ -125,21 +134,22 @@ pub(crate) fn classify_name_ref(
125 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None); 134 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
126 135
127 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { 136 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
128 tested_by!(goto_definition_works_for_methods); 137 tested_by!(goto_def_for_methods);
129 if let Some(func) = analyzer.resolve_method_call(&method_call) { 138 if let Some(func) = analyzer.resolve_method_call(&method_call) {
130 return Some(from_assoc_item(db, func.into())); 139 return Some(from_assoc_item(db, func.into()));
131 } 140 }
132 } 141 }
133 142
134 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 143 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
135 tested_by!(goto_definition_works_for_fields); 144 tested_by!(goto_def_for_fields);
136 if let Some(field) = analyzer.resolve_field(&field_expr) { 145 if let Some(field) = analyzer.resolve_field(&field_expr) {
137 return Some(from_struct_field(db, field)); 146 return Some(from_struct_field(db, field));
138 } 147 }
139 } 148 }
140 149
141 if let Some(record_field) = ast::RecordField::cast(parent.clone()) { 150 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
142 tested_by!(goto_definition_works_for_record_fields); 151 tested_by!(goto_def_for_record_fields);
152 tested_by!(goto_def_for_field_init_shorthand);
143 if let Some(field_def) = analyzer.resolve_record_field(&record_field) { 153 if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
144 return Some(from_struct_field(db, field_def)); 154 return Some(from_struct_field(db, field_def));
145 } 155 }
@@ -151,7 +161,7 @@ pub(crate) fn classify_name_ref(
151 let visibility = None; 161 let visibility = None;
152 162
153 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) {
154 tested_by!(goto_definition_works_for_macros); 164 tested_by!(goto_def_for_macros);
155 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) { 165 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) {
156 let kind = NameKind::Macro(macro_def); 166 let kind = NameKind::Macro(macro_def);
157 return Some(NameDefinition { kind, container, visibility }); 167 return Some(NameDefinition { kind, container, visibility });
@@ -168,9 +178,8 @@ pub(crate) fn classify_name_ref(
168 let kind = NameKind::Local(local); 178 let kind = NameKind::Local(local);
169 Some(NameDefinition { kind, container, visibility: None }) 179 Some(NameDefinition { kind, container, visibility: None })
170 } 180 }
171 PathResolution::GenericParam(par) => { 181 PathResolution::TypeParam(par) => {
172 // FIXME: get generic param def 182 let kind = NameKind::TypeParam(par);
173 let kind = NameKind::GenericParam(par);
174 Some(NameDefinition { kind, container, visibility }) 183 Some(NameDefinition { kind, container, visibility })
175 } 184 }
176 PathResolution::Macro(def) => { 185 PathResolution::Macro(def) => {
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs
index 10d3a2364..8c67c8863 100644
--- a/crates/ra_ide/src/references/name_definition.rs
+++ b/crates/ra_ide/src/references/name_definition.rs
@@ -4,8 +4,8 @@
4//! Note that the reference search is possible for not all of the classified items. 4//! Note that the reference search is possible for not all of the classified items.
5 5
6use hir::{ 6use hir::{
7 Adt, AssocItem, GenericParam, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, 7 Adt, AssocItem, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, StructField,
8 StructField, VariantDef, 8 TypeParam, VariantDef,
9}; 9};
10use ra_syntax::{ast, ast::VisibilityOwner}; 10use ra_syntax::{ast, ast::VisibilityOwner};
11 11
@@ -19,7 +19,7 @@ pub enum NameKind {
19 Def(ModuleDef), 19 Def(ModuleDef),
20 SelfType(ImplBlock), 20 SelfType(ImplBlock),
21 Local(Local), 21 Local(Local),
22 GenericParam(GenericParam), 22 TypeParam(TypeParam),
23} 23}
24 24
25#[derive(PartialEq, Eq)] 25#[derive(PartialEq, Eq)]
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index d58496049..b804d5f6d 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -2,7 +2,7 @@
2 2
3use hir::ModuleSource; 3use hir::ModuleSource;
4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt}; 4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; 5use ra_syntax::{algo::find_node_at_offset, ast, tokenize, AstNode, SyntaxKind, SyntaxNode};
6use ra_text_edit::TextEdit; 6use ra_text_edit::TextEdit;
7 7
8use crate::{ 8use crate::{
@@ -17,6 +17,13 @@ pub(crate) fn rename(
17 position: FilePosition, 17 position: FilePosition,
18 new_name: &str, 18 new_name: &str,
19) -> Option<RangeInfo<SourceChange>> { 19) -> Option<RangeInfo<SourceChange>> {
20 let tokens = tokenize(new_name);
21 if tokens.len() != 1
22 || (tokens[0].kind != SyntaxKind::IDENT && tokens[0].kind != SyntaxKind::UNDERSCORE)
23 {
24 return None;
25 }
26
20 let parse = db.parse(position.file_id); 27 let parse = db.parse(position.file_id);
21 if let Some((ast_name, ast_module)) = 28 if let Some((ast_name, ast_module)) =
22 find_name_and_module_at_offset(parse.tree().syntax(), position) 29 find_name_and_module_at_offset(parse.tree().syntax(), position)
@@ -55,7 +62,7 @@ fn rename_mod(
55) -> Option<SourceChange> { 62) -> Option<SourceChange> {
56 let mut source_file_edits = Vec::new(); 63 let mut source_file_edits = Vec::new();
57 let mut file_system_edits = Vec::new(); 64 let mut file_system_edits = Vec::new();
58 let module_src = hir::Source { file_id: position.file_id.into(), value: ast_module.clone() }; 65 let module_src = hir::InFile { file_id: position.file_id.into(), value: ast_module.clone() };
59 if let Some(module) = hir::Module::from_declaration(db, module_src) { 66 if let Some(module) = hir::Module::from_declaration(db, module_src) {
60 let src = module.definition_source(db); 67 let src = module.definition_source(db);
61 let file_id = src.file_id.original_file(db); 68 let file_id = src.file_id.original_file(db);
@@ -124,6 +131,49 @@ mod tests {
124 }; 131 };
125 132
126 #[test] 133 #[test]
134 fn test_rename_to_underscore() {
135 test_rename(
136 r#"
137 fn main() {
138 let i<|> = 1;
139 }"#,
140 "_",
141 r#"
142 fn main() {
143 let _ = 1;
144 }"#,
145 );
146 }
147
148 #[test]
149 fn test_rename_to_raw_identifier() {
150 test_rename(
151 r#"
152 fn main() {
153 let i<|> = 1;
154 }"#,
155 "r#fn",
156 r#"
157 fn main() {
158 let r#fn = 1;
159 }"#,
160 );
161 }
162
163 #[test]
164 fn test_rename_to_invalid_identifier() {
165 let (analysis, position) = single_file_with_position(
166 "
167 fn main() {
168 let i<|> = 1;
169 }",
170 );
171 let new_name = "invalid!";
172 let source_change = analysis.rename(position, new_name).unwrap();
173 assert!(source_change.is_none());
174 }
175
176 #[test]
127 fn test_rename_for_local() { 177 fn test_rename_for_local() {
128 test_rename( 178 test_rename(
129 r#" 179 r#"
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs
index f5c9589f4..241dd358f 100644
--- a/crates/ra_ide/src/references/search_scope.rs
+++ b/crates/ra_ide/src/references/search_scope.rs
@@ -5,7 +5,7 @@
5use std::mem; 5use std::mem;
6 6
7use hir::{DefWithBody, HasSource, ModuleSource}; 7use hir::{DefWithBody, HasSource, ModuleSource};
8use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; 8use ra_db::{FileId, SourceDatabaseExt};
9use ra_prof::profile; 9use ra_prof::profile;
10use ra_syntax::{AstNode, TextRange}; 10use ra_syntax::{AstNode, TextRange};
11use rustc_hash::FxHashMap; 11use rustc_hash::FxHashMap;
@@ -120,15 +120,11 @@ impl NameDefinition {
120 } 120 }
121 if vis.as_str() == "pub" { 121 if vis.as_str() == "pub" {
122 let krate = self.container.krate(); 122 let krate = self.container.krate();
123 let crate_graph = db.crate_graph(); 123 for rev_dep in krate.reverse_dependencies(db) {
124 for crate_id in crate_graph.iter() { 124 let root_file = rev_dep.root_file(db);
125 let mut crate_deps = crate_graph.dependencies(crate_id); 125 let source_root_id = db.file_source_root(root_file);
126 if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { 126 let source_root = db.source_root(source_root_id);
127 let root_file = crate_graph.crate_root(crate_id); 127 res.extend(source_root.walk().map(|id| (id, None)));
128 let source_root_id = db.file_source_root(root_file);
129 let source_root = db.source_root(source_root_id);
130 res.extend(source_root.walk().map(|id| (id, None)));
131 }
132 } 128 }
133 return SearchScope::new(res); 129 return SearchScope::new(res);
134 } 130 }
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 8039a5164..e213e1a06 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Source; 3use hir::InFile;
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
6use ra_syntax::{ 6use ra_syntax::{
@@ -66,8 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
66 return None; 66 return None;
67 } 67 }
68 let range = module.syntax().text_range(); 68 let range = module.syntax().text_range();
69 let src = hir::ModuleSource::from_child_node(db, Source::new(file_id.into(), &module.syntax())); 69 let src = hir::ModuleSource::from_child_node(db, InFile::new(file_id.into(), &module.syntax()));
70 let module = hir::Module::from_definition(db, Source::new(file_id.into(), src))?; 70 let module = hir::Module::from_definition(db, InFile::new(file_id.into(), 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/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index b39c4d371..a097cf8e8 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -5,12 +5,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
13.type\.builtin { color: #8CD0D3; }
14.type\.param { color: #20999D; }
12.attribute { color: #94BFF3; } 15.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; }
14.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
15.variable { color: #DCDCCC; } 19.variable { color: #DCDCCC; }
16.variable\.mut { color: #DCDCCC; text-decoration: underline; } 20.variable\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -21,28 +25,37 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
21</style> 25</style>
22<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span> 26<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span>
23<span class="keyword">struct</span> <span class="type">Foo</span> { 27<span class="keyword">struct</span> <span class="type">Foo</span> {
24 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type">i32</span>, 28 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type.builtin">i32</span>,
25 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type">i32</span>, 29 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type.builtin">i32</span>,
26} 30}
27 31
28<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">T</span> { 32<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type.param">T</span> {
29 <span class="macro">unimplemented</span><span class="macro">!</span>(); 33 <span class="macro">unimplemented</span><span class="macro">!</span>();
30 <span class="function">foo</span>::&lt;<span class="type">i32</span>&gt;(); 34 <span class="function">foo</span>::&lt;<span class="type.builtin">i32</span>&gt;();
31} 35}
32 36
33<span class="comment">// comment</span> 37<span class="comment">// comment</span>
34<span class="keyword">fn</span> <span class="function">main</span>() { 38<span class="keyword">fn</span> <span class="function">main</span>() {
35 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal">92</span>); 39 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal.numeric">92</span>);
36 40
37 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); 41 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>();
38 <span class="keyword.control">if</span> <span class="keyword">true</span> { 42 <span class="keyword.control">if</span> <span class="keyword">true</span> {
39 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal">0</span>, <span class="field">y</span>: <span class="literal">1</span> }); 43 <span class="keyword">let</span> <span class="variable">x</span> = <span class="literal.numeric">92</span>;
44 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> });
40 } 45 }
41 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal">0</span>); } 46 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); }
42 47
43 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal">42</span>; 48 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal.numeric">42</span>;
44 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>; 49 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>;
45 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>; 50 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>;
46 51
47 <span class="variable.mut">y</span>; 52 <span class="variable.mut">y</span>;
53}
54
55<span class="keyword">enum</span> <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
56 <span class="constant">V</span>(<span class="type.param">X</span>)
57}
58
59<span class="keyword">impl</span>&lt;<span class="type.param">X</span>&gt; <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
60 <span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type">E</span>&lt;<span class="type.param">T</span>&gt; {}
48}</code></pre> \ No newline at end of file 61}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 79f11ea80..110556c09 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -5,12 +5,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
13.type\.builtin { color: #8CD0D3; }
14.type\.param { color: #20999D; }
12.attribute { color: #94BFF3; } 15.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; }
14.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
15.variable { color: #DCDCCC; } 19.variable { color: #DCDCCC; }
16.variable\.mut { color: #DCDCCC; text-decoration: underline; } 20.variable\.mut { color: #DCDCCC; text-decoration: underline; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 9a3e4c82f..0228ee7e9 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Name, Source}; 5use hir::{InFile, Name};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@@ -16,6 +16,34 @@ use crate::{
16 FileId, 16 FileId,
17}; 17};
18 18
19pub mod tags {
20 pub(crate) const FIELD: &str = "field";
21 pub(crate) const FUNCTION: &str = "function";
22 pub(crate) const MODULE: &str = "module";
23 pub(crate) const TYPE: &str = "type";
24 pub(crate) const CONSTANT: &str = "constant";
25 pub(crate) const MACRO: &str = "macro";
26 pub(crate) const VARIABLE: &str = "variable";
27 pub(crate) const VARIABLE_MUT: &str = "variable.mut";
28 pub(crate) const TEXT: &str = "text";
29
30 pub(crate) const TYPE_BUILTIN: &str = "type.builtin";
31 pub(crate) const TYPE_SELF: &str = "type.self";
32 pub(crate) const TYPE_PARAM: &str = "type.param";
33 pub(crate) const TYPE_LIFETIME: &str = "type.lifetime";
34
35 pub(crate) const LITERAL_BYTE: &str = "literal.byte";
36 pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric";
37 pub(crate) const LITERAL_CHAR: &str = "literal.char";
38 pub(crate) const LITERAL_COMMENT: &str = "comment";
39 pub(crate) const LITERAL_STRING: &str = "string";
40 pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute";
41
42 pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe";
43 pub(crate) const KEYWORD_CONTROL: &str = "keyword.control";
44 pub(crate) const KEYWORD: &str = "keyword";
45}
46
19#[derive(Debug)] 47#[derive(Debug)]
20pub struct HighlightedRange { 48pub struct HighlightedRange {
21 pub range: TextRange, 49 pub range: TextRange,
@@ -71,17 +99,16 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
71 bindings_shadow_count.clear(); 99 bindings_shadow_count.clear();
72 continue; 100 continue;
73 } 101 }
74 COMMENT => "comment", 102 COMMENT => tags::LITERAL_COMMENT,
75 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING,
76 ATTR => "attribute", 104 ATTR => tags::LITERAL_ATTRIBUTE,
105 // Special-case field init shorthand
106 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD,
107 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue,
77 NAME_REF => { 108 NAME_REF => {
78 if node.ancestors().any(|it| it.kind() == ATTR) {
79 continue;
80 }
81
82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 109 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
83 let name_kind = 110 let name_kind =
84 classify_name_ref(db, Source::new(file_id.into(), &name_ref)).map(|d| d.kind); 111 classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
85 112
86 if let Some(Local(local)) = &name_kind { 113 if let Some(Local(local)) = &name_kind {
87 if let Some(name) = local.name(db) { 114 if let Some(name) = local.name(db) {
@@ -90,12 +117,12 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
90 } 117 }
91 }; 118 };
92 119
93 name_kind.map_or("text", |it| highlight_name(db, it)) 120 name_kind.map_or(tags::TEXT, |it| highlight_name(db, it))
94 } 121 }
95 NAME => { 122 NAME => {
96 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); 123 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
97 let name_kind = 124 let name_kind =
98 classify_name(db, Source::new(file_id.into(), &name)).map(|d| d.kind); 125 classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind);
99 126
100 if let Some(Local(local)) = &name_kind { 127 if let Some(Local(local)) = &name_kind {
101 if let Some(name) = local.name(db) { 128 if let Some(name) = local.name(db) {
@@ -107,18 +134,21 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
107 134
108 match name_kind { 135 match name_kind {
109 Some(name_kind) => highlight_name(db, name_kind), 136 Some(name_kind) => highlight_name(db, name_kind),
110 None => name.syntax().parent().map_or("function", |x| match x.kind() { 137 None => name.syntax().parent().map_or(tags::FUNCTION, |x| match x.kind() {
111 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", 138 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => tags::TYPE,
112 RECORD_FIELD_DEF => "field", 139 TYPE_PARAM => tags::TYPE_PARAM,
113 _ => "function", 140 RECORD_FIELD_DEF => tags::FIELD,
141 _ => tags::FUNCTION,
114 }), 142 }),
115 } 143 }
116 } 144 }
117 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 145 INT_NUMBER | FLOAT_NUMBER => tags::LITERAL_NUMERIC,
118 LIFETIME => "parameter", 146 BYTE => tags::LITERAL_BYTE,
119 T![unsafe] => "keyword.unsafe", 147 CHAR => tags::LITERAL_CHAR,
120 k if is_control_keyword(k) => "keyword.control", 148 LIFETIME => tags::TYPE_LIFETIME,
121 k if k.is_keyword() => "keyword", 149 T![unsafe] => tags::KEYWORD_UNSAFE,
150 k if is_control_keyword(k) => tags::KEYWORD_CONTROL,
151 k if k.is_keyword() => tags::KEYWORD,
122 _ => { 152 _ => {
123 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) { 153 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
124 if let Some(path) = macro_call.path() { 154 if let Some(path) = macro_call.path() {
@@ -135,7 +165,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
135 } 165 }
136 res.push(HighlightedRange { 166 res.push(HighlightedRange {
137 range: TextRange::from_to(range_start, range_end), 167 range: TextRange::from_to(range_start, range_end),
138 tag: "macro", 168 tag: tags::MACRO,
139 binding_hash: None, 169 binding_hash: None,
140 }) 170 })
141 } 171 }
@@ -211,29 +241,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
211 241
212fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { 242fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
213 match name_kind { 243 match name_kind {
214 Macro(_) => "macro", 244 Macro(_) => tags::MACRO,
215 Field(_) => "field", 245 Field(_) => tags::FIELD,
216 AssocItem(hir::AssocItem::Function(_)) => "function", 246 AssocItem(hir::AssocItem::Function(_)) => tags::FUNCTION,
217 AssocItem(hir::AssocItem::Const(_)) => "constant", 247 AssocItem(hir::AssocItem::Const(_)) => tags::CONSTANT,
218 AssocItem(hir::AssocItem::TypeAlias(_)) => "type", 248 AssocItem(hir::AssocItem::TypeAlias(_)) => tags::TYPE,
219 Def(hir::ModuleDef::Module(_)) => "module", 249 Def(hir::ModuleDef::Module(_)) => tags::MODULE,
220 Def(hir::ModuleDef::Function(_)) => "function", 250 Def(hir::ModuleDef::Function(_)) => tags::FUNCTION,
221 Def(hir::ModuleDef::Adt(_)) => "type", 251 Def(hir::ModuleDef::Adt(_)) => tags::TYPE,
222 Def(hir::ModuleDef::EnumVariant(_)) => "constant", 252 Def(hir::ModuleDef::EnumVariant(_)) => tags::CONSTANT,
223 Def(hir::ModuleDef::Const(_)) => "constant", 253 Def(hir::ModuleDef::Const(_)) => tags::CONSTANT,
224 Def(hir::ModuleDef::Static(_)) => "constant", 254 Def(hir::ModuleDef::Static(_)) => tags::CONSTANT,
225 Def(hir::ModuleDef::Trait(_)) => "type", 255 Def(hir::ModuleDef::Trait(_)) => tags::TYPE,
226 Def(hir::ModuleDef::TypeAlias(_)) => "type", 256 Def(hir::ModuleDef::TypeAlias(_)) => tags::TYPE,
227 Def(hir::ModuleDef::BuiltinType(_)) => "type", 257 Def(hir::ModuleDef::BuiltinType(_)) => tags::TYPE_BUILTIN,
228 SelfType(_) => "type", 258 SelfType(_) => tags::TYPE_SELF,
229 GenericParam(_) => "type", 259 TypeParam(_) => tags::TYPE_PARAM,
230 Local(local) => { 260 Local(local) => {
231 if local.is_mut(db) { 261 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
232 "variable.mut" 262 tags::VARIABLE_MUT
233 } else if local.ty(db).is_mutable_reference() {
234 "variable.mut"
235 } else { 263 } else {
236 "variable" 264 tags::VARIABLE
237 } 265 }
238 } 266 }
239 } 267 }
@@ -251,12 +279,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
251 279
252.comment { color: #7F9F7F; } 280.comment { color: #7F9F7F; }
253.string { color: #CC9393; } 281.string { color: #CC9393; }
282.field { color: #94BFF3; }
254.function { color: #93E0E3; } 283.function { color: #93E0E3; }
255.parameter { color: #94BFF3; } 284.parameter { color: #94BFF3; }
256.builtin { color: #DD6718; }
257.text { color: #DCDCCC; } 285.text { color: #DCDCCC; }
286.type { color: #7CB8BB; }
287.type\\.builtin { color: #8CD0D3; }
288.type\\.param { color: #20999D; }
258.attribute { color: #94BFF3; } 289.attribute { color: #94BFF3; }
259.literal { color: #BFEBBF; } 290.literal { color: #BFEBBF; }
291.literal\\.numeric { color: #6A8759; }
260.macro { color: #94BFF3; } 292.macro { color: #94BFF3; }
261.variable { color: #DCDCCC; } 293.variable { color: #DCDCCC; }
262.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 294.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -293,7 +325,8 @@ fn main() {
293 325
294 let mut vec = Vec::new(); 326 let mut vec = Vec::new();
295 if true { 327 if true {
296 vec.push(Foo { x: 0, y: 1 }); 328 let x = 92;
329 vec.push(Foo { x, y: 1 });
297 } 330 }
298 unsafe { vec.set_len(0); } 331 unsafe { vec.set_len(0); }
299 332
@@ -303,6 +336,14 @@ fn main() {
303 336
304 y; 337 y;
305} 338}
339
340enum E<X> {
341 V(X)
342}
343
344impl<X> E<X> {
345 fn new<T>() -> E<T> {}
346}
306"# 347"#
307 .trim(), 348 .trim(),
308 ); 349 );
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 21aef842c..60cbc38a9 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -13,9 +13,8 @@ relative-path = "1.0.0"
13serde_json = "1.0.34" 13serde_json = "1.0.34"
14serde = { version = "1.0.83", features = ["derive"] } 14serde = { version = "1.0.83", features = ["derive"] }
15crossbeam-channel = "0.4" 15crossbeam-channel = "0.4"
16flexi_logger = "0.14.0"
17log = "0.4.3" 16log = "0.4.3"
18lsp-types = { version = "0.61.0", features = ["proposed"] } 17lsp-types = { version = "0.66.0", features = ["proposed"] }
19rustc-hash = "1.0" 18rustc-hash = "1.0"
20parking_lot = "0.10.0" 19parking_lot = "0.10.0"
21jod-thread = "0.1.0" 20jod-thread = "0.1.0"
@@ -27,6 +26,7 @@ lsp-server = "0.3.0"
27ra_project_model = { path = "../ra_project_model" } 26ra_project_model = { path = "../ra_project_model" }
28ra_prof = { path = "../ra_prof" } 27ra_prof = { path = "../ra_prof" }
29ra_vfs_glob = { path = "../ra_vfs_glob" } 28ra_vfs_glob = { path = "../ra_vfs_glob" }
29env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] }
30 30
31[dev-dependencies] 31[dev-dependencies]
32tempfile = "3" 32tempfile = "3"
diff --git a/crates/ra_lsp_server/build.rs b/crates/ra_lsp_server/build.rs
new file mode 100644
index 000000000..05f9772c0
--- /dev/null
+++ b/crates/ra_lsp_server/build.rs
@@ -0,0 +1,15 @@
1//! Just embed git-hash to `--version`
2
3use std::process::Command;
4
5fn main() {
6 let rev = rev().unwrap_or_else(|| "???????".to_string());
7 println!("cargo:rustc-env=REV={}", rev)
8}
9
10fn rev() -> Option<String> {
11 let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().ok()?;
12 let stdout = String::from_utf8(output.stdout).ok()?;
13 let short_hash = stdout.get(0..7)?;
14 Some(short_hash.to_owned())
15}
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index eea0965ed..eeca67ee1 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -1,11 +1,12 @@
1//! FIXME: write short doc here 1//! Advertizes the capabilities of the LSP Server.
2 2
3use lsp_types::{ 3use lsp_types::{
4 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, 4 CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
5 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, GenericCapability, 5 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability,
6 ImplementationProviderCapability, RenameOptions, RenameProviderCapability, ServerCapabilities, 6 ImplementationProviderCapability, RenameOptions, RenameProviderCapability,
7 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 7 SelectionRangeProviderCapability, ServerCapabilities, SignatureHelpOptions,
8 TextDocumentSyncOptions, TypeDefinitionProviderCapability, 8 TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
9 TypeDefinitionProviderCapability, WorkDoneProgressOptions,
9}; 10};
10 11
11pub fn server_capabilities() -> ServerCapabilities { 12pub fn server_capabilities() -> ServerCapabilities {
@@ -21,10 +22,14 @@ pub fn server_capabilities() -> ServerCapabilities {
21 completion_provider: Some(CompletionOptions { 22 completion_provider: Some(CompletionOptions {
22 resolve_provider: None, 23 resolve_provider: None,
23 trigger_characters: Some(vec![":".to_string(), ".".to_string()]), 24 trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
25 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
24 }), 26 }),
25 signature_help_provider: Some(SignatureHelpOptions { 27 signature_help_provider: Some(SignatureHelpOptions {
26 trigger_characters: Some(vec!["(".to_string(), ",".to_string(), ")".to_string()]), 28 trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
29 retrigger_characters: None,
30 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
27 }), 31 }),
32 declaration_provider: None,
28 definition_provider: Some(true), 33 definition_provider: Some(true),
29 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), 34 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
30 implementation_provider: Some(ImplementationProviderCapability::Simple(true)), 35 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
@@ -40,10 +45,11 @@ pub fn server_capabilities() -> ServerCapabilities {
40 first_trigger_character: "=".to_string(), 45 first_trigger_character: "=".to_string(),
41 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), 46 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]),
42 }), 47 }),
43 selection_range_provider: Some(GenericCapability::default()), 48 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
44 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 49 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
45 rename_provider: Some(RenameProviderCapability::Options(RenameOptions { 50 rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
46 prepare_provider: Some(true), 51 prepare_provider: Some(true),
52 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
47 })), 53 })),
48 document_link_provider: None, 54 document_link_provider: None,
49 color_provider: None, 55 color_provider: None,
diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs
index 8045f3d60..67942aa41 100644
--- a/crates/ra_lsp_server/src/config.rs
+++ b/crates/ra_lsp_server/src/config.rs
@@ -9,6 +9,7 @@
9 9
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
12use ra_project_model::CargoFeatures;
12use serde::{Deserialize, Deserializer}; 13use serde::{Deserialize, Deserializer};
13 14
14/// Client provided initialization options 15/// Client provided initialization options
@@ -37,6 +38,9 @@ pub struct ServerConfig {
37 38
38 /// Fine grained feature flags to disable specific features. 39 /// Fine grained feature flags to disable specific features.
39 pub feature_flags: FxHashMap<String, bool>, 40 pub feature_flags: FxHashMap<String, bool>,
41
42 /// Cargo feature configurations.
43 pub cargo_features: CargoFeatures,
40} 44}
41 45
42impl Default for ServerConfig { 46impl Default for ServerConfig {
@@ -49,6 +53,7 @@ impl Default for ServerConfig {
49 max_inlay_hint_length: None, 53 max_inlay_hint_length: None,
50 with_sysroot: true, 54 with_sysroot: true,
51 feature_flags: FxHashMap::default(), 55 feature_flags: FxHashMap::default(),
56 cargo_features: Default::default(),
52 } 57 }
53 } 58 }
54} 59}
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index b13093cfe..e93d4ea33 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Convenience module responsible for translating between rust-analyzer's types and LSP types.
2 2
3use lsp_types::{ 3use lsp_types::{
4 self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation, 4 self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation,
@@ -130,6 +130,11 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
130 deprecated: Some(self.deprecated()), 130 deprecated: Some(self.deprecated()),
131 ..Default::default() 131 ..Default::default()
132 }; 132 };
133
134 if self.deprecated() {
135 res.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated])
136 }
137
133 res.insert_text_format = Some(match self.insert_text_format() { 138 res.insert_text_format = Some(match self.insert_text_format() {
134 InsertTextFormat::Snippet => lsp_types::InsertTextFormat::Snippet, 139 InsertTextFormat::Snippet => lsp_types::InsertTextFormat::Snippet,
135 InsertTextFormat::PlainText => lsp_types::InsertTextFormat::PlainText, 140 InsertTextFormat::PlainText => lsp_types::InsertTextFormat::PlainText,
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index e13c8ca14..cdd925c9f 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -1,24 +1,22 @@
1//! `ra_lsp_server` binary 1//! `ra_lsp_server` binary
2 2
3use flexi_logger::{Duplicate, Logger};
4use lsp_server::Connection; 3use lsp_server::Connection;
5use ra_lsp_server::{show_message, Result, ServerConfig}; 4use ra_lsp_server::{show_message, Result, ServerConfig};
6use ra_prof; 5use ra_prof;
7 6
8fn main() -> Result<()> { 7fn main() -> Result<()> {
9 setup_logging()?; 8 setup_logging()?;
10 run_server()?; 9 match Args::parse()? {
10 Args::Version => println!("rust-analyzer {}", env!("REV")),
11 Args::Run => run_server()?,
12 }
11 Ok(()) 13 Ok(())
12} 14}
13 15
14fn setup_logging() -> Result<()> { 16fn setup_logging() -> Result<()> {
15 std::env::set_var("RUST_BACKTRACE", "short"); 17 std::env::set_var("RUST_BACKTRACE", "short");
16 18
17 let logger = Logger::with_env_or_str("error").duplicate_to_stderr(Duplicate::All); 19 env_logger::try_init()?;
18 match std::env::var("RA_LOG_DIR") {
19 Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?,
20 _ => logger.start()?,
21 };
22 20
23 ra_prof::set_filter(match std::env::var("RA_PROFILE") { 21 ra_prof::set_filter(match std::env::var("RA_PROFILE") {
24 Ok(spec) => ra_prof::Filter::from_spec(&spec), 22 Ok(spec) => ra_prof::Filter::from_spec(&spec),
@@ -27,6 +25,19 @@ fn setup_logging() -> Result<()> {
27 Ok(()) 25 Ok(())
28} 26}
29 27
28enum Args {
29 Version,
30 Run,
31}
32
33impl Args {
34 fn parse() -> Result<Args> {
35 let res =
36 if std::env::args().any(|it| it == "--version") { Args::Version } else { Args::Run };
37 Ok(res)
38 }
39}
40
30fn run_server() -> Result<()> { 41fn run_server() -> Result<()> {
31 log::info!("lifecycle: server started"); 42 log::info!("lifecycle: server started");
32 43
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 83845f1e0..dda318e43 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! The main loop of `ra_lsp_server` responsible for dispatching LSP requests/replies and
2//! notifications back to the client.
2 3
3mod handlers; 4mod handlers;
4mod subscriptions; 5mod subscriptions;
@@ -67,6 +68,7 @@ pub fn main_loop(
67 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( 68 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
68 ws_root.as_path(), 69 ws_root.as_path(),
69 config.with_sysroot, 70 config.with_sysroot,
71 &config.cargo_features,
70 ); 72 );
71 match workspace { 73 match workspace {
72 Ok(workspace) => loaded_workspaces.push(workspace), 74 Ok(workspace) => loaded_workspaces.push(workspace),
@@ -130,7 +132,7 @@ pub fn main_loop(
130 let feature_flags = { 132 let feature_flags = {
131 let mut ff = FeatureFlags::default(); 133 let mut ff = FeatureFlags::default();
132 for (flag, value) in config.feature_flags { 134 for (flag, value) in config.feature_flags {
133 if let Err(_) = ff.set(flag.as_str(), value) { 135 if ff.set(flag.as_str(), value).is_err() {
134 log::error!("unknown feature flag: {:?}", flag); 136 log::error!("unknown feature flag: {:?}", flag);
135 show_message( 137 show_message(
136 req::MessageType::Error, 138 req::MessageType::Error,
@@ -303,7 +305,6 @@ fn loop_turn(
303 log::info!("queued count = {}", queue_count); 305 log::info!("queued count = {}", queue_count);
304 } 306 }
305 307
306 let mut state_changed = false;
307 match event { 308 match event {
308 Event::Task(task) => { 309 Event::Task(task) => {
309 on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); 310 on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state);
@@ -311,7 +312,6 @@ fn loop_turn(
311 } 312 }
312 Event::Vfs(task) => { 313 Event::Vfs(task) => {
313 world_state.vfs.write().handle_task(task); 314 world_state.vfs.write().handle_task(task);
314 state_changed = true;
315 } 315 }
316 Event::Lib(lib) => { 316 Event::Lib(lib) => {
317 world_state.add_lib(lib); 317 world_state.add_lib(lib);
@@ -336,7 +336,6 @@ fn loop_turn(
336 &mut loop_state.subscriptions, 336 &mut loop_state.subscriptions,
337 not, 337 not,
338 )?; 338 )?;
339 state_changed = true;
340 } 339 }
341 Message::Response(resp) => { 340 Message::Response(resp) => {
342 let removed = loop_state.pending_responses.remove(&resp.id); 341 let removed = loop_state.pending_responses.remove(&resp.id);
@@ -347,7 +346,12 @@ fn loop_turn(
347 }, 346 },
348 }; 347 };
349 348
350 loop_state.pending_libraries.extend(world_state.process_changes()); 349 let mut state_changed = false;
350 if let Some(changes) = world_state.process_changes() {
351 state_changed = true;
352 loop_state.pending_libraries.extend(changes);
353 }
354
351 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS 355 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS
352 && !loop_state.pending_libraries.is_empty() 356 && !loop_state.pending_libraries.is_empty()
353 { 357 {
@@ -520,7 +524,8 @@ fn on_notification(
520 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { 524 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
521 subs.remove_sub(FileId(file_id.0)); 525 subs.remove_sub(FileId(file_id.0));
522 } 526 }
523 let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() }; 527 let params =
528 req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None };
524 let not = notification_new::<req::PublishDiagnostics>(params); 529 let not = notification_new::<req::PublishDiagnostics>(params);
525 msg_sender.send(not.into()).unwrap(); 530 msg_sender.send(not.into()).unwrap();
526 return Ok(()); 531 return Ok(());
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index c81fa7f67..39eb3df3e 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! This module is responsible for implementing handlers for Lanuage Server Protocol.
2//! The majority of requests are fulfilled by calling into the `ra_ide` crate.
2 3
3use std::{fmt::Write as _, io::Write as _}; 4use std::{fmt::Write as _, io::Write as _};
4 5
@@ -164,7 +165,7 @@ pub fn handle_on_type_formatting(
164 165
165 // in `ra_ide`, the `on_type` invariant is that 166 // in `ra_ide`, the `on_type` invariant is that
166 // `text.char_at(position) == typed_char`. 167 // `text.char_at(position) == typed_char`.
167 position.offset = position.offset - TextUnit::of_char('.'); 168 position.offset -= TextUnit::of_char('.');
168 let char_typed = params.ch.chars().next().unwrap_or('\0'); 169 let char_typed = params.ch.chars().next().unwrap_or('\0');
169 170
170 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, 171 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
@@ -480,8 +481,6 @@ pub fn handle_prepare_rename(
480 let _p = profile("handle_prepare_rename"); 481 let _p = profile("handle_prepare_rename");
481 let position = params.try_conv_with(&world)?; 482 let position = params.try_conv_with(&world)?;
482 483
483 // We support renaming references like handle_rename does.
484 // In the future we may want to reject the renaming of things like keywords here too.
485 let optional_change = world.analysis().rename(position, "dummy")?; 484 let optional_change = world.analysis().rename(position, "dummy")?;
486 let range = match optional_change { 485 let range = match optional_change {
487 None => return Ok(None), 486 None => return Ok(None),
@@ -557,12 +556,18 @@ pub fn handle_formatting(
557 let _p = profile("handle_formatting"); 556 let _p = profile("handle_formatting");
558 let file_id = params.text_document.try_conv_with(&world)?; 557 let file_id = params.text_document.try_conv_with(&world)?;
559 let file = world.analysis().file_text(file_id)?; 558 let file = world.analysis().file_text(file_id)?;
559 let crate_ids = world.analysis().crate_for(file_id)?;
560 560
561 let file_line_index = world.analysis().file_line_index(file_id)?; 561 let file_line_index = world.analysis().file_line_index(file_id)?;
562 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); 562 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
563 563
564 use std::process; 564 use std::process;
565 let mut rustfmt = process::Command::new("rustfmt"); 565 let mut rustfmt = process::Command::new("rustfmt");
566 if let Some(&crate_id) = crate_ids.first() {
567 // Assume all crates are in the same edition
568 let edition = world.analysis().crate_edition(crate_id)?;
569 rustfmt.args(&["--edition", &edition.to_string()]);
570 }
566 rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()); 571 rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped());
567 572
568 if let Ok(path) = params.text_document.uri.to_file_path() { 573 if let Ok(path) = params.text_document.uri.to_file_path() {
@@ -644,6 +649,7 @@ pub fn handle_code_action(
644 diagnostics: None, 649 diagnostics: None,
645 edit: None, 650 edit: None,
646 command: Some(command), 651 command: Some(command),
652 is_preferred: None,
647 }; 653 };
648 res.push(action.into()); 654 res.push(action.into());
649 } 655 }
@@ -666,6 +672,7 @@ pub fn handle_code_action(
666 diagnostics: None, 672 diagnostics: None,
667 edit: None, 673 edit: None,
668 command: Some(command), 674 command: Some(command),
675 is_preferred: None,
669 }; 676 };
670 res.push(action.into()); 677 res.push(action.into());
671 } 678 }
@@ -824,9 +831,10 @@ pub fn publish_diagnostics(
824 source: Some("rust-analyzer".to_string()), 831 source: Some("rust-analyzer".to_string()),
825 message: d.message, 832 message: d.message,
826 related_information: None, 833 related_information: None,
834 tags: None,
827 }) 835 })
828 .collect(); 836 .collect();
829 Ok(req::PublishDiagnosticsParams { uri, diagnostics }) 837 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })
830} 838}
831 839
832pub fn publish_decorations( 840pub fn publish_decorations(
diff --git a/crates/ra_lsp_server/src/main_loop/pending_requests.rs b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
index e7ea7aa5b..2d2213464 100644
--- a/crates/ra_lsp_server/src/main_loop/pending_requests.rs
+++ b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Datastructures that keep track of inflight requests.
2 2
3use std::time::{Duration, Instant}; 3use std::time::{Duration, Instant};
4 4
diff --git a/crates/ra_lsp_server/src/main_loop/subscriptions.rs b/crates/ra_lsp_server/src/main_loop/subscriptions.rs
index 609b2adcc..b0bae90f5 100644
--- a/crates/ra_lsp_server/src/main_loop/subscriptions.rs
+++ b/crates/ra_lsp_server/src/main_loop/subscriptions.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Keeps track of file subscriptions.
2 2
3use ra_ide::FileId; 3use ra_ide::FileId;
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
index f51fc4ade..76bef45cc 100644
--- a/crates/ra_lsp_server/src/markdown.rs
+++ b/crates/ra_lsp_server/src/markdown.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Transforms markdown
2 2
3pub(crate) fn format_docs(src: &str) -> String { 3pub(crate) fn format_docs(src: &str) -> String {
4 let mut processed_lines = Vec::new(); 4 let mut processed_lines = Vec::new();
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 39361b7e8..b34e6f9b8 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Defines `rust-analyzer` specific custom messages.
2 2
3use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 3use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url};
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
@@ -10,8 +10,9 @@ pub use lsp_types::{
10 DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, 10 DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions,
11 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, 11 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
12 FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams, 12 FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams,
13 ReferenceParams, Registration, RegistrationParams, ShowMessageParams, SignatureHelp, 13 ReferenceParams, Registration, RegistrationParams, SelectionRange, SelectionRangeParams,
14 TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, 14 ShowMessageParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, TextEdit,
15 WorkspaceEdit, WorkspaceSymbolParams,
15}; 16};
16 17
17pub enum AnalyzerStatus {} 18pub enum AnalyzerStatus {}
@@ -67,28 +68,6 @@ pub struct ExpandMacroParams {
67 pub position: Option<Position>, 68 pub position: Option<Position>,
68} 69}
69 70
70pub enum SelectionRangeRequest {}
71
72impl Request for SelectionRangeRequest {
73 type Params = SelectionRangeParams;
74 type Result = Vec<SelectionRange>;
75 const METHOD: &'static str = "textDocument/selectionRange";
76}
77
78#[derive(Deserialize, Debug)]
79#[serde(rename_all = "camelCase")]
80pub struct SelectionRangeParams {
81 pub text_document: TextDocumentIdentifier,
82 pub positions: Vec<Position>,
83}
84
85#[derive(Serialize, Debug)]
86#[serde(rename_all = "camelCase")]
87pub struct SelectionRange {
88 pub range: Range,
89 pub parent: Option<Box<SelectionRange>>,
90}
91
92pub enum FindMatchingBrace {} 71pub enum FindMatchingBrace {}
93 72
94impl Request for FindMatchingBrace { 73impl Request for FindMatchingBrace {
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 927449b45..79431e7e6 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -1,4 +1,7 @@
1//! FIXME: write short doc here 1//! The context or environment in which the language server functions.
2//! In our server implementation this is know as the `WorldState`.
3//!
4//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
2 5
3use std::{ 6use std::{
4 path::{Path, PathBuf}, 7 path::{Path, PathBuf},
@@ -17,11 +20,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 20use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
18use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 21use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
19use relative_path::RelativePathBuf; 22use relative_path::RelativePathBuf;
23use std::path::{Component, Prefix};
20 24
21use crate::{ 25use crate::{
22 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 26 main_loop::pending_requests::{CompletedRequest, LatestRequests},
23 LspError, Result, 27 LspError, Result,
24}; 28};
29use std::str::FromStr;
25 30
26#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
27pub struct Options { 32pub struct Options {
@@ -140,10 +145,10 @@ impl WorldState {
140 /// FIXME: better API here 145 /// FIXME: better API here
141 pub fn process_changes( 146 pub fn process_changes(
142 &mut self, 147 &mut self,
143 ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> { 148 ) -> Option<Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>> {
144 let changes = self.vfs.write().commit_changes(); 149 let changes = self.vfs.write().commit_changes();
145 if changes.is_empty() { 150 if changes.is_empty() {
146 return Vec::new(); 151 return None;
147 } 152 }
148 let mut libs = Vec::new(); 153 let mut libs = Vec::new();
149 let mut change = AnalysisChange::new(); 154 let mut change = AnalysisChange::new();
@@ -177,7 +182,7 @@ impl WorldState {
177 } 182 }
178 } 183 }
179 self.analysis_host.apply_change(change); 184 self.analysis_host.apply_change(change);
180 libs 185 Some(libs)
181 } 186 }
182 187
183 pub fn add_lib(&mut self, data: LibraryData) { 188 pub fn add_lib(&mut self, data: LibraryData) {
@@ -233,8 +238,8 @@ impl WorldSnapshot {
233 238
234 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { 239 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
235 let path = self.vfs.read().file2path(VfsFile(id.0)); 240 let path = self.vfs.read().file2path(VfsFile(id.0));
236 let url = Url::from_file_path(&path) 241 let url = url_from_path_with_drive_lowercasing(path)?;
237 .map_err(|_| format!("can't convert path to url: {}", path.display()))?; 242
238 Ok(url) 243 Ok(url)
239 } 244 }
240 245
@@ -279,3 +284,61 @@ impl WorldSnapshot {
279 self.analysis.feature_flags() 284 self.analysis.feature_flags()
280 } 285 }
281} 286}
287
288/// Returns a `Url` object from a given path, will lowercase drive letters if present.
289/// This will only happen when processing windows paths.
290///
291/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
292fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
293 let component_has_windows_drive = path.as_ref().components().any(|comp| {
294 if let Component::Prefix(c) = comp {
295 match c.kind() {
296 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
297 _ => return false,
298 }
299 }
300 false
301 });
302
303 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
304 if component_has_windows_drive {
305 let url_original = Url::from_file_path(&path)
306 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
307
308 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
309
310 // There is a drive partition, but we never found a colon.
311 // This should not happen, but in this case we just pass it through.
312 if drive_partition.len() == 1 {
313 return Ok(url_original);
314 }
315
316 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
317 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
318
319 Ok(url)
320 } else {
321 Ok(Url::from_file_path(&path)
322 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
323 }
324}
325
326// `Url` is not able to parse windows paths on unix machines.
327#[cfg(target_os = "windows")]
328#[cfg(test)]
329mod path_conversion_windows_tests {
330 use super::url_from_path_with_drive_lowercasing;
331 #[test]
332 fn test_lowercase_drive_letter_with_drive() {
333 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
334
335 assert_eq!(url.to_string(), "file:///c:/Test");
336 }
337
338 #[test]
339 fn test_drive_without_colon_passthrough() {
340 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
341
342 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
343 }
344}
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 2ba82ab05..dff63a12d 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -4,7 +4,8 @@ use std::{collections::HashMap, time::Instant};
4 4
5use lsp_types::{ 5use lsp_types::{
6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, 6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions,
7 Position, Range, TextDocumentItem, TextDocumentPositionParams, 7 PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams,
8 WorkDoneProgressParams,
8}; 9};
9use ra_lsp_server::req::{ 10use ra_lsp_server::req::{
10 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, 11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
@@ -12,15 +13,19 @@ use ra_lsp_server::req::{
12}; 13};
13use serde_json::json; 14use serde_json::json;
14use tempfile::TempDir; 15use tempfile::TempDir;
16use test_utils::skip_slow_tests;
15 17
16use crate::support::{project, Project}; 18use crate::support::{project, Project};
17 19
18const LOG: &'static str = "";
19const PROFILE: &'static str = ""; 20const PROFILE: &'static str = "";
20// const PROFILE: &'static str = "*@3>100"; 21// const PROFILE: &'static str = "*@3>100";
21 22
22#[test] 23#[test]
23fn completes_items_from_standard_library() { 24fn completes_items_from_standard_library() {
25 if skip_slow_tests() {
26 return;
27 }
28
24 let project_start = Instant::now(); 29 let project_start = Instant::now();
25 let server = Project::with_fixture( 30 let server = Project::with_fixture(
26 r#" 31 r#"
@@ -44,6 +49,8 @@ use std::collections::Spam;
44 Position::new(0, 23), 49 Position::new(0, 23),
45 ), 50 ),
46 context: None, 51 context: None,
52 partial_result_params: PartialResultParams::default(),
53 work_done_progress_params: WorkDoneProgressParams::default(),
47 }); 54 });
48 assert!(format!("{}", res).contains("HashMap")); 55 assert!(format!("{}", res).contains("HashMap"));
49 eprintln!("completion took {:?}", completion_start.elapsed()); 56 eprintln!("completion took {:?}", completion_start.elapsed());
@@ -51,6 +58,10 @@ use std::collections::Spam;
51 58
52#[test] 59#[test]
53fn test_runnables_no_project() { 60fn test_runnables_no_project() {
61 if skip_slow_tests() {
62 return;
63 }
64
54 let server = project( 65 let server = project(
55 r" 66 r"
56//- lib.rs 67//- lib.rs
@@ -100,6 +111,10 @@ fn foo() {
100 111
101#[test] 112#[test]
102fn test_runnables_project() { 113fn test_runnables_project() {
114 if skip_slow_tests() {
115 return;
116 }
117
103 let code = r#" 118 let code = r#"
104//- foo/Cargo.toml 119//- foo/Cargo.toml
105[package] 120[package]
@@ -171,8 +186,13 @@ fn main() {}
171 186
172#[test] 187#[test]
173fn test_format_document() { 188fn test_format_document() {
189 if skip_slow_tests() {
190 return;
191 }
192
174 let server = project( 193 let server = project(
175 r#" 194 r#"
195//- Cargo.toml
176[package] 196[package]
177name = "foo" 197name = "foo"
178version = "0.0.0" 198version = "0.0.0"
@@ -194,8 +214,12 @@ pub use std::collections::HashMap;
194 options: FormattingOptions { 214 options: FormattingOptions {
195 tab_size: 4, 215 tab_size: 4,
196 insert_spaces: false, 216 insert_spaces: false,
217 insert_final_newline: None,
218 trim_final_newlines: None,
219 trim_trailing_whitespace: None,
197 properties: HashMap::new(), 220 properties: HashMap::new(),
198 }, 221 },
222 work_done_progress_params: WorkDoneProgressParams::default(),
199 }, 223 },
200 json!([ 224 json!([
201 { 225 {
@@ -221,7 +245,77 @@ pub use std::collections::HashMap;
221} 245}
222 246
223#[test] 247#[test]
248fn test_format_document_2018() {
249 if skip_slow_tests() {
250 return;
251 }
252
253 let server = project(
254 r#"
255//- Cargo.toml
256[package]
257name = "foo"
258version = "0.0.0"
259edition = "2018"
260
261//- src/lib.rs
262mod bar;
263
264async fn test() {
265}
266
267fn main() {
268}
269
270pub use std::collections::HashMap;
271"#,
272 );
273 server.wait_until_workspace_is_loaded();
274
275 server.request::<Formatting>(
276 DocumentFormattingParams {
277 text_document: server.doc_id("src/lib.rs"),
278 options: FormattingOptions {
279 tab_size: 4,
280 insert_spaces: false,
281 properties: HashMap::new(),
282 insert_final_newline: None,
283 trim_final_newlines: None,
284 trim_trailing_whitespace: None,
285 },
286 work_done_progress_params: WorkDoneProgressParams::default(),
287 },
288 json!([
289 {
290 "newText": r#"mod bar;
291
292async fn test() {}
293
294fn main() {}
295
296pub use std::collections::HashMap;
297"#,
298 "range": {
299 "end": {
300 "character": 0,
301 "line": 10
302 },
303 "start": {
304 "character": 0,
305 "line": 0
306 }
307 }
308 }
309 ]),
310 );
311}
312
313#[test]
224fn test_missing_module_code_action() { 314fn test_missing_module_code_action() {
315 if skip_slow_tests() {
316 return;
317 }
318
225 let server = project( 319 let server = project(
226 r#" 320 r#"
227//- Cargo.toml 321//- Cargo.toml
@@ -242,6 +336,8 @@ fn main() {}
242 text_document: server.doc_id("src/lib.rs"), 336 text_document: server.doc_id("src/lib.rs"),
243 range: Range::new(Position::new(0, 4), Position::new(0, 7)), 337 range: Range::new(Position::new(0, 4), Position::new(0, 7)),
244 context: empty_context(), 338 context: empty_context(),
339 partial_result_params: PartialResultParams::default(),
340 work_done_progress_params: WorkDoneProgressParams::default(),
245 }, 341 },
246 json!([ 342 json!([
247 { 343 {
@@ -273,6 +369,8 @@ fn main() {}
273 text_document: server.doc_id("src/lib.rs"), 369 text_document: server.doc_id("src/lib.rs"),
274 range: Range::new(Position::new(2, 4), Position::new(2, 7)), 370 range: Range::new(Position::new(2, 4), Position::new(2, 7)),
275 context: empty_context(), 371 context: empty_context(),
372 partial_result_params: PartialResultParams::default(),
373 work_done_progress_params: WorkDoneProgressParams::default(),
276 }, 374 },
277 json!([]), 375 json!([]),
278 ); 376 );
@@ -280,6 +378,10 @@ fn main() {}
280 378
281#[test] 379#[test]
282fn test_missing_module_code_action_in_json_project() { 380fn test_missing_module_code_action_in_json_project() {
381 if skip_slow_tests() {
382 return;
383 }
384
283 let tmp_dir = TempDir::new().unwrap(); 385 let tmp_dir = TempDir::new().unwrap();
284 386
285 let path = tmp_dir.path(); 387 let path = tmp_dir.path();
@@ -317,6 +419,8 @@ fn main() {{}}
317 text_document: server.doc_id("src/lib.rs"), 419 text_document: server.doc_id("src/lib.rs"),
318 range: Range::new(Position::new(0, 4), Position::new(0, 7)), 420 range: Range::new(Position::new(0, 4), Position::new(0, 7)),
319 context: empty_context(), 421 context: empty_context(),
422 partial_result_params: PartialResultParams::default(),
423 work_done_progress_params: WorkDoneProgressParams::default(),
320 }, 424 },
321 json!([ 425 json!([
322 { 426 {
@@ -348,6 +452,8 @@ fn main() {{}}
348 text_document: server.doc_id("src/lib.rs"), 452 text_document: server.doc_id("src/lib.rs"),
349 range: Range::new(Position::new(2, 4), Position::new(2, 7)), 453 range: Range::new(Position::new(2, 4), Position::new(2, 7)),
350 context: empty_context(), 454 context: empty_context(),
455 partial_result_params: PartialResultParams::default(),
456 work_done_progress_params: WorkDoneProgressParams::default(),
351 }, 457 },
352 json!([]), 458 json!([]),
353 ); 459 );
@@ -355,6 +461,10 @@ fn main() {{}}
355 461
356#[test] 462#[test]
357fn diagnostics_dont_block_typing() { 463fn diagnostics_dont_block_typing() {
464 if skip_slow_tests() {
465 return;
466 }
467
358 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect(); 468 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
359 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect(); 469 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
360 let server = Project::with_fixture(&format!( 470 let server = Project::with_fixture(&format!(
@@ -423,6 +533,10 @@ fn main() {{}}
423 533
424#[test] 534#[test]
425fn preserves_dos_line_endings() { 535fn preserves_dos_line_endings() {
536 if skip_slow_tests() {
537 return;
538 }
539
426 let server = Project::with_fixture( 540 let server = Project::with_fixture(
427 &" 541 &"
428//- Cargo.toml 542//- Cargo.toml
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 86073b57d..d5ea52fa9 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -7,7 +7,6 @@ use std::{
7}; 7};
8 8
9use crossbeam_channel::{after, select, Receiver}; 9use crossbeam_channel::{after, select, Receiver};
10use flexi_logger::Logger;
11use lsp_server::{Connection, Message, Notification, Request}; 10use lsp_server::{Connection, Message, Notification, Request};
12use lsp_types::{ 11use lsp_types::{
13 notification::{DidOpenTextDocument, Exit}, 12 notification::{DidOpenTextDocument, Exit},
@@ -53,7 +52,7 @@ impl<'a> Project<'a> {
53 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap()); 52 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
54 static INIT: Once = Once::new(); 53 static INIT: Once = Once::new();
55 INIT.call_once(|| { 54 INIT.call_once(|| {
56 let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); 55 let _ = env_logger::builder().is_test(true).try_init().unwrap();
57 ra_prof::set_filter(if crate::PROFILE.is_empty() { 56 ra_prof::set_filter(if crate::PROFILE.is_empty() {
58 ra_prof::Filter::disabled() 57 ra_prof::Filter::disabled()
59 } else { 58 } else {
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index bbddebe67..2c6ae5658 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -67,7 +67,15 @@ impl Shift {
67 .token_trees 67 .token_trees
68 .iter() 68 .iter()
69 .filter_map(|tt| match tt { 69 .filter_map(|tt| match tt {
70 tt::TokenTree::Subtree(subtree) => max_id(subtree), 70 tt::TokenTree::Subtree(subtree) => {
71 let tree_id = max_id(subtree);
72 match subtree.delimiter {
73 Some(it) if it.id != tt::TokenId::unspecified() => {
74 Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0)))
75 }
76 _ => tree_id,
77 }
78 }
71 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) 79 tt::TokenTree::Leaf(tt::Leaf::Ident(ident))
72 if ident.id != tt::TokenId::unspecified() => 80 if ident.id != tt::TokenId::unspecified() =>
73 { 81 {
@@ -85,9 +93,15 @@ impl Shift {
85 match t { 93 match t {
86 tt::TokenTree::Leaf(leaf) => match leaf { 94 tt::TokenTree::Leaf(leaf) => match leaf {
87 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), 95 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id),
88 _ => (), 96 tt::Leaf::Punct(punct) => punct.id = self.shift(punct.id),
97 tt::Leaf::Literal(lit) => lit.id = self.shift(lit.id),
89 }, 98 },
90 tt::TokenTree::Subtree(tt) => self.shift_all(tt), 99 tt::TokenTree::Subtree(tt) => {
100 if let Some(it) = tt.delimiter.as_mut() {
101 it.id = self.shift(it.id);
102 };
103 self.shift_all(tt)
104 }
91 } 105 }
92 } 106 }
93 } 107 }
@@ -104,6 +118,7 @@ impl Shift {
104 } 118 }
105} 119}
106 120
121#[derive(Debug, Eq, PartialEq)]
107pub enum Origin { 122pub enum Origin {
108 Def, 123 Def,
109 Call, 124 Call,
@@ -159,14 +174,14 @@ impl Rule {
159 .expect_subtree() 174 .expect_subtree()
160 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 175 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
161 .clone(); 176 .clone();
162 lhs.delimiter = tt::Delimiter::None; 177 lhs.delimiter = None;
163 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; 178 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?;
164 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; 179 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?;
165 let mut rhs = src 180 let mut rhs = src
166 .expect_subtree() 181 .expect_subtree()
167 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 182 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
168 .clone(); 183 .clone();
169 rhs.delimiter = tt::Delimiter::None; 184 rhs.delimiter = None;
170 Ok(crate::Rule { lhs, rhs }) 185 Ok(crate::Rule { lhs, rhs })
171 } 186 }
172} 187}
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 33b9d483d..e36b5a412 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -16,7 +16,7 @@ impl Bindings {
16 fn push_optional(&mut self, name: &SmolStr) { 16 fn push_optional(&mut self, name: &SmolStr) {
17 // FIXME: Do we have a better way to represent an empty token ? 17 // FIXME: Do we have a better way to represent an empty token ?
18 // Insert an empty subtree for empty token 18 // Insert an empty subtree for empty token
19 let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(); 19 let tt = tt::Subtree::default().into();
20 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); 20 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
21 } 21 }
22 22
@@ -65,7 +65,7 @@ macro_rules! bail {
65} 65}
66 66
67pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { 67pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> {
68 assert!(pattern.delimiter == tt::Delimiter::None); 68 assert!(pattern.delimiter == None);
69 69
70 let mut res = Bindings::default(); 70 let mut res = Bindings::default();
71 let mut src = TtIter::new(src); 71 let mut src = TtIter::new(src);
@@ -106,7 +106,7 @@ fn match_subtree(
106 } 106 }
107 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { 107 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
108 let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; 108 let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?;
109 if lhs.delimiter != rhs.delimiter { 109 if lhs.delimiter_kind() != rhs.delimiter_kind() {
110 bail!("mismatched delimiter") 110 bail!("mismatched delimiter")
111 } 111 }
112 let mut src = TtIter::new(rhs); 112 let mut src = TtIter::new(rhs);
@@ -210,7 +210,7 @@ impl<'a> TtIter<'a> {
210 0 => Err(()), 210 0 => Err(()),
211 1 => Ok(res[0].clone()), 211 1 => Ok(res[0].clone()),
212 _ => Ok(tt::TokenTree::Subtree(tt::Subtree { 212 _ => Ok(tt::TokenTree::Subtree(tt::Subtree {
213 delimiter: tt::Delimiter::None, 213 delimiter: None,
214 token_trees: res.into_iter().cloned().collect(), 214 token_trees: res.into_iter().cloned().collect(),
215 })), 215 })),
216 } 216 }
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index ed094d5bb..eda66cd50 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -50,7 +50,7 @@ pub(super) fn transcribe(
50 template: &tt::Subtree, 50 template: &tt::Subtree,
51 bindings: &Bindings, 51 bindings: &Bindings,
52) -> Result<tt::Subtree, ExpandError> { 52) -> Result<tt::Subtree, ExpandError> {
53 assert!(template.delimiter == tt::Delimiter::None); 53 assert!(template.delimiter == None);
54 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; 54 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
55 expand_subtree(&mut ctx, template) 55 expand_subtree(&mut ctx, template)
56} 56}
@@ -106,9 +106,14 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError>
106 // ``` 106 // ```
107 // We just treat it a normal tokens 107 // We just treat it a normal tokens
108 let tt = tt::Subtree { 108 let tt = tt::Subtree {
109 delimiter: tt::Delimiter::None, 109 delimiter: None,
110 token_trees: vec![ 110 token_trees: vec![
111 tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }).into(), 111 tt::Leaf::from(tt::Punct {
112 char: '$',
113 spacing: tt::Spacing::Alone,
114 id: tt::TokenId::unspecified(),
115 })
116 .into(),
112 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) 117 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
113 .into(), 118 .into(),
114 ], 119 ],
@@ -147,7 +152,7 @@ fn expand_repeat(
147 ctx.var_expanded = false; 152 ctx.var_expanded = false;
148 153
149 while let Ok(mut t) = expand_subtree(ctx, template) { 154 while let Ok(mut t) = expand_subtree(ctx, template) {
150 t.delimiter = tt::Delimiter::None; 155 t.delimiter = None;
151 // if no var expanded in the child, we count it as a fail 156 // if no var expanded in the child, we count it as a fail
152 if !ctx.var_expanded { 157 if !ctx.var_expanded {
153 break; 158 break;
@@ -212,7 +217,7 @@ fn expand_repeat(
212 217
213 // Check if it is a single token subtree without any delimiter 218 // Check if it is a single token subtree without any delimiter
214 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 219 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
215 let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into(); 220 let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
216 Ok(Fragment::Tokens(tt)) 221 Ok(Fragment::Tokens(tt))
217} 222}
218 223
@@ -225,7 +230,7 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
225 230
226fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { 231fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
227 match tt.delimiter { 232 match tt.delimiter {
228 tt::Delimiter::None => buf.extend(tt.token_trees), 233 None => buf.extend(tt.token_trees),
229 _ => buf.push(tt.into()), 234 _ => buf.push(tt.into()),
230 } 235 }
231} 236}
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs
index 7ef45f6dc..b841c39d3 100644
--- a/crates/ra_mbe/src/subtree_source.rs
+++ b/crates/ra_mbe/src/subtree_source.rs
@@ -70,11 +70,11 @@ impl<'a> SubtreeTokenSource<'a> {
70 } 70 }
71 Some(tt::TokenTree::Subtree(subtree)) => { 71 Some(tt::TokenTree::Subtree(subtree)) => {
72 self.cached_cursor.set(cursor.subtree().unwrap()); 72 self.cached_cursor.set(cursor.subtree().unwrap());
73 cached.push(Some(convert_delim(subtree.delimiter, false))); 73 cached.push(Some(convert_delim(subtree.delimiter_kind(), false)));
74 } 74 }
75 None => { 75 None => {
76 if let Some(subtree) = cursor.end() { 76 if let Some(subtree) = cursor.end() {
77 cached.push(Some(convert_delim(subtree.delimiter, true))); 77 cached.push(Some(convert_delim(subtree.delimiter_kind(), true)));
78 self.cached_cursor.set(cursor.bump()); 78 self.cached_cursor.set(cursor.bump());
79 } 79 }
80 } 80 }
@@ -114,12 +114,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> {
114 } 114 }
115} 115}
116 116
117fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken { 117fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
118 let (kinds, texts) = match d { 118 let (kinds, texts) = match d {
119 tt::Delimiter::Parenthesis => ([T!['('], T![')']], "()"), 119 Some(tt::DelimiterKind::Parenthesis) => ([T!['('], T![')']], "()"),
120 tt::Delimiter::Brace => ([T!['{'], T!['}']], "{}"), 120 Some(tt::DelimiterKind::Brace) => ([T!['{'], T!['}']], "{}"),
121 tt::Delimiter::Bracket => ([T!['['], T![']']], "[]"), 121 Some(tt::DelimiterKind::Bracket) => ([T!['['], T![']']], "[]"),
122 tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""), 122 None => ([L_DOLLAR, R_DOLLAR], ""),
123 }; 123 };
124 124
125 let idx = closing as usize; 125 let idx = closing as usize;
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 1de399fee..ea2cac069 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -2,25 +2,45 @@
2 2
3use ra_parser::{FragmentKind, ParseError, TreeSink}; 3use ra_parser::{FragmentKind, ParseError, TreeSink};
4use ra_syntax::{ 4use ra_syntax::{
5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, 5 ast, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
6 SyntaxTreeBuilder, TextRange, TextUnit, T, 6 SyntaxTreeBuilder, TextRange, TextUnit, T,
7}; 7};
8use rustc_hash::FxHashMap;
8use std::iter::successors; 9use std::iter::successors;
9use tt::buffer::{Cursor, TokenBuffer}; 10use tt::buffer::{Cursor, TokenBuffer};
10 11
11use crate::subtree_source::SubtreeTokenSource; 12use crate::subtree_source::SubtreeTokenSource;
12use crate::ExpandError; 13use crate::ExpandError;
13 14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16pub enum TokenTextRange {
17 Token(TextRange),
18 Delimiter(TextRange, TextRange),
19}
20
21impl TokenTextRange {
22 pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> {
23 match self {
24 TokenTextRange::Token(it) => Some(it),
25 TokenTextRange::Delimiter(open, close) => match kind {
26 T!['{'] | T!['('] | T!['['] => Some(open),
27 T!['}'] | T![')'] | T![']'] => Some(close),
28 _ => None,
29 },
30 }
31 }
32}
33
14/// Maps `tt::TokenId` to the relative range of the original token. 34/// Maps `tt::TokenId` to the relative range of the original token.
15#[derive(Debug, PartialEq, Eq, Default)] 35#[derive(Debug, PartialEq, Eq, Default)]
16pub struct TokenMap { 36pub struct TokenMap {
17 /// Maps `tt::TokenId` to the *relative* source range. 37 /// Maps `tt::TokenId` to the *relative* source range.
18 entries: Vec<(tt::TokenId, TextRange)>, 38 entries: Vec<(tt::TokenId, TokenTextRange)>,
19} 39}
20 40
21/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro 41/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
22/// will consume). 42/// will consume).
23pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 43pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> Option<(tt::Subtree, TokenMap)> {
24 syntax_node_to_token_tree(ast.syntax()) 44 syntax_node_to_token_tree(ast.syntax())
25} 45}
26 46
@@ -51,7 +71,7 @@ pub fn token_tree_to_syntax_node(
51) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { 71) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
52 let tmp; 72 let tmp;
53 let tokens = match tt { 73 let tokens = match tt {
54 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), 74 tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(),
55 _ => { 75 _ => {
56 tmp = [tt.clone().into()]; 76 tmp = [tt.clone().into()];
57 &tmp[..] 77 &tmp[..]
@@ -71,17 +91,32 @@ pub fn token_tree_to_syntax_node(
71 91
72impl TokenMap { 92impl TokenMap {
73 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { 93 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> {
74 let &(token_id, _) = self.entries.iter().find(|(_, range)| *range == relative_range)?; 94 let &(token_id, _) = self.entries.iter().find(|(_, range)| match range {
95 TokenTextRange::Token(it) => *it == relative_range,
96 TokenTextRange::Delimiter(open, close) => {
97 *open == relative_range || *close == relative_range
98 }
99 })?;
75 Some(token_id) 100 Some(token_id)
76 } 101 }
77 102
78 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> { 103 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TokenTextRange> {
79 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; 104 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?;
80 Some(range) 105 Some(range)
81 } 106 }
82 107
83 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { 108 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) {
84 self.entries.push((token_id, relative_range)); 109 self.entries.push((token_id, TokenTextRange::Token(relative_range)));
110 }
111
112 fn insert_delim(
113 &mut self,
114 token_id: tt::TokenId,
115 open_relative_range: TextRange,
116 close_relative_range: TextRange,
117 ) {
118 self.entries
119 .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range)));
85 } 120 }
86} 121}
87 122
@@ -121,7 +156,10 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
121 token_trees.push(mk_punct('!')); 156 token_trees.push(mk_punct('!'));
122 } 157 }
123 token_trees.push(tt::TokenTree::from(tt::Subtree { 158 token_trees.push(tt::TokenTree::from(tt::Subtree {
124 delimiter: tt::Delimiter::Bracket, 159 delimiter: Some(tt::Delimiter {
160 kind: tt::DelimiterKind::Bracket,
161 id: tt::TokenId::unspecified(),
162 }),
125 token_trees: meta_tkns, 163 token_trees: meta_tkns,
126 })); 164 }));
127 165
@@ -136,11 +174,15 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
136 } 174 }
137 175
138 fn mk_punct(c: char) -> tt::TokenTree { 176 fn mk_punct(c: char) -> tt::TokenTree {
139 tt::TokenTree::from(tt::Leaf::from(tt::Punct { char: c, spacing: tt::Spacing::Alone })) 177 tt::TokenTree::from(tt::Leaf::from(tt::Punct {
178 char: c,
179 spacing: tt::Spacing::Alone,
180 id: tt::TokenId::unspecified(),
181 }))
140 } 182 }
141 183
142 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree { 184 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
143 let lit = tt::Literal { text: doc_comment_text(comment) }; 185 let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() };
144 186
145 tt::TokenTree::from(tt::Leaf::from(lit)) 187 tt::TokenTree::from(tt::Leaf::from(lit))
146 } 188 }
@@ -156,7 +198,7 @@ impl Convertor {
156 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> { 198 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> {
157 // This tree is empty 199 // This tree is empty
158 if tt.first_child_or_token().is_none() { 200 if tt.first_child_or_token().is_none() {
159 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 201 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
160 } 202 }
161 203
162 let first_child = tt.first_child_or_token()?; 204 let first_child = tt.first_child_or_token()?;
@@ -173,7 +215,7 @@ impl Convertor {
173 .last() 215 .last()
174 .unwrap(); 216 .unwrap();
175 if first_child.kind().is_trivia() { 217 if first_child.kind().is_trivia() {
176 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 218 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
177 } 219 }
178 220
179 let last_child = successors(Some(last_child), |it| { 221 let last_child = successors(Some(last_child), |it| {
@@ -186,12 +228,16 @@ impl Convertor {
186 .last() 228 .last()
187 .unwrap(); 229 .unwrap();
188 230
189 let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { 231 let (delimiter_kind, skip_first) = match (first_child.kind(), last_child.kind()) {
190 (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), 232 (T!['('], T![')']) => (Some(tt::DelimiterKind::Parenthesis), true),
191 (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), 233 (T!['{'], T!['}']) => (Some(tt::DelimiterKind::Brace), true),
192 (T!['['], T![']']) => (tt::Delimiter::Bracket, true), 234 (T!['['], T![']']) => (Some(tt::DelimiterKind::Bracket), true),
193 _ => (tt::Delimiter::None, false), 235 _ => (None, false),
194 }; 236 };
237 let delimiter = delimiter_kind.map(|kind| tt::Delimiter {
238 kind,
239 id: self.alloc_delim(first_child.text_range(), last_child.text_range()),
240 });
195 241
196 let mut token_trees = Vec::new(); 242 let mut token_trees = Vec::new();
197 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable(); 243 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable();
@@ -208,13 +254,8 @@ impl Convertor {
208 } else if token.kind().is_trivia() { 254 } else if token.kind().is_trivia() {
209 continue; 255 continue;
210 } else if token.kind().is_punct() { 256 } else if token.kind().is_punct() {
211 assert!( 257 // we need to pull apart joined punctuation tokens
212 token.text().len() == 1, 258 let last_spacing = match child_iter.peek() {
213 "Input ast::token punct must be single char."
214 );
215 let char = token.text().chars().next().unwrap();
216
217 let spacing = match child_iter.peek() {
218 Some(NodeOrToken::Token(token)) => { 259 Some(NodeOrToken::Token(token)) => {
219 if token.kind().is_punct() { 260 if token.kind().is_punct() {
220 tt::Spacing::Joint 261 tt::Spacing::Joint
@@ -224,30 +265,47 @@ impl Convertor {
224 } 265 }
225 _ => tt::Spacing::Alone, 266 _ => tt::Spacing::Alone,
226 }; 267 };
227 268 let spacing_iter = std::iter::repeat(tt::Spacing::Joint)
228 token_trees.push(tt::Leaf::from(tt::Punct { char, spacing }).into()); 269 .take(token.text().len() - 1)
270 .chain(std::iter::once(last_spacing));
271 for (char, spacing) in token.text().chars().zip(spacing_iter) {
272 token_trees.push(
273 tt::Leaf::from(tt::Punct {
274 char,
275 spacing,
276 id: self.alloc(token.text_range()),
277 })
278 .into(),
279 );
280 }
229 } else { 281 } else {
230 let child: tt::TokenTree = 282 macro_rules! make_leaf {
231 if token.kind() == T![true] || token.kind() == T![false] { 283 ($i:ident) => {
232 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() 284 tt::$i {
233 } else if token.kind().is_keyword() 285 id: self.alloc(token.text_range()),
234 || token.kind() == IDENT 286 text: token.text().clone(),
235 || token.kind() == LIFETIME 287 }
236 { 288 .into()
237 let id = self.alloc(token.text_range());
238 let text = token.text().clone();
239 tt::Leaf::from(tt::Ident { text, id }).into()
240 } else if token.kind().is_literal() {
241 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into()
242 } else {
243 return None;
244 }; 289 };
245 token_trees.push(child); 290 }
291
292 let child: tt::Leaf = match token.kind() {
293 T![true] | T![false] => make_leaf!(Literal),
294 IDENT | LIFETIME => make_leaf!(Ident),
295 k if k.is_keyword() => make_leaf!(Ident),
296 k if k.is_literal() => make_leaf!(Literal),
297 _ => return None,
298 };
299 token_trees.push(child.into());
246 } 300 }
247 } 301 }
248 NodeOrToken::Node(node) => { 302 NodeOrToken::Node(node) => {
249 let child = self.go(&node)?.into(); 303 let child_subtree = self.go(&node)?;
250 token_trees.push(child); 304 if child_subtree.delimiter.is_none() && node.kind() != SyntaxKind::TOKEN_TREE {
305 token_trees.extend(child_subtree.token_trees);
306 } else {
307 token_trees.push(child_subtree.into());
308 }
251 } 309 }
252 }; 310 };
253 } 311 }
@@ -263,11 +321,26 @@ impl Convertor {
263 self.map.insert(token_id, relative_range); 321 self.map.insert(token_id, relative_range);
264 token_id 322 token_id
265 } 323 }
324
325 fn alloc_delim(
326 &mut self,
327 open_abs_range: TextRange,
328 close_abs_range: TextRange,
329 ) -> tt::TokenId {
330 let open_relative_range = open_abs_range - self.global_offset;
331 let close_relative_range = close_abs_range - self.global_offset;
332 let token_id = tt::TokenId(self.next_id);
333 self.next_id += 1;
334
335 self.map.insert_delim(token_id, open_relative_range, close_relative_range);
336 token_id
337 }
266} 338}
267 339
268struct TtTreeSink<'a> { 340struct TtTreeSink<'a> {
269 buf: String, 341 buf: String,
270 cursor: Cursor<'a>, 342 cursor: Cursor<'a>,
343 open_delims: FxHashMap<tt::TokenId, TextUnit>,
271 text_pos: TextUnit, 344 text_pos: TextUnit,
272 inner: SyntaxTreeBuilder, 345 inner: SyntaxTreeBuilder,
273 token_map: TokenMap, 346 token_map: TokenMap,
@@ -282,6 +355,7 @@ impl<'a> TtTreeSink<'a> {
282 TtTreeSink { 355 TtTreeSink {
283 buf: String::new(), 356 buf: String::new(),
284 cursor, 357 cursor,
358 open_delims: FxHashMap::default(),
285 text_pos: 0.into(), 359 text_pos: 0.into(),
286 inner: SyntaxTreeBuilder::default(), 360 inner: SyntaxTreeBuilder::default(),
287 roots: smallvec::SmallVec::new(), 361 roots: smallvec::SmallVec::new(),
@@ -294,16 +368,16 @@ impl<'a> TtTreeSink<'a> {
294 } 368 }
295} 369}
296 370
297fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { 371fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr {
298 let texts = match d { 372 let texts = match d {
299 tt::Delimiter::Parenthesis => "()", 373 Some(tt::DelimiterKind::Parenthesis) => "()",
300 tt::Delimiter::Brace => "{}", 374 Some(tt::DelimiterKind::Brace) => "{}",
301 tt::Delimiter::Bracket => "[]", 375 Some(tt::DelimiterKind::Bracket) => "[]",
302 tt::Delimiter::None => "", 376 None => return "".into(),
303 }; 377 };
304 378
305 let idx = closing as usize; 379 let idx = closing as usize;
306 let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; 380 let text = &texts[idx..texts.len() - (1 - idx)];
307 text.into() 381 text.into()
308} 382}
309 383
@@ -319,34 +393,49 @@ impl<'a> TreeSink for TtTreeSink<'a> {
319 break; 393 break;
320 } 394 }
321 395
322 match self.cursor.token_tree() { 396 let text: SmolStr = match self.cursor.token_tree() {
323 Some(tt::TokenTree::Leaf(leaf)) => { 397 Some(tt::TokenTree::Leaf(leaf)) => {
324 // Mark the range if needed 398 // Mark the range if needed
325 if let tt::Leaf::Ident(ident) = leaf { 399 let id = match leaf {
326 if kind == IDENT { 400 tt::Leaf::Ident(ident) => ident.id,
327 let range = 401 tt::Leaf::Punct(punct) => punct.id,
328 TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); 402 tt::Leaf::Literal(lit) => lit.id,
329 self.token_map.insert(ident.id, range); 403 };
330 } 404 let text = SmolStr::new(format!("{}", leaf));
331 } 405 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text));
332 406 self.token_map.insert(id, range);
333 self.cursor = self.cursor.bump(); 407 self.cursor = self.cursor.bump();
334 self.buf += &format!("{}", leaf); 408 text
335 } 409 }
336 Some(tt::TokenTree::Subtree(subtree)) => { 410 Some(tt::TokenTree::Subtree(subtree)) => {
337 self.cursor = self.cursor.subtree().unwrap(); 411 self.cursor = self.cursor.subtree().unwrap();
338 self.buf += &delim_to_str(subtree.delimiter, false); 412 if let Some(id) = subtree.delimiter.map(|it| it.id) {
413 self.open_delims.insert(id, self.text_pos);
414 }
415 delim_to_str(subtree.delimiter_kind(), false)
339 } 416 }
340 None => { 417 None => {
341 if let Some(parent) = self.cursor.end() { 418 if let Some(parent) = self.cursor.end() {
342 self.cursor = self.cursor.bump(); 419 self.cursor = self.cursor.bump();
343 self.buf += &delim_to_str(parent.delimiter, true); 420 if let Some(id) = parent.delimiter.map(|it| it.id) {
421 if let Some(open_delim) = self.open_delims.get(&id) {
422 let open_range =
423 TextRange::offset_len(*open_delim, TextUnit::from_usize(1));
424 let close_range =
425 TextRange::offset_len(self.text_pos, TextUnit::from_usize(1));
426 self.token_map.insert_delim(id, open_range, close_range);
427 }
428 }
429 delim_to_str(parent.delimiter_kind(), true)
430 } else {
431 continue;
344 } 432 }
345 } 433 }
346 }; 434 };
435 self.buf += &text;
436 self.text_pos += TextUnit::of_str(&text);
347 } 437 }
348 438
349 self.text_pos += TextUnit::of_str(&self.buf);
350 let text = SmolStr::new(self.buf.as_str()); 439 let text = SmolStr::new(self.buf.as_str());
351 self.buf.clear(); 440 self.buf.clear();
352 self.inner.token(kind, text); 441 self.inner.token(kind, text);
@@ -387,13 +476,16 @@ impl<'a> TreeSink for TtTreeSink<'a> {
387#[cfg(test)] 476#[cfg(test)]
388mod tests { 477mod tests {
389 use super::*; 478 use super::*;
390 use crate::tests::{create_rules, expand}; 479 use crate::tests::parse_macro;
391 use ra_parser::TokenSource; 480 use ra_parser::TokenSource;
392 use ra_syntax::algo::{insert_children, InsertPosition}; 481 use ra_syntax::{
482 algo::{insert_children, InsertPosition},
483 ast::AstNode,
484 };
393 485
394 #[test] 486 #[test]
395 fn convert_tt_token_source() { 487 fn convert_tt_token_source() {
396 let rules = create_rules( 488 let expansion = parse_macro(
397 r#" 489 r#"
398 macro_rules! literals { 490 macro_rules! literals {
399 ($i:ident) => { 491 ($i:ident) => {
@@ -406,8 +498,8 @@ mod tests {
406 } 498 }
407 } 499 }
408 "#, 500 "#,
409 ); 501 )
410 let expansion = expand(&rules, "literals!(foo);"); 502 .expand_tt("literals!(foo);");
411 let tts = &[expansion.into()]; 503 let tts = &[expansion.into()];
412 let buffer = tt::buffer::TokenBuffer::new(tts); 504 let buffer = tt::buffer::TokenBuffer::new(tts);
413 let mut tt_src = SubtreeTokenSource::new(&buffer); 505 let mut tt_src = SubtreeTokenSource::new(&buffer);
@@ -435,7 +527,7 @@ mod tests {
435 527
436 #[test] 528 #[test]
437 fn stmts_token_trees_to_expr_is_err() { 529 fn stmts_token_trees_to_expr_is_err() {
438 let rules = create_rules( 530 let expansion = parse_macro(
439 r#" 531 r#"
440 macro_rules! stmts { 532 macro_rules! stmts {
441 () => { 533 () => {
@@ -446,8 +538,8 @@ mod tests {
446 } 538 }
447 } 539 }
448 "#, 540 "#,
449 ); 541 )
450 let expansion = expand(&rules, "stmts!();"); 542 .expand_tt("stmts!();");
451 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); 543 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
452 } 544 }
453 545
@@ -489,6 +581,14 @@ mod tests {
489 let token_tree = ast::TokenTree::cast(token_tree).unwrap(); 581 let token_tree = ast::TokenTree::cast(token_tree).unwrap();
490 let tt = ast_to_token_tree(&token_tree).unwrap().0; 582 let tt = ast_to_token_tree(&token_tree).unwrap().0;
491 583
492 assert_eq!(tt.delimiter, tt::Delimiter::Brace); 584 assert_eq!(tt.delimiter_kind(), Some(tt::DelimiterKind::Brace));
585 }
586
587 #[test]
588 fn test_token_tree_multi_char_punct() {
589 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap();
590 let struct_def = source_file.syntax().descendants().find_map(ast::StructDef::cast).unwrap();
591 let tt = ast_to_token_tree(&struct_def).unwrap().0;
592 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap();
493 } 593 }
494} 594}
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 0109a4d98..e640d115b 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,5 +1,7 @@
1use std::fmt::Write;
2
1use ra_parser::FragmentKind; 3use ra_parser::FragmentKind;
2use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; 4use ra_syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T};
3use test_utils::assert_eq_text; 5use test_utils::assert_eq_text;
4 6
5use super::*; 7use super::*;
@@ -61,13 +63,14 @@ mod rule_parsing {
61 63
62#[test] 64#[test]
63fn test_token_id_shift() { 65fn test_token_id_shift() {
64 let macro_definition = r#" 66 let expansion = parse_macro(
67 r#"
65macro_rules! foobar { 68macro_rules! foobar {
66 ($e:ident) => { foo bar $e } 69 ($e:ident) => { foo bar $e }
67} 70}
68"#; 71"#,
69 let rules = create_rules(macro_definition); 72 )
70 let expansion = expand(&rules, "foobar!(baz);"); 73 .expand_tt("foobar!(baz);");
71 74
72 fn get_id(t: &tt::TokenTree) -> Option<u32> { 75 fn get_id(t: &tt::TokenTree) -> Option<u32> {
73 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t { 76 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
@@ -77,18 +80,47 @@ macro_rules! foobar {
77 } 80 }
78 81
79 assert_eq!(expansion.token_trees.len(), 3); 82 assert_eq!(expansion.token_trees.len(), 3);
80 // ($e:ident) => { foo bar $e } 83 // {($e:ident) => { foo bar $e }}
81 // 0 1 2 3 4 84 // 012345 67 8 9 T 12
82 assert_eq!(get_id(&expansion.token_trees[0]), Some(2)); 85 assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
83 assert_eq!(get_id(&expansion.token_trees[1]), Some(3)); 86 assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
84 87
85 // So baz should be 5 88 // The input args of macro call include parentheses:
86 assert_eq!(get_id(&expansion.token_trees[2]), Some(5)); 89 // (baz)
90 // So baz should be 12+1+1
91 assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
92}
93
94#[test]
95fn test_token_map() {
96 let expanded = parse_macro(
97 r#"
98macro_rules! foobar {
99 ($e:ident) => { fn $e() {} }
100}
101"#,
102 )
103 .expand_tt("foobar!(baz);");
104
105 let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap();
106 let content = node.syntax_node().to_string();
107
108 let get_text = |id, kind| -> String {
109 content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string()
110 };
111
112 assert_eq!(expanded.token_trees.len(), 4);
113 // {($e:ident) => { fn $e() {} }}
114 // 012345 67 8 9 T12 3
115
116 assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
117 assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
118 assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
87} 119}
88 120
89#[test] 121#[test]
90fn test_convert_tt() { 122fn test_convert_tt() {
91 let macro_definition = r#" 123 parse_macro(r#"
92macro_rules! impl_froms { 124macro_rules! impl_froms {
93 ($e:ident: $($v:ident),*) => { 125 ($e:ident: $($v:ident),*) => {
94 $( 126 $(
@@ -100,24 +132,17 @@ macro_rules! impl_froms {
100 )* 132 )*
101 } 133 }
102} 134}
103"#; 135"#)
104 136 .assert_expand_tt(
105 let macro_invocation = r#" 137 "impl_froms!(TokenTree: Leaf, Subtree);",
106impl_froms!(TokenTree: Leaf, Subtree); 138 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
107"#; 139 impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
108 140 );
109 let rules = create_rules(macro_definition);
110 let expansion = expand(&rules, macro_invocation);
111 assert_eq!(
112 expansion.to_string(),
113 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
114 impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
115 )
116} 141}
117 142
118#[test] 143#[test]
119fn test_expr_order() { 144fn test_expr_order() {
120 let rules = create_rules( 145 let expanded = parse_macro(
121 r#" 146 r#"
122 macro_rules! foo { 147 macro_rules! foo {
123 ($ i:expr) => { 148 ($ i:expr) => {
@@ -125,11 +150,10 @@ fn test_expr_order() {
125 } 150 }
126 } 151 }
127"#, 152"#,
128 ); 153 )
129 let expanded = expand(&rules, "foo! { 1 + 1}"); 154 .expand_items("foo! { 1 + 1}");
130 let tree = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
131 155
132 let dump = format!("{:#?}", tree); 156 let dump = format!("{:#?}", expanded);
133 assert_eq_text!( 157 assert_eq_text!(
134 dump.trim(), 158 dump.trim(),
135 r#"MACRO_ITEMS@[0; 15) 159 r#"MACRO_ITEMS@[0; 15)
@@ -161,7 +185,7 @@ fn test_expr_order() {
161 185
162#[test] 186#[test]
163fn test_fail_match_pattern_by_first_token() { 187fn test_fail_match_pattern_by_first_token() {
164 let rules = create_rules( 188 parse_macro(
165 r#" 189 r#"
166 macro_rules! foo { 190 macro_rules! foo {
167 ($ i:ident) => ( 191 ($ i:ident) => (
@@ -175,16 +199,15 @@ fn test_fail_match_pattern_by_first_token() {
175 ) 199 )
176 } 200 }
177"#, 201"#,
178 ); 202 )
179 203 .assert_expand_items("foo! { foo }", "mod foo {}")
180 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 204 .assert_expand_items("foo! { = bar }", "fn bar () {}")
181 assert_expansion(MacroKind::Items, &rules, "foo! { = bar }", "fn bar () {}"); 205 .assert_expand_items("foo! { + Baz }", "struct Baz ;");
182 assert_expansion(MacroKind::Items, &rules, "foo! { + Baz }", "struct Baz ;");
183} 206}
184 207
185#[test] 208#[test]
186fn test_fail_match_pattern_by_last_token() { 209fn test_fail_match_pattern_by_last_token() {
187 let rules = create_rules( 210 parse_macro(
188 r#" 211 r#"
189 macro_rules! foo { 212 macro_rules! foo {
190 ($ i:ident) => ( 213 ($ i:ident) => (
@@ -198,16 +221,15 @@ fn test_fail_match_pattern_by_last_token() {
198 ) 221 )
199 } 222 }
200"#, 223"#,
201 ); 224 )
202 225 .assert_expand_items("foo! { foo }", "mod foo {}")
203 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 226 .assert_expand_items("foo! { bar = }", "fn bar () {}")
204 assert_expansion(MacroKind::Items, &rules, "foo! { bar = }", "fn bar () {}"); 227 .assert_expand_items("foo! { Baz + }", "struct Baz ;");
205 assert_expansion(MacroKind::Items, &rules, "foo! { Baz + }", "struct Baz ;");
206} 228}
207 229
208#[test] 230#[test]
209fn test_fail_match_pattern_by_word_token() { 231fn test_fail_match_pattern_by_word_token() {
210 let rules = create_rules( 232 parse_macro(
211 r#" 233 r#"
212 macro_rules! foo { 234 macro_rules! foo {
213 ($ i:ident) => ( 235 ($ i:ident) => (
@@ -221,16 +243,15 @@ fn test_fail_match_pattern_by_word_token() {
221 ) 243 )
222 } 244 }
223"#, 245"#,
224 ); 246 )
225 247 .assert_expand_items("foo! { foo }", "mod foo {}")
226 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 248 .assert_expand_items("foo! { spam bar }", "fn bar () {}")
227 assert_expansion(MacroKind::Items, &rules, "foo! { spam bar }", "fn bar () {}"); 249 .assert_expand_items("foo! { eggs Baz }", "struct Baz ;");
228 assert_expansion(MacroKind::Items, &rules, "foo! { eggs Baz }", "struct Baz ;");
229} 250}
230 251
231#[test] 252#[test]
232fn test_match_group_pattern_by_separator_token() { 253fn test_match_group_pattern_by_separator_token() {
233 let rules = create_rules( 254 parse_macro(
234 r#" 255 r#"
235 macro_rules! foo { 256 macro_rules! foo {
236 ($ ($ i:ident),*) => ($ ( 257 ($ ($ i:ident),*) => ($ (
@@ -245,16 +266,15 @@ fn test_match_group_pattern_by_separator_token() {
245 ) 266 )
246 } 267 }
247"#, 268"#,
248 ); 269 )
249 270 .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}")
250 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "mod foo {} mod bar {}"); 271 .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}")
251 assert_expansion(MacroKind::Items, &rules, "foo! { foo# bar }", "fn foo () {} fn bar () {}"); 272 .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
252 assert_expansion(MacroKind::Items, &rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
253} 273}
254 274
255#[test] 275#[test]
256fn test_match_group_pattern_with_multiple_defs() { 276fn test_match_group_pattern_with_multiple_defs() {
257 let rules = create_rules( 277 parse_macro(
258 r#" 278 r#"
259 macro_rules! foo { 279 macro_rules! foo {
260 ($ ($ i:ident),*) => ( struct Bar { $ ( 280 ($ ($ i:ident),*) => ( struct Bar { $ (
@@ -262,19 +282,13 @@ fn test_match_group_pattern_with_multiple_defs() {
262 )*} ); 282 )*} );
263 } 283 }
264"#, 284"#,
265 ); 285 )
266 286 .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
267 assert_expansion(
268 MacroKind::Items,
269 &rules,
270 "foo! { foo, bar }",
271 "struct Bar {fn foo {} fn bar {}}",
272 );
273} 287}
274 288
275#[test] 289#[test]
276fn test_match_group_pattern_with_multiple_statement() { 290fn test_match_group_pattern_with_multiple_statement() {
277 let rules = create_rules( 291 parse_macro(
278 r#" 292 r#"
279 macro_rules! foo { 293 macro_rules! foo {
280 ($ ($ i:ident),*) => ( fn baz { $ ( 294 ($ ($ i:ident),*) => ( fn baz { $ (
@@ -282,14 +296,13 @@ fn test_match_group_pattern_with_multiple_statement() {
282 )*} ); 296 )*} );
283 } 297 }
284"#, 298"#,
285 ); 299 )
286 300 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
287 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
288} 301}
289 302
290#[test] 303#[test]
291fn test_match_group_pattern_with_multiple_statement_without_semi() { 304fn test_match_group_pattern_with_multiple_statement_without_semi() {
292 let rules = create_rules( 305 parse_macro(
293 r#" 306 r#"
294 macro_rules! foo { 307 macro_rules! foo {
295 ($ ($ i:ident),*) => ( fn baz { $ ( 308 ($ ($ i:ident),*) => ( fn baz { $ (
@@ -297,14 +310,13 @@ fn test_match_group_pattern_with_multiple_statement_without_semi() {
297 );*} ); 310 );*} );
298 } 311 }
299"#, 312"#,
300 ); 313 )
301 314 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
302 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ;bar ()}");
303} 315}
304 316
305#[test] 317#[test]
306fn test_match_group_empty_fixed_token() { 318fn test_match_group_empty_fixed_token() {
307 let rules = create_rules( 319 parse_macro(
308 r#" 320 r#"
309 macro_rules! foo { 321 macro_rules! foo {
310 ($ ($ i:ident)* #abc) => ( fn baz { $ ( 322 ($ ($ i:ident)* #abc) => ( fn baz { $ (
@@ -312,69 +324,59 @@ fn test_match_group_empty_fixed_token() {
312 )*} ); 324 )*} );
313 } 325 }
314"#, 326"#,
315 ); 327 )
316 328 .assert_expand_items("foo! {#abc}", "fn baz {}");
317 assert_expansion(MacroKind::Items, &rules, "foo! {#abc}", "fn baz {}");
318} 329}
319 330
320#[test] 331#[test]
321fn test_match_group_in_subtree() { 332fn test_match_group_in_subtree() {
322 let rules = create_rules( 333 parse_macro(
323 r#" 334 r#"
324 macro_rules! foo { 335 macro_rules! foo {
325 (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( 336 (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
326 $ i (); 337 $ i ();
327 )*} ); 338 )*} );
328 }"#, 339 }"#,
329 ); 340 )
330 341 .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
331 assert_expansion(MacroKind::Items, &rules, "foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
332} 342}
333 343
334#[test] 344#[test]
335fn test_match_group_with_multichar_sep() { 345fn test_match_group_with_multichar_sep() {
336 let rules = create_rules( 346 parse_macro(
337 r#" 347 r#"
338 macro_rules! foo { 348 macro_rules! foo {
339 (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} ); 349 (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
340 }"#, 350 }"#,
341 ); 351 )
342 352 .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
343 assert_expansion(
344 MacroKind::Items,
345 &rules,
346 "foo! (fn baz {true true} );",
347 "fn baz () -> bool {true &&true}",
348 );
349} 353}
350 354
351#[test] 355#[test]
352fn test_match_group_zero_match() { 356fn test_match_group_zero_match() {
353 let rules = create_rules( 357 parse_macro(
354 r#" 358 r#"
355 macro_rules! foo { 359 macro_rules! foo {
356 ( $($i:ident)* ) => (); 360 ( $($i:ident)* ) => ();
357 }"#, 361 }"#,
358 ); 362 )
359 363 .assert_expand_items("foo! ();", "");
360 assert_expansion(MacroKind::Items, &rules, "foo! ();", "");
361} 364}
362 365
363#[test] 366#[test]
364fn test_match_group_in_group() { 367fn test_match_group_in_group() {
365 let rules = create_rules( 368 parse_macro(
366 r#" 369 r#"
367 macro_rules! foo { 370 macro_rules! foo {
368 { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); 371 { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
369 }"#, 372 }"#,
370 ); 373 )
371 374 .assert_expand_items("foo! ( (a b) );", "(a b)");
372 assert_expansion(MacroKind::Items, &rules, "foo! ( (a b) );", "(a b)");
373} 375}
374 376
375#[test] 377#[test]
376fn test_expand_to_item_list() { 378fn test_expand_to_item_list() {
377 let rules = create_rules( 379 let tree = parse_macro(
378 " 380 "
379 macro_rules! structs { 381 macro_rules! structs {
380 ($($i:ident),*) => { 382 ($($i:ident),*) => {
@@ -382,9 +384,8 @@ fn test_expand_to_item_list() {
382 } 384 }
383 } 385 }
384 ", 386 ",
385 ); 387 )
386 let expansion = expand(&rules, "structs!(Foo, Bar);"); 388 .expand_items("structs!(Foo, Bar);");
387 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Items).unwrap().0.syntax_node();
388 assert_eq!( 389 assert_eq!(
389 format!("{:#?}", tree).trim(), 390 format!("{:#?}", tree).trim(),
390 r#" 391 r#"
@@ -441,7 +442,7 @@ fn test_expand_literals_to_token_tree() {
441 unreachable!("It is not a literal"); 442 unreachable!("It is not a literal");
442 } 443 }
443 444
444 let rules = create_rules( 445 let expansion = parse_macro(
445 r#" 446 r#"
446 macro_rules! literals { 447 macro_rules! literals {
447 ($i:ident) => { 448 ($i:ident) => {
@@ -454,8 +455,8 @@ fn test_expand_literals_to_token_tree() {
454 } 455 }
455 } 456 }
456 "#, 457 "#,
457 ); 458 )
458 let expansion = expand(&rules, "literals!(foo);"); 459 .expand_tt("literals!(foo);");
459 let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees; 460 let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees;
460 461
461 // [let] [a] [=] ['c'] [;] 462 // [let] [a] [=] ['c'] [;]
@@ -470,7 +471,7 @@ fn test_expand_literals_to_token_tree() {
470 471
471#[test] 472#[test]
472fn test_two_idents() { 473fn test_two_idents() {
473 let rules = create_rules( 474 parse_macro(
474 r#" 475 r#"
475 macro_rules! foo { 476 macro_rules! foo {
476 ($ i:ident, $ j:ident) => { 477 ($ i:ident, $ j:ident) => {
@@ -478,18 +479,13 @@ fn test_two_idents() {
478 } 479 }
479 } 480 }
480"#, 481"#,
481 ); 482 )
482 assert_expansion( 483 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
483 MacroKind::Items,
484 &rules,
485 "foo! { foo, bar }",
486 "fn foo () {let a = foo ; let b = bar ;}",
487 );
488} 484}
489 485
490#[test] 486#[test]
491fn test_tt_to_stmts() { 487fn test_tt_to_stmts() {
492 let rules = create_rules( 488 let stmts = parse_macro(
493 r#" 489 r#"
494 macro_rules! foo { 490 macro_rules! foo {
495 () => { 491 () => {
@@ -499,11 +495,8 @@ fn test_tt_to_stmts() {
499 } 495 }
500 } 496 }
501"#, 497"#,
502 ); 498 )
503 499 .expand_statements("foo!{}");
504 let expanded = expand(&rules, "foo!{}");
505 let stmts =
506 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node();
507 500
508 assert_eq!( 501 assert_eq!(
509 format!("{:#?}", stmts).trim(), 502 format!("{:#?}", stmts).trim(),
@@ -543,7 +536,7 @@ fn test_tt_to_stmts() {
543 536
544#[test] 537#[test]
545fn test_match_literal() { 538fn test_match_literal() {
546 let rules = create_rules( 539 parse_macro(
547 r#" 540 r#"
548 macro_rules! foo { 541 macro_rules! foo {
549 ('(') => { 542 ('(') => {
@@ -551,8 +544,8 @@ fn test_match_literal() {
551 } 544 }
552 } 545 }
553"#, 546"#,
554 ); 547 )
555 assert_expansion(MacroKind::Items, &rules, "foo! ['('];", "fn foo () {}"); 548 .assert_expand_items("foo! ['('];", "fn foo () {}");
556} 549}
557 550
558// The following tests are port from intellij-rust directly 551// The following tests are port from intellij-rust directly
@@ -560,7 +553,7 @@ fn test_match_literal() {
560 553
561#[test] 554#[test]
562fn test_path() { 555fn test_path() {
563 let rules = create_rules( 556 parse_macro(
564 r#" 557 r#"
565 macro_rules! foo { 558 macro_rules! foo {
566 ($ i:path) => { 559 ($ i:path) => {
@@ -568,11 +561,9 @@ fn test_path() {
568 } 561 }
569 } 562 }
570"#, 563"#,
571 ); 564 )
572 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo ;}"); 565 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}")
573 assert_expansion( 566 .assert_expand_items(
574 MacroKind::Items,
575 &rules,
576 "foo! { bar::<u8>::baz::<u8> }", 567 "foo! { bar::<u8>::baz::<u8> }",
577 "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}", 568 "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}",
578 ); 569 );
@@ -580,7 +571,7 @@ fn test_path() {
580 571
581#[test] 572#[test]
582fn test_two_paths() { 573fn test_two_paths() {
583 let rules = create_rules( 574 parse_macro(
584 r#" 575 r#"
585 macro_rules! foo { 576 macro_rules! foo {
586 ($ i:path, $ j:path) => { 577 ($ i:path, $ j:path) => {
@@ -588,18 +579,13 @@ fn test_two_paths() {
588 } 579 }
589 } 580 }
590"#, 581"#,
591 ); 582 )
592 assert_expansion( 583 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
593 MacroKind::Items,
594 &rules,
595 "foo! { foo, bar }",
596 "fn foo () {let a = foo ; let b = bar ;}",
597 );
598} 584}
599 585
600#[test] 586#[test]
601fn test_path_with_path() { 587fn test_path_with_path() {
602 let rules = create_rules( 588 parse_macro(
603 r#" 589 r#"
604 macro_rules! foo { 590 macro_rules! foo {
605 ($ i:path) => { 591 ($ i:path) => {
@@ -607,13 +593,13 @@ fn test_path_with_path() {
607 } 593 }
608 } 594 }
609"#, 595"#,
610 ); 596 )
611 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); 597 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}");
612} 598}
613 599
614#[test] 600#[test]
615fn test_expr() { 601fn test_expr() {
616 let rules = create_rules( 602 parse_macro(
617 r#" 603 r#"
618 macro_rules! foo { 604 macro_rules! foo {
619 ($ i:expr) => { 605 ($ i:expr) => {
@@ -621,11 +607,8 @@ fn test_expr() {
621 } 607 }
622 } 608 }
623"#, 609"#,
624 ); 610 )
625 611 .assert_expand_items(
626 assert_expansion(
627 MacroKind::Items,
628 &rules,
629 "foo! { 2 + 2 * baz(3).quux() }", 612 "foo! { 2 + 2 * baz(3).quux() }",
630 "fn bar () {2 + 2 * baz (3) . quux () ;}", 613 "fn bar () {2 + 2 * baz (3) . quux () ;}",
631 ); 614 );
@@ -633,7 +616,7 @@ fn test_expr() {
633 616
634#[test] 617#[test]
635fn test_last_expr() { 618fn test_last_expr() {
636 let rules = create_rules( 619 parse_macro(
637 r#" 620 r#"
638 macro_rules! vec { 621 macro_rules! vec {
639 ($($item:expr),*) => { 622 ($($item:expr),*) => {
@@ -647,10 +630,8 @@ fn test_last_expr() {
647 }; 630 };
648 } 631 }
649"#, 632"#,
650 ); 633 )
651 assert_expansion( 634 .assert_expand_items(
652 MacroKind::Items,
653 &rules,
654 "vec!(1,2,3);", 635 "vec!(1,2,3);",
655 "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}", 636 "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}",
656 ); 637 );
@@ -658,7 +639,7 @@ fn test_last_expr() {
658 639
659#[test] 640#[test]
660fn test_ty() { 641fn test_ty() {
661 let rules = create_rules( 642 parse_macro(
662 r#" 643 r#"
663 macro_rules! foo { 644 macro_rules! foo {
664 ($ i:ty) => ( 645 ($ i:ty) => (
@@ -666,18 +647,13 @@ fn test_ty() {
666 ) 647 )
667 } 648 }
668"#, 649"#,
669 ); 650 )
670 assert_expansion( 651 .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}");
671 MacroKind::Items,
672 &rules,
673 "foo! { Baz<u8> }",
674 "fn bar () -> Baz < u8 > {unimplemented ! ()}",
675 );
676} 652}
677 653
678#[test] 654#[test]
679fn test_ty_with_complex_type() { 655fn test_ty_with_complex_type() {
680 let rules = create_rules( 656 parse_macro(
681 r#" 657 r#"
682 macro_rules! foo { 658 macro_rules! foo {
683 ($ i:ty) => ( 659 ($ i:ty) => (
@@ -685,20 +661,14 @@ fn test_ty_with_complex_type() {
685 ) 661 )
686 } 662 }
687"#, 663"#,
688 ); 664 )
689
690 // Reference lifetime struct with generic type 665 // Reference lifetime struct with generic type
691 assert_expansion( 666 .assert_expand_items(
692 MacroKind::Items,
693 &rules,
694 "foo! { &'a Baz<u8> }", 667 "foo! { &'a Baz<u8> }",
695 "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}", 668 "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}",
696 ); 669 )
697
698 // extern "Rust" func type 670 // extern "Rust" func type
699 assert_expansion( 671 .assert_expand_items(
700 MacroKind::Items,
701 &rules,
702 r#"foo! { extern "Rust" fn() -> Ret }"#, 672 r#"foo! { extern "Rust" fn() -> Ret }"#,
703 r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#, 673 r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#,
704 ); 674 );
@@ -706,19 +676,19 @@ fn test_ty_with_complex_type() {
706 676
707#[test] 677#[test]
708fn test_pat_() { 678fn test_pat_() {
709 let rules = create_rules( 679 parse_macro(
710 r#" 680 r#"
711 macro_rules! foo { 681 macro_rules! foo {
712 ($ i:pat) => { fn foo() { let $ i; } } 682 ($ i:pat) => { fn foo() { let $ i; } }
713 } 683 }
714"#, 684"#,
715 ); 685 )
716 assert_expansion(MacroKind::Items, &rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); 686 .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}");
717} 687}
718 688
719#[test] 689#[test]
720fn test_stmt() { 690fn test_stmt() {
721 let rules = create_rules( 691 parse_macro(
722 r#" 692 r#"
723 macro_rules! foo { 693 macro_rules! foo {
724 ($ i:stmt) => ( 694 ($ i:stmt) => (
@@ -726,14 +696,14 @@ fn test_stmt() {
726 ) 696 )
727 } 697 }
728"#, 698"#,
729 ); 699 )
730 assert_expansion(MacroKind::Items, &rules, "foo! { 2 }", "fn bar () {2 ;}"); 700 .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}")
731 assert_expansion(MacroKind::Items, &rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); 701 .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
732} 702}
733 703
734#[test] 704#[test]
735fn test_single_item() { 705fn test_single_item() {
736 let rules = create_rules( 706 parse_macro(
737 r#" 707 r#"
738 macro_rules! foo { 708 macro_rules! foo {
739 ($ i:item) => ( 709 ($ i:item) => (
@@ -741,13 +711,13 @@ fn test_single_item() {
741 ) 711 )
742 } 712 }
743"#, 713"#,
744 ); 714 )
745 assert_expansion(MacroKind::Items, &rules, "foo! {mod c {}}", "mod c {}"); 715 .assert_expand_items("foo! {mod c {}}", "mod c {}");
746} 716}
747 717
748#[test] 718#[test]
749fn test_all_items() { 719fn test_all_items() {
750 let rules = create_rules( 720 parse_macro(
751 r#" 721 r#"
752 macro_rules! foo { 722 macro_rules! foo {
753 ($ ($ i:item)*) => ($ ( 723 ($ ($ i:item)*) => ($ (
@@ -755,10 +725,8 @@ fn test_all_items() {
755 )*) 725 )*)
756 } 726 }
757"#, 727"#,
758 ); 728 ).
759 assert_expansion( 729 assert_expand_items(
760 MacroKind::Items,
761 &rules,
762 r#" 730 r#"
763 foo! { 731 foo! {
764 extern crate a; 732 extern crate a;
@@ -782,19 +750,19 @@ fn test_all_items() {
782 750
783#[test] 751#[test]
784fn test_block() { 752fn test_block() {
785 let rules = create_rules( 753 parse_macro(
786 r#" 754 r#"
787 macro_rules! foo { 755 macro_rules! foo {
788 ($ i:block) => { fn foo() $ i } 756 ($ i:block) => { fn foo() $ i }
789 } 757 }
790"#, 758"#,
791 ); 759 )
792 assert_expansion(MacroKind::Stmts, &rules, "foo! { { 1; } }", "fn foo () {1 ;}"); 760 .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}");
793} 761}
794 762
795#[test] 763#[test]
796fn test_meta() { 764fn test_meta() {
797 let rules = create_rules( 765 parse_macro(
798 r#" 766 r#"
799 macro_rules! foo { 767 macro_rules! foo {
800 ($ i:meta) => ( 768 ($ i:meta) => (
@@ -803,10 +771,8 @@ fn test_meta() {
803 ) 771 )
804 } 772 }
805"#, 773"#,
806 ); 774 )
807 assert_expansion( 775 .assert_expand_items(
808 MacroKind::Items,
809 &rules,
810 r#"foo! { cfg(target_os = "windows") }"#, 776 r#"foo! { cfg(target_os = "windows") }"#,
811 r#"# [cfg (target_os = "windows")] fn bar () {}"#, 777 r#"# [cfg (target_os = "windows")] fn bar () {}"#,
812 ); 778 );
@@ -814,7 +780,7 @@ fn test_meta() {
814 780
815#[test] 781#[test]
816fn test_meta_doc_comments() { 782fn test_meta_doc_comments() {
817 let rules = create_rules( 783 parse_macro(
818 r#" 784 r#"
819 macro_rules! foo { 785 macro_rules! foo {
820 ($(#[$ i:meta])+) => ( 786 ($(#[$ i:meta])+) => (
@@ -823,10 +789,8 @@ fn test_meta_doc_comments() {
823 ) 789 )
824 } 790 }
825"#, 791"#,
826 ); 792 ).
827 assert_expansion( 793 assert_expand_items(
828 MacroKind::Items,
829 &rules,
830 r#"foo! { 794 r#"foo! {
831 /// Single Line Doc 1 795 /// Single Line Doc 1
832 /** 796 /**
@@ -839,69 +803,68 @@ fn test_meta_doc_comments() {
839 803
840#[test] 804#[test]
841fn test_tt_block() { 805fn test_tt_block() {
842 let rules = create_rules( 806 parse_macro(
843 r#" 807 r#"
844 macro_rules! foo { 808 macro_rules! foo {
845 ($ i:tt) => { fn foo() $ i } 809 ($ i:tt) => { fn foo() $ i }
846 } 810 }
847 "#, 811 "#,
848 ); 812 )
849 assert_expansion(MacroKind::Items, &rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); 813 .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
850} 814}
851 815
852#[test] 816#[test]
853fn test_tt_group() { 817fn test_tt_group() {
854 let rules = create_rules( 818 parse_macro(
855 r#" 819 r#"
856 macro_rules! foo { 820 macro_rules! foo {
857 ($($ i:tt)*) => { $($ i)* } 821 ($($ i:tt)*) => { $($ i)* }
858 } 822 }
859 "#, 823 "#,
860 ); 824 )
861 assert_expansion(MacroKind::Items, &rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); 825 .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
862} 826}
863#[test] 827#[test]
864fn test_lifetime() { 828fn test_lifetime() {
865 let rules = create_rules( 829 parse_macro(
866 r#" 830 r#"
867 macro_rules! foo { 831 macro_rules! foo {
868 ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } 832 ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
869 } 833 }
870"#, 834"#,
871 ); 835 )
872 assert_expansion(MacroKind::Items, &rules, r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#); 836 .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
873} 837}
874 838
875#[test] 839#[test]
876fn test_literal() { 840fn test_literal() {
877 let rules = create_rules( 841 parse_macro(
878 r#" 842 r#"
879 macro_rules! foo { 843 macro_rules! foo {
880 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; 844 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;};
881 } 845 }
882"#, 846"#,
883 ); 847 )
884 assert_expansion(MacroKind::Items, &rules, r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); 848 .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#);
885} 849}
886 850
887#[test] 851#[test]
888fn test_vis() { 852fn test_vis() {
889 let rules = create_rules( 853 parse_macro(
890 r#" 854 r#"
891 macro_rules! foo { 855 macro_rules! foo {
892 ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; 856 ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
893 } 857 }
894"#, 858"#,
895 ); 859 )
896 assert_expansion(MacroKind::Items, &rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); 860 .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
897 861 // test optional cases
898 // test optional casse 862 .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
899 assert_expansion(MacroKind::Items, &rules, r#"foo!(foo);"#, r#"fn foo () {}"#);
900} 863}
901 864
902#[test] 865#[test]
903fn test_inner_macro_rules() { 866fn test_inner_macro_rules() {
904 let rules = create_rules( 867 parse_macro(
905 r#" 868 r#"
906macro_rules! foo { 869macro_rules! foo {
907 ($a:ident, $b:ident, $c:tt) => { 870 ($a:ident, $b:ident, $c:tt) => {
@@ -917,10 +880,8 @@ macro_rules! foo {
917 } 880 }
918} 881}
919"#, 882"#,
920 ); 883 ).
921 assert_expansion( 884 assert_expand_items(
922 MacroKind::Items,
923 &rules,
924 r#"foo!(x,y, 1);"#, 885 r#"foo!(x,y, 1);"#,
925 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, 886 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
926 ); 887 );
@@ -929,7 +890,7 @@ macro_rules! foo {
929// The following tests are based on real world situations 890// The following tests are based on real world situations
930#[test] 891#[test]
931fn test_vec() { 892fn test_vec() {
932 let rules = create_rules( 893 let fixture = parse_macro(
933 r#" 894 r#"
934 macro_rules! vec { 895 macro_rules! vec {
935 ($($item:expr),*) => { 896 ($($item:expr),*) => {
@@ -944,16 +905,14 @@ fn test_vec() {
944} 905}
945"#, 906"#,
946 ); 907 );
947 assert_expansion(MacroKind::Items, &rules, r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#); 908 fixture
948 assert_expansion( 909 .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
949 MacroKind::Items, 910 .assert_expand_items(
950 &rules, 911 r#"vec![1u32,2];"#,
951 r#"vec![1u32,2];"#, 912 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
952 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, 913 );
953 );
954 914
955 let expansion = expand(&rules, r#"vec![1u32,2];"#); 915 let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
956 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Expr).unwrap().0.syntax_node();
957 916
958 assert_eq!( 917 assert_eq!(
959 format!("{:#?}", tree).trim(), 918 format!("{:#?}", tree).trim(),
@@ -1027,7 +986,7 @@ fn test_vec() {
1027fn test_winapi_struct() { 986fn test_winapi_struct() {
1028 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 987 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
1029 988
1030 let rules = create_rules( 989 parse_macro(
1031 r#" 990 r#"
1032macro_rules! STRUCT { 991macro_rules! STRUCT {
1033 ($(#[$attrs:meta])* struct $name:ident { 992 ($(#[$attrs:meta])* struct $name:ident {
@@ -1049,17 +1008,19 @@ macro_rules! STRUCT {
1049 ); 1008 );
1050} 1009}
1051"#, 1010"#,
1052 ); 1011 ).
1053 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs 1012 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
1054 assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, 1013 assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
1055 "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); 1014 "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1056 assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, 1015 )
1057 "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); 1016 .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
1017 "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1018 );
1058} 1019}
1059 1020
1060#[test] 1021#[test]
1061fn test_int_base() { 1022fn test_int_base() {
1062 let rules = create_rules( 1023 parse_macro(
1063 r#" 1024 r#"
1064macro_rules! int_base { 1025macro_rules! int_base {
1065 ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { 1026 ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
@@ -1072,17 +1033,15 @@ macro_rules! int_base {
1072 } 1033 }
1073} 1034}
1074"#, 1035"#,
1075 ); 1036 ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
1076
1077 assert_expansion(MacroKind::Items, &rules, r#" int_base!{Binary for isize as usize -> Binary}"#,
1078 "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}" 1037 "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
1079 ); 1038 );
1080} 1039}
1081 1040
1082#[test] 1041#[test]
1083fn test_generate_pattern_iterators() { 1042fn test_generate_pattern_iterators() {
1084 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs 1043 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
1085 let rules = create_rules( 1044 parse_macro(
1086 r#" 1045 r#"
1087macro_rules! generate_pattern_iterators { 1046macro_rules! generate_pattern_iterators {
1088 { double ended; with $(#[$common_stability_attribute:meta])*, 1047 { double ended; with $(#[$common_stability_attribute:meta])*,
@@ -1093,11 +1052,7 @@ macro_rules! generate_pattern_iterators {
1093 } 1052 }
1094} 1053}
1095"#, 1054"#,
1096 ); 1055 ).assert_expand_items(
1097
1098 assert_expansion(
1099 MacroKind::Items,
1100 &rules,
1101 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#, 1056 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
1102 "fn foo () {}", 1057 "fn foo () {}",
1103 ); 1058 );
@@ -1106,7 +1061,7 @@ macro_rules! generate_pattern_iterators {
1106#[test] 1061#[test]
1107fn test_impl_fn_for_zst() { 1062fn test_impl_fn_for_zst() {
1108 // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs 1063 // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
1109 let rules = create_rules( 1064 parse_macro(
1110 r#" 1065 r#"
1111macro_rules! impl_fn_for_zst { 1066macro_rules! impl_fn_for_zst {
1112 { $( $( #[$attr: meta] )* 1067 { $( $( #[$attr: meta] )*
@@ -1147,9 +1102,7 @@ $body: block; )+
1147} 1102}
1148 } 1103 }
1149"#, 1104"#,
1150 ); 1105 ).assert_expand_items(r#"
1151
1152 assert_expansion(MacroKind::Items, &rules, r#"
1153impl_fn_for_zst ! { 1106impl_fn_for_zst ! {
1154 # [ derive ( Clone ) ] 1107 # [ derive ( Clone ) ]
1155 struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { 1108 struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug {
@@ -1166,13 +1119,14 @@ impl_fn_for_zst ! {
1166 } ; 1119 } ;
1167 } 1120 }
1168"#, 1121"#,
1169 "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"); 1122 "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"
1123 );
1170} 1124}
1171 1125
1172#[test] 1126#[test]
1173fn test_impl_nonzero_fmt() { 1127fn test_impl_nonzero_fmt() {
1174 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 1128 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
1175 let rules = create_rules( 1129 parse_macro(
1176 r#" 1130 r#"
1177 macro_rules! impl_nonzero_fmt { 1131 macro_rules! impl_nonzero_fmt {
1178 ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { 1132 ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
@@ -1180,11 +1134,7 @@ fn test_impl_nonzero_fmt() {
1180 } 1134 }
1181 } 1135 }
1182"#, 1136"#,
1183 ); 1137 ).assert_expand_items(
1184
1185 assert_expansion(
1186 MacroKind::Items,
1187 &rules,
1188 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#, 1138 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
1189 "fn foo () {}", 1139 "fn foo () {}",
1190 ); 1140 );
@@ -1193,7 +1143,7 @@ fn test_impl_nonzero_fmt() {
1193#[test] 1143#[test]
1194fn test_cfg_if_items() { 1144fn test_cfg_if_items() {
1195 // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 1145 // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
1196 let rules = create_rules( 1146 parse_macro(
1197 r#" 1147 r#"
1198 macro_rules! __cfg_if_items { 1148 macro_rules! __cfg_if_items {
1199 (($($not:meta,)*) ; ) => {}; 1149 (($($not:meta,)*) ; ) => {};
@@ -1202,11 +1152,7 @@ fn test_cfg_if_items() {
1202 } 1152 }
1203 } 1153 }
1204"#, 1154"#,
1205 ); 1155 ).assert_expand_items(
1206
1207 assert_expansion(
1208 MacroKind::Items,
1209 &rules,
1210 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, 1156 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
1211 "__cfg_if_items ! {(rustdoc ,) ;}", 1157 "__cfg_if_items ! {(rustdoc ,) ;}",
1212 ); 1158 );
@@ -1215,7 +1161,7 @@ fn test_cfg_if_items() {
1215#[test] 1161#[test]
1216fn test_cfg_if_main() { 1162fn test_cfg_if_main() {
1217 // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 1163 // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
1218 let rules = create_rules( 1164 parse_macro(
1219 r#" 1165 r#"
1220 macro_rules! cfg_if { 1166 macro_rules! cfg_if {
1221 ($( 1167 ($(
@@ -1236,9 +1182,7 @@ fn test_cfg_if_main() {
1236 }; 1182 };
1237 } 1183 }
1238"#, 1184"#,
1239 ); 1185 ).assert_expand_items(r#"
1240
1241 assert_expansion(MacroKind::Items, &rules, r#"
1242cfg_if ! { 1186cfg_if ! {
1243 if # [ cfg ( target_env = "msvc" ) ] { 1187 if # [ cfg ( target_env = "msvc" ) ] {
1244 // no extra unwinder support needed 1188 // no extra unwinder support needed
@@ -1250,11 +1194,8 @@ cfg_if ! {
1250 } 1194 }
1251 } 1195 }
1252"#, 1196"#,
1253 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); 1197 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
1254 1198 ).assert_expand_items(
1255 assert_expansion(
1256 MacroKind::Items,
1257 &rules,
1258 r#" 1199 r#"
1259cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } 1200cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
1260"#, 1201"#,
@@ -1265,7 +1206,7 @@ cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" ,
1265#[test] 1206#[test]
1266fn test_proptest_arbitrary() { 1207fn test_proptest_arbitrary() {
1267 // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16 1208 // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
1268 let rules = create_rules( 1209 parse_macro(
1269 r#" 1210 r#"
1270macro_rules! arbitrary { 1211macro_rules! arbitrary {
1271 ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; 1212 ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
@@ -1280,22 +1221,21 @@ macro_rules! arbitrary {
1280 }; 1221 };
1281 1222
1282}"#, 1223}"#,
1283 ); 1224 ).assert_expand_items(r#"arbitrary ! ( [ A : Arbitrary ]
1284
1285 assert_expansion(MacroKind::Items, &rules, r#"arbitrary ! ( [ A : Arbitrary ]
1286 Vec < A > , 1225 Vec < A > ,
1287 VecStrategy < A :: Strategy > , 1226 VecStrategy < A :: Strategy > ,
1288 RangedParams1 < A :: Parameters > ; 1227 RangedParams1 < A :: Parameters > ;
1289 args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) } 1228 args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) }
1290 ) ;"#, 1229 ) ;"#,
1291 "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"); 1230 "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"
1231 );
1292} 1232}
1293 1233
1294#[test] 1234#[test]
1295fn test_old_ridl() { 1235fn test_old_ridl() {
1296 // This is from winapi 2.8, which do not have a link from github 1236 // This is from winapi 2.8, which do not have a link from github
1297 // 1237 //
1298 let rules = create_rules( 1238 let expanded = parse_macro(
1299 r#" 1239 r#"
1300#[macro_export] 1240#[macro_export]
1301macro_rules! RIDL { 1241macro_rules! RIDL {
@@ -1311,21 +1251,17 @@ macro_rules! RIDL {
1311 } 1251 }
1312 }; 1252 };
1313}"#, 1253}"#,
1314 ); 1254 ).expand_tt(r#"
1255 RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1256 fn GetDataSize(&mut self) -> UINT
1257 }}"#);
1315 1258
1316 let expanded = expand(
1317 &rules,
1318 r#"
1319RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1320 fn GetDataSize(&mut self) -> UINT
1321}}"#,
1322 );
1323 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}"); 1259 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
1324} 1260}
1325 1261
1326#[test] 1262#[test]
1327fn test_quick_error() { 1263fn test_quick_error() {
1328 let rules = create_rules( 1264 let expanded = parse_macro(
1329 r#" 1265 r#"
1330macro_rules! quick_error { 1266macro_rules! quick_error {
1331 1267
@@ -1348,10 +1284,8 @@ macro_rules! quick_error {
1348 1284
1349} 1285}
1350"#, 1286"#,
1351 ); 1287 )
1352 1288 .expand_tt(
1353 let expanded = expand(
1354 &rules,
1355 r#" 1289 r#"
1356quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ 1290quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1357 => One : UNIT [] {} 1291 => One : UNIT [] {}
@@ -1365,7 +1299,7 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1365 1299
1366#[test] 1300#[test]
1367fn test_empty_repeat_vars_in_empty_repeat_vars() { 1301fn test_empty_repeat_vars_in_empty_repeat_vars() {
1368 let rules = create_rules( 1302 parse_macro(
1369 r#" 1303 r#"
1370macro_rules! delegate_impl { 1304macro_rules! delegate_impl {
1371 ([$self_type:ident, $self_wrap:ty, $self_map:ident] 1305 ([$self_type:ident, $self_wrap:ty, $self_map:ident]
@@ -1412,103 +1346,117 @@ macro_rules! delegate_impl {
1412 } 1346 }
1413} 1347}
1414"#, 1348"#,
1415 ); 1349 ).assert_expand_items(
1416
1417 assert_expansion(
1418 MacroKind::Items,
1419 &rules,
1420 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, 1350 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
1421 "impl <> Data for & \'a mut G where G : Data {}", 1351 "impl <> Data for & \'a mut G where G : Data {}",
1422 ); 1352 );
1423} 1353}
1424 1354
1425pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { 1355#[test]
1426 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 1356fn expr_interpolation() {
1427 let macro_definition = 1357 let expanded = parse_macro(
1428 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 1358 r#"
1359 macro_rules! id {
1360 ($expr:expr) => {
1361 map($expr)
1362 }
1363 }
1364 "#,
1365 )
1366 .expand_expr("id!(x + foo);");
1429 1367
1430 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 1368 assert_eq!(expanded.to_string(), "map(x+foo)");
1431 crate::MacroRules::parse(&definition_tt).unwrap()
1432} 1369}
1433 1370
1434pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { 1371pub(crate) struct MacroFixture {
1435 let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); 1372 rules: MacroRules,
1436 let macro_invocation = 1373}
1437 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1438 1374
1439 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap(); 1375impl MacroFixture {
1376 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
1377 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
1378 let macro_invocation =
1379 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1440 1380
1441 rules.expand(&invocation_tt).unwrap() 1381 let (invocation_tt, _) =
1442} 1382 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
1443 1383
1444pub(crate) enum MacroKind { 1384 self.rules.expand(&invocation_tt).unwrap()
1445 Items, 1385 }
1446 Stmts,
1447}
1448 1386
1449pub(crate) fn assert_expansion( 1387 fn expand_items(&self, invocation: &str) -> SyntaxNode {
1450 kind: MacroKind, 1388 let expanded = self.expand_tt(invocation);
1451 rules: &MacroRules, 1389 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node()
1452 invocation: &str, 1390 }
1453 expected: &str,
1454) -> tt::Subtree {
1455 let expanded = expand(rules, invocation);
1456 assert_eq!(expanded.to_string(), expected);
1457 1391
1458 let expected = expected.replace("$crate", "C_C__C"); 1392 fn expand_statements(&self, invocation: &str) -> SyntaxNode {
1393 let expanded = self.expand_tt(invocation);
1394 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node()
1395 }
1459 1396
1460 // wrap the given text to a macro call 1397 fn expand_expr(&self, invocation: &str) -> SyntaxNode {
1461 let expected = { 1398 let expanded = self.expand_tt(invocation);
1462 let wrapped = format!("wrap_macro!( {} )", expected); 1399 token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node()
1463 let wrapped = ast::SourceFile::parse(&wrapped); 1400 }
1464 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1465 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1466 wrapped.delimiter = tt::Delimiter::None;
1467 wrapped
1468 };
1469 let (expanded_tree, expected_tree) = match kind {
1470 MacroKind::Items => {
1471 let expanded_tree =
1472 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
1473 let expected_tree =
1474 token_tree_to_syntax_node(&expected, FragmentKind::Items).unwrap().0.syntax_node();
1475
1476 (
1477 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1478 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1479 )
1480 }
1481 1401
1482 MacroKind::Stmts => { 1402 fn assert_expand_tt(&self, invocation: &str, expected: &str) {
1483 let expanded_tree = token_tree_to_syntax_node(&expanded, FragmentKind::Statements) 1403 let expansion = self.expand_tt(invocation);
1484 .unwrap() 1404 assert_eq!(expansion.to_string(), expected);
1485 .0 1405 }
1486 .syntax_node();
1487 let expected_tree = token_tree_to_syntax_node(&expected, FragmentKind::Statements)
1488 .unwrap()
1489 .0
1490 .syntax_node();
1491
1492 (
1493 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1494 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1495 )
1496 }
1497 };
1498 1406
1499 let expected_tree = expected_tree.replace("C_C__C", "$crate"); 1407 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture {
1500 assert_eq!( 1408 self.assert_expansion(FragmentKind::Items, invocation, expected);
1501 expanded_tree, expected_tree, 1409 self
1502 "\nleft:\n{}\nright:\n{}", 1410 }
1503 expanded_tree, expected_tree, 1411
1504 ); 1412 fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture {
1413 self.assert_expansion(FragmentKind::Statements, invocation, expected);
1414 self
1415 }
1505 1416
1506 expanded 1417 fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) {
1418 let expanded = self.expand_tt(invocation);
1419 assert_eq!(expanded.to_string(), expected);
1420
1421 let expected = expected.replace("$crate", "C_C__C");
1422
1423 // wrap the given text to a macro call
1424 let expected = {
1425 let wrapped = format!("wrap_macro!( {} )", expected);
1426 let wrapped = ast::SourceFile::parse(&wrapped);
1427 let wrapped =
1428 wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1429 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1430 wrapped.delimiter = None;
1431 wrapped
1432 };
1433
1434 let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
1435 let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();
1436
1437 let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
1438 let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();
1439
1440 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1441 assert_eq!(
1442 expanded_tree, expected_tree,
1443 "\nleft:\n{}\nright:\n{}",
1444 expanded_tree, expected_tree,
1445 );
1446 }
1507} 1447}
1508 1448
1509pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { 1449pub(crate) fn parse_macro(macro_definition: &str) -> MacroFixture {
1510 use std::fmt::Write; 1450 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
1451 let macro_definition =
1452 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1453
1454 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
1455 let rules = MacroRules::parse(&definition_tt).unwrap();
1456 MacroFixture { rules }
1457}
1511 1458
1459fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
1512 let mut level = 0; 1460 let mut level = 0;
1513 let mut buf = String::new(); 1461 let mut buf = String::new();
1514 macro_rules! indent { 1462 macro_rules! indent {
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 6e9e212b7..22f64a9f4 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -264,7 +264,7 @@ fn name_r(p: &mut Parser, recovery: TokenSet) {
264} 264}
265 265
266fn name(p: &mut Parser) { 266fn name(p: &mut Parser) {
267 name_r(p, TokenSet::empty()) 267 name_r(p, TokenSet::EMPTY)
268} 268}
269 269
270fn name_ref(p: &mut Parser) { 270fn name_ref(p: &mut Parser) {
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index f06191963..4ac1d6334 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -43,6 +43,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
43 T!['('], 43 T!['('],
44 T!['{'], 44 T!['{'],
45 T!['['], 45 T!['['],
46 L_DOLLAR,
46 T![|], 47 T![|],
47 T![move], 48 T![move],
48 T![box], 49 T![box],
@@ -248,7 +249,12 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
248 p.error("expected `{`"); 249 p.error("expected `{`");
249 } 250 }
250 } 251 }
251 expr(p); 252
253 if p.at_ts(EXPR_FIRST) {
254 expr(p);
255 } else {
256 p.error("expected expression");
257 }
252 m.complete(p, LAMBDA_EXPR) 258 m.complete(p, LAMBDA_EXPR)
253} 259}
254 260
@@ -438,7 +444,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
438 // } 444 // }
439 attributes::outer_attributes(p); 445 attributes::outer_attributes(p);
440 446
441 patterns::pattern_list_r(p, TokenSet::empty()); 447 patterns::pattern_list_r(p, TokenSet::EMPTY);
442 if p.at(T![if]) { 448 if p.at(T![if]) {
443 match_guard(p); 449 match_guard(p);
444 } 450 }
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 370990e21..6e23d9b72 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -33,7 +33,7 @@ pub(super) enum ItemFlavor {
33 33
34pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ 34pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
35 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, 35 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
36 CRATE_KW, USE_KW 36 CRATE_KW, USE_KW, MACRO_KW
37]; 37];
38 38
39pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { 39pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
@@ -249,6 +249,11 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
249 // } 249 // }
250 adt::struct_def(p, m); 250 adt::struct_def(p, m);
251 } 251 }
252 // test pub_macro_def
253 // pub macro m($:ident) {}
254 T![macro] => {
255 macro_def(p, m);
256 }
252 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { 257 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
253 // test union_items 258 // test union_items
254 // union Foo {} 259 // union Foo {}
@@ -379,6 +384,29 @@ pub(crate) fn mod_item_list(p: &mut Parser) {
379 m.complete(p, ITEM_LIST); 384 m.complete(p, ITEM_LIST);
380} 385}
381 386
387// test macro_def
388// macro m { ($i:ident) => {} }
389// macro m($i:ident) {}
390fn macro_def(p: &mut Parser, m: Marker) {
391 p.expect(T![macro]);
392 name_r(p, ITEM_RECOVERY_SET);
393 if p.at(T!['{']) {
394 token_tree(p);
395 } else if !p.at(T!['(']) {
396 p.error("unmatched `(`");
397 } else {
398 let m = p.start();
399 token_tree(p);
400 match p.current() {
401 T!['{'] | T!['['] | T!['('] => token_tree(p),
402 _ => p.error("expected `{`, `[`, `(`"),
403 }
404 m.complete(p, TOKEN_TREE);
405 }
406
407 m.complete(p, MACRO_DEF);
408}
409
382fn macro_call(p: &mut Parser) -> BlockLike { 410fn macro_call(p: &mut Parser) -> BlockLike {
383 assert!(paths::is_use_path_start(p)); 411 assert!(paths::is_use_path_start(p));
384 paths::use_path(p); 412 paths::use_path(p);
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index f5d12278c..422a4e3dc 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -50,7 +50,7 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
50 // let m!(x) = 0; 50 // let m!(x) = 0;
51 // } 51 // }
52 if lhs.kind() == PATH_PAT && p.at(T![!]) { 52 if lhs.kind() == PATH_PAT && p.at(T![!]) {
53 let m = lhs.precede(p); 53 let m = lhs.undo_completion(p);
54 items::macro_call_after_excl(p); 54 items::macro_call_after_excl(p);
55 m.complete(p, MACRO_CALL); 55 m.complete(p, MACRO_CALL);
56 } 56 }
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index 34406b5bd..50e4900c3 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -25,6 +25,7 @@ fn type_param_list(p: &mut Parser) {
25 match p.current() { 25 match p.current() {
26 LIFETIME => lifetime_param(p, m), 26 LIFETIME => lifetime_param(p, m),
27 IDENT => type_param(p, m), 27 IDENT => type_param(p, m),
28 CONST_KW => type_const_param(p, m),
28 _ => { 29 _ => {
29 m.abandon(p); 30 m.abandon(p);
30 p.err_and_bump("expected type parameter") 31 p.err_and_bump("expected type parameter")
@@ -62,6 +63,16 @@ fn type_param(p: &mut Parser, m: Marker) {
62 m.complete(p, TYPE_PARAM); 63 m.complete(p, TYPE_PARAM);
63} 64}
64 65
66// test const_param
67// struct S<const N: u32>;
68fn type_const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW));
70 p.bump(T![const]);
71 name(p);
72 types::ascription(p);
73 m.complete(p, CONST_PARAM);
74}
75
65// test type_param_bounds 76// test type_param_bounds
66// struct S<T: 'a + ?Sized + (Copy)>; 77// struct S<T: 'a + ?Sized + (Copy)>;
67pub(super) fn bounds(p: &mut Parser) { 78pub(super) fn bounds(p: &mut Parser) {
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 45241e566..65134277e 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -83,6 +83,7 @@ pub fn parse(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink) {
83 parse_from_tokens(token_source, tree_sink, grammar::root); 83 parse_from_tokens(token_source, tree_sink, grammar::root);
84} 84}
85 85
86#[derive(Clone, Copy)]
86pub enum FragmentKind { 87pub enum FragmentKind {
87 Path, 88 Path,
88 Expr, 89 Expr,
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index dafd5247b..1071c46dc 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -208,7 +208,7 @@ impl<'t> Parser<'t> {
208 208
209 /// Create an error node and consume the next token. 209 /// Create an error node and consume the next token.
210 pub(crate) fn err_and_bump(&mut self, message: &str) { 210 pub(crate) fn err_and_bump(&mut self, message: &str) {
211 self.err_recover(message, TokenSet::empty()); 211 self.err_recover(message, TokenSet::EMPTY);
212 } 212 }
213 213
214 /// Create an error node and consume the next token. 214 /// Create an error node and consume the next token.
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index fe0fcdb33..af2945f57 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -100,6 +100,7 @@ pub enum SyntaxKind {
100 TRY_KW, 100 TRY_KW,
101 BOX_KW, 101 BOX_KW,
102 AWAIT_KW, 102 AWAIT_KW,
103 MACRO_KW,
103 AUTO_KW, 104 AUTO_KW,
104 DEFAULT_KW, 105 DEFAULT_KW,
105 EXISTENTIAL_KW, 106 EXISTENTIAL_KW,
@@ -136,6 +137,7 @@ pub enum SyntaxKind {
136 TYPE_ALIAS_DEF, 137 TYPE_ALIAS_DEF,
137 MACRO_CALL, 138 MACRO_CALL,
138 TOKEN_TREE, 139 TOKEN_TREE,
140 MACRO_DEF,
139 PAREN_TYPE, 141 PAREN_TYPE,
140 TUPLE_TYPE, 142 TUPLE_TYPE,
141 NEVER_TYPE, 143 NEVER_TYPE,
@@ -227,6 +229,7 @@ pub enum SyntaxKind {
227 TYPE_PARAM_LIST, 229 TYPE_PARAM_LIST,
228 LIFETIME_PARAM, 230 LIFETIME_PARAM,
229 TYPE_PARAM, 231 TYPE_PARAM,
232 CONST_PARAM,
230 TYPE_ARG_LIST, 233 TYPE_ARG_LIST,
231 LIFETIME_ARG, 234 LIFETIME_ARG,
232 TYPE_ARG, 235 TYPE_ARG,
@@ -251,7 +254,7 @@ impl SyntaxKind {
251 | SUPER_KW | IN_KW | WHERE_KW | FOR_KW | LOOP_KW | WHILE_KW | CONTINUE_KW 254 | SUPER_KW | IN_KW | WHERE_KW | FOR_KW | LOOP_KW | WHILE_KW | CONTINUE_KW
252 | BREAK_KW | IF_KW | ELSE_KW | MATCH_KW | CONST_KW | STATIC_KW | MUT_KW | UNSAFE_KW 255 | BREAK_KW | IF_KW | ELSE_KW | MATCH_KW | CONST_KW | STATIC_KW | MUT_KW | UNSAFE_KW
253 | TYPE_KW | REF_KW | LET_KW | MOVE_KW | RETURN_KW | TRY_KW | BOX_KW | AWAIT_KW 256 | TYPE_KW | REF_KW | LET_KW | MOVE_KW | RETURN_KW | TRY_KW | BOX_KW | AWAIT_KW
254 | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true, 257 | MACRO_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true,
255 _ => false, 258 _ => false,
256 } 259 }
257 } 260 }
@@ -314,6 +317,7 @@ impl SyntaxKind {
314 "try" => TRY_KW, 317 "try" => TRY_KW,
315 "box" => BOX_KW, 318 "box" => BOX_KW,
316 "await" => AWAIT_KW, 319 "await" => AWAIT_KW,
320 "macro" => MACRO_KW,
317 _ => return None, 321 _ => return None,
318 }; 322 };
319 Some(kw) 323 Some(kw)
@@ -628,6 +632,9 @@ macro_rules! T {
628 ( await ) => { 632 ( await ) => {
629 $crate::SyntaxKind::AWAIT_KW 633 $crate::SyntaxKind::AWAIT_KW
630 }; 634 };
635 ( macro ) => {
636 $crate::SyntaxKind::MACRO_KW
637 };
631 ( auto ) => { 638 ( auto ) => {
632 $crate::SyntaxKind::AUTO_KW 639 $crate::SyntaxKind::AUTO_KW
633 }; 640 };
diff --git a/crates/ra_parser/src/token_set.rs b/crates/ra_parser/src/token_set.rs
index 2a6952c01..994017acf 100644
--- a/crates/ra_parser/src/token_set.rs
+++ b/crates/ra_parser/src/token_set.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! A bit-set of `SyntaxKind`s.
2 2
3use crate::SyntaxKind; 3use crate::SyntaxKind;
4 4
@@ -7,9 +7,7 @@ use crate::SyntaxKind;
7pub(crate) struct TokenSet(u128); 7pub(crate) struct TokenSet(u128);
8 8
9impl TokenSet { 9impl TokenSet {
10 pub(crate) const fn empty() -> TokenSet { 10 pub(crate) const EMPTY: TokenSet = TokenSet(0);
11 TokenSet(0)
12 }
13 11
14 pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet { 12 pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet {
15 TokenSet(mask(kind)) 13 TokenSet(mask(kind))
@@ -30,7 +28,7 @@ const fn mask(kind: SyntaxKind) -> u128 {
30 28
31#[macro_export] 29#[macro_export]
32macro_rules! token_set { 30macro_rules! token_set {
33 ($($t:expr),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* }; 31 ($($t:expr),*) => { TokenSet::EMPTY$(.union(TokenSet::singleton($t)))* };
34 ($($t:expr),* ,) => { token_set!($($t),*) }; 32 ($($t:expr),* ,) => { token_set!($($t),*) };
35} 33}
36 34
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index 845b2221c..f260c40a3 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -217,7 +217,7 @@ fn print(
217 total: Option<Duration>, 217 total: Option<Duration>,
218) { 218) {
219 let mut last = 0; 219 let mut last = 0;
220 let indent = repeat(" ").take(lvl + 1).collect::<String>(); 220 let indent = repeat(" ").take(lvl).collect::<String>();
221 // We output hierarchy for long calls, but sum up all short calls 221 // We output hierarchy for long calls, but sum up all short calls
222 let mut short = Vec::new(); 222 let mut short = Vec::new();
223 let mut accounted_for = Duration::default(); 223 let mut accounted_for = Duration::default();
@@ -227,7 +227,7 @@ fn print(
227 } 227 }
228 accounted_for += duration; 228 accounted_for += duration;
229 if duration >= longer_than { 229 if duration >= longer_than {
230 writeln!(out, "{} {:6}ms - {}", indent, duration.as_millis(), msg) 230 writeln!(out, "{}{:5}ms - {}", indent, duration.as_millis(), msg)
231 .expect("printing profiling info to stdout"); 231 .expect("printing profiling info to stdout");
232 232
233 print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration)); 233 print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration));
@@ -245,14 +245,14 @@ fn print(
245 count += 1; 245 count += 1;
246 total_duration += *time; 246 total_duration += *time;
247 }); 247 });
248 writeln!(out, "{} {:6}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count) 248 writeln!(out, "{}{:5}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
249 .expect("printing profiling info to stdout"); 249 .expect("printing profiling info to stdout");
250 } 250 }
251 251
252 if let Some(total) = total { 252 if let Some(total) = total {
253 if let Some(unaccounted) = total.checked_sub(accounted_for) { 253 if let Some(unaccounted) = total.checked_sub(accounted_for) {
254 if unaccounted >= longer_than && last > 0 { 254 if unaccounted >= longer_than && last > 0 {
255 writeln!(out, "{} {:6}ms - ???", indent, unaccounted.as_millis()) 255 writeln!(out, "{}{:5}ms - ???", indent, unaccounted.as_millis())
256 .expect("printing profiling info to stdout"); 256 .expect("printing profiling info to stdout");
257 } 257 }
258 } 258 }
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 351997dcd..c862d3912 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -6,6 +6,7 @@ use cargo_metadata::{CargoOpt, MetadataCommand};
6use ra_arena::{impl_arena_id, Arena, RawId}; 6use ra_arena::{impl_arena_id, Arena, RawId};
7use ra_db::Edition; 7use ra_db::Edition;
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use serde::Deserialize;
9 10
10use crate::Result; 11use crate::Result;
11 12
@@ -23,6 +24,26 @@ pub struct CargoWorkspace {
23 pub(crate) workspace_root: PathBuf, 24 pub(crate) workspace_root: PathBuf,
24} 25}
25 26
27#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
28#[serde(rename_all = "camelCase", default)]
29pub struct CargoFeatures {
30 /// Do not activate the `default` feature.
31 pub no_default_features: bool,
32
33 /// Activate all available features
34 pub all_features: bool,
35
36 /// List of features to activate.
37 /// This will be ignored if `cargo_all_features` is true.
38 pub features: Vec<String>,
39}
40
41impl Default for CargoFeatures {
42 fn default() -> Self {
43 CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
44 }
45}
46
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27pub struct Package(RawId); 48pub struct Package(RawId);
28impl_arena_id!(Package); 49impl_arena_id!(Package);
@@ -132,9 +153,21 @@ impl Target {
132} 153}
133 154
134impl CargoWorkspace { 155impl CargoWorkspace {
135 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> { 156 pub fn from_cargo_metadata(
157 cargo_toml: &Path,
158 cargo_features: &CargoFeatures,
159 ) -> Result<CargoWorkspace> {
136 let mut meta = MetadataCommand::new(); 160 let mut meta = MetadataCommand::new();
137 meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); 161 meta.manifest_path(cargo_toml);
162 if cargo_features.all_features {
163 meta.features(CargoOpt::AllFeatures);
164 } else if cargo_features.no_default_features {
165 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
166 // https://github.com/oli-obk/cargo_metadata/issues/79
167 meta.features(CargoOpt::NoDefaultFeatures);
168 } else {
169 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
170 }
138 if let Some(parent) = cargo_toml.parent() { 171 if let Some(parent) = cargo_toml.parent() {
139 meta.current_dir(parent); 172 meta.current_dir(parent);
140 } 173 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 55ff4d6ef..d71b7031a 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -18,7 +18,7 @@ use rustc_hash::FxHashMap;
18use serde_json::from_reader; 18use serde_json::from_reader;
19 19
20pub use crate::{ 20pub use crate::{
21 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 21 cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind},
22 json_project::JsonProject, 22 json_project::JsonProject,
23 sysroot::Sysroot, 23 sysroot::Sysroot,
24}; 24};
@@ -60,11 +60,15 @@ impl PackageRoot {
60} 60}
61 61
62impl ProjectWorkspace { 62impl ProjectWorkspace {
63 pub fn discover(path: &Path) -> Result<ProjectWorkspace> { 63 pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> {
64 ProjectWorkspace::discover_with_sysroot(path, true) 64 ProjectWorkspace::discover_with_sysroot(path, true, cargo_features)
65 } 65 }
66 66
67 pub fn discover_with_sysroot(path: &Path, with_sysroot: bool) -> Result<ProjectWorkspace> { 67 pub fn discover_with_sysroot(
68 path: &Path,
69 with_sysroot: bool,
70 cargo_features: &CargoFeatures,
71 ) -> Result<ProjectWorkspace> {
68 match find_rust_project_json(path) { 72 match find_rust_project_json(path) {
69 Some(json_path) => { 73 Some(json_path) => {
70 let file = File::open(json_path)?; 74 let file = File::open(json_path)?;
@@ -73,7 +77,7 @@ impl ProjectWorkspace {
73 } 77 }
74 None => { 78 None => {
75 let cargo_toml = find_cargo_toml(path)?; 79 let cargo_toml = find_cargo_toml(path)?;
76 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; 80 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features)?;
77 let sysroot = 81 let sysroot =
78 if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() }; 82 if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() };
79 Ok(ProjectWorkspace::Cargo { cargo, sysroot }) 83 Ok(ProjectWorkspace::Cargo { cargo, sysroot })
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 5db2b58c0..b6ebb129d 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -12,19 +12,20 @@ doctest = false
12 12
13[dependencies] 13[dependencies]
14itertools = "0.8.0" 14itertools = "0.8.0"
15rowan = "0.7.0" 15rowan = "0.8.0"
16rustc_lexer = "0.1.0" 16rustc_lexer = "0.1.0"
17rustc-hash = "1.0.1" 17rustc-hash = "1.0.1"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.2.0" 19once_cell = "1.2.0"
20 20
21ra_text_edit = { path = "../ra_text_edit" }
22ra_parser = { path = "../ra_parser" }
23
21# This crate transitively depends on `smol_str` via `rowan`. 24# This crate transitively depends on `smol_str` via `rowan`.
22# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 25# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
23# to reduce number of compilations 26# to reduce number of compilations
24smol_str = { version = "0.1.12", features = ["serde"] } 27smol_str = { version = "0.1.12", features = ["serde"] }
25 28serde = { version = "1", features = ["derive"] }
26ra_text_edit = { path = "../ra_text_edit" }
27ra_parser = { path = "../ra_parser" }
28 29
29[dev-dependencies] 30[dev-dependencies]
30test_utils = { path = "../test_utils" } 31test_utils = { path = "../test_utils" }
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 1c075082a..e4061e994 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -140,13 +140,13 @@ pub fn insert_children(
140 }); 140 });
141 141
142 let new_children = match &position { 142 let new_children = match &position {
143 InsertPosition::First => to_insert.chain(old_children).collect::<Box<[_]>>(), 143 InsertPosition::First => to_insert.chain(old_children).collect::<Vec<_>>(),
144 InsertPosition::Last => old_children.chain(to_insert).collect::<Box<[_]>>(), 144 InsertPosition::Last => old_children.chain(to_insert).collect::<Vec<_>>(),
145 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => { 145 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
146 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 }; 146 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
147 let split_at = position_of_child(parent, anchor.clone()) + take_anchor; 147 let split_at = position_of_child(parent, anchor.clone()) + take_anchor;
148 let before = old_children.by_ref().take(split_at).collect::<Vec<_>>(); 148 let before = old_children.by_ref().take(split_at).collect::<Vec<_>>();
149 before.into_iter().chain(to_insert).chain(old_children).collect::<Box<[_]>>() 149 before.into_iter().chain(to_insert).chain(old_children).collect::<Vec<_>>()
150 } 150 }
151 }; 151 };
152 152
@@ -174,7 +174,7 @@ pub fn replace_children(
174 .into_iter() 174 .into_iter()
175 .chain(to_insert.map(to_green_element)) 175 .chain(to_insert.map(to_green_element))
176 .chain(old_children.skip(end + 1 - start)) 176 .chain(old_children.skip(end + 1 - start))
177 .collect::<Box<[_]>>(); 177 .collect::<Vec<_>>();
178 with_children(parent, new_children) 178 with_children(parent, new_children)
179} 179}
180 180
@@ -187,7 +187,7 @@ pub fn replace_descendants(
187 map: &FxHashMap<SyntaxElement, SyntaxElement>, 187 map: &FxHashMap<SyntaxElement, SyntaxElement>,
188) -> SyntaxNode { 188) -> SyntaxNode {
189 // FIXME: this could be made much faster. 189 // FIXME: this could be made much faster.
190 let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Box<[_]>>(); 190 let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Vec<_>>();
191 return with_children(parent, new_children); 191 return with_children(parent, new_children);
192 192
193 fn go( 193 fn go(
@@ -211,7 +211,7 @@ pub fn replace_descendants(
211 211
212fn with_children( 212fn with_children(
213 parent: &SyntaxNode, 213 parent: &SyntaxNode,
214 new_children: Box<[NodeOrToken<rowan::GreenNode, rowan::GreenToken>]>, 214 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
215) -> SyntaxNode { 215) -> SyntaxNode {
216 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>(); 216 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>();
217 let new_node = 217 let new_node =
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 95bf9db14..ae5d63927 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -104,7 +104,7 @@ impl ast::ItemList {
104 } 104 }
105 }; 105 };
106 106
107 let indent = leading_indent(self.syntax()).unwrap_or("".into()); 107 let indent = leading_indent(self.syntax()).unwrap_or_default();
108 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 108 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
109 let to_insert = iter::once(ws.ws().into()); 109 let to_insert = iter::once(ws.ws().into());
110 match existing_ws { 110 match existing_ws {
@@ -133,7 +133,7 @@ impl ast::RecordFieldList {
133 let space = if is_multiline { 133 let space = if is_multiline {
134 ws = tokens::WsBuilder::new(&format!( 134 ws = tokens::WsBuilder::new(&format!(
135 "\n{} ", 135 "\n{} ",
136 leading_indent(self.syntax()).unwrap_or("".into()) 136 leading_indent(self.syntax()).unwrap_or_default()
137 )); 137 ));
138 ws.ws() 138 ws.ws()
139 } else { 139 } else {
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c06076e3d..9f9d6e63c 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -312,6 +312,7 @@ impl AstNode for Block {
312 } 312 }
313} 313}
314impl ast::AttrsOwner for Block {} 314impl ast::AttrsOwner for Block {}
315impl ast::ModuleItemOwner for Block {}
315impl Block { 316impl Block {
316 pub fn statements(&self) -> AstChildren<Stmt> { 317 pub fn statements(&self) -> AstChildren<Stmt> {
317 AstChildren::new(&self.syntax) 318 AstChildren::new(&self.syntax)
@@ -550,6 +551,36 @@ impl ConstDef {
550 } 551 }
551} 552}
552#[derive(Debug, Clone, PartialEq, Eq, Hash)] 553#[derive(Debug, Clone, PartialEq, Eq, Hash)]
554pub struct ConstParam {
555 pub(crate) syntax: SyntaxNode,
556}
557impl AstNode for ConstParam {
558 fn can_cast(kind: SyntaxKind) -> bool {
559 match kind {
560 CONST_PARAM => true,
561 _ => false,
562 }
563 }
564 fn cast(syntax: SyntaxNode) -> Option<Self> {
565 if Self::can_cast(syntax.kind()) {
566 Some(Self { syntax })
567 } else {
568 None
569 }
570 }
571 fn syntax(&self) -> &SyntaxNode {
572 &self.syntax
573 }
574}
575impl ast::NameOwner for ConstParam {}
576impl ast::AttrsOwner for ConstParam {}
577impl ast::TypeAscriptionOwner for ConstParam {}
578impl ConstParam {
579 pub fn default_val(&self) -> Option<Expr> {
580 AstChildren::new(&self.syntax).next()
581 }
582}
583#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub struct ContinueExpr { 584pub struct ContinueExpr {
554 pub(crate) syntax: SyntaxNode, 585 pub(crate) syntax: SyntaxNode,
555} 586}
@@ -1425,6 +1456,9 @@ impl LambdaExpr {
1425 pub fn param_list(&self) -> Option<ParamList> { 1456 pub fn param_list(&self) -> Option<ParamList> {
1426 AstChildren::new(&self.syntax).next() 1457 AstChildren::new(&self.syntax).next()
1427 } 1458 }
1459 pub fn ret_type(&self) -> Option<RetType> {
1460 AstChildren::new(&self.syntax).next()
1461 }
1428 pub fn body(&self) -> Option<Expr> { 1462 pub fn body(&self) -> Option<Expr> {
1429 AstChildren::new(&self.syntax).next() 1463 AstChildren::new(&self.syntax).next()
1430 } 1464 }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 40db570da..04a5408fe 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -168,8 +168,7 @@ pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetSt
168 168
169fn ast_from_text<N: AstNode>(text: &str) -> N { 169fn ast_from_text<N: AstNode>(text: &str) -> N {
170 let parse = SourceFile::parse(text); 170 let parse = SourceFile::parse(text);
171 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 171 parse.tree().syntax().descendants().find_map(N::cast).unwrap()
172 res
173} 172}
174 173
175pub mod tokens { 174pub mod tokens {
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index d1be40abe..08aafb610 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -94,7 +94,8 @@ Grammar(
94 "return", 94 "return",
95 "try", 95 "try",
96 "box", 96 "box",
97 "await" 97 "await",
98 "macro"
98 ], 99 ],
99 contextual_keywords: [ 100 contextual_keywords: [
100 "auto", 101 "auto",
@@ -140,6 +141,7 @@ Grammar(
140 "TYPE_ALIAS_DEF", 141 "TYPE_ALIAS_DEF",
141 "MACRO_CALL", 142 "MACRO_CALL",
142 "TOKEN_TREE", 143 "TOKEN_TREE",
144 "MACRO_DEF",
143 145
144 "PAREN_TYPE", 146 "PAREN_TYPE",
145 "TUPLE_TYPE", 147 "TUPLE_TYPE",
@@ -243,6 +245,7 @@ Grammar(
243 "TYPE_PARAM_LIST", 245 "TYPE_PARAM_LIST",
244 "LIFETIME_PARAM", 246 "LIFETIME_PARAM",
245 "TYPE_PARAM", 247 "TYPE_PARAM",
248 "CONST_PARAM",
246 "TYPE_ARG_LIST", 249 "TYPE_ARG_LIST",
247 "LIFETIME_ARG", 250 "LIFETIME_ARG",
248 "TYPE_ARG", 251 "TYPE_ARG",
@@ -426,7 +429,7 @@ Grammar(
426 "PathExpr": (options: ["Path"]), 429 "PathExpr": (options: ["Path"]),
427 "LambdaExpr": ( 430 "LambdaExpr": (
428 options: [ 431 options: [
429 "ParamList", 432 "ParamList", "RetType",
430 ["body", "Expr"], 433 ["body", "Expr"],
431 ] 434 ]
432 ), 435 ),
@@ -602,6 +605,10 @@ Grammar(
602 options: [("default_type", "TypeRef")], 605 options: [("default_type", "TypeRef")],
603 traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"], 606 traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"],
604 ), 607 ),
608 "ConstParam": (
609 options: [("default_val", "Expr")],
610 traits: ["NameOwner", "AttrsOwner", "TypeAscriptionOwner"],
611 ),
605 "LifetimeParam": ( 612 "LifetimeParam": (
606 traits: ["AttrsOwner"], 613 traits: ["AttrsOwner"],
607 ), 614 ),
@@ -653,6 +660,7 @@ Grammar(
653 ], 660 ],
654 traits: [ 661 traits: [
655 "AttrsOwner", 662 "AttrsOwner",
663 "ModuleItemOwner",
656 ] 664 ]
657 ), 665 ),
658 "ParamList": ( 666 "ParamList": (
@@ -664,14 +672,14 @@ Grammar(
664 "SelfParam": ( 672 "SelfParam": (
665 traits: [ 673 traits: [
666 "TypeAscriptionOwner", 674 "TypeAscriptionOwner",
667 "AttrsOwner", 675 "AttrsOwner",
668 ] 676 ]
669 ), 677 ),
670 "Param": ( 678 "Param": (
671 options: [ "Pat" ], 679 options: [ "Pat" ],
672 traits: [ 680 traits: [
673 "TypeAscriptionOwner", 681 "TypeAscriptionOwner",
674 "AttrsOwner", 682 "AttrsOwner",
675 ] 683 ]
676 ), 684 ),
677 "UseItem": ( 685 "UseItem": (
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index e049fce61..db6230aab 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -1,6 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{iter::successors, marker::PhantomData}; 3use std::{
4 hash::{Hash, Hasher},
5 iter::successors,
6 marker::PhantomData,
7};
4 8
5use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; 9use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};
6 10
@@ -43,7 +47,7 @@ impl SyntaxNodePtr {
43} 47}
44 48
45/// Like `SyntaxNodePtr`, but remembers the type of node 49/// Like `SyntaxNodePtr`, but remembers the type of node
46#[derive(Debug, Hash)] 50#[derive(Debug)]
47pub struct AstPtr<N: AstNode> { 51pub struct AstPtr<N: AstNode> {
48 raw: SyntaxNodePtr, 52 raw: SyntaxNodePtr,
49 _ty: PhantomData<fn() -> N>, 53 _ty: PhantomData<fn() -> N>,
@@ -64,6 +68,12 @@ impl<N: AstNode> PartialEq for AstPtr<N> {
64 } 68 }
65} 69}
66 70
71impl<N: AstNode> Hash for AstPtr<N> {
72 fn hash<H: Hasher>(&self, state: &mut H) {
73 self.raw.hash(state)
74 }
75}
76
67impl<N: AstNode> AstPtr<N> { 77impl<N: AstNode> AstPtr<N> {
68 pub fn new(node: &N) -> AstPtr<N> { 78 pub fn new(node: &N) -> AstPtr<N> {
69 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData } 79 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index b2f5b8c64..041c6ea8d 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -40,7 +40,7 @@ pub use rowan::{Direction, NodeOrToken};
40 40
41pub struct SyntaxTreeBuilder { 41pub struct SyntaxTreeBuilder {
42 errors: Vec<SyntaxError>, 42 errors: Vec<SyntaxError>,
43 inner: GreenNodeBuilder, 43 inner: GreenNodeBuilder<'static>,
44} 44}
45 45
46impl Default for SyntaxTreeBuilder { 46impl Default for SyntaxTreeBuilder {
diff --git a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt b/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt
deleted file mode 100644
index c5be73a5a..000000000
--- a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt
+++ /dev/null
@@ -1,328 +0,0 @@
1SOURCE_FILE@[0; 349)
2 MACRO_CALL@[0; 41)
3 PATH@[0; 5)
4 PATH_SEGMENT@[0; 5)
5 NAME_REF@[0; 5)
6 IDENT@[0; 5) "macro"
7 WHITESPACE@[5; 6) " "
8 NAME@[6; 21)
9 IDENT@[6; 21) "parse_use_trees"
10 TOKEN_TREE@[21; 41)
11 L_PAREN@[21; 22) "("
12 DOLLAR@[22; 23) "$"
13 TOKEN_TREE@[23; 32)
14 L_PAREN@[23; 24) "("
15 DOLLAR@[24; 25) "$"
16 IDENT@[25; 26) "s"
17 COLON@[26; 27) ":"
18 IDENT@[27; 31) "expr"
19 R_PAREN@[31; 32) ")"
20 COMMA@[32; 33) ","
21 STAR@[33; 34) "*"
22 WHITESPACE@[34; 35) " "
23 DOLLAR@[35; 36) "$"
24 TOKEN_TREE@[36; 39)
25 L_PAREN@[36; 37) "("
26 COMMA@[37; 38) ","
27 R_PAREN@[38; 39) ")"
28 STAR@[39; 40) "*"
29 R_PAREN@[40; 41) ")"
30 WHITESPACE@[41; 42) " "
31 ERROR@[42; 93)
32 L_CURLY@[42; 43) "{"
33 WHITESPACE@[43; 48) "\n "
34 MACRO_CALL@[48; 91)
35 PATH@[48; 51)
36 PATH_SEGMENT@[48; 51)
37 NAME_REF@[48; 51)
38 IDENT@[48; 51) "vec"
39 EXCL@[51; 52) "!"
40 TOKEN_TREE@[52; 91)
41 L_BRACK@[52; 53) "["
42 WHITESPACE@[53; 62) "\n "
43 DOLLAR@[62; 63) "$"
44 TOKEN_TREE@[63; 84)
45 L_PAREN@[63; 64) "("
46 IDENT@[64; 78) "parse_use_tree"
47 TOKEN_TREE@[78; 82)
48 L_PAREN@[78; 79) "("
49 DOLLAR@[79; 80) "$"
50 IDENT@[80; 81) "s"
51 R_PAREN@[81; 82) ")"
52 COMMA@[82; 83) ","
53 R_PAREN@[83; 84) ")"
54 STAR@[84; 85) "*"
55 WHITESPACE@[85; 90) "\n "
56 R_BRACK@[90; 91) "]"
57 WHITESPACE@[91; 92) "\n"
58 R_CURLY@[92; 93) "}"
59 WHITESPACE@[93; 95) "\n\n"
60 FN_DEF@[95; 348)
61 ATTR@[95; 102)
62 POUND@[95; 96) "#"
63 L_BRACK@[96; 97) "["
64 PATH@[97; 101)
65 PATH_SEGMENT@[97; 101)
66 NAME_REF@[97; 101)
67 IDENT@[97; 101) "test"
68 R_BRACK@[101; 102) "]"
69 WHITESPACE@[102; 103) "\n"
70 FN_KW@[103; 105) "fn"
71 WHITESPACE@[105; 106) " "
72 NAME@[106; 125)
73 IDENT@[106; 125) "test_use_tree_merge"
74 PARAM_LIST@[125; 127)
75 L_PAREN@[125; 126) "("
76 R_PAREN@[126; 127) ")"
77 WHITESPACE@[127; 128) " "
78 BLOCK_EXPR@[128; 348)
79 BLOCK@[128; 348)
80 L_CURLY@[128; 129) "{"
81 WHITESPACE@[129; 134) "\n "
82 EXPR_STMT@[134; 139)
83 PATH_EXPR@[134; 139)
84 PATH@[134; 139)
85 PATH_SEGMENT@[134; 139)
86 NAME_REF@[134; 139)
87 IDENT@[134; 139) "macro"
88 WHITESPACE@[139; 140) " "
89 EXPR_STMT@[140; 154)
90 CALL_EXPR@[140; 154)
91 PATH_EXPR@[140; 150)
92 PATH@[140; 150)
93 PATH_SEGMENT@[140; 150)
94 NAME_REF@[140; 150)
95 IDENT@[140; 150) "test_merge"
96 ARG_LIST@[150; 154)
97 L_PAREN@[150; 151) "("
98 ARRAY_EXPR@[151; 154)
99 L_BRACK@[151; 152) "["
100 ERROR@[152; 153)
101 DOLLAR@[152; 153) "$"
102 PAREN_EXPR@[153; 154)
103 L_PAREN@[153; 154) "("
104 EXPR_STMT@[154; 155)
105 ERROR@[154; 155)
106 DOLLAR@[154; 155) "$"
107 EXPR_STMT@[155; 160)
108 PATH_EXPR@[155; 160)
109 PATH@[155; 160)
110 PATH_SEGMENT@[155; 160)
111 NAME_REF@[155; 160)
112 IDENT@[155; 160) "input"
113 EXPR_STMT@[160; 161)
114 ERROR@[160; 161)
115 COLON@[160; 161) ":"
116 EXPR_STMT@[161; 165)
117 PATH_EXPR@[161; 165)
118 PATH@[161; 165)
119 PATH_SEGMENT@[161; 165)
120 NAME_REF@[161; 165)
121 IDENT@[161; 165) "expr"
122 EXPR_STMT@[165; 166)
123 ERROR@[165; 166)
124 R_PAREN@[165; 166) ")"
125 EXPR_STMT@[166; 167)
126 ERROR@[166; 167)
127 COMMA@[166; 167) ","
128 EXPR_STMT@[167; 170)
129 PREFIX_EXPR@[167; 170)
130 STAR@[167; 168) "*"
131 WHITESPACE@[168; 169) " "
132 ERROR@[169; 170)
133 DOLLAR@[169; 170) "$"
134 EXPR_STMT@[170; 171)
135 PAREN_EXPR@[170; 171)
136 L_PAREN@[170; 171) "("
137 EXPR_STMT@[171; 172)
138 ERROR@[171; 172)
139 COMMA@[171; 172) ","
140 EXPR_STMT@[172; 173)
141 ERROR@[172; 173)
142 R_PAREN@[172; 173) ")"
143 EXPR_STMT@[173; 175)
144 PREFIX_EXPR@[173; 175)
145 STAR@[173; 174) "*"
146 ERROR@[174; 175)
147 R_BRACK@[174; 175) "]"
148 EXPR_STMT@[175; 176)
149 ERROR@[175; 176)
150 COMMA@[175; 176) ","
151 WHITESPACE@[176; 177) " "
152 EXPR_STMT@[177; 180)
153 ARRAY_EXPR@[177; 180)
154 L_BRACK@[177; 178) "["
155 ERROR@[178; 179)
156 DOLLAR@[178; 179) "$"
157 PAREN_EXPR@[179; 180)
158 L_PAREN@[179; 180) "("
159 EXPR_STMT@[180; 181)
160 ERROR@[180; 181)
161 DOLLAR@[180; 181) "$"
162 EXPR_STMT@[181; 187)
163 PATH_EXPR@[181; 187)
164 PATH@[181; 187)
165 PATH_SEGMENT@[181; 187)
166 NAME_REF@[181; 187)
167 IDENT@[181; 187) "output"
168 EXPR_STMT@[187; 188)
169 ERROR@[187; 188)
170 COLON@[187; 188) ":"
171 EXPR_STMT@[188; 192)
172 PATH_EXPR@[188; 192)
173 PATH@[188; 192)
174 PATH_SEGMENT@[188; 192)
175 NAME_REF@[188; 192)
176 IDENT@[188; 192) "expr"
177 EXPR_STMT@[192; 193)
178 ERROR@[192; 193)
179 R_PAREN@[192; 193) ")"
180 EXPR_STMT@[193; 194)
181 ERROR@[193; 194)
182 COMMA@[193; 194) ","
183 EXPR_STMT@[194; 197)
184 PREFIX_EXPR@[194; 197)
185 STAR@[194; 195) "*"
186 WHITESPACE@[195; 196) " "
187 ERROR@[196; 197)
188 DOLLAR@[196; 197) "$"
189 EXPR_STMT@[197; 198)
190 PAREN_EXPR@[197; 198)
191 L_PAREN@[197; 198) "("
192 EXPR_STMT@[198; 199)
193 ERROR@[198; 199)
194 COMMA@[198; 199) ","
195 EXPR_STMT@[199; 200)
196 ERROR@[199; 200)
197 R_PAREN@[199; 200) ")"
198 EXPR_STMT@[200; 202)
199 PREFIX_EXPR@[200; 202)
200 STAR@[200; 201) "*"
201 ERROR@[201; 202)
202 R_BRACK@[201; 202) "]"
203 EXPR_STMT@[202; 203)
204 ERROR@[202; 203)
205 R_PAREN@[202; 203) ")"
206 WHITESPACE@[203; 204) " "
207 BLOCK_EXPR@[204; 346)
208 BLOCK@[204; 346)
209 L_CURLY@[204; 205) "{"
210 WHITESPACE@[205; 214) "\n "
211 EXPR_STMT@[214; 340)
212 MACRO_CALL@[214; 339)
213 PATH@[214; 223)
214 PATH_SEGMENT@[214; 223)
215 NAME_REF@[214; 223)
216 IDENT@[214; 223) "assert_eq"
217 EXCL@[223; 224) "!"
218 TOKEN_TREE@[224; 339)
219 L_PAREN@[224; 225) "("
220 WHITESPACE@[225; 238) "\n "
221 IDENT@[238; 253) "merge_use_trees"
222 TOKEN_TREE@[253; 284)
223 L_PAREN@[253; 254) "("
224 IDENT@[254; 269) "parse_use_trees"
225 EXCL@[269; 270) "!"
226 TOKEN_TREE@[270; 283)
227 L_PAREN@[270; 271) "("
228 DOLLAR@[271; 272) "$"
229 TOKEN_TREE@[272; 281)
230 L_PAREN@[272; 273) "("
231 DOLLAR@[273; 274) "$"
232 IDENT@[274; 279) "input"
233 COMMA@[279; 280) ","
234 R_PAREN@[280; 281) ")"
235 STAR@[281; 282) "*"
236 R_PAREN@[282; 283) ")"
237 R_PAREN@[283; 284) ")"
238 COMMA@[284; 285) ","
239 WHITESPACE@[285; 298) "\n "
240 IDENT@[298; 313) "parse_use_trees"
241 EXCL@[313; 314) "!"
242 TOKEN_TREE@[314; 328)
243 L_PAREN@[314; 315) "("
244 DOLLAR@[315; 316) "$"
245 TOKEN_TREE@[316; 326)
246 L_PAREN@[316; 317) "("
247 DOLLAR@[317; 318) "$"
248 IDENT@[318; 324) "output"
249 COMMA@[324; 325) ","
250 R_PAREN@[325; 326) ")"
251 STAR@[326; 327) "*"
252 R_PAREN@[327; 328) ")"
253 COMMA@[328; 329) ","
254 WHITESPACE@[329; 338) "\n "
255 R_PAREN@[338; 339) ")"
256 SEMI@[339; 340) ";"
257 WHITESPACE@[340; 345) "\n "
258 R_CURLY@[345; 346) "}"
259 WHITESPACE@[346; 347) "\n"
260 R_CURLY@[347; 348) "}"
261 WHITESPACE@[348; 349) "\n"
262error 5: expected EXCL
263error 41: expected SEMI
264error 42: expected an item
265error 139: expected SEMI
266error 152: expected expression
267error 153: expected COMMA
268error 154: expected expression
269error 154: expected R_PAREN
270error 154: expected COMMA
271error 154: expected expression
272error 154: expected R_BRACK
273error 154: expected COMMA
274error 154: expected SEMI
275error 154: expected expression
276error 155: expected SEMI
277error 160: expected SEMI
278error 160: expected expression
279error 161: expected SEMI
280error 165: expected SEMI
281error 165: expected expression
282error 166: expected SEMI
283error 166: expected expression
284error 167: expected SEMI
285error 169: expected expression
286error 170: expected SEMI
287error 171: expected expression
288error 171: expected R_PAREN
289error 171: expected SEMI
290error 171: expected expression
291error 172: expected SEMI
292error 172: expected expression
293error 173: expected SEMI
294error 174: expected expression
295error 175: expected SEMI
296error 175: expected expression
297error 176: expected SEMI
298error 178: expected expression
299error 179: expected COMMA
300error 180: expected expression
301error 180: expected R_PAREN
302error 180: expected COMMA
303error 180: expected expression
304error 180: expected R_BRACK
305error 180: expected SEMI
306error 180: expected expression
307error 181: expected SEMI
308error 187: expected SEMI
309error 187: expected expression
310error 188: expected SEMI
311error 192: expected SEMI
312error 192: expected expression
313error 193: expected SEMI
314error 193: expected expression
315error 194: expected SEMI
316error 196: expected expression
317error 197: expected SEMI
318error 198: expected expression
319error 198: expected R_PAREN
320error 198: expected SEMI
321error 198: expected expression
322error 199: expected SEMI
323error 199: expected expression
324error 200: expected SEMI
325error 201: expected expression
326error 202: expected SEMI
327error 202: expected expression
328error 203: expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
new file mode 100644
index 000000000..a2f74bd87
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
@@ -0,0 +1,5 @@
1fn foo() -> i32 {
2 [1, 2, 3].iter()
3 .map(|it|)
4 .max::<i32>();
5}
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
new file mode 100644
index 000000000..d1544634c
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
@@ -0,0 +1,83 @@
1SOURCE_FILE@[0; 83)
2 FN_DEF@[0; 82)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " "
11 RET_TYPE@[9; 15)
12 THIN_ARROW@[9; 11) "->"
13 WHITESPACE@[11; 12) " "
14 PATH_TYPE@[12; 15)
15 PATH@[12; 15)
16 PATH_SEGMENT@[12; 15)
17 NAME_REF@[12; 15)
18 IDENT@[12; 15) "i32"
19 WHITESPACE@[15; 16) " "
20 BLOCK_EXPR@[16; 82)
21 BLOCK@[16; 82)
22 L_CURLY@[16; 17) "{"
23 WHITESPACE@[17; 22) "\n "
24 EXPR_STMT@[22; 80)
25 METHOD_CALL_EXPR@[22; 79)
26 METHOD_CALL_EXPR@[22; 57)
27 METHOD_CALL_EXPR@[22; 38)
28 ARRAY_EXPR@[22; 31)
29 L_BRACK@[22; 23) "["
30 LITERAL@[23; 24)
31 INT_NUMBER@[23; 24) "1"
32 COMMA@[24; 25) ","
33 WHITESPACE@[25; 26) " "
34 LITERAL@[26; 27)
35 INT_NUMBER@[26; 27) "2"
36 COMMA@[27; 28) ","
37 WHITESPACE@[28; 29) " "
38 LITERAL@[29; 30)
39 INT_NUMBER@[29; 30) "3"
40 R_BRACK@[30; 31) "]"
41 DOT@[31; 32) "."
42 NAME_REF@[32; 36)
43 IDENT@[32; 36) "iter"
44 ARG_LIST@[36; 38)
45 L_PAREN@[36; 37) "("
46 R_PAREN@[37; 38) ")"
47 WHITESPACE@[38; 47) "\n "
48 DOT@[47; 48) "."
49 NAME_REF@[48; 51)
50 IDENT@[48; 51) "map"
51 ARG_LIST@[51; 57)
52 L_PAREN@[51; 52) "("
53 LAMBDA_EXPR@[52; 56)
54 PARAM_LIST@[52; 56)
55 PIPE@[52; 53) "|"
56 PARAM@[53; 55)
57 BIND_PAT@[53; 55)
58 NAME@[53; 55)
59 IDENT@[53; 55) "it"
60 PIPE@[55; 56) "|"
61 R_PAREN@[56; 57) ")"
62 WHITESPACE@[57; 66) "\n "
63 DOT@[66; 67) "."
64 NAME_REF@[67; 70)
65 IDENT@[67; 70) "max"
66 TYPE_ARG_LIST@[70; 77)
67 COLONCOLON@[70; 72) "::"
68 L_ANGLE@[72; 73) "<"
69 TYPE_ARG@[73; 76)
70 PATH_TYPE@[73; 76)
71 PATH@[73; 76)
72 PATH_SEGMENT@[73; 76)
73 NAME_REF@[73; 76)
74 IDENT@[73; 76) "i32"
75 R_ANGLE@[76; 77) ">"
76 ARG_LIST@[77; 79)
77 L_PAREN@[77; 78) "("
78 R_PAREN@[78; 79) ")"
79 SEMI@[79; 80) ";"
80 WHITESPACE@[80; 81) "\n"
81 R_CURLY@[81; 82) "}"
82 WHITESPACE@[82; 83) "\n"
83error 56: expected expression
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
index 4a714ad6b..b05ccc0ed 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
@@ -16,11 +16,10 @@ SOURCE_FILE@[0; 33)
16 LET_KW@[16; 19) "let" 16 LET_KW@[16; 19) "let"
17 WHITESPACE@[19; 20) " " 17 WHITESPACE@[19; 20) " "
18 MACRO_CALL@[20; 25) 18 MACRO_CALL@[20; 25)
19 PATH_PAT@[20; 21) 19 PATH@[20; 21)
20 PATH@[20; 21) 20 PATH_SEGMENT@[20; 21)
21 PATH_SEGMENT@[20; 21) 21 NAME_REF@[20; 21)
22 NAME_REF@[20; 21) 22 IDENT@[20; 21) "m"
23 IDENT@[20; 21) "m"
24 EXCL@[21; 22) "!" 23 EXCL@[21; 22) "!"
25 TOKEN_TREE@[22; 25) 24 TOKEN_TREE@[22; 25)
26 L_PAREN@[22; 23) "(" 25 L_PAREN@[22; 23) "("
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs
new file mode 100644
index 000000000..8cdb3b703
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs
@@ -0,0 +1 @@
struct S<const N: u32>;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt
new file mode 100644
index 000000000..f81de7bac
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt
@@ -0,0 +1,23 @@
1SOURCE_FILE@[0; 24)
2 STRUCT_DEF@[0; 23)
3 STRUCT_KW@[0; 6) "struct"
4 WHITESPACE@[6; 7) " "
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 TYPE_PARAM_LIST@[8; 22)
8 L_ANGLE@[8; 9) "<"
9 CONST_PARAM@[9; 21)
10 CONST_KW@[9; 14) "const"
11 WHITESPACE@[14; 15) " "
12 NAME@[15; 16)
13 IDENT@[15; 16) "N"
14 COLON@[16; 17) ":"
15 WHITESPACE@[17; 18) " "
16 PATH_TYPE@[18; 21)
17 PATH@[18; 21)
18 PATH_SEGMENT@[18; 21)
19 NAME_REF@[18; 21)
20 IDENT@[18; 21) "u32"
21 R_ANGLE@[21; 22) ">"
22 SEMI@[22; 23) ";"
23 WHITESPACE@[23; 24) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs
new file mode 100644
index 000000000..319a4e2aa
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs
@@ -0,0 +1,2 @@
1macro m { ($i:ident) => {} }
2macro m($i:ident) {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt
new file mode 100644
index 000000000..3556099bd
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt
@@ -0,0 +1,45 @@
1SOURCE_FILE@[0; 50)
2 MACRO_DEF@[0; 28)
3 MACRO_KW@[0; 5) "macro"
4 WHITESPACE@[5; 6) " "
5 NAME@[6; 7)
6 IDENT@[6; 7) "m"
7 WHITESPACE@[7; 8) " "
8 TOKEN_TREE@[8; 28)
9 L_CURLY@[8; 9) "{"
10 WHITESPACE@[9; 10) " "
11 TOKEN_TREE@[10; 20)
12 L_PAREN@[10; 11) "("
13 DOLLAR@[11; 12) "$"
14 IDENT@[12; 13) "i"
15 COLON@[13; 14) ":"
16 IDENT@[14; 19) "ident"
17 R_PAREN@[19; 20) ")"
18 WHITESPACE@[20; 21) " "
19 EQ@[21; 22) "="
20 R_ANGLE@[22; 23) ">"
21 WHITESPACE@[23; 24) " "
22 TOKEN_TREE@[24; 26)
23 L_CURLY@[24; 25) "{"
24 R_CURLY@[25; 26) "}"
25 WHITESPACE@[26; 27) " "
26 R_CURLY@[27; 28) "}"
27 WHITESPACE@[28; 29) "\n"
28 MACRO_DEF@[29; 49)
29 MACRO_KW@[29; 34) "macro"
30 WHITESPACE@[34; 35) " "
31 NAME@[35; 36)
32 IDENT@[35; 36) "m"
33 TOKEN_TREE@[36; 49)
34 TOKEN_TREE@[36; 46)
35 L_PAREN@[36; 37) "("
36 DOLLAR@[37; 38) "$"
37 IDENT@[38; 39) "i"
38 COLON@[39; 40) ":"
39 IDENT@[40; 45) "ident"
40 R_PAREN@[45; 46) ")"
41 WHITESPACE@[46; 47) " "
42 TOKEN_TREE@[47; 49)
43 L_CURLY@[47; 48) "{"
44 R_CURLY@[48; 49) "}"
45 WHITESPACE@[49; 50) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs
new file mode 100644
index 000000000..3b2be597f
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs
@@ -0,0 +1 @@
pub macro m($:ident) {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt
new file mode 100644
index 000000000..cfd79d9c2
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt
@@ -0,0 +1,21 @@
1SOURCE_FILE@[0; 24)
2 MACRO_DEF@[0; 23)
3 VISIBILITY@[0; 3)
4 PUB_KW@[0; 3) "pub"
5 WHITESPACE@[3; 4) " "
6 MACRO_KW@[4; 9) "macro"
7 WHITESPACE@[9; 10) " "
8 NAME@[10; 11)
9 IDENT@[10; 11) "m"
10 TOKEN_TREE@[11; 23)
11 TOKEN_TREE@[11; 20)
12 L_PAREN@[11; 12) "("
13 DOLLAR@[12; 13) "$"
14 COLON@[13; 14) ":"
15 IDENT@[14; 19) "ident"
16 R_PAREN@[19; 20) ")"
17 WHITESPACE@[20; 21) " "
18 TOKEN_TREE@[21; 23)
19 L_CURLY@[21; 22) "{"
20 R_CURLY@[22; 23) "}"
21 WHITESPACE@[23; 24) "\n"
diff --git a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs
index 781047ba1..781047ba1 100644
--- a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs
+++ b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs
diff --git a/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt
new file mode 100644
index 000000000..2be523fc3
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt
@@ -0,0 +1,176 @@
1SOURCE_FILE@[0; 349)
2 MACRO_DEF@[0; 93)
3 MACRO_KW@[0; 5) "macro"
4 WHITESPACE@[5; 6) " "
5 NAME@[6; 21)
6 IDENT@[6; 21) "parse_use_trees"
7 TOKEN_TREE@[21; 93)
8 TOKEN_TREE@[21; 41)
9 L_PAREN@[21; 22) "("
10 DOLLAR@[22; 23) "$"
11 TOKEN_TREE@[23; 32)
12 L_PAREN@[23; 24) "("
13 DOLLAR@[24; 25) "$"
14 IDENT@[25; 26) "s"
15 COLON@[26; 27) ":"
16 IDENT@[27; 31) "expr"
17 R_PAREN@[31; 32) ")"
18 COMMA@[32; 33) ","
19 STAR@[33; 34) "*"
20 WHITESPACE@[34; 35) " "
21 DOLLAR@[35; 36) "$"
22 TOKEN_TREE@[36; 39)
23 L_PAREN@[36; 37) "("
24 COMMA@[37; 38) ","
25 R_PAREN@[38; 39) ")"
26 STAR@[39; 40) "*"
27 R_PAREN@[40; 41) ")"
28 WHITESPACE@[41; 42) " "
29 TOKEN_TREE@[42; 93)
30 L_CURLY@[42; 43) "{"
31 WHITESPACE@[43; 48) "\n "
32 IDENT@[48; 51) "vec"
33 EXCL@[51; 52) "!"
34 TOKEN_TREE@[52; 91)
35 L_BRACK@[52; 53) "["
36 WHITESPACE@[53; 62) "\n "
37 DOLLAR@[62; 63) "$"
38 TOKEN_TREE@[63; 84)
39 L_PAREN@[63; 64) "("
40 IDENT@[64; 78) "parse_use_tree"
41 TOKEN_TREE@[78; 82)
42 L_PAREN@[78; 79) "("
43 DOLLAR@[79; 80) "$"
44 IDENT@[80; 81) "s"
45 R_PAREN@[81; 82) ")"
46 COMMA@[82; 83) ","
47 R_PAREN@[83; 84) ")"
48 STAR@[84; 85) "*"
49 WHITESPACE@[85; 90) "\n "
50 R_BRACK@[90; 91) "]"
51 WHITESPACE@[91; 92) "\n"
52 R_CURLY@[92; 93) "}"
53 WHITESPACE@[93; 95) "\n\n"
54 FN_DEF@[95; 348)
55 ATTR@[95; 102)
56 POUND@[95; 96) "#"
57 L_BRACK@[96; 97) "["
58 PATH@[97; 101)
59 PATH_SEGMENT@[97; 101)
60 NAME_REF@[97; 101)
61 IDENT@[97; 101) "test"
62 R_BRACK@[101; 102) "]"
63 WHITESPACE@[102; 103) "\n"
64 FN_KW@[103; 105) "fn"
65 WHITESPACE@[105; 106) " "
66 NAME@[106; 125)
67 IDENT@[106; 125) "test_use_tree_merge"
68 PARAM_LIST@[125; 127)
69 L_PAREN@[125; 126) "("
70 R_PAREN@[126; 127) ")"
71 WHITESPACE@[127; 128) " "
72 BLOCK_EXPR@[128; 348)
73 BLOCK@[128; 348)
74 L_CURLY@[128; 129) "{"
75 WHITESPACE@[129; 134) "\n "
76 MACRO_DEF@[134; 346)
77 MACRO_KW@[134; 139) "macro"
78 WHITESPACE@[139; 140) " "
79 NAME@[140; 150)
80 IDENT@[140; 150) "test_merge"
81 TOKEN_TREE@[150; 346)
82 TOKEN_TREE@[150; 203)
83 L_PAREN@[150; 151) "("
84 TOKEN_TREE@[151; 175)
85 L_BRACK@[151; 152) "["
86 DOLLAR@[152; 153) "$"
87 TOKEN_TREE@[153; 166)
88 L_PAREN@[153; 154) "("
89 DOLLAR@[154; 155) "$"
90 IDENT@[155; 160) "input"
91 COLON@[160; 161) ":"
92 IDENT@[161; 165) "expr"
93 R_PAREN@[165; 166) ")"
94 COMMA@[166; 167) ","
95 STAR@[167; 168) "*"
96 WHITESPACE@[168; 169) " "
97 DOLLAR@[169; 170) "$"
98 TOKEN_TREE@[170; 173)
99 L_PAREN@[170; 171) "("
100 COMMA@[171; 172) ","
101 R_PAREN@[172; 173) ")"
102 STAR@[173; 174) "*"
103 R_BRACK@[174; 175) "]"
104 COMMA@[175; 176) ","
105 WHITESPACE@[176; 177) " "
106 TOKEN_TREE@[177; 202)
107 L_BRACK@[177; 178) "["
108 DOLLAR@[178; 179) "$"
109 TOKEN_TREE@[179; 193)
110 L_PAREN@[179; 180) "("
111 DOLLAR@[180; 181) "$"
112 IDENT@[181; 187) "output"
113 COLON@[187; 188) ":"
114 IDENT@[188; 192) "expr"
115 R_PAREN@[192; 193) ")"
116 COMMA@[193; 194) ","
117 STAR@[194; 195) "*"
118 WHITESPACE@[195; 196) " "
119 DOLLAR@[196; 197) "$"
120 TOKEN_TREE@[197; 200)
121 L_PAREN@[197; 198) "("
122 COMMA@[198; 199) ","
123 R_PAREN@[199; 200) ")"
124 STAR@[200; 201) "*"
125 R_BRACK@[201; 202) "]"
126 R_PAREN@[202; 203) ")"
127 WHITESPACE@[203; 204) " "
128 TOKEN_TREE@[204; 346)
129 L_CURLY@[204; 205) "{"
130 WHITESPACE@[205; 214) "\n "
131 IDENT@[214; 223) "assert_eq"
132 EXCL@[223; 224) "!"
133 TOKEN_TREE@[224; 339)
134 L_PAREN@[224; 225) "("
135 WHITESPACE@[225; 238) "\n "
136 IDENT@[238; 253) "merge_use_trees"
137 TOKEN_TREE@[253; 284)
138 L_PAREN@[253; 254) "("
139 IDENT@[254; 269) "parse_use_trees"
140 EXCL@[269; 270) "!"
141 TOKEN_TREE@[270; 283)
142 L_PAREN@[270; 271) "("
143 DOLLAR@[271; 272) "$"
144 TOKEN_TREE@[272; 281)
145 L_PAREN@[272; 273) "("
146 DOLLAR@[273; 274) "$"
147 IDENT@[274; 279) "input"
148 COMMA@[279; 280) ","
149 R_PAREN@[280; 281) ")"
150 STAR@[281; 282) "*"
151 R_PAREN@[282; 283) ")"
152 R_PAREN@[283; 284) ")"
153 COMMA@[284; 285) ","
154 WHITESPACE@[285; 298) "\n "
155 IDENT@[298; 313) "parse_use_trees"
156 EXCL@[313; 314) "!"
157 TOKEN_TREE@[314; 328)
158 L_PAREN@[314; 315) "("
159 DOLLAR@[315; 316) "$"
160 TOKEN_TREE@[316; 326)
161 L_PAREN@[316; 317) "("
162 DOLLAR@[317; 318) "$"
163 IDENT@[318; 324) "output"
164 COMMA@[324; 325) ","
165 R_PAREN@[325; 326) ")"
166 STAR@[326; 327) "*"
167 R_PAREN@[327; 328) ")"
168 COMMA@[328; 329) ","
169 WHITESPACE@[329; 338) "\n "
170 R_PAREN@[338; 339) ")"
171 SEMI@[339; 340) ";"
172 WHITESPACE@[340; 345) "\n "
173 R_CURLY@[345; 346) "}"
174 WHITESPACE@[346; 347) "\n"
175 R_CURLY@[347; 348) "}"
176 WHITESPACE@[348; 349) "\n"
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 20c251ff4..10f424aae 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -33,14 +33,14 @@ impl TokenId {
33 } 33 }
34} 34}
35 35
36#[derive(Debug, Clone, PartialEq, Eq)] 36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37pub enum TokenTree { 37pub enum TokenTree {
38 Leaf(Leaf), 38 Leaf(Leaf),
39 Subtree(Subtree), 39 Subtree(Subtree),
40} 40}
41impl_froms!(TokenTree: Leaf, Subtree); 41impl_froms!(TokenTree: Leaf, Subtree);
42 42
43#[derive(Debug, Clone, PartialEq, Eq)] 43#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub enum Leaf { 44pub enum Leaf {
45 Literal(Literal), 45 Literal(Literal),
46 Punct(Punct), 46 Punct(Punct),
@@ -48,38 +48,45 @@ pub enum Leaf {
48} 48}
49impl_froms!(Leaf: Literal, Punct, Ident); 49impl_froms!(Leaf: Literal, Punct, Ident);
50 50
51#[derive(Debug, Clone, PartialEq, Eq)] 51#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
52pub struct Subtree { 52pub struct Subtree {
53 pub delimiter: Delimiter, 53 pub delimiter: Option<Delimiter>,
54 pub token_trees: Vec<TokenTree>, 54 pub token_trees: Vec<TokenTree>,
55} 55}
56 56
57#[derive(Clone, Copy, Debug, PartialEq, Eq)] 57#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
58pub enum Delimiter { 58pub struct Delimiter {
59 pub id: TokenId,
60 pub kind: DelimiterKind,
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
64pub enum DelimiterKind {
59 Parenthesis, 65 Parenthesis,
60 Brace, 66 Brace,
61 Bracket, 67 Bracket,
62 None,
63} 68}
64 69
65#[derive(Debug, Clone, PartialEq, Eq)] 70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
66pub struct Literal { 71pub struct Literal {
67 pub text: SmolStr, 72 pub text: SmolStr,
73 pub id: TokenId,
68} 74}
69 75
70#[derive(Debug, Clone, Copy, PartialEq, Eq)] 76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub struct Punct { 77pub struct Punct {
72 pub char: char, 78 pub char: char,
73 pub spacing: Spacing, 79 pub spacing: Spacing,
80 pub id: TokenId,
74} 81}
75 82
76#[derive(Debug, Clone, Copy, PartialEq, Eq)] 83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub enum Spacing { 84pub enum Spacing {
78 Alone, 85 Alone,
79 Joint, 86 Joint,
80} 87}
81 88
82#[derive(Debug, Clone, PartialEq, Eq)] 89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
83pub struct Ident { 90pub struct Ident {
84 pub text: SmolStr, 91 pub text: SmolStr,
85 pub id: TokenId, 92 pub id: TokenId,
@@ -96,11 +103,11 @@ impl fmt::Display for TokenTree {
96 103
97impl fmt::Display for Subtree { 104impl fmt::Display for Subtree {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 let (l, r) = match self.delimiter { 106 let (l, r) = match self.delimiter_kind() {
100 Delimiter::Parenthesis => ("(", ")"), 107 Some(DelimiterKind::Parenthesis) => ("(", ")"),
101 Delimiter::Brace => ("{", "}"), 108 Some(DelimiterKind::Brace) => ("{", "}"),
102 Delimiter::Bracket => ("[", "]"), 109 Some(DelimiterKind::Bracket) => ("[", "]"),
103 Delimiter::None => ("", ""), 110 None => ("", ""),
104 }; 111 };
105 f.write_str(l)?; 112 f.write_str(l)?;
106 let mut needs_space = false; 113 let mut needs_space = false;
@@ -164,6 +171,10 @@ impl Subtree {
164 171
165 self.token_trees.len() + children_count 172 self.token_trees.len() + children_count
166 } 173 }
174
175 pub fn delimiter_kind(&self) -> Option<DelimiterKind> {
176 self.delimiter.map(|it| it.kind)
177 }
167} 178}
168 179
169pub mod buffer; 180pub mod buffer;
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 1244ea8cf..659f77b71 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -207,8 +207,8 @@ pub fn lines_match(expected: &str, actual: &str) -> bool {
207 // Let's not deal with / vs \ (windows...) 207 // Let's not deal with / vs \ (windows...)
208 // First replace backslash-escaped backslashes with forward slashes 208 // First replace backslash-escaped backslashes with forward slashes
209 // which can occur in, for example, JSON output 209 // which can occur in, for example, JSON output
210 let expected = expected.replace("\\\\", "/").replace("\\", "/"); 210 let expected = expected.replace(r"\\", "/").replace(r"\", "/");
211 let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/"); 211 let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/");
212 for (i, part) in expected.split("[..]").enumerate() { 212 for (i, part) in expected.split("[..]").enumerate() {
213 match actual.find(part) { 213 match actual.find(part) {
214 Some(j) => { 214 Some(j) => {
@@ -356,6 +356,17 @@ pub fn read_text(path: &Path) -> String {
356 .replace("\r\n", "\n") 356 .replace("\r\n", "\n")
357} 357}
358 358
359pub fn skip_slow_tests() -> bool {
360 let should_skip = std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err();
361 if should_skip {
362 eprintln!("ignoring slow test")
363 } else {
364 let path = project_dir().join("./target/.slow_tests_cookie");
365 fs::write(&path, ".").unwrap();
366 }
367 should_skip
368}
369
359const REWRITE: bool = false; 370const REWRITE: bool = false;
360 371
361fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 372fn assert_equal_text(expected: &str, actual: &str, path: &Path) {