diff options
Diffstat (limited to 'crates')
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] | ||
2 | name = "expect" | ||
3 | version = "0.1.0" | ||
4 | authors = ["rust-analyzer developers"] | ||
5 | edition = "2018" | ||
6 | |||
7 | [dependencies] | ||
8 | once_cell = "1" | ||
9 | difference = "2" | ||
10 | stdx = { 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 | ||
3 | use std::{ | ||
4 | collections::HashMap, | ||
5 | env, fmt, fs, | ||
6 | ops::Range, | ||
7 | panic, | ||
8 | path::{Path, PathBuf}, | ||
9 | sync::Mutex, | ||
10 | }; | ||
11 | |||
12 | use difference::Changeset; | ||
13 | use once_cell::sync::Lazy; | ||
14 | use stdx::{lines_with_ends, trim_indent}; | ||
15 | |||
16 | const HELP: &str = " | ||
17 | You can update all `expect![[]]` tests by: | ||
18 | |||
19 | env UPDATE_EXPECT=1 cargo test | ||
20 | |||
21 | To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer. | ||
22 | "; | ||
23 | |||
24 | fn update_expect() -> bool { | ||
25 | env::var("UPDATE_EXPECT").is_ok() | ||
26 | } | ||
27 | |||
28 | /// expect![[""]] | ||
29 | #[macro_export] | ||
30 | macro_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)] | ||
41 | pub struct Expect { | ||
42 | pub file: &'static str, | ||
43 | pub line: u32, | ||
44 | pub column: u32, | ||
45 | pub data: &'static str, | ||
46 | } | ||
47 | |||
48 | impl 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)] | ||
91 | struct Runtime { | ||
92 | help_printed: bool, | ||
93 | per_file: HashMap<&'static str, FileRuntime>, | ||
94 | } | ||
95 | static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default); | ||
96 | |||
97 | impl 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 | |||
142 | struct FileRuntime { | ||
143 | path: PathBuf, | ||
144 | original_text: String, | ||
145 | patchwork: Patchwork, | ||
146 | } | ||
147 | |||
148 | impl 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)] | ||
164 | struct Location { | ||
165 | line_indent: usize, | ||
166 | literal_range: Range<usize>, | ||
167 | } | ||
168 | |||
169 | #[derive(Debug)] | ||
170 | struct Patchwork { | ||
171 | text: String, | ||
172 | indels: Vec<(Range<usize>, usize)>, | ||
173 | } | ||
174 | |||
175 | impl 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 | |||
199 | fn 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 | |||
238 | fn 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)] | ||
249 | mod 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 @@ | |||
5 | use std::{ | 5 | use 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)] |
50 | pub struct FlycheckHandle { | 51 | pub 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 | ||
56 | impl FlycheckHandle { | 57 | impl 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 { | |||
85 | pub enum Progress { | 85 | pub 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 | ||
107 | enum Event { | 106 | enum 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 | ||
235 | fn run_cargo( | 215 | struct 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 | 222 | impl 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 | |||
250 | struct CargoActor { | ||
251 | child_stdout: process::ChildStdout, | ||
252 | sender: Sender<cargo_metadata::Message>, | ||
253 | } | ||
254 | |||
255 | impl 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 | 296 | struct JodChild(process::Child); |
269 | let _ = child.kill(); | ||
270 | 297 | ||
271 | let exit_status = child.wait()?; | 298 | impl 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(()) | 305 | impl ops::DerefMut for JodChild { |
306 | fn deref_mut(&mut self) -> &mut process::Child { | ||
307 | &mut self.0 | ||
308 | } | ||
309 | } | ||
310 | |||
311 | impl 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::{ | |||
55 | pub(crate) struct AssistContext<'a> { | 55 | pub(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 @@ | |||
2 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
3 | 3 | ||
4 | use hir::{HirDisplay, PathResolution, SemanticsScope}; | 4 | use hir::{HirDisplay, PathResolution, SemanticsScope}; |
5 | use ra_ide_db::RootDatabase; | ||
6 | use ra_syntax::{ | 5 | use 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 | ||
34 | pub struct SubstituteTypeParams<'a> { | 33 | pub 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 | ||
40 | impl<'a> SubstituteTypeParams<'a> { | 39 | impl<'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 | ||
128 | pub struct QualifyPaths<'a> { | 127 | pub 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 | ||
134 | impl<'a> QualifyPaths<'a> { | 133 | impl<'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) |
124 | fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { | 124 | fn 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 | // ``` |
37 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 37 | pub(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 @@ | |||
1 | use ra_syntax::{ | 1 | use 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 | }; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | 9 | use 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 | ||
32 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | fn 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 | ||
74 | fn 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 | |||
85 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | 70 | fn 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 @@ | |||
1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | 1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; |
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ast, AstNode, TextRange, TextSize}; |
4 | ast, AstNode, | ||
5 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | ||
6 | SyntaxNode, TextRange, TextSize, | ||
7 | }; | ||
8 | 4 | ||
9 | use crate::{AssistContext, AssistId, Assists}; | 5 | use 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 | ||
180 | fn 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)] |
192 | mod tests { | 177 | mod 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 | ||
83 | fn contains_placeholder(a: &ast::MatchArm) -> bool { | 83 | fn 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 @@ | |||
1 | use std::collections::HashMap; | 1 | use itertools::Itertools; |
2 | use rustc_hash::FxHashMap; | ||
2 | 3 | ||
3 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | 4 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; |
4 | use itertools::Itertools; | ||
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; | 6 | use 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 | ||
90 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> { | 90 | fn 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}; | |||
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | use ra_syntax::{ | 8 | use 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 | }; |
12 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
13 | 15 | ||
@@ -120,6 +122,13 @@ pub(crate) fn resolve_target_trait( | |||
120 | } | 122 | } |
121 | } | 123 | } |
122 | 124 | ||
125 | pub(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 | |||
123 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | 132 | pub(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)] |
68 | pub struct CrateId(pub u32); | 68 | pub struct CrateId(pub u32); |
69 | 69 | ||
70 | #[derive(Debug, Clone, PartialEq, Eq)] | 70 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
71 | pub struct CrateName(SmolStr); | 71 | pub struct CrateName(SmolStr); |
72 | 72 | ||
73 | impl CrateName { | 73 | impl CrateName { |
@@ -94,6 +94,13 @@ impl fmt::Display for CrateName { | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | impl 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)] |
98 | pub struct ProcMacroId(pub u32); | 105 | pub 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)] |
139 | pub struct Dependency { | 146 | pub struct Dependency { |
140 | pub crate_id: CrateId, | 147 | pub crate_id: CrateId, |
141 | pub name: SmolStr, | 148 | pub name: CrateName, |
142 | } | 149 | } |
143 | 150 | ||
144 | impl CrateGraph { | 151 | impl 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 | ||
249 | impl CrateData { | 256 | impl 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)] |
84 | pub struct FileRange { | 84 | pub 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 | }; |
34 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 34 | use ra_db::{CrateId, Edition, FileId}; |
35 | use ra_prof::profile; | 35 | use ra_prof::profile; |
36 | use ra_syntax::ast::{self, AttrsOwner, NameOwner}; | 36 | use ra_syntax::ast::{self, AttrsOwner, NameOwner}; |
37 | use rustc_hash::FxHashSet; | 37 | use 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); | |||
543 | impl Adt { | 543 | impl 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 { | |||
775 | impl TypeAlias { | 775 | impl 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 | ||
422 | pub struct SemanticsScope<'a, DB> { | 422 | pub struct SemanticsScope<'a> { |
423 | pub db: &'a DB, | 423 | pub db: &'a dyn HirDatabase, |
424 | resolver: Resolver, | 424 | resolver: Resolver, |
425 | } | 425 | } |
426 | 426 | ||
427 | impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | 427 | impl<'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 | ||
4 | use std::collections::hash_map::Entry; | ||
5 | |||
4 | use hir_expand::name::Name; | 6 | use hir_expand::name::Name; |
5 | use once_cell::sync::Lazy; | 7 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 8 | use ra_db::CrateId; |
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports { | |||
27 | 29 | ||
28 | #[derive(Debug, Default, PartialEq, Eq)] | 30 | #[derive(Debug, Default, PartialEq, Eq)] |
29 | pub struct ItemScope { | 31 | pub 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. |
66 | impl ItemScope { | 72 | impl 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) = ¶m.name { | 519 | if let Some(name) = ¶m.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 | ||
341 | fn 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 | |||
340 | fn include_str_expand( | 359 | fn 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 | ||
29 | pub trait AstDiagnostic { | 29 | pub 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 | ||
34 | impl dyn Diagnostic { | 34 | impl 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 | ||
118 | impl AsName for ra_db::Dependency { | 118 | impl 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 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } | 30 | chalk-solve = { version = "0.15.0" } |
31 | chalk-ir = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } | 31 | chalk-ir = { version = "0.15.0" } |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | insta = "0.16.0" | 34 | insta = "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 | }; |
19 | use hir_expand::name::Name; | 19 | use 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 { | |||
32 | impl AstDiagnostic for NoSuchField { | 32 | impl 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 { | |||
65 | impl AstDiagnostic for MissingFields { | 65 | impl 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 { | |||
135 | impl AstDiagnostic for MissingOkInTailExpr { | 135 | impl 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 { | |||
163 | impl AstDiagnostic for BreakOutsideOfLoop { | 163 | impl 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 { | |||
191 | impl AstDiagnostic for MissingUnsafe { | 191 | impl 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 | ||
621 | impl GenericPredicate { | 621 | impl 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 |
948 | pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> Substs { | 950 | pub(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 | ||
961 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | 988 | fn 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::{ | |||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; |
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | use rustc_hash::FxHashSet; | 11 | use ra_syntax::TextRange; |
12 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
12 | use stdx::format_to; | 13 | use stdx::format_to; |
14 | use test_utils::extract_annotations; | ||
13 | 15 | ||
14 | use crate::{ | 16 | use 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 | ||
159 | impl TestDB { | 184 | impl 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 | }; |
22 | use hir_expand::{db::AstDatabase, InFile}; | 22 | use hir_expand::{db::AstDatabase, InFile}; |
23 | use insta::assert_snapshot; | 23 | use insta::assert_snapshot; |
24 | use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; | 24 | use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase}; |
25 | use ra_syntax::{ | 25 | use 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 | ||
40 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 40 | fn 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 | ||
44 | fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { | 44 | fn 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 | ||
48 | fn type_at_pos_displayed( | 48 | fn 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 | |||
67 | fn 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 | ||
70 | fn 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 | |||
75 | fn infer(ra_fixture: &str) -> String { | 84 | fn 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 @@ | |||
1 | use super::infer_with_mismatches; | ||
2 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
3 | use test_utils::mark; | 2 | use test_utils::mark; |
4 | 3 | ||
4 | use super::infer_with_mismatches; | ||
5 | |||
5 | // Infer with some common definitions and impls. | 6 | // Infer with some common definitions and impls. |
6 | fn infer(source: &str) -> String { | 7 | fn 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 @@ | |||
1 | use super::displayed_source_at_pos; | 1 | use super::check_types_source_code; |
2 | use crate::test_db::TestDB; | ||
3 | use ra_db::fixture::WithFixture; | ||
4 | 2 | ||
5 | #[test] | 3 | #[test] |
6 | fn qualify_path_to_submodule() { | 4 | fn qualify_path_to_submodule() { |
7 | let (db, pos) = TestDB::with_position( | 5 | check_types_source_code( |
8 | r#" | 6 | r#" |
9 | //- /main.rs | ||
10 | |||
11 | mod foo { | 7 | mod foo { |
12 | pub struct Foo; | 8 | pub struct Foo; |
13 | } | 9 | } |
14 | 10 | ||
15 | fn bar() { | 11 | fn 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] |
26 | fn omit_default_type_parameters() { | 21 | fn omit_default_type_parameters() { |
27 | let (db, pos) = TestDB::with_position( | 22 | check_types_source_code( |
28 | r" | 23 | r#" |
29 | //- /main.rs | 24 | struct Foo<T = u8> { t: T } |
30 | struct Foo<T = u8> { t: T } | 25 | fn 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 | 34 | struct Foo<K, T = u8> { k: K, t: T } |
42 | struct Foo<K, T = u8> { k: K, t: T } | 35 | fn 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 @@ | |||
1 | use std::fs; | 1 | use std::fs; |
2 | 2 | ||
3 | use insta::assert_snapshot; | 3 | use insta::assert_snapshot; |
4 | use ra_db::fixture::WithFixture; | ||
5 | use test_utils::project_dir; | 4 | use test_utils::project_dir; |
6 | 5 | ||
7 | use crate::test_db::TestDB; | 6 | use super::{check_types, infer}; |
8 | |||
9 | use super::{infer, type_at, type_at_pos}; | ||
10 | 7 | ||
11 | #[test] | 8 | #[test] |
12 | fn cfg_impl_def() { | 9 | fn 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 |
16 | use foo::S as T; | 13 | use foo::S as T; |
@@ -28,8 +25,8 @@ impl S { | |||
28 | 25 | ||
29 | fn test() { | 26 | fn 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 |
35 | struct S; | 32 | struct 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] |
255 | fn processes_impls_generated_by_macros() { | 251 | fn processes_impls_generated_by_macros() { |
256 | let t = type_at( | 252 | check_types( |
257 | r#" | 253 | r#" |
258 | //- /main.rs | ||
259 | macro_rules! m { | 254 | macro_rules! m { |
260 | ($ident:ident) => (impl Trait for $ident {}) | 255 | ($ident:ident) => (impl Trait for $ident {}) |
261 | } | 256 | } |
262 | trait Trait { fn foo(self) -> u128 {} } | 257 | trait Trait { fn foo(self) -> u128 {} } |
263 | struct S; | 258 | struct S; |
264 | m!(S); | 259 | m!(S); |
265 | fn test() { S.foo()<|>; } | 260 | fn test() { S.foo(); } |
261 | //^ u128 | ||
266 | "#, | 262 | "#, |
267 | ); | 263 | ); |
268 | assert_eq!(t, "u128"); | ||
269 | } | 264 | } |
270 | 265 | ||
271 | #[test] | 266 | #[test] |
272 | fn infer_assoc_items_generated_by_macros() { | 267 | fn infer_assoc_items_generated_by_macros() { |
273 | let t = type_at( | 268 | check_types( |
274 | r#" | 269 | r#" |
275 | //- /main.rs | ||
276 | macro_rules! m { | 270 | macro_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 | ||
284 | fn test() { S.foo()<|>; } | 278 | fn test() { S.foo(); } |
279 | //^ u128 | ||
285 | "#, | 280 | "#, |
286 | ); | 281 | ); |
287 | assert_eq!(t, "u128"); | ||
288 | } | 282 | } |
289 | 283 | ||
290 | #[test] | 284 | #[test] |
291 | fn infer_assoc_items_generated_by_macros_chain() { | 285 | fn infer_assoc_items_generated_by_macros_chain() { |
292 | let t = type_at( | 286 | check_types( |
293 | r#" | 287 | r#" |
294 | //- /main.rs | ||
295 | macro_rules! m_inner { | 288 | macro_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 | ||
307 | fn test() { S.foo()<|>; } | 300 | fn test() { S.foo(); } |
301 | //^ u128 | ||
308 | "#, | 302 | "#, |
309 | ); | 303 | ); |
310 | assert_eq!(t, "u128"); | ||
311 | } | 304 | } |
312 | 305 | ||
313 | #[test] | 306 | #[test] |
314 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | 307 | fn 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 |
318 | fn test() { | 311 | fn 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 { | |||
335 | pub fn baz() -> usize { 31usize } | 328 | pub 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] |
342 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { | 334 | fn 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 |
346 | use foo::Trait; | 338 | use foo::Trait; |
@@ -348,7 +340,8 @@ use foo::Trait; | |||
348 | fn test() { | 340 | fn 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 { | |||
375 | expand!(); | 368 | expand!(); |
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] |
431 | fn infer_local_inner_macros() { | 423 | fn 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 |
435 | fn test() { | 427 | fn 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] |
533 | fn infer_builtin_macros_include() { | 524 | fn 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 {() => {}} | |||
540 | include!("foo.rs"); | 531 | include!("foo.rs"); |
541 | 532 | ||
542 | fn main() { | 533 | fn main() { |
543 | bar()<|>; | 534 | bar(); |
544 | } | 535 | } //^ u32 |
545 | 536 | ||
546 | //- /foo.rs | 537 | //- /foo.rs |
547 | fn bar() -> u32 {0} | 538 | fn 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 {() => {}} | |||
565 | include!("foo.rs"); | 555 | include!("foo.rs"); |
566 | 556 | ||
567 | fn main() { | 557 | fn 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] |
578 | fn infer_builtin_macros_include_concat() { | 567 | fn 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 {() => {}} | |||
588 | include!(concat!("f", "oo.rs")); | 577 | include!(concat!("f", "oo.rs")); |
589 | 578 | ||
590 | fn main() { | 579 | fn main() { |
591 | bar()<|>; | 580 | bar(); |
592 | } | 581 | } //^ u32 |
593 | 582 | ||
594 | //- /foo.rs | 583 | //- /foo.rs |
595 | fn bar() -> u32 {0} | 584 | fn bar() -> u32 {0} |
596 | "#, | 585 | "#, |
597 | ); | 586 | ); |
598 | assert_eq!("u32", type_at_pos(&db, pos)); | ||
599 | } | 587 | } |
600 | 588 | ||
601 | #[test] | 589 | #[test] |
602 | fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { | 590 | fn 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 {() => {}} | |||
615 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); | 603 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); |
616 | 604 | ||
617 | fn main() { | 605 | fn main() { |
618 | bar()<|>; | 606 | bar(); |
619 | } | 607 | } //^ {unknown} |
620 | 608 | ||
621 | //- /foo.rs | 609 | //- /foo.rs |
622 | fn bar() -> u32 {0} | 610 | fn bar() -> u32 {0} |
623 | "#, | 611 | "#, |
624 | ); | 612 | ); |
625 | assert_eq!("{unknown}", type_at_pos(&db, pos)); | ||
626 | } | 613 | } |
627 | 614 | ||
628 | #[test] | 615 | #[test] |
629 | fn infer_builtin_macros_include_itself_should_failed() { | 616 | fn 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] |
634 | macro_rules! include {() => {}} | 620 | macro_rules! include {() => {}} |
635 | 621 | ||
636 | include!("main.rs"); | 622 | include!("main.rs"); |
637 | 623 | ||
638 | fn main() { | 624 | fn 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] |
688 | fn infer_derive_clone_simple() { | 673 | fn 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)] |
693 | struct S; | 678 | struct S; |
694 | fn test() { | 679 | fn 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] |
712 | fn infer_derive_clone_in_core() { | 696 | fn 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 |
727 | use core::S; | 711 | use core::S; |
728 | fn test() { | 712 | fn 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] |
737 | fn infer_derive_clone_with_params() { | 720 | fn 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; | |||
744 | struct Wrapper<T>(T); | 727 | struct Wrapper<T>(T); |
745 | struct NonClone; | 728 | struct NonClone; |
746 | fn test() { | 729 | fn 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] |
764 | fn infer_custom_derive_simple() { | 747 | fn 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 |
769 | use foo::Foo; | 752 | use foo::Foo; |
@@ -772,11 +755,10 @@ use foo::Foo; | |||
772 | struct S{} | 755 | struct S{} |
773 | 756 | ||
774 | fn test() { | 757 | fn 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 @@ | |||
1 | use super::{infer, type_at, type_at_pos}; | ||
2 | use crate::test_db::TestDB; | ||
3 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
4 | use ra_db::fixture::WithFixture; | 2 | |
3 | use super::{check_types, infer}; | ||
5 | 4 | ||
6 | #[test] | 5 | #[test] |
7 | fn infer_slice_method() { | 6 | fn infer_slice_method() { |
@@ -246,13 +245,13 @@ fn test() { | |||
246 | 245 | ||
247 | #[test] | 246 | #[test] |
248 | fn cross_crate_associated_method_call() { | 247 | fn 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 |
252 | fn test() { | 251 | fn 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 |
258 | mod foo { | 257 | mod 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] |
686 | fn method_resolution_unify_impl_self_type() { | 684 | fn method_resolution_unify_impl_self_type() { |
687 | let t = type_at( | 685 | check_types( |
688 | r#" | 686 | r#" |
689 | //- /main.rs | ||
690 | struct S<T>; | 687 | struct S<T>; |
691 | impl S<u32> { fn foo(&self) -> u8 {} } | 688 | impl S<u32> { fn foo(&self) -> u8 {} } |
692 | impl S<i32> { fn foo(&self) -> i8 {} } | 689 | impl S<i32> { fn foo(&self) -> i8 {} } |
693 | fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; } | 690 | fn 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] |
700 | fn method_resolution_trait_before_autoref() { | 697 | fn method_resolution_trait_before_autoref() { |
701 | let t = type_at( | 698 | check_types( |
702 | r#" | 699 | r#" |
703 | //- /main.rs | ||
704 | trait Trait { fn foo(self) -> u128; } | 700 | trait Trait { fn foo(self) -> u128; } |
705 | struct S; | 701 | struct S; |
706 | impl S { fn foo(&self) -> i8 { 0 } } | 702 | impl S { fn foo(&self) -> i8 { 0 } } |
707 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 703 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
708 | fn test() { S.foo()<|>; } | 704 | fn test() { S.foo(); } |
705 | //^ u128 | ||
709 | "#, | 706 | "#, |
710 | ); | 707 | ); |
711 | assert_eq!(t, "u128"); | ||
712 | } | 708 | } |
713 | 709 | ||
714 | #[test] | 710 | #[test] |
715 | fn method_resolution_by_value_before_autoref() { | 711 | fn method_resolution_by_value_before_autoref() { |
716 | let t = type_at( | 712 | check_types( |
717 | r#" | 713 | r#" |
718 | //- /main.rs | ||
719 | trait Clone { fn clone(&self) -> Self; } | 714 | trait Clone { fn clone(&self) -> Self; } |
720 | struct S; | 715 | struct S; |
721 | impl Clone for S {} | 716 | impl Clone for S {} |
722 | impl Clone for &S {} | 717 | impl Clone for &S {} |
723 | fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } | 718 | fn 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] |
730 | fn method_resolution_trait_before_autoderef() { | 725 | fn method_resolution_trait_before_autoderef() { |
731 | let t = type_at( | 726 | check_types( |
732 | r#" | 727 | r#" |
733 | //- /main.rs | ||
734 | trait Trait { fn foo(self) -> u128; } | 728 | trait Trait { fn foo(self) -> u128; } |
735 | struct S; | 729 | struct S; |
736 | impl S { fn foo(self) -> i8 { 0 } } | 730 | impl S { fn foo(self) -> i8 { 0 } } |
737 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 731 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
738 | fn test() { (&S).foo()<|>; } | 732 | fn test() { (&S).foo(); } |
733 | //^ u128 | ||
739 | "#, | 734 | "#, |
740 | ); | 735 | ); |
741 | assert_eq!(t, "u128"); | ||
742 | } | 736 | } |
743 | 737 | ||
744 | #[test] | 738 | #[test] |
745 | fn method_resolution_impl_before_trait() { | 739 | fn method_resolution_impl_before_trait() { |
746 | let t = type_at( | 740 | check_types( |
747 | r#" | 741 | r#" |
748 | //- /main.rs | ||
749 | trait Trait { fn foo(self) -> u128; } | 742 | trait Trait { fn foo(self) -> u128; } |
750 | struct S; | 743 | struct S; |
751 | impl S { fn foo(self) -> i8 { 0 } } | 744 | impl S { fn foo(self) -> i8 { 0 } } |
752 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 745 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
753 | fn test() { S.foo()<|>; } | 746 | fn test() { S.foo(); } |
747 | //^ i8 | ||
754 | "#, | 748 | "#, |
755 | ); | 749 | ); |
756 | assert_eq!(t, "i8"); | ||
757 | } | 750 | } |
758 | 751 | ||
759 | #[test] | 752 | #[test] |
760 | fn method_resolution_impl_ref_before_trait() { | 753 | fn method_resolution_impl_ref_before_trait() { |
761 | let t = type_at( | 754 | check_types( |
762 | r#" | 755 | r#" |
763 | //- /main.rs | ||
764 | trait Trait { fn foo(self) -> u128; } | 756 | trait Trait { fn foo(self) -> u128; } |
765 | struct S; | 757 | struct S; |
766 | impl S { fn foo(&self) -> i8 { 0 } } | 758 | impl S { fn foo(&self) -> i8 { 0 } } |
767 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 759 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
768 | fn test() { S.foo()<|>; } | 760 | fn test() { S.foo(); } |
761 | //^ i8 | ||
769 | "#, | 762 | "#, |
770 | ); | 763 | ); |
771 | assert_eq!(t, "i8"); | ||
772 | } | 764 | } |
773 | 765 | ||
774 | #[test] | 766 | #[test] |
775 | fn method_resolution_trait_autoderef() { | 767 | fn method_resolution_trait_autoderef() { |
776 | let t = type_at( | 768 | check_types( |
777 | r#" | 769 | r#" |
778 | //- /main.rs | ||
779 | trait Trait { fn foo(self) -> u128; } | 770 | trait Trait { fn foo(self) -> u128; } |
780 | struct S; | 771 | struct S; |
781 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 772 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
782 | fn test() { (&S).foo()<|>; } | 773 | fn test() { (&S).foo(); } |
774 | //^ u128 | ||
783 | "#, | 775 | "#, |
784 | ); | 776 | ); |
785 | assert_eq!(t, "u128"); | ||
786 | } | 777 | } |
787 | 778 | ||
788 | #[test] | 779 | #[test] |
789 | fn method_resolution_unsize_array() { | 780 | fn 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"] |
794 | impl<T> [T] { | 784 | impl<T> [T] { |
795 | fn len(&self) -> usize { loop {} } | 785 | fn len(&self) -> usize { loop {} } |
796 | } | 786 | } |
797 | fn test() { | 787 | fn 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] |
807 | fn method_resolution_trait_from_prelude() { | 796 | fn 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 |
811 | struct S; | 800 | struct S; |
812 | impl Clone for S {} | 801 | impl Clone for S {} |
813 | 802 | ||
814 | fn test() { | 803 | fn 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] |
832 | fn method_resolution_where_clause_for_unknown_trait() { | 821 | fn 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 | ||
837 | trait Trait { fn foo(self) -> u128; } | 825 | trait Trait { fn foo(self) -> u128; } |
838 | struct S; | 826 | struct S; |
839 | impl<T> Trait for T where T: UnknownTrait {} | 827 | impl<T> Trait for T where T: UnknownTrait {} |
840 | fn test() { (&S).foo()<|>; } | 828 | fn test() { (&S).foo(); } |
829 | //^ u128 | ||
841 | "#, | 830 | "#, |
842 | ); | 831 | ); |
843 | assert_eq!(t, "u128"); | ||
844 | } | 832 | } |
845 | 833 | ||
846 | #[test] | 834 | #[test] |
847 | fn method_resolution_where_clause_not_met() { | 835 | fn 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 | ||
852 | trait Clone {} | 842 | trait Clone {} |
853 | trait Trait { fn foo(self) -> u128; } | 843 | trait Trait { fn foo(self) -> u128; } |
854 | struct S; | 844 | struct S; |
855 | impl<T> Trait for T where T: Clone {} | 845 | impl<T> Trait for T where T: Clone {} |
856 | fn test() { (&S).foo()<|>; } | 846 | fn 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] |
866 | fn method_resolution_where_clause_inline_not_met() { | 853 | fn 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 | ||
871 | trait Clone {} | 857 | trait Clone {} |
872 | trait Trait { fn foo(self) -> u128; } | 858 | trait Trait { fn foo(self) -> u128; } |
873 | struct S; | 859 | struct S; |
874 | impl<T: Clone> Trait for T {} | 860 | impl<T: Clone> Trait for T {} |
875 | fn test() { (&S).foo()<|>; } | 861 | fn test() { (&S).foo(); } |
862 | //^ {unknown} | ||
876 | "#, | 863 | "#, |
877 | ); | 864 | ); |
878 | assert_eq!(t, "{unknown}"); | ||
879 | } | 865 | } |
880 | 866 | ||
881 | #[test] | 867 | #[test] |
882 | fn method_resolution_where_clause_1() { | 868 | fn method_resolution_where_clause_1() { |
883 | let t = type_at( | 869 | check_types( |
884 | r#" | 870 | r#" |
885 | //- /main.rs | ||
886 | trait Clone {} | 871 | trait Clone {} |
887 | trait Trait { fn foo(self) -> u128; } | 872 | trait Trait { fn foo(self) -> u128; } |
888 | struct S; | 873 | struct S; |
889 | impl Clone for S {} | 874 | impl Clone for S {} |
890 | impl<T> Trait for T where T: Clone {} | 875 | impl<T> Trait for T where T: Clone {} |
891 | fn test() { S.foo()<|>; } | 876 | fn test() { S.foo(); } |
877 | //^ u128 | ||
892 | "#, | 878 | "#, |
893 | ); | 879 | ); |
894 | assert_eq!(t, "u128"); | ||
895 | } | 880 | } |
896 | 881 | ||
897 | #[test] | 882 | #[test] |
898 | fn method_resolution_where_clause_2() { | 883 | fn method_resolution_where_clause_2() { |
899 | let t = type_at( | 884 | check_types( |
900 | r#" | 885 | r#" |
901 | //- /main.rs | ||
902 | trait Into<T> { fn into(self) -> T; } | 886 | trait Into<T> { fn into(self) -> T; } |
903 | trait From<T> { fn from(other: T) -> Self; } | 887 | trait From<T> { fn from(other: T) -> Self; } |
904 | struct S1; | 888 | struct S1; |
905 | struct S2; | 889 | struct S2; |
906 | impl From<S2> for S1 {} | 890 | impl From<S2> for S1 {} |
907 | impl<T, U> Into<U> for T where U: From<T> {} | 891 | impl<T, U> Into<U> for T where U: From<T> {} |
908 | fn test() { S2.into()<|>; } | 892 | fn test() { S2.into(); } |
893 | //^ {unknown} | ||
909 | "#, | 894 | "#, |
910 | ); | 895 | ); |
911 | assert_eq!(t, "{unknown}"); | ||
912 | } | 896 | } |
913 | 897 | ||
914 | #[test] | 898 | #[test] |
915 | fn method_resolution_where_clause_inline() { | 899 | fn method_resolution_where_clause_inline() { |
916 | let t = type_at( | 900 | check_types( |
917 | r#" | 901 | r#" |
918 | //- /main.rs | ||
919 | trait Into<T> { fn into(self) -> T; } | 902 | trait Into<T> { fn into(self) -> T; } |
920 | trait From<T> { fn from(other: T) -> Self; } | 903 | trait From<T> { fn from(other: T) -> Self; } |
921 | struct S1; | 904 | struct S1; |
922 | struct S2; | 905 | struct S2; |
923 | impl From<S2> for S1 {} | 906 | impl From<S2> for S1 {} |
924 | impl<T, U: From<T>> Into<U> for T {} | 907 | impl<T, U: From<T>> Into<U> for T {} |
925 | fn test() { S2.into()<|>; } | 908 | fn test() { S2.into(); } |
909 | //^ {unknown} | ||
926 | "#, | 910 | "#, |
927 | ); | 911 | ); |
928 | assert_eq!(t, "{unknown}"); | ||
929 | } | 912 | } |
930 | 913 | ||
931 | #[test] | 914 | #[test] |
932 | fn method_resolution_overloaded_method() { | 915 | fn 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 | ||
937 | struct Wrapper<T>(T); | 919 | struct Wrapper<T>(T); |
938 | struct Foo<T>(T); | 920 | struct Foo<T>(T); |
939 | struct Bar<T>(T); | 921 | struct Bar<T>(T); |
@@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> { | |||
953 | fn main() { | 935 | fn 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] |
964 | fn method_resolution_encountering_fn_type() { | 946 | fn method_resolution_encountering_fn_type() { |
965 | type_at( | 947 | check_types( |
966 | r#" | 948 | r#" |
967 | //- /main.rs | 949 | //- /main.rs |
968 | fn foo() {} | 950 | fn foo() {} |
969 | trait FnOnce { fn call(self); } | 951 | trait FnOnce { fn call(self); } |
970 | fn test() { foo.call()<|>; } | 952 | fn test() { foo.call(); } |
953 | //^ {unknown} | ||
971 | "#, | 954 | "#, |
972 | ); | 955 | ); |
973 | } | 956 | } |
974 | 957 | ||
975 | #[test] | 958 | #[test] |
976 | fn method_resolution_non_parameter_type() { | 959 | fn method_resolution_non_parameter_type() { |
977 | let t = type_at( | 960 | check_types( |
978 | r#" | 961 | r#" |
979 | //- /main.rs | ||
980 | mod a { | 962 | mod 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>) | |||
988 | where | 970 | where |
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] |
999 | fn method_resolution_3373() { | 980 | fn method_resolution_3373() { |
1000 | let t = type_at( | 981 | check_types( |
1001 | r#" | 982 | r#" |
1002 | //- /main.rs | ||
1003 | struct A<T>(T); | 983 | struct A<T>(T); |
1004 |