aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/expect/Cargo.toml10
-rw-r--r--crates/expect/src/lib.rs293
-rw-r--r--crates/flycheck/src/lib.rs208
-rw-r--r--crates/ra_assists/src/assist_context.rs8
-rw-r--r--crates/ra_assists/src/ast_transform.rs16
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs2
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs6
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs2
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs2
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs25
-rw-r--r--crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs10
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs8
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs43
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs5
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs10
-rw-r--r--crates/ra_assists/src/utils.rs11
-rw-r--r--crates/ra_db/src/fixture.rs8
-rw-r--r--crates/ra_db/src/input.rs24
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs15
-rw-r--r--crates/ra_hir/src/semantics.rs16
-rw-r--r--crates/ra_hir_def/src/item_scope.rs109
-rw-r--r--crates/ra_hir_def/src/resolver.rs8
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs35
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/name.rs3
-rw-r--r--crates/ra_hir_ty/Cargo.toml4
-rw-r--r--crates/ra_hir_ty/src/db.rs4
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs10
-rw-r--r--crates/ra_hir_ty/src/display.rs18
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs6
-rw-r--r--crates/ra_hir_ty/src/lib.rs10
-rw-r--r--crates/ra_hir_ty/src/lower.rs43
-rw-r--r--crates/ra_hir_ty/src/test_db.rs27
-rw-r--r--crates/ra_hir_ty/src/tests.rs47
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/display_source_code.rs49
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs116
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs158
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs118
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs21
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs134
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs342
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs2
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs45
-rw-r--r--crates/ra_ide/src/goto_definition.rs1052
-rw-r--r--crates/ra_ide/src/goto_implementation.rs193
-rw-r--r--crates/ra_ide/src/inlay_hints.rs985
-rw-r--r--crates/ra_ide/src/join_lines.rs5
-rw-r--r--crates/ra_ide/src/mock_analysis.rs24
-rw-r--r--crates/ra_ide/src/runnables.rs1036
-rw-r--r--crates/ra_ide/src/ssr.rs2
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs5
-rw-r--r--crates/ra_mbe/src/parser.rs5
-rw-r--r--crates/ra_parser/src/grammar.rs5
-rw-r--r--crates/ra_parser/src/grammar/paths.rs5
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs5
-rw-r--r--crates/ra_parser/src/syntax_kind.rs5
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs17
-rw-r--r--crates/ra_project_model/src/lib.rs13
-rw-r--r--crates/ra_project_model/src/project_json.rs17
-rw-r--r--crates/ra_ssr/src/lib.rs165
-rw-r--r--crates/ra_ssr/src/matching.rs14
-rw-r--r--crates/ra_ssr/src/parsing.rs4
-rw-r--r--crates/ra_ssr/src/replacing.rs35
-rw-r--r--crates/ra_ssr/src/tests.rs212
-rw-r--r--crates/ra_syntax/src/algo.rs4
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs5
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs16
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs5
-rw-r--r--crates/ra_tt/src/buffer.rs5
-rw-r--r--crates/rust-analyzer/Cargo.toml3
-rw-r--r--crates/rust-analyzer/src/bin/args.rs80
-rw-r--r--crates/rust-analyzer/src/bin/main.rs8
-rw-r--r--crates/rust-analyzer/src/cli.rs12
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs41
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs7
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs71
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs10
-rw-r--r--crates/rust-analyzer/src/handlers.rs36
-rw-r--r--crates/rust-analyzer/src/line_endings.rs14
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs13
-rw-r--r--crates/test_utils/src/lib.rs53
-rw-r--r--crates/vfs-notify/src/lib.rs8
-rw-r--r--crates/vfs/src/file_set.rs2
92 files changed, 3162 insertions, 3095 deletions
diff --git a/crates/expect/Cargo.toml b/crates/expect/Cargo.toml
new file mode 100644
index 000000000..caee43106
--- /dev/null
+++ b/crates/expect/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "expect"
3version = "0.1.0"
4authors = ["rust-analyzer developers"]
5edition = "2018"
6
7[dependencies]
8once_cell = "1"
9difference = "2"
10stdx = { path = "../stdx" }
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
new file mode 100644
index 000000000..dd7b96aab
--- /dev/null
+++ b/crates/expect/src/lib.rs
@@ -0,0 +1,293 @@
1//! Snapshot testing library, see
2//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
3use std::{
4 collections::HashMap,
5 env, fmt, fs,
6 ops::Range,
7 panic,
8 path::{Path, PathBuf},
9 sync::Mutex,
10};
11
12use difference::Changeset;
13use once_cell::sync::Lazy;
14use stdx::{lines_with_ends, trim_indent};
15
16const HELP: &str = "
17You can update all `expect![[]]` tests by:
18
19 env UPDATE_EXPECT=1 cargo test
20
21To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
22";
23
24fn update_expect() -> bool {
25 env::var("UPDATE_EXPECT").is_ok()
26}
27
28/// expect![[""]]
29#[macro_export]
30macro_rules! expect {
31 [[$lit:literal]] => {$crate::Expect {
32 file: file!(),
33 line: line!(),
34 column: column!(),
35 data: $lit,
36 }};
37 [[]] => { $crate::expect![[""]] };
38}
39
40#[derive(Debug)]
41pub struct Expect {
42 pub file: &'static str,
43 pub line: u32,
44 pub column: u32,
45 pub data: &'static str,
46}
47
48impl Expect {
49 pub fn assert_eq(&self, actual: &str) {
50 let trimmed = self.trimmed();
51 if &trimmed == actual {
52 return;
53 }
54 Runtime::fail(self, &trimmed, actual);
55 }
56 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
57 let actual = format!("{:#?}\n", actual);
58 self.assert_eq(&actual)
59 }
60
61 fn trimmed(&self) -> String {
62 if !self.data.contains('\n') {
63 return self.data.to_string();
64 }
65 trim_indent(self.data)
66 }
67
68 fn locate(&self, file: &str) -> Location {
69 let mut target_line = None;
70 let mut line_start = 0;
71 for (i, line) in lines_with_ends(file).enumerate() {
72 if i == self.line as usize - 1 {
73 let pat = "expect![[";
74 let offset = line.find(pat).unwrap();
75 let literal_start = line_start + offset + pat.len();
76 let indent = line.chars().take_while(|&it| it == ' ').count();
77 target_line = Some((literal_start, indent));
78 break;
79 }
80 line_start += line.len();
81 }
82 let (literal_start, line_indent) = target_line.unwrap();
83 let literal_length =
84 file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
85 let literal_range = literal_start..literal_start + literal_length;
86 Location { line_indent, literal_range }
87 }
88}
89
90#[derive(Default)]
91struct Runtime {
92 help_printed: bool,
93 per_file: HashMap<&'static str, FileRuntime>,
94}
95static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);
96
97impl Runtime {
98 fn fail(expect: &Expect, expected: &str, actual: &str) {
99 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
100 let mut updated = "";
101 if update_expect() {
102 updated = " (updated)";
103 rt.per_file
104 .entry(expect.file)
105 .or_insert_with(|| FileRuntime::new(expect))
106 .update(expect, actual);
107 }
108 let print_help = !rt.help_printed && !update_expect();
109 rt.help_printed = true;
110
111 let help = if print_help { HELP } else { "" };
112
113 let diff = Changeset::new(actual, expected, "\n");
114
115 println!(
116 "\n
117\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m{}
118 \x1b[1m\x1b[34m-->\x1b[0m {}:{}:{}
119{}
120\x1b[1mExpect\x1b[0m:
121----
122{}
123----
124
125\x1b[1mActual\x1b[0m:
126----
127{}
128----
129
130\x1b[1mDiff\x1b[0m:
131----
132{}
133----
134",
135 updated, expect.file, expect.line, expect.column, help, expected, actual, diff
136 );
137 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
138 panic::resume_unwind(Box::new(()));
139 }
140}
141
142struct FileRuntime {
143 path: PathBuf,
144 original_text: String,
145 patchwork: Patchwork,
146}
147
148impl FileRuntime {
149 fn new(expect: &Expect) -> FileRuntime {
150 let path = workspace_root().join(expect.file);
151 let original_text = fs::read_to_string(&path).unwrap();
152 let patchwork = Patchwork::new(original_text.clone());
153 FileRuntime { path, original_text, patchwork }
154 }
155 fn update(&mut self, expect: &Expect, actual: &str) {
156 let loc = expect.locate(&self.original_text);
157 let patch = format_patch(loc.line_indent.clone(), actual);
158 self.patchwork.patch(loc.literal_range, &patch);
159 fs::write(&self.path, &self.patchwork.text).unwrap()
160 }
161}
162
163#[derive(Debug)]
164struct Location {
165 line_indent: usize,
166 literal_range: Range<usize>,
167}
168
169#[derive(Debug)]
170struct Patchwork {
171 text: String,
172 indels: Vec<(Range<usize>, usize)>,
173}
174
175impl Patchwork {
176 fn new(text: String) -> Patchwork {
177 Patchwork { text, indels: Vec::new() }
178 }
179 fn patch(&mut self, mut range: Range<usize>, patch: &str) {
180 self.indels.push((range.clone(), patch.len()));
181 self.indels.sort_by_key(|(delete, _insert)| delete.start);
182
183 let (delete, insert) = self
184 .indels
185 .iter()
186 .take_while(|(delete, _)| delete.start < range.start)
187 .map(|(delete, insert)| (delete.end - delete.start, insert))
188 .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));
189
190 for pos in &mut [&mut range.start, &mut range.end] {
191 **pos -= delete;
192 **pos += insert;
193 }
194
195 self.text.replace_range(range, &patch);
196 }
197}
198
199fn format_patch(line_indent: usize, patch: &str) -> String {
200 let mut max_hashes = 0;
201 let mut cur_hashes = 0;
202 for byte in patch.bytes() {
203 if byte != b'#' {
204 cur_hashes = 0;
205 continue;
206 }
207 cur_hashes += 1;
208 max_hashes = max_hashes.max(cur_hashes);
209 }
210 let hashes = &"#".repeat(max_hashes + 1);
211 let indent = &" ".repeat(line_indent);
212 let is_multiline = patch.contains('\n');
213
214 let mut buf = String::new();
215 buf.push('r');
216 buf.push_str(hashes);
217 buf.push('"');
218 if is_multiline {
219 buf.push('\n');
220 }
221 let mut final_newline = false;
222 for line in lines_with_ends(patch) {
223 if is_multiline {
224 buf.push_str(indent);
225 buf.push_str(" ");
226 }
227 buf.push_str(line);
228 final_newline = line.ends_with('\n');
229 }
230 if final_newline {
231 buf.push_str(indent);
232 }
233 buf.push('"');
234 buf.push_str(hashes);
235 buf
236}
237
238fn workspace_root() -> PathBuf {
239 Path::new(
240 &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
241 )
242 .ancestors()
243 .nth(2)
244 .unwrap()
245 .to_path_buf()
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_format_patch() {
254 let patch = format_patch(0, "hello\nworld\n");
255 expect![[r##"
256 r#"
257 hello
258 world
259 "#"##]]
260 .assert_eq(&patch);
261
262 let patch = format_patch(4, "single line");
263 expect![[r##"r#"single line"#"##]].assert_eq(&patch);
264 }
265
266 #[test]
267 fn test_patchwork() {
268 let mut patchwork = Patchwork::new("one two three".to_string());
269 patchwork.patch(4..7, "zwei");
270 patchwork.patch(0..3, "один");
271 patchwork.patch(8..13, "3");
272 expect![[r#"
273 Patchwork {
274 text: "один zwei 3",
275 indels: [
276 (
277 0..3,
278 8,
279 ),
280 (
281 4..7,
282 4,
283 ),
284 (
285 8..13,
286 1,
287 ),
288 ],
289 }
290 "#]]
291 .assert_debug_eq(&patchwork);
292 }
293}
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 92ec4f92e..1023d3040 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -5,8 +5,9 @@
5use std::{ 5use std::{
6 fmt, 6 fmt,
7 io::{self, BufReader}, 7 io::{self, BufReader},
8 ops,
8 path::PathBuf, 9 path::PathBuf,
9 process::{Command, Stdio}, 10 process::{self, Command, Stdio},
10 time::Duration, 11 time::Duration,
11}; 12};
12 13
@@ -49,8 +50,8 @@ impl fmt::Display for FlycheckConfig {
49#[derive(Debug)] 50#[derive(Debug)]
50pub struct FlycheckHandle { 51pub struct FlycheckHandle {
51 // XXX: drop order is significant 52 // XXX: drop order is significant
52 cmd_send: Sender<Restart>, 53 sender: Sender<Restart>,
53 handle: jod_thread::JoinHandle, 54 thread: jod_thread::JoinHandle,
54} 55}
55 56
56impl FlycheckHandle { 57impl FlycheckHandle {
@@ -59,16 +60,15 @@ impl FlycheckHandle {
59 config: FlycheckConfig, 60 config: FlycheckConfig,
60 workspace_root: PathBuf, 61 workspace_root: PathBuf,
61 ) -> FlycheckHandle { 62 ) -> FlycheckHandle {
62 let (cmd_send, cmd_recv) = unbounded::<Restart>(); 63 let actor = FlycheckActor::new(sender, config, workspace_root);
63 let handle = jod_thread::spawn(move || { 64 let (sender, receiver) = unbounded::<Restart>();
64 FlycheckActor::new(sender, config, workspace_root).run(cmd_recv); 65 let thread = jod_thread::spawn(move || actor.run(receiver));
65 }); 66 FlycheckHandle { sender, thread }
66 FlycheckHandle { cmd_send, handle }
67 } 67 }
68 68
69 /// Schedule a re-start of the cargo check worker. 69 /// Schedule a re-start of the cargo check worker.
70 pub fn update(&self) { 70 pub fn update(&self) {
71 self.cmd_send.send(Restart).unwrap(); 71 self.sender.send(Restart).unwrap();
72 } 72 }
73} 73}
74 74
@@ -85,7 +85,7 @@ pub enum Message {
85pub enum Progress { 85pub enum Progress {
86 DidStart, 86 DidStart,
87 DidCheckCrate(String), 87 DidCheckCrate(String),
88 DidFinish, 88 DidFinish(io::Result<()>),
89 DidCancel, 89 DidCancel,
90} 90}
91 91
@@ -100,8 +100,7 @@ struct FlycheckActor {
100 /// doesn't provide a way to read sub-process output without blocking, so we 100 /// doesn't provide a way to read sub-process output without blocking, so we
101 /// have to wrap sub-processes output handling in a thread and pass messages 101 /// have to wrap sub-processes output handling in a thread and pass messages
102 /// back over a channel. 102 /// back over a channel.
103 // XXX: drop order is significant 103 cargo_handle: Option<CargoHandle>,
104 check_process: Option<(Receiver<cargo_metadata::Message>, jod_thread::JoinHandle)>,
105} 104}
106 105
107enum Event { 106enum Event {
@@ -115,29 +114,36 @@ impl FlycheckActor {
115 config: FlycheckConfig, 114 config: FlycheckConfig,
116 workspace_root: PathBuf, 115 workspace_root: PathBuf,
117 ) -> FlycheckActor { 116 ) -> FlycheckActor {
118 FlycheckActor { sender, config, workspace_root, check_process: None } 117 FlycheckActor { sender, config, workspace_root, cargo_handle: None }
119 } 118 }
120 fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> { 119 fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
121 let check_chan = self.check_process.as_ref().map(|(chan, _thread)| chan); 120 let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
122 select! { 121 select! {
123 recv(inbox) -> msg => msg.ok().map(Event::Restart), 122 recv(inbox) -> msg => msg.ok().map(Event::Restart),
124 recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())), 123 recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
125 } 124 }
126 } 125 }
127 fn run(&mut self, inbox: Receiver<Restart>) { 126 fn run(mut self, inbox: Receiver<Restart>) {
128 while let Some(event) = self.next_event(&inbox) { 127 while let Some(event) = self.next_event(&inbox) {
129 match event { 128 match event {
130 Event::Restart(Restart) => { 129 Event::Restart(Restart) => {
131 while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} 130 while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {}
131
132 self.cancel_check_process(); 132 self.cancel_check_process();
133 self.check_process = Some(self.start_check_process()); 133
134 self.send(Message::Progress(Progress::DidStart)); 134 let mut command = self.check_command();
135 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
136 if let Ok(child) = command.spawn().map(JodChild) {
137 self.cargo_handle = Some(CargoHandle::spawn(child));
138 self.send(Message::Progress(Progress::DidStart));
139 }
135 } 140 }
136 Event::CheckEvent(None) => { 141 Event::CheckEvent(None) => {
137 // Watcher finished, replace it with a never channel to 142 // Watcher finished, replace it with a never channel to
138 // avoid busy-waiting. 143 // avoid busy-waiting.
139 assert!(self.check_process.take().is_some()); 144 let cargo_handle = self.cargo_handle.take().unwrap();
140 self.send(Message::Progress(Progress::DidFinish)); 145 let res = cargo_handle.join();
146 self.send(Message::Progress(Progress::DidFinish(res)));
141 } 147 }
142 Event::CheckEvent(Some(message)) => match message { 148 Event::CheckEvent(Some(message)) => match message {
143 cargo_metadata::Message::CompilerArtifact(msg) => { 149 cargo_metadata::Message::CompilerArtifact(msg) => {
@@ -162,11 +168,11 @@ impl FlycheckActor {
162 self.cancel_check_process(); 168 self.cancel_check_process();
163 } 169 }
164 fn cancel_check_process(&mut self) { 170 fn cancel_check_process(&mut self) {
165 if self.check_process.take().is_some() { 171 if self.cargo_handle.take().is_some() {
166 self.send(Message::Progress(Progress::DidCancel)); 172 self.send(Message::Progress(Progress::DidCancel));
167 } 173 }
168 } 174 }
169 fn start_check_process(&self) -> (Receiver<cargo_metadata::Message>, jod_thread::JoinHandle) { 175 fn check_command(&self) -> Command {
170 let mut cmd = match &self.config { 176 let mut cmd = match &self.config {
171 FlycheckConfig::CargoCommand { 177 FlycheckConfig::CargoCommand {
172 command, 178 command,
@@ -198,33 +204,7 @@ impl FlycheckActor {
198 } 204 }
199 }; 205 };
200 cmd.current_dir(&self.workspace_root); 206 cmd.current_dir(&self.workspace_root);
201 207 cmd
202 let (message_send, message_recv) = unbounded();
203 let thread = jod_thread::spawn(move || {
204 // If we trigger an error here, we will do so in the loop instead,
205 // which will break out of the loop, and continue the shutdown
206 let res = run_cargo(cmd, &mut |message| {
207 // Skip certain kinds of messages to only spend time on what's useful
208 match &message {
209 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
210 return true
211 }
212 cargo_metadata::Message::BuildScriptExecuted(_)
213 | cargo_metadata::Message::Unknown => return true,
214 _ => {}
215 }
216
217 // if the send channel was closed, we want to shutdown
218 message_send.send(message).is_ok()
219 });
220
221 if let Err(err) = res {
222 // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
223 // to display user-caused misconfiguration errors instead of just logging them here
224 log::error!("Cargo watcher failed {:?}", err);
225 }
226 });
227 (message_recv, thread)
228 } 208 }
229 209
230 fn send(&self, check_task: Message) { 210 fn send(&self, check_task: Message) {
@@ -232,54 +212,104 @@ impl FlycheckActor {
232 } 212 }
233} 213}
234 214
235fn run_cargo( 215struct CargoHandle {
236 mut command: Command, 216 child: JodChild,
237 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, 217 #[allow(unused)]
238) -> io::Result<()> { 218 thread: jod_thread::JoinHandle<io::Result<bool>>,
239 let mut child = 219 receiver: Receiver<cargo_metadata::Message>,
240 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?; 220}
241 221
242 // We manually read a line at a time, instead of using serde's 222impl CargoHandle {
243 // stream deserializers, because the deserializer cannot recover 223 fn spawn(mut child: JodChild) -> CargoHandle {
244 // from an error, resulting in it getting stuck, because we try to 224 let child_stdout = child.stdout.take().unwrap();
245 // be resillient against failures. 225 let (sender, receiver) = unbounded();
246 // 226 let actor = CargoActor::new(child_stdout, sender);
247 // Because cargo only outputs one JSON object per line, we can 227 let thread = jod_thread::spawn(move || actor.run());
248 // simply skip a line if it doesn't parse, which just ignores any 228 CargoHandle { child, thread, receiver }
249 // erroneus output. 229 }
250 let stdout = BufReader::new(child.stdout.take().unwrap()); 230 fn join(mut self) -> io::Result<()> {
251 let mut read_at_least_one_message = false; 231 // It is okay to ignore the result, as it only errors if the process is already dead
252 for message in cargo_metadata::Message::parse_stream(stdout) { 232 let _ = self.child.kill();
253 let message = match message { 233 let exit_status = self.child.wait()?;
254 Ok(message) => message, 234 let read_at_least_one_message = self.thread.join()?;
255 Err(err) => { 235 if !exit_status.success() && !read_at_least_one_message {
256 log::error!("Invalid json from cargo check, ignoring ({})", err); 236 // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
257 continue; 237 // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
258 } 238 return Err(io::Error::new(
259 }; 239 io::ErrorKind::Other,
240 format!(
241 "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})",
242 exit_status
243 ),
244 ));
245 }
246 Ok(())
247 }
248}
249
250struct CargoActor {
251 child_stdout: process::ChildStdout,
252 sender: Sender<cargo_metadata::Message>,
253}
254
255impl CargoActor {
256 fn new(
257 child_stdout: process::ChildStdout,
258 sender: Sender<cargo_metadata::Message>,
259 ) -> CargoActor {
260 CargoActor { child_stdout, sender }
261 }
262 fn run(self) -> io::Result<bool> {
263 // We manually read a line at a time, instead of using serde's
264 // stream deserializers, because the deserializer cannot recover
265 // from an error, resulting in it getting stuck, because we try to
266 // be resilient against failures.
267 //
268 // Because cargo only outputs one JSON object per line, we can
269 // simply skip a line if it doesn't parse, which just ignores any
270 // erroneus output.
271 let stdout = BufReader::new(self.child_stdout);
272 let mut read_at_least_one_message = false;
273 for message in cargo_metadata::Message::parse_stream(stdout) {
274 let message = match message {
275 Ok(message) => message,
276 Err(err) => {
277 log::error!("Invalid json from cargo check, ignoring ({})", err);
278 continue;
279 }
280 };
260 281
261 read_at_least_one_message = true; 282 read_at_least_one_message = true;
262 283
263 if !on_message(message) { 284 // Skip certain kinds of messages to only spend time on what's useful
264 break; 285 match &message {
286 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (),
287 cargo_metadata::Message::BuildScriptExecuted(_)
288 | cargo_metadata::Message::Unknown => (),
289 _ => self.sender.send(message).unwrap(),
290 }
265 } 291 }
292 Ok(read_at_least_one_message)
266 } 293 }
294}
267 295
268 // It is okay to ignore the result, as it only errors if the process is already dead 296struct JodChild(process::Child);
269 let _ = child.kill();
270 297
271 let exit_status = child.wait()?; 298impl ops::Deref for JodChild {
272 if !exit_status.success() && !read_at_least_one_message { 299 type Target = process::Child;
273 // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: 300 fn deref(&self) -> &process::Child {
274 // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 301 &self.0
275 return Err(io::Error::new(
276 io::ErrorKind::Other,
277 format!(
278 "the command produced no valid metadata (exit code: {:?}): {:?}",
279 exit_status, command
280 ),
281 ));
282 } 302 }
303}
283 304
284 Ok(()) 305impl ops::DerefMut for JodChild {
306 fn deref_mut(&mut self) -> &mut process::Child {
307 &mut self.0
308 }
309}
310
311impl Drop for JodChild {
312 fn drop(&mut self) {
313 let _ = self.0.kill();
314 }
285} 315}
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index ee614de72..3640bb4d2 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -55,7 +55,6 @@ use crate::{
55pub(crate) struct AssistContext<'a> { 55pub(crate) struct AssistContext<'a> {
56 pub(crate) config: &'a AssistConfig, 56 pub(crate) config: &'a AssistConfig,
57 pub(crate) sema: Semantics<'a, RootDatabase>, 57 pub(crate) sema: Semantics<'a, RootDatabase>,
58 pub(crate) db: &'a RootDatabase,
59 pub(crate) frange: FileRange, 58 pub(crate) frange: FileRange,
60 source_file: SourceFile, 59 source_file: SourceFile,
61} 60}
@@ -67,8 +66,11 @@ impl<'a> AssistContext<'a> {
67 frange: FileRange, 66 frange: FileRange,
68 ) -> AssistContext<'a> { 67 ) -> AssistContext<'a> {
69 let source_file = sema.parse(frange.file_id); 68 let source_file = sema.parse(frange.file_id);
70 let db = sema.db; 69 AssistContext { config, sema, frange, source_file }
71 AssistContext { config, sema, db, frange, source_file } 70 }
71
72 pub(crate) fn db(&self) -> &RootDatabase {
73 self.sema.db
72 } 74 }
73 75
74 // NB, this ignores active selection. 76 // NB, this ignores active selection.
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index 00fa95b6c..01adb834c 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -2,7 +2,6 @@
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use hir::{HirDisplay, PathResolution, SemanticsScope}; 4use hir::{HirDisplay, PathResolution, SemanticsScope};
5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 5use ra_syntax::{
7 algo::SyntaxRewriter, 6 algo::SyntaxRewriter,
8 ast::{self, AstNode}, 7 ast::{self, AstNode},
@@ -32,14 +31,14 @@ impl<'a> AstTransform<'a> for NullTransformer {
32} 31}
33 32
34pub struct SubstituteTypeParams<'a> { 33pub struct SubstituteTypeParams<'a> {
35 source_scope: &'a SemanticsScope<'a, RootDatabase>, 34 source_scope: &'a SemanticsScope<'a>,
36 substs: FxHashMap<hir::TypeParam, ast::TypeRef>, 35 substs: FxHashMap<hir::TypeParam, ast::TypeRef>,
37 previous: Box<dyn AstTransform<'a> + 'a>, 36 previous: Box<dyn AstTransform<'a> + 'a>,
38} 37}
39 38
40impl<'a> SubstituteTypeParams<'a> { 39impl<'a> SubstituteTypeParams<'a> {
41 pub fn for_trait_impl( 40 pub fn for_trait_impl(
42 source_scope: &'a SemanticsScope<'a, RootDatabase>, 41 source_scope: &'a SemanticsScope<'a>,
43 // FIXME: there's implicit invariant that `trait_` and `source_scope` match... 42 // FIXME: there's implicit invariant that `trait_` and `source_scope` match...
44 trait_: hir::Trait, 43 trait_: hir::Trait,
45 impl_def: ast::ImplDef, 44 impl_def: ast::ImplDef,
@@ -126,16 +125,13 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
126} 125}
127 126
128pub struct QualifyPaths<'a> { 127pub struct QualifyPaths<'a> {
129 target_scope: &'a SemanticsScope<'a, RootDatabase>, 128 target_scope: &'a SemanticsScope<'a>,
130 source_scope: &'a SemanticsScope<'a, RootDatabase>, 129 source_scope: &'a SemanticsScope<'a>,
131 previous: Box<dyn AstTransform<'a> + 'a>, 130 previous: Box<dyn AstTransform<'a> + 'a>,
132} 131}
133 132
134impl<'a> QualifyPaths<'a> { 133impl<'a> QualifyPaths<'a> {
135 pub fn new( 134 pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
136 target_scope: &'a SemanticsScope<'a, RootDatabase>,
137 source_scope: &'a SemanticsScope<'a, RootDatabase>,
138 ) -> Self {
139 Self { target_scope, source_scope, previous: Box::new(NullTransformer) } 135 Self { target_scope, source_scope, previous: Box::new(NullTransformer) }
140 } 136 }
141 137
@@ -156,7 +152,7 @@ impl<'a> QualifyPaths<'a> {
156 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; 152 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?;
157 match resolution { 153 match resolution {
158 PathResolution::Def(def) => { 154 PathResolution::Def(def) => {
159 let found_path = from.find_use_path(self.source_scope.db, def)?; 155 let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
160 let mut path = path_to_ast(found_path); 156 let mut path = path_to_ast(found_path);
161 157
162 let type_args = p 158 let type_args = p
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 90b06a625..11df922a2 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -57,7 +57,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
57 return None; 57 return None;
58 } 58 }
59 59
60 let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?; 60 let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
61 acc.add( 61 acc.add(
62 AssistId("add_explicit_type"), 62 AssistId("add_explicit_type"),
63 format!("Insert explicit type `{}`", inferred_type), 63 format!("Insert explicit type `{}`", inferred_type),
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 1cfbd75aa..fc4e82309 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -117,7 +117,7 @@ impl FunctionBuilder {
117 let mut file = ctx.frange.file_id; 117 let mut file = ctx.frange.file_id;
118 let target = match &target_module { 118 let target = match &target_module {
119 Some(target_module) => { 119 Some(target_module) => {
120 let module_source = target_module.definition_source(ctx.db); 120 let module_source = target_module.definition_source(ctx.db());
121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?; 121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
122 file = in_file; 122 file = in_file;
123 target 123 target
@@ -269,7 +269,7 @@ fn fn_arg_type(
269 return None; 269 return None;
270 } 270 }
271 271
272 if let Ok(rendered) = ty.display_source_code(ctx.db, target_module.into()) { 272 if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) {
273 Some(rendered) 273 Some(rendered)
274 } else { 274 } else {
275 None 275 None
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index abacd4065..77e092f62 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -128,9 +128,9 @@ fn add_missing_impl_members_inner(
128 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) 128 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def)
129 .iter() 129 .iter()
130 .map(|i| match i { 130 .map(|i| match i {
131 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), 131 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db()).value),
132 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db).value), 132 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db()).value),
133 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db).value), 133 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db()).value),
134 }) 134 })
135 .filter(|t| def_name(&t).is_some()) 135 .filter(|t| def_name(&t).is_some())
136 .filter(|t| match t { 136 .filter(|t| match t {
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 837aa8377..e41b2aa06 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -122,7 +122,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
122// FIXME: change the new fn checking to a more semantic approach when that's more 122// FIXME: change the new fn checking to a more semantic approach when that's more
123// viable (e.g. we process proc macros, etc) 123// viable (e.g. we process proc macros, etc)
124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { 124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> {
125 let db = ctx.db; 125 let db = ctx.db();
126 let module = strukt.syntax().ancestors().find(|node| { 126 let module = strukt.syntax().ancestors().find(|node| {
127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
128 })?; 128 })?;
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index d1cafa7d9..e8060a491 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -36,7 +36,7 @@ use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, Group
36// ``` 36// ```
37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let auto_import_assets = AutoImportAssets::new(&ctx)?; 38 let auto_import_assets = AutoImportAssets::new(&ctx)?;
39 let proposed_imports = auto_import_assets.search_for_imports(ctx.db); 39 let proposed_imports = auto_import_assets.search_for_imports(ctx.db());
40 if proposed_imports.is_empty() { 40 if proposed_imports.is_empty() {
41 return None; 41 return None;
42 } 42 }
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index c21d75be0..157c7b665 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -1,15 +1,12 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{ 4 SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY},
5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, 5 T,
6 WHITESPACE,
7 },
8 SyntaxNode, TextSize, T,
9}; 6};
10use test_utils::mark; 7use test_utils::mark;
11 8
12use crate::{AssistContext, AssistId, Assists}; 9use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
13 10
14// Assist: change_visibility 11// Assist: change_visibility
15// 12//
@@ -30,9 +27,8 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
30} 27}
31 28
32fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { 30 let item_keyword = ctx.token_at_offset().find(|leaf| {
34 T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, 31 matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait])
35 _ => false,
36 }); 32 });
37 33
38 let (offset, target) = if let Some(keyword) = item_keyword { 34 let (offset, target) = if let Some(keyword) = item_keyword {
@@ -71,17 +67,6 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
71 }) 67 })
72} 68}
73 69
74fn vis_offset(node: &SyntaxNode) -> TextSize {
75 node.children_with_tokens()
76 .skip_while(|it| match it.kind() {
77 WHITESPACE | COMMENT | ATTR => true,
78 _ => false,
79 })
80 .next()
81 .map(|it| it.text_range().start())
82 .unwrap_or_else(|| node.text_range().start())
83}
84
85fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { 70fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
86 if vis.syntax().text() == "pub" { 71 if vis.syntax().text() == "pub" {
87 let target = vis.syntax().text_range(); 72 let target = vis.syntax().text_range();
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
index 43b4584b4..bdf9d7ae2 100644
--- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -37,15 +37,15 @@ pub(crate) fn extract_struct_from_enum_variant(
37 }; 37 };
38 let variant_name = variant.name()?.to_string(); 38 let variant_name = variant.name()?.to_string();
39 let variant_hir = ctx.sema.to_def(&variant)?; 39 let variant_hir = ctx.sema.to_def(&variant)?;
40 if existing_struct_def(ctx.db, &variant_name, &variant_hir) { 40 if existing_struct_def(ctx.db(), &variant_name, &variant_hir) {
41 return None; 41 return None;
42 } 42 }
43 let enum_ast = variant.parent_enum(); 43 let enum_ast = variant.parent_enum();
44 let visibility = enum_ast.visibility(); 44 let visibility = enum_ast.visibility();
45 let enum_hir = ctx.sema.to_def(&enum_ast)?; 45 let enum_hir = ctx.sema.to_def(&enum_ast)?;
46 let variant_hir_name = variant_hir.name(ctx.db); 46 let variant_hir_name = variant_hir.name(ctx.db());
47 let enum_module_def = ModuleDef::from(enum_hir); 47 let enum_module_def = ModuleDef::from(enum_hir);
48 let current_module = enum_hir.module(ctx.db); 48 let current_module = enum_hir.module(ctx.db());
49 let target = variant.syntax().text_range(); 49 let target = variant.syntax().text_range();
50 acc.add( 50 acc.add(
51 AssistId("extract_struct_from_enum_variant"), 51 AssistId("extract_struct_from_enum_variant"),
@@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
53 target, 53 target,
54 |builder| { 54 |builder| {
55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); 55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
56 let res = definition.find_usages(&ctx.db, None); 56 let res = definition.find_usages(&ctx.db(), None);
57 let start_offset = variant.parent_enum().syntax().text_range().start(); 57 let start_offset = variant.parent_enum().syntax().text_range().start();
58 let mut visited_modules_set = FxHashSet::default(); 58 let mut visited_modules_set = FxHashSet::default();
59 visited_modules_set.insert(current_module); 59 visited_modules_set.insert(current_module);
@@ -101,7 +101,7 @@ fn insert_import(
101 enum_module_def: &ModuleDef, 101 enum_module_def: &ModuleDef,
102 variant_hir_name: &Name, 102 variant_hir_name: &Name,
103) -> Option<()> { 103) -> Option<()> {
104 let db = ctx.db; 104 let db = ctx.db();
105 let mod_path = module.find_use_path(db, enum_module_def.clone()); 105 let mod_path = module.find_use_path(db, enum_module_def.clone());
106 if let Some(mut mod_path) = mod_path { 106 if let Some(mut mod_path) = mod_path {
107 mod_path.segments.pop(); 107 mod_path.segments.pop();
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 64270c86f..5b1235682 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -51,11 +51,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
51 let module = ctx.sema.scope(expr.syntax()).module()?; 51 let module = ctx.sema.scope(expr.syntax()).module()?;
52 52
53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { 53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
54 let variants = enum_def.variants(ctx.db); 54 let variants = enum_def.variants(ctx.db());
55 55
56 let mut variants = variants 56 let mut variants = variants
57 .into_iter() 57 .into_iter()
58 .filter_map(|variant| build_pat(ctx.db, module, variant)) 58 .filter_map(|variant| build_pat(ctx.db(), module, variant))
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
@@ -84,11 +84,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
84 // where each tuple represents a proposed match arm. 84 // where each tuple represents a proposed match arm.
85 enum_defs 85 enum_defs
86 .into_iter() 86 .into_iter()
87 .map(|enum_def| enum_def.variants(ctx.db)) 87 .map(|enum_def| enum_def.variants(ctx.db()))
88 .multi_cartesian_product() 88 .multi_cartesian_product()
89 .map(|variants| { 89 .map(|variants| {
90 let patterns = 90 let patterns =
91 variants.into_iter().filter_map(|variant| build_pat(ctx.db, module, variant)); 91 variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
92 ast::Pat::from(make::tuple_pat(patterns)) 92 ast::Pat::from(make::tuple_pat(patterns))
93 }) 93 })
94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 54601d1f3..c0f57c329 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -1,12 +1,8 @@
1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ra_db::FileId; 2use ra_db::FileId;
3use ra_syntax::{ 3use ra_syntax::{ast, AstNode, TextRange, TextSize};
4 ast, AstNode,
5 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
6 SyntaxNode, TextRange, TextSize,
7};
8 4
9use crate::{AssistContext, AssistId, Assists}; 5use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
10 6
11// FIXME: this really should be a fix for diagnostic, rather than an assist. 7// FIXME: this really should be a fix for diagnostic, rather than an assist.
12 8
@@ -45,14 +41,14 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
45 }; 41 };
46 42
47 let current_module = ctx.sema.scope(&path.syntax()).module()?; 43 let current_module = ctx.sema.scope(&path.syntax()).module()?;
48 let target_module = def.module(ctx.db)?; 44 let target_module = def.module(ctx.db())?;
49 45
50 let vis = target_module.visibility_of(ctx.db, &def)?; 46 let vis = target_module.visibility_of(ctx.db(), &def)?;
51 if vis.is_visible_from(ctx.db, current_module.into()) { 47 if vis.is_visible_from(ctx.db(), current_module.into()) {
52 return None; 48 return None;
53 }; 49 };
54 50
55 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?; 51 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?;
56 52
57 let missing_visibility = 53 let missing_visibility =
58 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 54 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
@@ -76,16 +72,16 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
76 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; 72 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?;
77 73
78 let current_module = ctx.sema.scope(record_field.syntax()).module()?; 74 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
79 let visibility = record_field_def.visibility(ctx.db); 75 let visibility = record_field_def.visibility(ctx.db());
80 if visibility.is_visible_from(ctx.db, current_module.into()) { 76 if visibility.is_visible_from(ctx.db(), current_module.into()) {
81 return None; 77 return None;
82 } 78 }
83 79
84 let parent = record_field_def.parent_def(ctx.db); 80 let parent = record_field_def.parent_def(ctx.db());
85 let parent_name = parent.name(ctx.db); 81 let parent_name = parent.name(ctx.db());
86 let target_module = parent.module(ctx.db); 82 let target_module = parent.module(ctx.db());
87 83
88 let in_file_source = record_field_def.source(ctx.db); 84 let in_file_source = record_field_def.source(ctx.db());
89 let (offset, target) = match in_file_source.value { 85 let (offset, target) = match in_file_source.value {
90 hir::FieldSource::Named(it) => { 86 hir::FieldSource::Named(it) => {
91 let s = it.syntax(); 87 let s = it.syntax();
@@ -99,9 +95,9 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
99 95
100 let missing_visibility = 96 let missing_visibility =
101 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 97 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
102 let target_file = in_file_source.file_id.original_file(ctx.db); 98 let target_file = in_file_source.file_id.original_file(ctx.db());
103 99
104 let target_name = record_field_def.name(ctx.db); 100 let target_name = record_field_def.name(ctx.db());
105 let assist_label = 101 let assist_label =
106 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); 102 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
107 103
@@ -177,17 +173,6 @@ fn target_data_for_def(
177 Some((offset, target, target_file, target_name)) 173 Some((offset, target, target_file, target_name))
178} 174}
179 175
180fn vis_offset(node: &SyntaxNode) -> TextSize {
181 node.children_with_tokens()
182 .skip_while(|it| match it.kind() {
183 WHITESPACE | COMMENT | ATTR => true,
184 _ => false,
185 })
186 .next()
187 .map(|it| it.text_range().start())
188 .unwrap_or_else(|| node.text_range().start())
189}
190
191#[cfg(test)] 176#[cfg(test)]
192mod tests { 177mod tests {
193 use crate::tests::{check_assist, check_assist_not_applicable}; 178 use crate::tests::{check_assist, check_assist_not_applicable};
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index d26e68847..f4fb0056b 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
44 44
45 let def = ctx.sema.to_def(&bind_pat)?; 45 let def = ctx.sema.to_def(&bind_pat)?;
46 let def = Definition::Local(def); 46 let def = Definition::Local(def);
47 let refs = def.find_usages(ctx.db, None); 47 let refs = def.find_usages(ctx.db(), None);
48 if refs.is_empty() { 48 if refs.is_empty() {
49 mark::hit!(test_not_applicable_if_variable_unused); 49 mark::hit!(test_not_applicable_if_variable_unused);
50 return None; 50 return None;
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index ca04ec671..90ce66378 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -81,10 +81,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
81} 81}
82 82
83fn contains_placeholder(a: &ast::MatchArm) -> bool { 83fn contains_placeholder(a: &ast::MatchArm) -> bool {
84 match a.pat() { 84 matches!(a.pat(), Some(ast::Pat::PlaceholderPat(..)))
85 Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
86 _ => false,
87 }
88} 85}
89 86
90#[cfg(test)] 87#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index 897da2832..b8cf30e7f 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -1,7 +1,7 @@
1use std::collections::HashMap; 1use itertools::Itertools;
2use rustc_hash::FxHashMap;
2 3
3use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; 4use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; 6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
7 7
@@ -87,13 +87,13 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option
87 } 87 }
88} 88}
89 89
90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> { 90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
91 Some( 91 Some(
92 struct_definition(path, &ctx.sema)? 92 struct_definition(path, &ctx.sema)?
93 .fields(ctx.db) 93 .fields(ctx.db())
94 .iter() 94 .iter()
95 .enumerate() 95 .enumerate()
96 .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) 96 .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx))
97 .collect(), 97 .collect(),
98 ) 98 )
99} 99}
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index b7c45a619..02de902d6 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -7,7 +7,9 @@ use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type};
7use ra_ide_db::RootDatabase; 7use ra_ide_db::RootDatabase;
8use ra_syntax::{ 8use ra_syntax::{
9 ast::{self, make, NameOwner}, 9 ast::{self, make, NameOwner},
10 AstNode, SyntaxNode, T, 10 AstNode,
11 SyntaxKind::*,
12 SyntaxNode, TextSize, T,
11}; 13};
12use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
13 15
@@ -120,6 +122,13 @@ pub(crate) fn resolve_target_trait(
120 } 122 }
121} 123}
122 124
125pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
126 node.children_with_tokens()
127 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
128 .map(|it| it.text_range().start())
129 .unwrap_or_else(|| node.text_range().start())
130}
131
123pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { 132pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
124 if let Some(expr) = invert_special_case(&expr) { 133 if let Some(expr) = invert_special_case(&expr) {
125 return expr; 134 return expr;
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 4f4fb4494..209713987 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -149,15 +149,17 @@ fn with_files(
149 let crate_id = crate_graph.add_crate_root( 149 let crate_id = crate_graph.add_crate_root(
150 file_id, 150 file_id,
151 meta.edition, 151 meta.edition,
152 Some(CrateName::new(&krate).unwrap()), 152 Some(krate.clone()),
153 meta.cfg, 153 meta.cfg,
154 meta.env, 154 meta.env,
155 Default::default(), 155 Default::default(),
156 ); 156 );
157 let prev = crates.insert(krate.clone(), crate_id); 157 let crate_name = CrateName::new(&krate).unwrap();
158 let prev = crates.insert(crate_name.clone(), crate_id);
158 assert!(prev.is_none()); 159 assert!(prev.is_none());
159 for dep in meta.deps { 160 for dep in meta.deps {
160 crate_deps.push((krate.clone(), dep)) 161 let dep = CrateName::new(&dep).unwrap();
162 crate_deps.push((crate_name.clone(), dep))
161 } 163 }
162 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { 164 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
163 assert!(default_crate_root.is_none()); 165 assert!(default_crate_root.is_none());
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 7f3660118..445a1ee48 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -67,7 +67,7 @@ pub struct CrateGraph {
67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
68pub struct CrateId(pub u32); 68pub struct CrateId(pub u32);
69 69
70#[derive(Debug, Clone, PartialEq, Eq)] 70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub struct CrateName(SmolStr); 71pub struct CrateName(SmolStr);
72 72
73impl CrateName { 73impl CrateName {
@@ -94,6 +94,13 @@ impl fmt::Display for CrateName {
94 } 94 }
95} 95}
96 96
97impl ops::Deref for CrateName {
98 type Target = str;
99 fn deref(&self) -> &Self::Target {
100 &*self.0
101 }
102}
103
97#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 104#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
98pub struct ProcMacroId(pub u32); 105pub struct ProcMacroId(pub u32);
99 106
@@ -117,7 +124,7 @@ pub struct CrateData {
117 /// The name to display to the end user. 124 /// The name to display to the end user.
118 /// This actual crate name can be different in a particular dependent crate 125 /// This actual crate name can be different in a particular dependent crate
119 /// or may even be missing for some cases, such as a dummy crate for the code snippet. 126 /// or may even be missing for some cases, such as a dummy crate for the code snippet.
120 pub display_name: Option<CrateName>, 127 pub display_name: Option<String>,
121 pub cfg_options: CfgOptions, 128 pub cfg_options: CfgOptions,
122 pub env: Env, 129 pub env: Env,
123 pub dependencies: Vec<Dependency>, 130 pub dependencies: Vec<Dependency>,
@@ -138,7 +145,7 @@ pub struct Env {
138#[derive(Debug, Clone, PartialEq, Eq)] 145#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Dependency { 146pub struct Dependency {
140 pub crate_id: CrateId, 147 pub crate_id: CrateId,
141 pub name: SmolStr, 148 pub name: CrateName,
142} 149}
143 150
144impl CrateGraph { 151impl CrateGraph {
@@ -146,7 +153,7 @@ impl CrateGraph {
146 &mut self, 153 &mut self,
147 file_id: FileId, 154 file_id: FileId,
148 edition: Edition, 155 edition: Edition,
149 display_name: Option<CrateName>, 156 display_name: Option<String>,
150 cfg_options: CfgOptions, 157 cfg_options: CfgOptions,
151 env: Env, 158 env: Env,
152 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, 159 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
@@ -178,7 +185,7 @@ impl CrateGraph {
178 if self.dfs_find(from, to, &mut FxHashSet::default()) { 185 if self.dfs_find(from, to, &mut FxHashSet::default()) {
179 return Err(CyclicDependenciesError); 186 return Err(CyclicDependenciesError);
180 } 187 }
181 self.arena.get_mut(&from).unwrap().add_dep(name.0, to); 188 self.arena.get_mut(&from).unwrap().add_dep(name, to);
182 Ok(()) 189 Ok(())
183 } 190 }
184 191
@@ -247,7 +254,7 @@ impl CrateId {
247} 254}
248 255
249impl CrateData { 256impl CrateData {
250 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 257 fn add_dep(&mut self, name: CrateName, crate_id: CrateId) {
251 self.dependencies.push(Dependency { name, crate_id }) 258 self.dependencies.push(Dependency { name, crate_id })
252 } 259 }
253} 260}
@@ -429,7 +436,10 @@ mod tests {
429 .is_ok()); 436 .is_ok());
430 assert_eq!( 437 assert_eq!(
431 graph[crate1].dependencies, 438 graph[crate1].dependencies,
432 vec![Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }] 439 vec![Dependency {
440 crate_id: crate2,
441 name: CrateName::new("crate_name_with_dashes").unwrap()
442 }]
433 ); 443 );
434 } 444 }
435} 445}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 4a3ba57da..1ddacc1f6 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -80,7 +80,7 @@ pub struct FilePosition {
80 pub offset: TextSize, 80 pub offset: TextSize,
81} 81}
82 82
83#[derive(Clone, Copy, Debug)] 83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub struct FileRange { 84pub struct FileRange {
85 pub file_id: FileId, 85 pub file_id: FileId,
86 pub range: TextRange, 86 pub range: TextRange,
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 27e94b7fe..e09eb77c2 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -31,7 +31,7 @@ use hir_ty::{
31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty, 31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
32 TyDefId, TypeCtor, 32 TyDefId, TypeCtor,
33}; 33};
34use ra_db::{CrateId, CrateName, Edition, FileId}; 34use ra_db::{CrateId, Edition, FileId};
35use ra_prof::profile; 35use ra_prof::profile;
36use ra_syntax::ast::{self, AttrsOwner, NameOwner}; 36use ra_syntax::ast::{self, AttrsOwner, NameOwner};
37use rustc_hash::FxHashSet; 37use rustc_hash::FxHashSet;
@@ -94,8 +94,8 @@ impl Crate {
94 db.crate_graph()[self.id].edition 94 db.crate_graph()[self.id].edition
95 } 95 }
96 96
97 pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateName> { 97 pub fn display_name(self, db: &dyn HirDatabase) -> Option<String> {
98 db.crate_graph()[self.id].display_name.as_ref().cloned() 98 db.crate_graph()[self.id].display_name.clone()
99 } 99 }
100 100
101 pub fn query_external_importables( 101 pub fn query_external_importables(
@@ -543,7 +543,7 @@ impl_froms!(Adt: Struct, Union, Enum);
543impl Adt { 543impl Adt {
544 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { 544 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
545 let subst = db.generic_defaults(self.into()); 545 let subst = db.generic_defaults(self.into());
546 subst.iter().any(|ty| ty == &Ty::Unknown) 546 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
547 } 547 }
548 548
549 /// Turns this ADT into a type. Any type parameters of the ADT will be 549 /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -775,7 +775,7 @@ pub struct TypeAlias {
775impl TypeAlias { 775impl TypeAlias {
776 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { 776 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
777 let subst = db.generic_defaults(self.id.into()); 777 let subst = db.generic_defaults(self.id.into());
778 subst.iter().any(|ty| ty == &Ty::Unknown) 778 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
779 } 779 }
780 780
781 pub fn module(self, db: &dyn HirDatabase) -> Module { 781 pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -1035,7 +1035,10 @@ impl TypeParam {
1035 let local_idx = hir_ty::param_idx(db, self.id)?; 1035 let local_idx = hir_ty::param_idx(db, self.id)?;
1036 let resolver = self.id.parent.resolver(db.upcast()); 1036 let resolver = self.id.parent.resolver(db.upcast());
1037 let environment = TraitEnvironment::lower(db, &resolver); 1037 let environment = TraitEnvironment::lower(db, &resolver);
1038 params.get(local_idx).cloned().map(|ty| Type { 1038 let ty = params.get(local_idx)?.clone();
1039 let subst = Substs::type_params(db, self.id.parent);
1040 let ty = ty.subst(&subst.prefix(local_idx));
1041 Some(Type {
1039 krate: self.id.parent.module(db.upcast()).krate, 1042 krate: self.id.parent.module(db.upcast()).krate,
1040 ty: InEnvironment { value: ty, environment }, 1043 ty: InEnvironment { value: ty, environment },
1041 }) 1044 })
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 6a49c424a..810c49d6f 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -297,19 +297,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
297 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) 297 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
298 } 298 }
299 299
300 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db, DB> { 300 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
301 let node = self.find_file(node.clone()); 301 let node = self.find_file(node.clone());
302 let resolver = self.analyze2(node.as_ref(), None).resolver; 302 let resolver = self.analyze2(node.as_ref(), None).resolver;
303 SemanticsScope { db: self.db, resolver } 303 SemanticsScope { db: self.db, resolver }
304 } 304 }
305 305
306 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db, DB> { 306 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
307 let node = self.find_file(node.clone()); 307 let node = self.find_file(node.clone());
308 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; 308 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
309 SemanticsScope { db: self.db, resolver } 309 SemanticsScope { db: self.db, resolver }
310 } 310 }
311 311
312 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db, DB> { 312 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
313 let resolver = def.id.resolver(self.db); 313 let resolver = def.id.resolver(self.db);
314 SemanticsScope { db: self.db, resolver } 314 SemanticsScope { db: self.db, resolver }
315 } 315 }
@@ -419,12 +419,12 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
419 node.ancestors().last().unwrap() 419 node.ancestors().last().unwrap()
420} 420}
421 421
422pub struct SemanticsScope<'a, DB> { 422pub struct SemanticsScope<'a> {
423 pub db: &'a DB, 423 pub db: &'a dyn HirDatabase,
424 resolver: Resolver, 424 resolver: Resolver,
425} 425}
426 426
427impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { 427impl<'a> SemanticsScope<'a> {
428 pub fn module(&self) -> Option<Module> { 428 pub fn module(&self) -> Option<Module> {
429 Some(Module { id: self.resolver.module()? }) 429 Some(Module { id: self.resolver.module()? })
430 } 430 }
@@ -433,13 +433,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
433 // FIXME: rename to visible_traits to not repeat scope? 433 // FIXME: rename to visible_traits to not repeat scope?
434 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { 434 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
435 let resolver = &self.resolver; 435 let resolver = &self.resolver;
436 resolver.traits_in_scope(self.db) 436 resolver.traits_in_scope(self.db.upcast())
437 } 437 }
438 438
439 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { 439 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
440 let resolver = &self.resolver; 440 let resolver = &self.resolver;
441 441
442 resolver.process_all_names(self.db, &mut |name, def| { 442 resolver.process_all_names(self.db.upcast(), &mut |name, def| {
443 let def = match def { 443 let def = match def {
444 resolver::ScopeDef::PerNs(it) => { 444 resolver::ScopeDef::PerNs(it) => {
445 let items = ScopeDef::all_items(it); 445 let items = ScopeDef::all_items(it);
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 4d446c707..beeb98559 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -1,6 +1,8 @@
1//! Describes items defined or visible (ie, imported) in a certain scope. 1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks. 2//! This is shared between modules and blocks.
3 3
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use ra_db::CrateId; 8use ra_db::CrateId;
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports {
27 29
28#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
29pub struct ItemScope { 31pub struct ItemScope {
30 visible: FxHashMap<Name, PerNs>, 32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
31 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
32 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
33 /// Macros visible in current module in legacy textual scope 39 /// Macros visible in current module in legacy textual scope
@@ -65,14 +71,16 @@ pub(crate) enum BuiltinShadowMode {
65/// Other methods will only resolve values, types and module scoped macros only. 71/// Other methods will only resolve values, types and module scoped macros only.
66impl ItemScope { 72impl ItemScope {
67 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 73 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
68 //FIXME: shadowing 74 // FIXME: shadowing
69 self.visible.iter().map(|(n, def)| (n, *def)) 75 let keys: FxHashSet<_> = self
70 } 76 .types
71 77 .keys()
72 pub fn entries_without_primitives<'a>( 78 .chain(self.values.keys())
73 &'a self, 79 .chain(self.macros.keys())
74 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 80 .chain(self.unresolved.iter())
75 self.visible.iter().map(|(n, def)| (n, *def)) 81 .collect();
82
83 keys.into_iter().map(move |name| (name, self.get(name)))
76 } 84 }
77 85
78 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 86 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -91,7 +99,7 @@ impl ItemScope {
91 99
92 /// Iterate over all module scoped macros 100 /// Iterate over all module scoped macros
93 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 101 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
94 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 102 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
95 } 103 }
96 104
97 /// Iterate over all legacy textual scoped macros visible at the end of the module 105 /// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -101,12 +109,16 @@ impl ItemScope {
101 109
102 /// Get a name from current module scope, legacy macros are not included 110 /// Get a name from current module scope, legacy macros are not included
103 pub(crate) fn get(&self, name: &Name) -> PerNs { 111 pub(crate) fn get(&self, name: &Name) -> PerNs {
104 self.visible.get(name).copied().unwrap_or_else(PerNs::none) 112 PerNs {
113 types: self.types.get(name).copied(),
114 values: self.values.get(name).copied(),
115 macros: self.macros.get(name).copied(),
116 }
105 } 117 }
106 118
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 119 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108 for (name, per_ns) in &self.visible { 120 for (name, per_ns) in self.entries() {
109 if let Some(vis) = item.match_with(*per_ns) { 121 if let Some(vis) = item.match_with(per_ns) {
110 return Some((name, vis)); 122 return Some((name, vis));
111 } 123 }
112 } 124 }
@@ -114,8 +126,8 @@ impl ItemScope {
114 } 126 }
115 127
116 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 128 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
117 self.visible.values().filter_map(|def| match def.take_types() { 129 self.types.values().filter_map(|(def, _)| match def {
118 Some(ModuleDefId::TraitId(t)) => Some(t), 130 ModuleDefId::TraitId(t) => Some(*t),
119 _ => None, 131 _ => None,
120 }) 132 })
121 } 133 }
@@ -138,21 +150,30 @@ impl ItemScope {
138 150
139 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 151 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
140 let mut changed = false; 152 let mut changed = false;
141 let existing = self.visible.entry(name).or_default();
142 153
143 if existing.types.is_none() && def.types.is_some() { 154 if let Some(types) = def.types {
144 existing.types = def.types; 155 self.types.entry(name.clone()).or_insert_with(|| {
145 changed = true; 156 changed = true;
157 types
158 });
146 } 159 }
147 160 if let Some(values) = def.values {
148 if existing.values.is_none() && def.values.is_some() { 161 self.values.entry(name.clone()).or_insert_with(|| {
149 existing.values = def.values; 162 changed = true;
150 changed = true; 163 values
164 });
165 }
166 if let Some(macros) = def.macros {
167 self.macros.entry(name.clone()).or_insert_with(|| {
168 changed = true;
169 macros
170 });
151 } 171 }
152 172
153 if existing.macros.is_none() && def.macros.is_some() { 173 if def.is_none() {
154 existing.macros = def.macros; 174 if self.unresolved.insert(name) {
155 changed = true; 175 changed = true;
176 }
156 } 177 }
157 178
158 changed 179 changed
@@ -166,17 +187,17 @@ impl ItemScope {
166 def_import_type: ImportType, 187 def_import_type: ImportType,
167 ) -> bool { 188 ) -> bool {
168 let mut changed = false; 189 let mut changed = false;
169 let existing = self.visible.entry(lookup.1.clone()).or_default();
170 190
171 macro_rules! check_changed { 191 macro_rules! check_changed {
172 ( 192 (
173 $changed:ident, 193 $changed:ident,
174 ( $existing:ident / $def:ident ) . $field:ident, 194 ( $this:ident / $def:ident ) . $field:ident,
175 $glob_imports:ident [ $lookup:ident ], 195 $glob_imports:ident [ $lookup:ident ],
176 $def_import_type:ident 196 $def_import_type:ident
177 ) => { 197 ) => {{
178 match ($existing.$field, $def.$field) { 198 let existing = $this.$field.entry($lookup.1.clone());
179 (None, Some(_)) => { 199 match (existing, $def.$field) {
200 (Entry::Vacant(entry), Some(_)) => {
180 match $def_import_type { 201 match $def_import_type {
181 ImportType::Glob => { 202 ImportType::Glob => {
182 $glob_imports.$field.insert($lookup.clone()); 203 $glob_imports.$field.insert($lookup.clone());
@@ -186,32 +207,42 @@ impl ItemScope {
186 } 207 }
187 } 208 }
188 209
189 $existing.$field = $def.$field; 210 if let Some(fld) = $def.$field {
211 entry.insert(fld);
212 }
190 $changed = true; 213 $changed = true;
191 } 214 }
192 (Some(_), Some(_)) 215 (Entry::Occupied(mut entry), Some(_))
193 if $glob_imports.$field.contains(&$lookup) 216 if $glob_imports.$field.contains(&$lookup)
194 && matches!($def_import_type, ImportType::Named) => 217 && matches!($def_import_type, ImportType::Named) =>
195 { 218 {
196 mark::hit!(import_shadowed); 219 mark::hit!(import_shadowed);
197 $glob_imports.$field.remove(&$lookup); 220 $glob_imports.$field.remove(&$lookup);
198 $existing.$field = $def.$field; 221 if let Some(fld) = $def.$field {
222 entry.insert(fld);
223 }
199 $changed = true; 224 $changed = true;
200 } 225 }
201 _ => {} 226 _ => {}
202 } 227 }
203 }; 228 }};
204 } 229 }
205 230
206 check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); 231 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
207 check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); 232 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
208 check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); 233 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
234
235 if def.is_none() {
236 if self.unresolved.insert(lookup.1) {
237 changed = true;
238 }
239 }
209 240
210 changed 241 changed
211 } 242 }
212 243
213 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 244 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
214 self.visible.iter().map(|(name, res)| (name.clone(), *res)) 245 self.entries().map(|(name, res)| (name.clone(), res))
215 } 246 }
216 247
217 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 248 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 15fdd9019..0bf51eb7b 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -511,11 +511,9 @@ impl Scope {
511 }); 511 });
512 } 512 }
513 } 513 }
514 Scope::LocalItemsScope(body) => { 514 Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| {
515 body.item_scope.entries_without_primitives().for_each(|(name, def)| { 515 f(name.clone(), ScopeDef::PerNs(def));
516 f(name.clone(), ScopeDef::PerNs(def)); 516 }),
517 })
518 }
519 Scope::GenericParams { params, def } => { 517 Scope::GenericParams { params, def } => {
520 for (local_id, param) in params.types.iter() { 518 for (local_id, param) in params.types.iter() {
521 if let Some(name) = &param.name { 519 if let Some(name) = &param.name {
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 26b667b55..f2d664863 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -161,7 +161,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
161 // XXX 161 // XXX
162 // All crates except core itself should have a dependency on core, 162 // All crates except core itself should have a dependency on core,
163 // We detect `core` by seeing whether it doesn't have such a dependency. 163 // We detect `core` by seeing whether it doesn't have such a dependency.
164 let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { 164 let tt = if cg[krate].dependencies.iter().any(|dep| &*dep.name == "core") {
165 quote! { core } 165 quote! { core }
166 } else { 166 } else {
167 quote! { crate } 167 quote! { crate }
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 631358f41..626f9efd0 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -99,6 +99,7 @@ register_builtin! {
99 EAGER: 99 EAGER:
100 (concat, Concat) => concat_expand, 100 (concat, Concat) => concat_expand,
101 (include, Include) => include_expand, 101 (include, Include) => include_expand,
102 (include_bytes, IncludeBytes) => include_bytes_expand,
102 (include_str, IncludeStr) => include_str_expand, 103 (include_str, IncludeStr) => include_str_expand,
103 (env, Env) => env_expand, 104 (env, Env) => env_expand,
104 (option_env, OptionEnv) => option_env_expand 105 (option_env, OptionEnv) => option_env_expand
@@ -337,6 +338,24 @@ fn include_expand(
337 Ok((res, FragmentKind::Items)) 338 Ok((res, FragmentKind::Items))
338} 339}
339 340
341fn include_bytes_expand(
342 _db: &dyn AstDatabase,
343 _arg_id: EagerMacroId,
344 tt: &tt::Subtree,
345) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
346 let _path = parse_string(tt)?;
347
348 // FIXME: actually read the file here if the user asked for macro expansion
349 let res = tt::Subtree {
350 delimiter: None,
351 token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
352 text: r#"b"""#.into(),
353 id: tt::TokenId::unspecified(),
354 }))],
355 };
356 Ok((res, FragmentKind::Expr))
357}
358
340fn include_str_expand( 359fn include_str_expand(
341 db: &dyn AstDatabase, 360 db: &dyn AstDatabase,
342 arg_id: EagerMacroId, 361 arg_id: EagerMacroId,
@@ -611,4 +630,20 @@ mod tests {
611 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),])"# 630 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),])"#
612 ); 631 );
613 } 632 }
633
634 #[test]
635 fn test_include_bytes_expand() {
636 let expanded = expand_builtin_macro(
637 r#"
638 #[rustc_builtin_macro]
639 macro_rules! include_bytes {
640 ($file:expr) => {{ /* compiler built-in */ }};
641 ($file:expr,) => {{ /* compiler built-in */ }};
642 }
643 include_bytes("foo");
644 "#,
645 );
646
647 assert_eq!(expanded, r#"b"""#);
648 }
614} 649}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 99209c6e8..545cff9bd 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -28,7 +28,7 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
28 28
29pub trait AstDiagnostic { 29pub trait AstDiagnostic {
30 type AST; 30 type AST;
31 fn ast(&self, db: &impl AstDatabase) -> Self::AST; 31 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
32} 32}
33 33
34impl dyn Diagnostic { 34impl dyn Diagnostic {
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index b475c8cc7..969a2e5b8 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -117,7 +117,7 @@ impl AsName for ast::FieldKind {
117 117
118impl AsName for ra_db::Dependency { 118impl AsName for ra_db::Dependency {
119 fn as_name(&self) -> Name { 119 fn as_name(&self) -> Name {
120 Name::new_text(self.name.clone()) 120 Name::new_text(SmolStr::new(&*self.name))
121 } 121 }
122} 122}
123 123
@@ -191,6 +191,7 @@ pub mod known {
191 stringify, 191 stringify,
192 concat, 192 concat,
193 include, 193 include,
194 include_bytes,
194 include_str, 195 include_str,
195 format_args, 196 format_args,
196 format_args_nl, 197 format_args_nl,
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 407322dc1..d6df48db2 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" }
27 27
28scoped-tls = "1" 28scoped-tls = "1"
29 29
30chalk-solve = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } 30chalk-solve = { version = "0.15.0" }
31chalk-ir = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } 31chalk-ir = { version = "0.15.0" }
32 32
33[dev-dependencies] 33[dev-dependencies]
34insta = "0.16.0" 34insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 7889b8d2c..cad553273 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -14,7 +14,7 @@ use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::CrateImplDefs,
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name; 19use hir_expand::name::Name;
20 20
@@ -65,7 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
65 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>; 65 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>;
66 66
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 67 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Substs; 68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 69
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index a59efb347..0289911de 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -32,7 +32,7 @@ impl Diagnostic for NoSuchField {
32impl AstDiagnostic for NoSuchField { 32impl AstDiagnostic for NoSuchField {
33 type AST = ast::RecordField; 33 type AST = ast::RecordField;
34 34
35 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 35 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
36 let root = db.parse_or_expand(self.source().file_id).unwrap(); 36 let root = db.parse_or_expand(self.source().file_id).unwrap();
37 let node = self.source().value.to_node(&root); 37 let node = self.source().value.to_node(&root);
38 ast::RecordField::cast(node).unwrap() 38 ast::RecordField::cast(node).unwrap()
@@ -65,7 +65,7 @@ impl Diagnostic for MissingFields {
65impl AstDiagnostic for MissingFields { 65impl AstDiagnostic for MissingFields {
66 type AST = ast::RecordFieldList; 66 type AST = ast::RecordFieldList;
67 67
68 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 68 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
69 let root = db.parse_or_expand(self.source().file_id).unwrap(); 69 let root = db.parse_or_expand(self.source().file_id).unwrap();
70 let node = self.source().value.to_node(&root); 70 let node = self.source().value.to_node(&root);
71 ast::RecordFieldList::cast(node).unwrap() 71 ast::RecordFieldList::cast(node).unwrap()
@@ -135,7 +135,7 @@ impl Diagnostic for MissingOkInTailExpr {
135impl AstDiagnostic for MissingOkInTailExpr { 135impl AstDiagnostic for MissingOkInTailExpr {
136 type AST = ast::Expr; 136 type AST = ast::Expr;
137 137
138 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 138 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
139 let root = db.parse_or_expand(self.file).unwrap(); 139 let root = db.parse_or_expand(self.file).unwrap();
140 let node = self.source().value.to_node(&root); 140 let node = self.source().value.to_node(&root);
141 ast::Expr::cast(node).unwrap() 141 ast::Expr::cast(node).unwrap()
@@ -163,7 +163,7 @@ impl Diagnostic for BreakOutsideOfLoop {
163impl AstDiagnostic for BreakOutsideOfLoop { 163impl AstDiagnostic for BreakOutsideOfLoop {
164 type AST = ast::Expr; 164 type AST = ast::Expr;
165 165
166 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 166 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
167 let root = db.parse_or_expand(self.file).unwrap(); 167 let root = db.parse_or_expand(self.file).unwrap();
168 let node = self.source().value.to_node(&root); 168 let node = self.source().value.to_node(&root);
169 ast::Expr::cast(node).unwrap() 169 ast::Expr::cast(node).unwrap()
@@ -191,7 +191,7 @@ impl Diagnostic for MissingUnsafe {
191impl AstDiagnostic for MissingUnsafe { 191impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr; 192 type AST = ast::Expr;
193 193
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 194 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap(); 195 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root); 196 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap() 197 ast::Expr::cast(node).unwrap()
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 3c97e1354..23cea1a2a 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -308,7 +308,6 @@ impl HirDisplay for ApplicationTy {
308 } 308 }
309 309
310 if self.parameters.len() > 0 { 310 if self.parameters.len() > 0 {
311 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
312 let parameters_to_write = 311 let parameters_to_write =
313 if f.display_target.is_source_code() || f.omit_verbose_types() { 312 if f.display_target.is_source_code() || f.omit_verbose_types() {
314 match self 313 match self
@@ -319,20 +318,23 @@ impl HirDisplay for ApplicationTy {
319 { 318 {
320 None => self.parameters.0.as_ref(), 319 None => self.parameters.0.as_ref(),
321 Some(default_parameters) => { 320 Some(default_parameters) => {
321 let mut default_from = 0;
322 for (i, parameter) in self.parameters.iter().enumerate() { 322 for (i, parameter) in self.parameters.iter().enumerate() {
323 match (parameter, default_parameters.get(i)) { 323 match (parameter, default_parameters.get(i)) {
324 (&Ty::Unknown, _) | (_, None) => { 324 (&Ty::Unknown, _) | (_, None) => {
325 non_default_parameters.push(parameter.clone()) 325 default_from = i + 1;
326 } 326 }
327 (_, Some(default_parameter)) 327 (_, Some(default_parameter)) => {
328 if parameter != default_parameter => 328 let actual_default = default_parameter
329 { 329 .clone()
330 non_default_parameters.push(parameter.clone()) 330 .subst(&self.parameters.prefix(i));
331 if parameter != &actual_default {
332 default_from = i + 1;
333 }
331 } 334 }
332 _ => (),
333 } 335 }
334 } 336 }
335 &non_default_parameters 337 &self.parameters.0[0..default_from]
336 } 338 }
337 } 339 }
338 } else { 340 } else {
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 61af5f064..22884522a 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -785,11 +785,7 @@ impl<'a> InferenceContext<'a> {
785 for &check_closures in &[false, true] { 785 for &check_closures in &[false, true] {
786 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); 786 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
787 for (&arg, param_ty) in args.iter().zip(param_iter) { 787 for (&arg, param_ty) in args.iter().zip(param_iter) {
788 let is_closure = match &self.body[arg] { 788 let is_closure = matches!(&self.body[arg], Expr::Lambda { .. });
789 Expr::Lambda { .. } => true,
790 _ => false,
791 };
792
793 if is_closure != check_closures { 789 if is_closure != check_closures {
794 continue; 790 continue;
795 } 791 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 414158139..c9513b752 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -620,17 +620,11 @@ pub enum GenericPredicate {
620 620
621impl GenericPredicate { 621impl GenericPredicate {
622 pub fn is_error(&self) -> bool { 622 pub fn is_error(&self) -> bool {
623 match self { 623 matches!(self, GenericPredicate::Error)
624 GenericPredicate::Error => true,
625 _ => false,
626 }
627 } 624 }
628 625
629 pub fn is_implemented(&self) -> bool { 626 pub fn is_implemented(&self) -> bool {
630 match self { 627 matches!(self, GenericPredicate::Implemented(_))
631 GenericPredicate::Implemented(_) => true,
632 _ => false,
633 }
634 } 628 }
635 629
636 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { 630 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index d5154f436..3dc154e92 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -578,11 +578,13 @@ fn substs_from_path_segment(
578 // (i.e. defaults aren't used). 578 // (i.e. defaults aren't used).
579 if !infer_args || had_explicit_args { 579 if !infer_args || had_explicit_args {
580 if let Some(def_generic) = def_generic { 580 if let Some(def_generic) = def_generic {
581 let default_substs = ctx.db.generic_defaults(def_generic); 581 let defaults = ctx.db.generic_defaults(def_generic);
582 assert_eq!(total_len, default_substs.len()); 582 assert_eq!(total_len, defaults.len());
583 583
584 for default_ty in default_substs.iter().skip(substs.len()) { 584 for default_ty in defaults.iter().skip(substs.len()) {
585 substs.push(default_ty.clone()); 585 // each default can depend on the previous parameters
586 let substs_so_far = Substs(substs.clone().into());
587 substs.push(default_ty.clone().subst(&substs_so_far));
586 } 588 }
587 } 589 }
588 } 590 }
@@ -945,17 +947,42 @@ pub(crate) fn generic_predicates_query(
945} 947}
946 948
947/// Resolve the default type params from generics 949/// Resolve the default type params from generics
948pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> Substs { 950pub(crate) fn generic_defaults_query(
951 db: &dyn HirDatabase,
952 def: GenericDefId,
953) -> Arc<[Binders<Ty>]> {
949 let resolver = def.resolver(db.upcast()); 954 let resolver = def.resolver(db.upcast());
950 let ctx = TyLoweringContext::new(db, &resolver); 955 let ctx =
956 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
951 let generic_params = generics(db.upcast(), def); 957 let generic_params = generics(db.upcast(), def);
952 958
953 let defaults = generic_params 959 let defaults = generic_params
954 .iter() 960 .iter()
955 .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t))) 961 .enumerate()
962 .map(|(idx, (_, p))| {
963 let mut ty = p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t));
964
965 // Each default can only refer to previous parameters.
966 ty.walk_mut_binders(
967 &mut |ty, binders| match ty {
968 Ty::Bound(BoundVar { debruijn, index }) if *debruijn == binders => {
969 if *index >= idx {
970 // type variable default referring to parameter coming
971 // after it. This is forbidden (FIXME: report
972 // diagnostic)
973 *ty = Ty::Unknown;
974 }
975 }
976 _ => {}
977 },
978 DebruijnIndex::INNERMOST,
979 );
980
981 Binders::new(idx, ty)
982 })
956 .collect(); 983 .collect();
957 984
958 Substs(defaults) 985 defaults
959} 986}
960 987
961fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { 988fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 9c2c6959d..fddf0604d 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -8,8 +8,10 @@ use std::{
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; 9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
11use rustc_hash::FxHashSet; 11use ra_syntax::TextRange;
12use rustc_hash::{FxHashMap, FxHashSet};
12use stdx::format_to; 13use stdx::format_to;
14use test_utils::extract_annotations;
13 15
14use crate::{ 16use crate::{
15 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator, 17 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
@@ -154,6 +156,29 @@ impl TestDB {
154 }); 156 });
155 (buf, count) 157 (buf, count)
156 } 158 }
159
160 pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
161 let mut files = Vec::new();
162 let crate_graph = self.crate_graph();
163 for krate in crate_graph.iter() {
164 let crate_def_map = self.crate_def_map(krate);
165 for (module_id, _) in crate_def_map.modules.iter() {
166 let file_id = crate_def_map[module_id].origin.file_id();
167 files.extend(file_id)
168 }
169 }
170 files
171 .into_iter()
172 .filter_map(|file_id| {
173 let text = self.file_text(file_id);
174 let annotations = extract_annotations(&text);
175 if annotations.is_empty() {
176 return None;
177 }
178 Some((file_id, annotations))
179 })
180 .collect()
181 }
157} 182}
158 183
159impl TestDB { 184impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 2a85ce85d..9084c3bed 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -17,11 +17,11 @@ use hir_def::{
17 item_scope::ItemScope, 17 item_scope::ItemScope,
18 keys, 18 keys,
19 nameres::CrateDefMap, 19 nameres::CrateDefMap,
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId, 20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 21};
22use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 23use insta::assert_snapshot;
24use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 24use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
25use ra_syntax::{ 25use ra_syntax::{
26 algo, 26 algo,
27 ast::{self, AstNode}, 27 ast::{self, AstNode},
@@ -37,21 +37,36 @@ use crate::{
37// against snapshots of the expected results using insta. Use cargo-insta to 37// against snapshots of the expected results using insta. Use cargo-insta to
38// update the snapshots. 38// update the snapshots.
39 39
40fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 40fn check_types(ra_fixture: &str) {
41 type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string()) 41 check_types_impl(ra_fixture, false)
42} 42}
43 43
44fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { 44fn check_types_source_code(ra_fixture: &str) {
45 type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap()) 45 check_types_impl(ra_fixture, true)
46} 46}
47 47
48fn type_at_pos_displayed( 48fn check_types_impl(ra_fixture: &str, display_source: bool) {
49 db: &TestDB, 49 let db = TestDB::with_files(ra_fixture);
50 pos: FilePosition, 50 let mut checked_one = false;
51 display_fn: impl FnOnce(&Ty, ModuleId) -> String, 51 for (file_id, annotations) in db.extract_annotations() {
52) -> String { 52 for (range, expected) in annotations {
53 let ty = type_at_range(&db, FileRange { file_id, range });
54 let actual = if display_source {
55 let module = db.module_for_file(file_id);
56 ty.display_source_code(&db, module).unwrap()
57 } else {
58 ty.display(&db).to_string()
59 };
60 assert_eq!(expected, actual);
61 checked_one = true;
62 }
63 }
64 assert!(checked_one, "no `//^` annotations found");
65}
66
67fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
53 let file = db.parse(pos.file_id).ok().unwrap(); 68 let file = db.parse(pos.file_id).ok().unwrap();
54 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 69 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
55 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 70 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
56 let module = db.module_for_file(pos.file_id); 71 let module = db.module_for_file(pos.file_id);
57 let func = *module.child_by_source(db)[keys::FUNCTION] 72 let func = *module.child_by_source(db)[keys::FUNCTION]
@@ -61,17 +76,11 @@ fn type_at_pos_displayed(
61 let (_body, source_map) = db.body_with_source_map(func.into()); 76 let (_body, source_map) = db.body_with_source_map(func.into());
62 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 77 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
63 let infer = db.infer(func.into()); 78 let infer = db.infer(func.into());
64 let ty = &infer[expr_id]; 79 return infer[expr_id].clone();
65 return display_fn(ty, module);
66 } 80 }
67 panic!("Can't find expression") 81 panic!("Can't find expression")
68} 82}
69 83
70fn type_at(ra_fixture: &str) -> String {
71 let (db, file_pos) = TestDB::with_position(ra_fixture);
72 type_at_pos(&db, file_pos)
73}
74
75fn infer(ra_fixture: &str) -> String { 84fn infer(ra_fixture: &str) -> String {
76 infer_with_mismatches(ra_fixture, false) 85 infer_with_mismatches(ra_fixture, false)
77} 86}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 5a1c6ccc3..136d28a91 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,7 +1,8 @@
1use super::infer_with_mismatches;
2use insta::assert_snapshot; 1use insta::assert_snapshot;
3use test_utils::mark; 2use test_utils::mark;
4 3
4use super::infer_with_mismatches;
5
5// Infer with some common definitions and impls. 6// Infer with some common definitions and impls.
6fn infer(source: &str) -> String { 7fn infer(source: &str) -> String {
7 let defs = r#" 8 let defs = r#"
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
index 5dfa0a014..b502135d8 100644
--- a/crates/ra_hir_ty/src/tests/display_source_code.rs
+++ b/crates/ra_hir_ty/src/tests/display_source_code.rs
@@ -1,50 +1,41 @@
1use super::displayed_source_at_pos; 1use super::check_types_source_code;
2use crate::test_db::TestDB;
3use ra_db::fixture::WithFixture;
4 2
5#[test] 3#[test]
6fn qualify_path_to_submodule() { 4fn qualify_path_to_submodule() {
7 let (db, pos) = TestDB::with_position( 5 check_types_source_code(
8 r#" 6 r#"
9//- /main.rs
10
11mod foo { 7mod foo {
12 pub struct Foo; 8 pub struct Foo;
13} 9}
14 10
15fn bar() { 11fn bar() {
16 let foo: foo::Foo = foo::Foo; 12 let foo: foo::Foo = foo::Foo;
17 foo<|> 13 foo
18} 14} //^ foo::Foo
19 15
20"#, 16"#,
21 ); 17 );
22 assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
23} 18}
24 19
25#[test] 20#[test]
26fn omit_default_type_parameters() { 21fn omit_default_type_parameters() {
27 let (db, pos) = TestDB::with_position( 22 check_types_source_code(
28 r" 23 r#"
29 //- /main.rs 24struct Foo<T = u8> { t: T }
30 struct Foo<T = u8> { t: T } 25fn main() {
31 fn main() { 26 let foo = Foo { t: 5u8 };
32 let foo = Foo { t: 5u8 }; 27 foo;
33 foo<|>; 28} //^ Foo
34 } 29"#,
35 ",
36 ); 30 );
37 assert_eq!("Foo", displayed_source_at_pos(&db, pos));
38 31
39 let (db, pos) = TestDB::with_position( 32 check_types_source_code(
40 r" 33 r#"
41 //- /main.rs 34struct Foo<K, T = u8> { k: K, t: T }
42 struct Foo<K, T = u8> { k: K, t: T } 35fn main() {
43 fn main() { 36 let foo = Foo { k: 400, t: 5u8 };
44 let foo = Foo { k: 400, t: 5u8 }; 37 foo;
45 foo<|>; 38} //^ Foo<i32>
46 } 39"#,
47 ",
48 ); 40 );
49 assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
50} 41}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index be2b48dcc..45c4e309e 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,16 +1,13 @@
1use std::fs; 1use std::fs;
2 2
3use insta::assert_snapshot; 3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5use test_utils::project_dir; 4use test_utils::project_dir;
6 5
7use crate::test_db::TestDB; 6use super::{check_types, infer};
8
9use super::{infer, type_at, type_at_pos};
10 7
11#[test] 8#[test]
12fn cfg_impl_def() { 9fn cfg_impl_def() {
13 let (db, pos) = TestDB::with_position( 10 check_types(
14 r#" 11 r#"
15//- /main.rs crate:main deps:foo cfg:test 12//- /main.rs crate:main deps:foo cfg:test
16use foo::S as T; 13use foo::S as T;
@@ -28,8 +25,8 @@ impl S {
28 25
29fn test() { 26fn test() {
30 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); 27 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
31 t<|>; 28 t;
32} 29} //^ (i32, {unknown}, i32, {unknown})
33 30
34//- /foo.rs crate:foo 31//- /foo.rs crate:foo
35struct S; 32struct S;
@@ -45,7 +42,6 @@ impl S {
45} 42}
46"#, 43"#,
47 ); 44 );
48 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
49} 45}
50 46
51#[test] 47#[test]
@@ -253,26 +249,24 @@ fn foo() {
253 249
254#[test] 250#[test]
255fn processes_impls_generated_by_macros() { 251fn processes_impls_generated_by_macros() {
256 let t = type_at( 252 check_types(
257 r#" 253 r#"
258//- /main.rs
259macro_rules! m { 254macro_rules! m {
260 ($ident:ident) => (impl Trait for $ident {}) 255 ($ident:ident) => (impl Trait for $ident {})
261} 256}
262trait Trait { fn foo(self) -> u128 {} } 257trait Trait { fn foo(self) -> u128 {} }
263struct S; 258struct S;
264m!(S); 259m!(S);
265fn test() { S.foo()<|>; } 260fn test() { S.foo(); }
261 //^ u128
266"#, 262"#,
267 ); 263 );
268 assert_eq!(t, "u128");
269} 264}
270 265
271#[test] 266#[test]
272fn infer_assoc_items_generated_by_macros() { 267fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 268 check_types(
274 r#" 269 r#"
275//- /main.rs
276macro_rules! m { 270macro_rules! m {
277 () => (fn foo(&self) -> u128 {0}) 271 () => (fn foo(&self) -> u128 {0})
278} 272}
@@ -281,17 +275,16 @@ impl S {
281 m!(); 275 m!();
282} 276}
283 277
284fn test() { S.foo()<|>; } 278fn test() { S.foo(); }
279 //^ u128
285"#, 280"#,
286 ); 281 );
287 assert_eq!(t, "u128");
288} 282}
289 283
290#[test] 284#[test]
291fn infer_assoc_items_generated_by_macros_chain() { 285fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 286 check_types(
293 r#" 287 r#"
294//- /main.rs
295macro_rules! m_inner { 288macro_rules! m_inner {
296 () => {fn foo(&self) -> u128 {0}} 289 () => {fn foo(&self) -> u128 {0}}
297} 290}
@@ -304,21 +297,21 @@ impl S {
304 m!(); 297 m!();
305} 298}
306 299
307fn test() { S.foo()<|>; } 300fn test() { S.foo(); }
301 //^ u128
308"#, 302"#,
309 ); 303 );
310 assert_eq!(t, "u128");
311} 304}
312 305
313#[test] 306#[test]
314fn infer_macro_with_dollar_crate_is_correct_in_expr() { 307fn infer_macro_with_dollar_crate_is_correct_in_expr() {
315 let (db, pos) = TestDB::with_position( 308 check_types(
316 r#" 309 r#"
317//- /main.rs crate:main deps:foo 310//- /main.rs crate:main deps:foo
318fn test() { 311fn test() {
319 let x = (foo::foo!(1), foo::foo!(2)); 312 let x = (foo::foo!(1), foo::foo!(2));
320 x<|>; 313 x;
321} 314} //^ (i32, usize)
322 315
323//- /lib.rs crate:foo 316//- /lib.rs crate:foo
324#[macro_export] 317#[macro_export]
@@ -335,12 +328,11 @@ macro_rules! bar {
335pub fn baz() -> usize { 31usize } 328pub fn baz() -> usize { 31usize }
336"#, 329"#,
337 ); 330 );
338 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
339} 331}
340 332
341#[test] 333#[test]
342fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { 334fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
343 let (db, pos) = TestDB::with_position( 335 check_types(
344 r#" 336 r#"
345//- /main.rs crate:main deps:foo 337//- /main.rs crate:main deps:foo
346use foo::Trait; 338use foo::Trait;
@@ -348,7 +340,8 @@ use foo::Trait;
348fn test() { 340fn test() {
349 let msg = foo::Message(foo::MessageRef); 341 let msg = foo::Message(foo::MessageRef);
350 let r = msg.deref(); 342 let r = msg.deref();
351 r<|>; 343 r;
344 //^ &MessageRef
352} 345}
353 346
354//- /lib.rs crate:foo 347//- /lib.rs crate:foo
@@ -375,7 +368,6 @@ macro_rules! expand {
375expand!(); 368expand!();
376"#, 369"#,
377 ); 370 );
378 assert_eq!("&MessageRef", type_at_pos(&db, pos));
379} 371}
380 372
381#[test] 373#[test]
@@ -429,13 +421,13 @@ fn main() {
429 421
430#[test] 422#[test]
431fn infer_local_inner_macros() { 423fn infer_local_inner_macros() {
432 let (db, pos) = TestDB::with_position( 424 check_types(
433 r#" 425 r#"
434//- /main.rs crate:main deps:foo 426//- /main.rs crate:main deps:foo
435fn test() { 427fn test() {
436 let x = foo::foo!(1); 428 let x = foo::foo!(1);
437 x<|>; 429 x;
438} 430} //^ i32
439 431
440//- /lib.rs crate:foo 432//- /lib.rs crate:foo
441#[macro_export(local_inner_macros)] 433#[macro_export(local_inner_macros)]
@@ -450,7 +442,6 @@ macro_rules! bar {
450 442
451"#, 443"#,
452 ); 444 );
453 assert_eq!("i32", type_at_pos(&db, pos));
454} 445}
455 446
456#[test] 447#[test]
@@ -531,7 +522,7 @@ fn main() {
531 522
532#[test] 523#[test]
533fn infer_builtin_macros_include() { 524fn infer_builtin_macros_include() {
534 let (db, pos) = TestDB::with_position( 525 check_types(
535 r#" 526 r#"
536//- /main.rs 527//- /main.rs
537#[rustc_builtin_macro] 528#[rustc_builtin_macro]
@@ -540,14 +531,13 @@ macro_rules! include {() => {}}
540include!("foo.rs"); 531include!("foo.rs");
541 532
542fn main() { 533fn main() {
543 bar()<|>; 534 bar();
544} 535} //^ u32
545 536
546//- /foo.rs 537//- /foo.rs
547fn bar() -> u32 {0} 538fn bar() -> u32 {0}
548"#, 539"#,
549 ); 540 );
550 assert_eq!("u32", type_at_pos(&db, pos));
551} 541}
552 542
553#[test] 543#[test]
@@ -565,18 +555,17 @@ macro_rules! include {() => {}}
565include!("foo.rs"); 555include!("foo.rs");
566 556
567fn main() { 557fn main() {
568 RegisterBlock { }<|>; 558 RegisterBlock { };
559 //^ RegisterBlock
569} 560}
570 "#; 561 "#;
571 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); 562 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
572 563 check_types(&fixture);
573 let (db, pos) = TestDB::with_position(&fixture);
574 assert_eq!("RegisterBlock", type_at_pos(&db, pos));
575} 564}
576 565
577#[test] 566#[test]
578fn infer_builtin_macros_include_concat() { 567fn infer_builtin_macros_include_concat() {
579 let (db, pos) = TestDB::with_position( 568 check_types(
580 r#" 569 r#"
581//- /main.rs 570//- /main.rs
582#[rustc_builtin_macro] 571#[rustc_builtin_macro]
@@ -588,19 +577,18 @@ macro_rules! concat {() => {}}
588include!(concat!("f", "oo.rs")); 577include!(concat!("f", "oo.rs"));
589 578
590fn main() { 579fn main() {
591 bar()<|>; 580 bar();
592} 581} //^ u32
593 582
594//- /foo.rs 583//- /foo.rs
595fn bar() -> u32 {0} 584fn bar() -> u32 {0}
596"#, 585"#,
597 ); 586 );
598 assert_eq!("u32", type_at_pos(&db, pos));
599} 587}
600 588
601#[test] 589#[test]
602fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { 590fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
603 let (db, pos) = TestDB::with_position( 591 check_types(
604 r#" 592 r#"
605//- /main.rs 593//- /main.rs
606#[rustc_builtin_macro] 594#[rustc_builtin_macro]
@@ -615,32 +603,29 @@ macro_rules! env {() => {}}
615include!(concat!(env!("OUT_DIR"), "/foo.rs")); 603include!(concat!(env!("OUT_DIR"), "/foo.rs"));
616 604
617fn main() { 605fn main() {
618 bar()<|>; 606 bar();
619} 607} //^ {unknown}
620 608
621//- /foo.rs 609//- /foo.rs
622fn bar() -> u32 {0} 610fn bar() -> u32 {0}
623"#, 611"#,
624 ); 612 );
625 assert_eq!("{unknown}", type_at_pos(&db, pos));
626} 613}
627 614
628#[test] 615#[test]
629fn infer_builtin_macros_include_itself_should_failed() { 616fn infer_builtin_macros_include_itself_should_failed() {
630 let (db, pos) = TestDB::with_position( 617 check_types(
631 r#" 618 r#"
632//- /main.rs
633#[rustc_builtin_macro] 619#[rustc_builtin_macro]
634macro_rules! include {() => {}} 620macro_rules! include {() => {}}
635 621
636include!("main.rs"); 622include!("main.rs");
637 623
638fn main() { 624fn main() {
639 0<|> 625 0
640} 626} //^ i32
641"#, 627"#,
642 ); 628 );
643 assert_eq!("i32", type_at_pos(&db, pos));
644} 629}
645 630
646#[test] 631#[test]
@@ -686,14 +671,14 @@ fn main() {
686 671
687#[test] 672#[test]
688fn infer_derive_clone_simple() { 673fn infer_derive_clone_simple() {
689 let (db, pos) = TestDB::with_position( 674 check_types(
690 r#" 675 r#"
691//- /main.rs crate:main deps:core 676//- /main.rs crate:main deps:core
692#[derive(Clone)] 677#[derive(Clone)]
693struct S; 678struct S;
694fn test() { 679fn test() {
695 S.clone()<|>; 680 S.clone();
696} 681} //^ S
697 682
698//- /lib.rs crate:core 683//- /lib.rs crate:core
699#[prelude_import] 684#[prelude_import]
@@ -705,12 +690,11 @@ mod clone {
705} 690}
706"#, 691"#,
707 ); 692 );
708 assert_eq!("S", type_at_pos(&db, pos));
709} 693}
710 694
711#[test] 695#[test]
712fn infer_derive_clone_in_core() { 696fn infer_derive_clone_in_core() {
713 let (db, pos) = TestDB::with_position( 697 check_types(
714 r#" 698 r#"
715//- /lib.rs crate:core 699//- /lib.rs crate:core
716#[prelude_import] 700#[prelude_import]
@@ -726,16 +710,15 @@ pub struct S;
726//- /main.rs crate:main deps:core 710//- /main.rs crate:main deps:core
727use core::S; 711use core::S;
728fn test() { 712fn test() {
729 S.clone()<|>; 713 S.clone();
730} 714} //^ S
731"#, 715"#,
732 ); 716 );
733 assert_eq!("S", type_at_pos(&db, pos));
734} 717}
735 718
736#[test] 719#[test]
737fn infer_derive_clone_with_params() { 720fn infer_derive_clone_with_params() {
738 let (db, pos) = TestDB::with_position( 721 check_types(
739 r#" 722 r#"
740//- /main.rs crate:main deps:core 723//- /main.rs crate:main deps:core
741#[derive(Clone)] 724#[derive(Clone)]
@@ -744,7 +727,8 @@ struct S;
744struct Wrapper<T>(T); 727struct Wrapper<T>(T);
745struct NonClone; 728struct NonClone;
746fn test() { 729fn test() {
747 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; 730 (Wrapper(S).clone(), Wrapper(NonClone).clone());
731 //^ (Wrapper<S>, {unknown})
748} 732}
749 733
750//- /lib.rs crate:core 734//- /lib.rs crate:core
@@ -757,13 +741,12 @@ mod clone {
757} 741}
758"#, 742"#,
759 ); 743 );
760 assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
761} 744}
762 745
763#[test] 746#[test]
764fn infer_custom_derive_simple() { 747fn infer_custom_derive_simple() {
765 // FIXME: this test current now do nothing 748 // FIXME: this test current now do nothing
766 let (db, pos) = TestDB::with_position( 749 check_types(
767 r#" 750 r#"
768//- /main.rs crate:main 751//- /main.rs crate:main
769use foo::Foo; 752use foo::Foo;
@@ -772,11 +755,10 @@ use foo::Foo;
772struct S{} 755struct S{}
773 756
774fn test() { 757fn test() {
775 S{}<|>; 758 S{};
776} 759} //^ S
777"#, 760"#,
778 ); 761 );
779 assert_eq!("S", type_at_pos(&db, pos));
780} 762}
781 763
782#[test] 764#[test]
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 20329bae4..9c8f22314 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1,7 +1,6 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
4use ra_db::fixture::WithFixture; 2
3use super::{check_types, infer};
5 4
6#[test] 5#[test]
7fn infer_slice_method() { 6fn infer_slice_method() {
@@ -246,13 +245,13 @@ fn test() {
246 245
247#[test] 246#[test]
248fn cross_crate_associated_method_call() { 247fn cross_crate_associated_method_call() {
249 let (db, pos) = TestDB::with_position( 248 check_types(
250 r#" 249 r#"
251//- /main.rs crate:main deps:other_crate 250//- /main.rs crate:main deps:other_crate
252fn test() { 251fn test() {
253 let x = other_crate::foo::S::thing(); 252 let x = other_crate::foo::S::thing();
254 x<|>; 253 x;
255} 254} //^ i128
256 255
257//- /lib.rs crate:other_crate 256//- /lib.rs crate:other_crate
258mod foo { 257mod foo {
@@ -263,7 +262,6 @@ mod foo {
263} 262}
264"#, 263"#,
265 ); 264 );
266 assert_eq!("i128", type_at_pos(&db, pos));
267} 265}
268 266
269#[test] 267#[test]
@@ -684,135 +682,127 @@ fn test() {
684 682
685#[test] 683#[test]
686fn method_resolution_unify_impl_self_type() { 684fn method_resolution_unify_impl_self_type() {
687 let t = type_at( 685 check_types(
688 r#" 686 r#"
689//- /main.rs
690struct S<T>; 687struct S<T>;
691impl S<u32> { fn foo(&self) -> u8 {} } 688impl S<u32> { fn foo(&self) -> u8 {} }
692impl S<i32> { fn foo(&self) -> i8 {} } 689impl S<i32> { fn foo(&self) -> i8 {} }
693fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; } 690fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
691 //^ (u8, i8)
694"#, 692"#,
695 ); 693 );
696 assert_eq!(t, "(u8, i8)");
697} 694}
698 695
699#[test] 696#[test]
700fn method_resolution_trait_before_autoref() { 697fn method_resolution_trait_before_autoref() {
701 let t = type_at( 698 check_types(
702 r#" 699 r#"
703//- /main.rs
704trait Trait { fn foo(self) -> u128; } 700trait Trait { fn foo(self) -> u128; }
705struct S; 701struct S;
706impl S { fn foo(&self) -> i8 { 0 } } 702impl S { fn foo(&self) -> i8 { 0 } }
707impl Trait for S { fn foo(self) -> u128 { 0 } } 703impl Trait for S { fn foo(self) -> u128 { 0 } }
708fn test() { S.foo()<|>; } 704fn test() { S.foo(); }
705 //^ u128
709"#, 706"#,
710 ); 707 );
711 assert_eq!(t, "u128");
712} 708}
713 709
714#[test] 710#[test]
715fn method_resolution_by_value_before_autoref() { 711fn method_resolution_by_value_before_autoref() {
716 let t = type_at( 712 check_types(
717 r#" 713 r#"
718//- /main.rs
719trait Clone { fn clone(&self) -> Self; } 714trait Clone { fn clone(&self) -> Self; }
720struct S; 715struct S;
721impl Clone for S {} 716impl Clone for S {}
722impl Clone for &S {} 717impl Clone for &S {}
723fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } 718fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
719 //^ (S, S, &S)
724"#, 720"#,
725 ); 721 );
726 assert_eq!(t, "(S, S, &S)");
727} 722}
728 723
729#[test] 724#[test]
730fn method_resolution_trait_before_autoderef() { 725fn method_resolution_trait_before_autoderef() {
731 let t = type_at( 726 check_types(
732 r#" 727 r#"
733//- /main.rs
734trait Trait { fn foo(self) -> u128; } 728trait Trait { fn foo(self) -> u128; }
735struct S; 729struct S;
736impl S { fn foo(self) -> i8 { 0 } } 730impl S { fn foo(self) -> i8 { 0 } }
737impl Trait for &S { fn foo(self) -> u128 { 0 } } 731impl Trait for &S { fn foo(self) -> u128 { 0 } }
738fn test() { (&S).foo()<|>; } 732fn test() { (&S).foo(); }
733 //^ u128
739"#, 734"#,
740 ); 735 );
741 assert_eq!(t, "u128");
742} 736}
743 737
744#[test] 738#[test]
745fn method_resolution_impl_before_trait() { 739fn method_resolution_impl_before_trait() {
746 let t = type_at( 740 check_types(
747 r#" 741 r#"
748//- /main.rs
749trait Trait { fn foo(self) -> u128; } 742trait Trait { fn foo(self) -> u128; }
750struct S; 743struct S;
751impl S { fn foo(self) -> i8 { 0 } } 744impl S { fn foo(self) -> i8 { 0 } }
752impl Trait for S { fn foo(self) -> u128 { 0 } } 745impl Trait for S { fn foo(self) -> u128 { 0 } }
753fn test() { S.foo()<|>; } 746fn test() { S.foo(); }
747 //^ i8
754"#, 748"#,
755 ); 749 );
756 assert_eq!(t, "i8");
757} 750}
758 751
759#[test] 752#[test]
760fn method_resolution_impl_ref_before_trait() { 753fn method_resolution_impl_ref_before_trait() {
761 let t = type_at( 754 check_types(
762 r#" 755 r#"
763//- /main.rs
764trait Trait { fn foo(self) -> u128; } 756trait Trait { fn foo(self) -> u128; }
765struct S; 757struct S;
766impl S { fn foo(&self) -> i8 { 0 } } 758impl S { fn foo(&self) -> i8 { 0 } }
767impl Trait for &S { fn foo(self) -> u128 { 0 } } 759impl Trait for &S { fn foo(self) -> u128 { 0 } }
768fn test() { S.foo()<|>; } 760fn test() { S.foo(); }
761 //^ i8
769"#, 762"#,
770 ); 763 );
771 assert_eq!(t, "i8");
772} 764}
773 765
774#[test] 766#[test]
775fn method_resolution_trait_autoderef() { 767fn method_resolution_trait_autoderef() {
776 let t = type_at( 768 check_types(
777 r#" 769 r#"
778//- /main.rs
779trait Trait { fn foo(self) -> u128; } 770trait Trait { fn foo(self) -> u128; }
780struct S; 771struct S;
781impl Trait for S { fn foo(self) -> u128 { 0 } } 772impl Trait for S { fn foo(self) -> u128 { 0 } }
782fn test() { (&S).foo()<|>; } 773fn test() { (&S).foo(); }
774 //^ u128
783"#, 775"#,
784 ); 776 );
785 assert_eq!(t, "u128");
786} 777}
787 778
788#[test] 779#[test]
789fn method_resolution_unsize_array() { 780fn method_resolution_unsize_array() {
790 let t = type_at( 781 check_types(
791 r#" 782 r#"
792//- /main.rs
793#[lang = "slice"] 783#[lang = "slice"]
794impl<T> [T] { 784impl<T> [T] {
795 fn len(&self) -> usize { loop {} } 785 fn len(&self) -> usize { loop {} }
796} 786}
797fn test() { 787fn test() {
798 let a = [1, 2, 3]; 788 let a = [1, 2, 3];
799 a.len()<|>; 789 a.len();
800} 790} //^ usize
801"#, 791"#,
802 ); 792 );
803 assert_eq!(t, "usize");
804} 793}
805 794
806#[test] 795#[test]
807fn method_resolution_trait_from_prelude() { 796fn method_resolution_trait_from_prelude() {
808 let (db, pos) = TestDB::with_position( 797 check_types(
809 r#" 798 r#"
810//- /main.rs crate:main deps:other_crate 799//- /main.rs crate:main deps:other_crate
811struct S; 800struct S;
812impl Clone for S {} 801impl Clone for S {}
813 802
814fn test() { 803fn test() {
815 S.clone()<|>; 804 S.clone();
805 //^ S
816} 806}
817 807
818//- /lib.rs crate:other_crate 808//- /lib.rs crate:other_crate
@@ -825,115 +815,107 @@ mod foo {
825} 815}
826"#, 816"#,
827 ); 817 );
828 assert_eq!("S", type_at_pos(&db, pos));
829} 818}
830 819
831#[test] 820#[test]
832fn method_resolution_where_clause_for_unknown_trait() { 821fn method_resolution_where_clause_for_unknown_trait() {
833 // The blanket impl currently applies because we ignore the unresolved where clause 822 // The blanket impl currently applies because we ignore the unresolved where clause
834 let t = type_at( 823 check_types(
835 r#" 824 r#"
836//- /main.rs
837trait Trait { fn foo(self) -> u128; } 825trait Trait { fn foo(self) -> u128; }
838struct S; 826struct S;
839impl<T> Trait for T where T: UnknownTrait {} 827impl<T> Trait for T where T: UnknownTrait {}
840fn test() { (&S).foo()<|>; } 828fn test() { (&S).foo(); }
829 //^ u128
841"#, 830"#,
842 ); 831 );
843 assert_eq!(t, "u128");
844} 832}
845 833
846#[test] 834#[test]
847fn method_resolution_where_clause_not_met() { 835fn method_resolution_where_clause_not_met() {
848 // The blanket impl shouldn't apply because we can't prove S: Clone 836 // The blanket impl shouldn't apply because we can't prove S: Clone
849 let t = type_at( 837 // This is also to make sure that we don't resolve to the foo method just
838 // because that's the only method named foo we can find, which would make
839 // the below tests not work
840 check_types(
850 r#" 841 r#"
851//- /main.rs
852trait Clone {} 842trait Clone {}
853trait Trait { fn foo(self) -> u128; } 843trait Trait { fn foo(self) -> u128; }
854struct S; 844struct S;
855impl<T> Trait for T where T: Clone {} 845impl<T> Trait for T where T: Clone {}
856fn test() { (&S).foo()<|>; } 846fn test() { (&S).foo(); }
847 //^ {unknown}
857"#, 848"#,
858 ); 849 );
859 // This is also to make sure that we don't resolve to the foo method just
860 // because that's the only method named foo we can find, which would make
861 // the below tests not work
862 assert_eq!(t, "{unknown}");
863} 850}
864 851
865#[test] 852#[test]
866fn method_resolution_where_clause_inline_not_met() { 853fn method_resolution_where_clause_inline_not_met() {
867 // The blanket impl shouldn't apply because we can't prove S: Clone 854 // The blanket impl shouldn't apply because we can't prove S: Clone
868 let t = type_at( 855 check_types(
869 r#" 856 r#"
870//- /main.rs
871trait Clone {} 857trait Clone {}
872trait Trait { fn foo(self) -> u128; } 858trait Trait { fn foo(self) -> u128; }
873struct S; 859struct S;
874impl<T: Clone> Trait for T {} 860impl<T: Clone> Trait for T {}
875fn test() { (&S).foo()<|>; } 861fn test() { (&S).foo(); }
862 //^ {unknown}
876"#, 863"#,
877 ); 864 );
878 assert_eq!(t, "{unknown}");
879} 865}
880 866
881#[test] 867#[test]
882fn method_resolution_where_clause_1() { 868fn method_resolution_where_clause_1() {
883 let t = type_at( 869 check_types(
884 r#" 870 r#"
885//- /main.rs
886trait Clone {} 871trait Clone {}
887trait Trait { fn foo(self) -> u128; } 872trait Trait { fn foo(self) -> u128; }
888struct S; 873struct S;
889impl Clone for S {} 874impl Clone for S {}
890impl<T> Trait for T where T: Clone {} 875impl<T> Trait for T where T: Clone {}
891fn test() { S.foo()<|>; } 876fn test() { S.foo(); }
877 //^ u128
892"#, 878"#,
893 ); 879 );
894 assert_eq!(t, "u128");
895} 880}
896 881
897#[test] 882#[test]
898fn method_resolution_where_clause_2() { 883fn method_resolution_where_clause_2() {
899 let t = type_at( 884 check_types(
900 r#" 885 r#"
901//- /main.rs
902trait Into<T> { fn into(self) -> T; } 886trait Into<T> { fn into(self) -> T; }
903trait From<T> { fn from(other: T) -> Self; } 887trait From<T> { fn from(other: T) -> Self; }
904struct S1; 888struct S1;
905struct S2; 889struct S2;
906impl From<S2> for S1 {} 890impl From<S2> for S1 {}
907impl<T, U> Into<U> for T where U: From<T> {} 891impl<T, U> Into<U> for T where U: From<T> {}
908fn test() { S2.into()<|>; } 892fn test() { S2.into(); }
893 //^ {unknown}
909"#, 894"#,
910 ); 895 );
911 assert_eq!(t, "{unknown}");
912} 896}
913 897
914#[test] 898#[test]
915fn method_resolution_where_clause_inline() { 899fn method_resolution_where_clause_inline() {
916 let t = type_at( 900 check_types(
917 r#" 901 r#"
918//- /main.rs
919trait Into<T> { fn into(self) -> T; } 902trait Into<T> { fn into(self) -> T; }
920trait From<T> { fn from(other: T) -> Self; } 903trait From<T> { fn from(other: T) -> Self; }
921struct S1; 904struct S1;
922struct S2; 905struct S2;
923impl From<S2> for S1 {} 906impl From<S2> for S1 {}
924impl<T, U: From<T>> Into<U> for T {} 907impl<T, U: From<T>> Into<U> for T {}
925fn test() { S2.into()<|>; } 908fn test() { S2.into(); }
909 //^ {unknown}
926"#, 910"#,
927 ); 911 );
928 assert_eq!(t, "{unknown}");
929} 912}
930 913
931#[test] 914#[test]
932fn method_resolution_overloaded_method() { 915fn method_resolution_overloaded_method() {
933 test_utils::mark::check!(impl_self_type_match_without_receiver); 916 test_utils::mark::check!(impl_self_type_match_without_receiver);
934 let t = type_at( 917 check_types(
935 r#" 918 r#"
936//- /main.rs
937struct Wrapper<T>(T); 919struct Wrapper<T>(T);
938struct Foo<T>(T); 920struct Foo<T>(T);
939struct Bar<T>(T); 921struct Bar<T>(T);
@@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> {
953fn main() { 935fn main() {
954 let a = Wrapper::<Foo<f32>>::new(1.0); 936 let a = Wrapper::<Foo<f32>>::new(1.0);
955 let b = Wrapper::<Bar<f32>>::new(1.0); 937 let b = Wrapper::<Bar<f32>>::new(1.0);
956 (a, b)<|>; 938 (a, b);
939 //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
957} 940}
958"#, 941"#,
959 ); 942 );
960 assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)")
961} 943}
962 944
963#[test] 945#[test]
964fn method_resolution_encountering_fn_type() { 946fn method_resolution_encountering_fn_type() {
965 type_at( 947 check_types(
966 r#" 948 r#"
967//- /main.rs 949//- /main.rs
968fn foo() {} 950fn foo() {}
969trait FnOnce { fn call(self); } 951trait FnOnce { fn call(self); }
970fn test() { foo.call()<|>; } 952fn test() { foo.call(); }
953 //^ {unknown}
971"#, 954"#,
972 ); 955 );
973} 956}
974 957
975#[test] 958#[test]
976fn method_resolution_non_parameter_type() { 959fn method_resolution_non_parameter_type() {
977 let t = type_at( 960 check_types(
978 r#" 961 r#"
979//- /main.rs
980mod a { 962mod a {
981 pub trait Foo { 963 pub trait Foo {
982 fn foo(&self); 964 fn foo(&self);
@@ -988,18 +970,16 @@ fn foo<T>(t: Wrapper<T>)
988where 970where
989 Wrapper<T>: a::Foo, 971 Wrapper<T>: a::Foo,
990{ 972{
991 t.foo()<|>; 973 t.foo();
992} 974} //^ {unknown}
993"#, 975"#,
994 ); 976 );
995 assert_eq!(t, "{unknown}");
996} 977}
997 978
998#[test] 979#[test]
999fn method_resolution_3373() { 980fn method_resolution_3373() {
1000 let t = type_at( 981 check_types(
1001 r#" 982 r#"
1002//- /main.rs
1003struct A<T>(T); 983struct A<T>(T);
1004