aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock28
-rw-r--r--crates/flycheck/src/lib.rs208
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs25
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs19
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs5
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs6
-rw-r--r--crates/ra_assists/src/utils.rs11
-rw-r--r--crates/ra_hir/src/code_model.rs19
-rw-r--r--crates/ra_hir_def/src/body/lower.rs8
-rw-r--r--crates/ra_hir_def/src/expr.rs5
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs73
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_ty/Cargo.toml4
-rw-r--r--crates/ra_hir_ty/src/db.rs4
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs28
-rw-r--r--crates/ra_hir_ty/src/display.rs18
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs7
-rw-r--r--crates/ra_hir_ty/src/lib.rs11
-rw-r--r--crates/ra_hir_ty/src/lower.rs43
-rw-r--r--crates/ra_hir_ty/src/test_db.rs22
-rw-r--r--crates/ra_hir_ty/src/tests.rs199
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/display_source_code.rs49
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs116
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs158
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs118
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs21
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs135
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs342
-rw-r--r--crates/ra_hir_ty/src/unsafe_validation.rs120
-rw-r--r--crates/ra_ide/src/inlay_hints.rs9
-rw-r--r--crates/ra_ide/src/join_lines.rs5
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs5
-rw-r--r--crates/ra_mbe/src/parser.rs5
-rw-r--r--crates/ra_parser/src/grammar.rs5
-rw-r--r--crates/ra_parser/src/grammar/paths.rs5
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs5
-rw-r--r--crates/ra_parser/src/syntax_kind.rs5
-rw-r--r--crates/ra_ssr/src/lib.rs3
-rw-r--r--crates/ra_ssr/src/matching.rs2
-rw-r--r--crates/ra_ssr/src/parsing.rs2
-rw-r--r--crates/ra_ssr/src/replacing.rs33
-rw-r--r--crates/ra_ssr/src/tests.rs17
-rw-r--r--crates/ra_syntax/src/algo.rs4
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs5
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs16
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs5
-rw-r--r--crates/ra_tt/src/buffer.rs5
-rw-r--r--crates/rust-analyzer/src/cli.rs10
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs10
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs7
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs10
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
-rw-r--r--crates/rust-analyzer/src/line_endings.rs14
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs40
-rw-r--r--crates/test_utils/src/lib.rs36
-rw-r--r--crates/vfs-notify/src/lib.rs8
-rw-r--r--docs/dev/README.md5
-rw-r--r--docs/user/manual.adoc2
63 files changed, 1211 insertions, 892 deletions
diff --git a/.gitignore b/.gitignore
index aef0fac33..472fe1a13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,5 @@ crates/*/target
7*.log 7*.log
8*.iml 8*.iml
9.vscode/settings.json 9.vscode/settings.json
10*.html
11generated_assists.adoc 10generated_assists.adoc
12generated_features.adoc 11generated_features.adoc
diff --git a/Cargo.lock b/Cargo.lock
index a70c22a94..b19d697f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -30,7 +30,7 @@ version = "0.11.0"
30source = "registry+https://github.com/rust-lang/crates.io-index" 30source = "registry+https://github.com/rust-lang/crates.io-index"
31checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 31checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
32dependencies = [ 32dependencies = [
33 "winapi 0.3.8", 33 "winapi 0.3.9",
34] 34]
35 35
36[[package]] 36[[package]]
@@ -135,8 +135,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
135 135
136[[package]] 136[[package]]
137name = "chalk-derive" 137name = "chalk-derive"
138version = "0.15.0-dev.0" 138version = "0.15.0"
139source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f" 139source = "registry+https://github.com/rust-lang/crates.io-index"
140checksum = "c7379caa72d04103fcfd9bde5642b816f58e3ffd6a0d39347e9e35a066648226"
140dependencies = [ 141dependencies = [
141 "proc-macro2", 142 "proc-macro2",
142 "quote", 143 "quote",
@@ -146,8 +147,9 @@ dependencies = [
146 147
147[[package]] 148[[package]]
148name = "chalk-engine" 149name = "chalk-engine"
149version = "0.15.0-dev.0" 150version = "0.15.0"
150source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f" 151source = "registry+https://github.com/rust-lang/crates.io-index"
152checksum = "8e8afe48b5663504b485791ab4fae69cf4864869a71ceec9c758fd4d03423722"
151dependencies = [ 153dependencies = [
152 "chalk-derive", 154 "chalk-derive",
153 "chalk-ir", 155 "chalk-ir",
@@ -157,8 +159,9 @@ dependencies = [
157 159
158[[package]] 160[[package]]
159name = "chalk-ir" 161name = "chalk-ir"
160version = "0.15.0-dev.0" 162version = "0.15.0"
161source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f" 163source = "registry+https://github.com/rust-lang/crates.io-index"
164checksum = "231e391a03c1fc45874171d92be9542efedc939bac59d9501ee28b9521feb406"
162dependencies = [ 165dependencies = [
163 "chalk-derive", 166 "chalk-derive",
164 "lazy_static", 167 "lazy_static",
@@ -166,8 +169,9 @@ dependencies = [
166 169
167[[package]] 170[[package]]
168name = "chalk-solve" 171name = "chalk-solve"
169version = "0.15.0-dev.0" 172version = "0.15.0"
170source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f" 173source = "registry+https://github.com/rust-lang/crates.io-index"
174checksum = "72c969c0fd06ad50538253327ca3445ff02cc9d0209f94c3cbf198ad9d365b48"
171dependencies = [ 175dependencies = [
172 "chalk-derive", 176 "chalk-derive",
173 "chalk-engine", 177 "chalk-engine",
@@ -554,9 +558,9 @@ dependencies = [
554 558
555[[package]] 559[[package]]
556name = "instant" 560name = "instant"
557version = "0.1.4" 561version = "0.1.5"
558source = "registry+https://github.com/rust-lang/crates.io-index" 562source = "registry+https://github.com/rust-lang/crates.io-index"
559checksum = "7777a24a1ce5de49fcdde84ec46efa487c3af49d5b6e6e0a50367cc5c1096182" 563checksum = "69da7ce1490173c2bf4d26bc8be429aaeeaf4cce6c4b970b7949651fa17655fe"
560 564
561[[package]] 565[[package]]
562name = "iovec" 566name = "iovec"
@@ -1791,7 +1795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1791checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1795checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
1792dependencies = [ 1796dependencies = [
1793 "libc", 1797 "libc",
1794 "winapi 0.3.8", 1798 "winapi 0.3.9",
1795] 1799]
1796 1800
1797[[package]] 1801[[package]]
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 92ec4f92e..1023d3040 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -5,8 +5,9 @@
5use std::{ 5use std::{
6 fmt, 6 fmt,
7 io::{self, BufReader}, 7 io::{self, BufReader},
8 ops,
8 path::PathBuf, 9 path::PathBuf,
9 process::{Command, Stdio}, 10 process::{self, Command, Stdio},
10 time::Duration, 11 time::Duration,
11}; 12};
12 13
@@ -49,8 +50,8 @@ impl fmt::Display for FlycheckConfig {
49#[derive(Debug)] 50#[derive(Debug)]
50pub struct FlycheckHandle { 51pub struct FlycheckHandle {
51 // XXX: drop order is significant 52 // XXX: drop order is significant
52 cmd_send: Sender<Restart>, 53 sender: Sender<Restart>,
53 handle: jod_thread::JoinHandle, 54 thread: jod_thread::JoinHandle,
54} 55}
55 56
56impl FlycheckHandle { 57impl FlycheckHandle {
@@ -59,16 +60,15 @@ impl FlycheckHandle {
59 config: FlycheckConfig, 60 config: FlycheckConfig,
60 workspace_root: PathBuf, 61 workspace_root: PathBuf,
61 ) -> FlycheckHandle { 62 ) -> FlycheckHandle {
62 let (cmd_send, cmd_recv) = unbounded::<Restart>(); 63 let actor = FlycheckActor::new(sender, config, workspace_root);
63 let handle = jod_thread::spawn(move || { 64 let (sender, receiver) = unbounded::<Restart>();
64 FlycheckActor::new(sender, config, workspace_root).run(cmd_recv); 65 let thread = jod_thread::spawn(move || actor.run(receiver));
65 }); 66 FlycheckHandle { sender, thread }
66 FlycheckHandle { cmd_send, handle }
67 } 67 }
68 68
69 /// Schedule a re-start of the cargo check worker. 69 /// Schedule a re-start of the cargo check worker.
70 pub fn update(&self) { 70 pub fn update(&self) {
71 self.cmd_send.send(Restart).unwrap(); 71 self.sender.send(Restart).unwrap();
72 } 72 }
73} 73}
74 74
@@ -85,7 +85,7 @@ pub enum Message {
85pub enum Progress { 85pub enum Progress {
86 DidStart, 86 DidStart,
87 DidCheckCrate(String), 87 DidCheckCrate(String),
88 DidFinish, 88 DidFinish(io::Result<()>),
89 DidCancel, 89 DidCancel,
90} 90}
91 91
@@ -100,8 +100,7 @@ struct FlycheckActor {
100 /// doesn't provide a way to read sub-process output without blocking, so we 100 /// doesn't provide a way to read sub-process output without blocking, so we
101 /// have to wrap sub-processes output handling in a thread and pass messages 101 /// have to wrap sub-processes output handling in a thread and pass messages
102 /// back over a channel. 102 /// back over a channel.
103 // XXX: drop order is significant 103 cargo_handle: Option<CargoHandle>,
104 check_process: Option<(Receiver<cargo_metadata::Message>, jod_thread::JoinHandle)>,
105} 104}
106 105
107enum Event { 106enum Event {
@@ -115,29 +114,36 @@ impl FlycheckActor {
115 config: FlycheckConfig, 114 config: FlycheckConfig,
116 workspace_root: PathBuf, 115 workspace_root: PathBuf,
117 ) -> FlycheckActor { 116 ) -> FlycheckActor {
118 FlycheckActor { sender, config, workspace_root, check_process: None } 117 FlycheckActor { sender, config, workspace_root, cargo_handle: None }
119 } 118 }
120 fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> { 119 fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
121 let check_chan = self.check_process.as_ref().map(|(chan, _thread)| chan); 120 let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
122 select! { 121 select! {
123 recv(inbox) -> msg => msg.ok().map(Event::Restart), 122 recv(inbox) -> msg => msg.ok().map(Event::Restart),
124 recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())), 123 recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
125 } 124 }
126 } 125 }
127 fn run(&mut self, inbox: Receiver<Restart>) { 126 fn run(mut self, inbox: Receiver<Restart>) {
128 while let Some(event) = self.next_event(&inbox) { 127 while let Some(event) = self.next_event(&inbox) {
129 match event { 128 match event {
130 Event::Restart(Restart) => { 129 Event::Restart(Restart) => {
131 while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} 130 while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {}
131
132 self.cancel_check_process(); 132 self.cancel_check_process();
133 self.check_process = Some(self.start_check_process()); 133
134 self.send(Message::Progress(Progress::DidStart)); 134 let mut command = self.check_command();
135 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
136 if let Ok(child) = command.spawn().map(JodChild) {
137 self.cargo_handle = Some(CargoHandle::spawn(child));
138 self.send(Message::Progress(Progress::DidStart));
139 }
135 } 140 }
136 Event::CheckEvent(None) => { 141 Event::CheckEvent(None) => {
137 // Watcher finished, replace it with a never channel to 142 // Watcher finished, replace it with a never channel to
138 // avoid busy-waiting. 143 // avoid busy-waiting.
139 assert!(self.check_process.take().is_some()); 144 let cargo_handle = self.cargo_handle.take().unwrap();
140 self.send(Message::Progress(Progress::DidFinish)); 145 let res = cargo_handle.join();
146 self.send(Message::Progress(Progress::DidFinish(res)));
141 } 147 }
142 Event::CheckEvent(Some(message)) => match message { 148 Event::CheckEvent(Some(message)) => match message {
143 cargo_metadata::Message::CompilerArtifact(msg) => { 149 cargo_metadata::Message::CompilerArtifact(msg) => {
@@ -162,11 +168,11 @@ impl FlycheckActor {
162 self.cancel_check_process(); 168 self.cancel_check_process();
163 } 169 }
164 fn cancel_check_process(&mut self) { 170 fn cancel_check_process(&mut self) {
165 if self.check_process.take().is_some() { 171 if self.cargo_handle.take().is_some() {
166 self.send(Message::Progress(Progress::DidCancel)); 172 self.send(Message::Progress(Progress::DidCancel));
167 } 173 }
168 } 174 }
169 fn start_check_process(&self) -> (Receiver<cargo_metadata::Message>, jod_thread::JoinHandle) { 175 fn check_command(&self) -> Command {
170 let mut cmd = match &self.config { 176 let mut cmd = match &self.config {
171 FlycheckConfig::CargoCommand { 177 FlycheckConfig::CargoCommand {
172 command, 178 command,
@@ -198,33 +204,7 @@ impl FlycheckActor {
198 } 204 }
199 }; 205 };
200 cmd.current_dir(&self.workspace_root); 206 cmd.current_dir(&self.workspace_root);
201 207 cmd
202 let (message_send, message_recv) = unbounded();
203 let thread = jod_thread::spawn(move || {
204 // If we trigger an error here, we will do so in the loop instead,
205 // which will break out of the loop, and continue the shutdown
206 let res = run_cargo(cmd, &mut |message| {
207 // Skip certain kinds of messages to only spend time on what's useful
208 match &message {
209 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
210 return true
211 }
212 cargo_metadata::Message::BuildScriptExecuted(_)
213 | cargo_metadata::Message::Unknown => return true,
214 _ => {}
215 }
216
217 // if the send channel was closed, we want to shutdown
218 message_send.send(message).is_ok()
219 });
220
221 if let Err(err) = res {
222 // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
223 // to display user-caused misconfiguration errors instead of just logging them here
224 log::error!("Cargo watcher failed {:?}", err);
225 }
226 });
227 (message_recv, thread)
228 } 208 }
229 209
230 fn send(&self, check_task: Message) { 210 fn send(&self, check_task: Message) {
@@ -232,54 +212,104 @@ impl FlycheckActor {
232 } 212 }
233} 213}
234 214
235fn run_cargo( 215struct CargoHandle {
236 mut command: Command, 216 child: JodChild,
237 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, 217 #[allow(unused)]
238) -> io::Result<()> { 218 thread: jod_thread::JoinHandle<io::Result<bool>>,
239 let mut child = 219 receiver: Receiver<cargo_metadata::Message>,
240 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?; 220}
241 221
242 // We manually read a line at a time, instead of using serde's 222impl CargoHandle {
243 // stream deserializers, because the deserializer cannot recover 223 fn spawn(mut child: JodChild) -> CargoHandle {
244 // from an error, resulting in it getting stuck, because we try to 224 let child_stdout = child.stdout.take().unwrap();
245 // be resillient against failures. 225 let (sender, receiver) = unbounded();
246 // 226 let actor = CargoActor::new(child_stdout, sender);
247 // Because cargo only outputs one JSON object per line, we can 227 let thread = jod_thread::spawn(move || actor.run());
248 // simply skip a line if it doesn't parse, which just ignores any 228 CargoHandle { child, thread, receiver }
249 // erroneus output. 229 }
250 let stdout = BufReader::new(child.stdout.take().unwrap()); 230 fn join(mut self) -> io::Result<()> {
251 let mut read_at_least_one_message = false; 231 // It is okay to ignore the result, as it only errors if the process is already dead
252 for message in cargo_metadata::Message::parse_stream(stdout) { 232 let _ = self.child.kill();
253 let message = match message { 233 let exit_status = self.child.wait()?;
254 Ok(message) => message, 234 let read_at_least_one_message = self.thread.join()?;
255 Err(err) => { 235 if !exit_status.success() && !read_at_least_one_message {
256 log::error!("Invalid json from cargo check, ignoring ({})", err); 236 // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
257 continue; 237 // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
258 } 238 return Err(io::Error::new(
259 }; 239 io::ErrorKind::Other,
240 format!(
241 "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})",
242 exit_status
243 ),
244 ));
245 }
246 Ok(())
247 }
248}
249
250struct CargoActor {
251 child_stdout: process::ChildStdout,
252 sender: Sender<cargo_metadata::Message>,
253}
254
255impl CargoActor {
256 fn new(
257 child_stdout: process::ChildStdout,
258 sender: Sender<cargo_metadata::Message>,
259 ) -> CargoActor {
260 CargoActor { child_stdout, sender }
261 }
262 fn run(self) -> io::Result<bool> {
263 // We manually read a line at a time, instead of using serde's
264 // stream deserializers, because the deserializer cannot recover
265 // from an error, resulting in it getting stuck, because we try to
266 // be resilient against failures.
267 //
268 // Because cargo only outputs one JSON object per line, we can
269 // simply skip a line if it doesn't parse, which just ignores any
270 // erroneus output.
271 let stdout = BufReader::new(self.child_stdout);
272 let mut read_at_least_one_message = false;
273 for message in cargo_metadata::Message::parse_stream(stdout) {
274 let message = match message {
275 Ok(message) => message,
276 Err(err) => {
277 log::error!("Invalid json from cargo check, ignoring ({})", err);
278 continue;
279 }
280 };
260 281
261 read_at_least_one_message = true; 282 read_at_least_one_message = true;
262 283
263 if !on_message(message) { 284 // Skip certain kinds of messages to only spend time on what's useful
264 break; 285 match &message {
286 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (),
287 cargo_metadata::Message::BuildScriptExecuted(_)
288 | cargo_metadata::Message::Unknown => (),
289 _ => self.sender.send(message).unwrap(),
290 }
265 } 291 }
292 Ok(read_at_least_one_message)
266 } 293 }
294}
267 295
268 // It is okay to ignore the result, as it only errors if the process is already dead 296struct JodChild(process::Child);
269 let _ = child.kill();
270 297
271 let exit_status = child.wait()?; 298impl ops::Deref for JodChild {
272 if !exit_status.success() && !read_at_least_one_message { 299 type Target = process::Child;
273 // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: 300 fn deref(&self) -> &process::Child {
274 // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 301 &self.0
275 return Err(io::Error::new(
276 io::ErrorKind::Other,
277 format!(
278 "the command produced no valid metadata (exit code: {:?}): {:?}",
279 exit_status, command
280 ),
281 ));
282 } 302 }
303}
283 304
284 Ok(()) 305impl ops::DerefMut for JodChild {
306 fn deref_mut(&mut self) -> &mut process::Child {
307 &mut self.0
308 }
309}
310
311impl Drop for JodChild {
312 fn drop(&mut self) {
313 let _ = self.0.kill();
314 }
285} 315}
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index c21d75be0..157c7b665 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -1,15 +1,12 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{ 4 SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY},
5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, 5 T,
6 WHITESPACE,
7 },
8 SyntaxNode, TextSize, T,
9}; 6};
10use test_utils::mark; 7use test_utils::mark;
11 8
12use crate::{AssistContext, AssistId, Assists}; 9use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
13 10
14// Assist: change_visibility 11// Assist: change_visibility
15// 12//
@@ -30,9 +27,8 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
30} 27}
31 28
32fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { 30 let item_keyword = ctx.token_at_offset().find(|leaf| {
34 T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, 31 matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait])
35 _ => false,
36 }); 32 });
37 33
38 let (offset, target) = if let Some(keyword) = item_keyword { 34 let (offset, target) = if let Some(keyword) = item_keyword {
@@ -71,17 +67,6 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
71 }) 67 })
72} 68}
73 69
74fn vis_offset(node: &SyntaxNode) -> TextSize {
75 node.children_with_tokens()
76 .skip_while(|it| match it.kind() {
77 WHITESPACE | COMMENT | ATTR => true,
78 _ => false,
79 })
80 .next()
81 .map(|it| it.text_range().start())
82 .unwrap_or_else(|| node.text_range().start())
83}
84
85fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { 70fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
86 if vis.syntax().text() == "pub" { 71 if vis.syntax().text() == "pub" {
87 let target = vis.syntax().text_range(); 72 let target = vis.syntax().text_range();
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 54601d1f3..19d4dac5e 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -1,12 +1,8 @@
1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ra_db::FileId; 2use ra_db::FileId;
3use ra_syntax::{ 3use ra_syntax::{ast, AstNode, TextRange, TextSize};
4 ast, AstNode,
5 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
6 SyntaxNode, TextRange, TextSize,
7};
8 4
9use crate::{AssistContext, AssistId, Assists}; 5use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
10 6
11// FIXME: this really should be a fix for diagnostic, rather than an assist. 7// FIXME: this really should be a fix for diagnostic, rather than an assist.
12 8
@@ -177,17 +173,6 @@ fn target_data_for_def(
177 Some((offset, target, target_file, target_name)) 173 Some((offset, target, target_file, target_name))
178} 174}
179 175
180fn vis_offset(node: &SyntaxNode) -> TextSize {
181 node.children_with_tokens()
182 .skip_while(|it| match it.kind() {
183 WHITESPACE | COMMENT | ATTR => true,
184 _ => false,
185 })
186 .next()
187 .map(|it| it.text_range().start())
188 .unwrap_or_else(|| node.text_range().start())
189}
190
191#[cfg(test)] 176#[cfg(test)]
192mod tests { 177mod tests {
193 use crate::tests::{check_assist, check_assist_not_applicable}; 178 use crate::tests::{check_assist, check_assist_not_applicable};
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index ca04ec671..90ce66378 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -81,10 +81,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
81} 81}
82 82
83fn contains_placeholder(a: &ast::MatchArm) -> bool { 83fn contains_placeholder(a: &ast::MatchArm) -> bool {
84 match a.pat() { 84 matches!(a.pat(), Some(ast::Pat::PlaceholderPat(..)))
85 Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
86 _ => false,
87 }
88} 85}
89 86
90#[cfg(test)] 87#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index 897da2832..bc58ce5fe 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -1,7 +1,7 @@
1use std::collections::HashMap; 1use itertools::Itertools;
2use rustc_hash::FxHashMap;
2 3
3use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; 4use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; 6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
7 7
@@ -87,7 +87,7 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option
87 } 87 }
88} 88}
89 89
90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> { 90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
91 Some( 91 Some(
92 struct_definition(path, &ctx.sema)? 92 struct_definition(path, &ctx.sema)?
93 .fields(ctx.db) 93 .fields(ctx.db)
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index b7c45a619..02de902d6 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -7,7 +7,9 @@ use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type};
7use ra_ide_db::RootDatabase; 7use ra_ide_db::RootDatabase;
8use ra_syntax::{ 8use ra_syntax::{
9 ast::{self, make, NameOwner}, 9 ast::{self, make, NameOwner},
10 AstNode, SyntaxNode, T, 10 AstNode,
11 SyntaxKind::*,
12 SyntaxNode, TextSize, T,
11}; 13};
12use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
13 15
@@ -120,6 +122,13 @@ pub(crate) fn resolve_target_trait(
120 } 122 }
121} 123}
122 124
125pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
126 node.children_with_tokens()
127 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
128 .map(|it| it.text_range().start())
129 .unwrap_or_else(|| node.text_range().start())
130}
131
123pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { 132pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
124 if let Some(expr) = invert_special_case(&expr) { 133 if let Some(expr) = invert_special_case(&expr) {
125 return expr; 134 return expr;
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index a379b9f49..e86077dd6 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -26,8 +26,10 @@ use hir_ty::{
26 autoderef, 26 autoderef,
27 display::{HirDisplayError, HirFormatter}, 27 display::{HirDisplayError, HirFormatter},
28 expr::ExprValidator, 28 expr::ExprValidator,
29 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, 29 method_resolution,
30 TraitEnvironment, Ty, TyDefId, TypeCtor, 30 unsafe_validation::UnsafeValidator,
31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
32 TyDefId, TypeCtor,
31}; 33};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 34use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 35use ra_prof::profile;
@@ -541,7 +543,7 @@ impl_froms!(Adt: Struct, Union, Enum);
541impl Adt { 543impl Adt {
542 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 {
543 let subst = db.generic_defaults(self.into()); 545 let subst = db.generic_defaults(self.into());
544 subst.iter().any(|ty| ty == &Ty::Unknown) 546 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
545 } 547 }
546 548
547 /// 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
@@ -677,7 +679,9 @@ impl Function {
677 let _p = profile("Function::diagnostics"); 679 let _p = profile("Function::diagnostics");
678 let infer = db.infer(self.id.into()); 680 let infer = db.infer(self.id.into());
679 infer.add_diagnostics(db, self.id, sink); 681 infer.add_diagnostics(db, self.id, sink);
680 let mut validator = ExprValidator::new(self.id, infer, sink); 682 let mut validator = ExprValidator::new(self.id, infer.clone(), sink);
683 validator.validate_body(db);
684 let mut validator = UnsafeValidator::new(self.id, infer, sink);
681 validator.validate_body(db); 685 validator.validate_body(db);
682 } 686 }
683} 687}
@@ -771,7 +775,7 @@ pub struct TypeAlias {
771impl TypeAlias { 775impl TypeAlias {
772 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 {
773 let subst = db.generic_defaults(self.id.into()); 777 let subst = db.generic_defaults(self.id.into());
774 subst.iter().any(|ty| ty == &Ty::Unknown) 778 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
775 } 779 }
776 780
777 pub fn module(self, db: &dyn HirDatabase) -> Module { 781 pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -1031,7 +1035,10 @@ impl TypeParam {
1031 let local_idx = hir_ty::param_idx(db, self.id)?; 1035 let local_idx = hir_ty::param_idx(db, self.id)?;
1032 let resolver = self.id.parent.resolver(db.upcast()); 1036 let resolver = self.id.parent.resolver(db.upcast());
1033 let environment = TraitEnvironment::lower(db, &resolver); 1037 let environment = TraitEnvironment::lower(db, &resolver);
1034 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 {
1035 krate: self.id.parent.module(db.upcast()).krate, 1042 krate: self.id.parent.module(db.upcast()).krate,
1036 ty: InEnvironment { value: ty, environment }, 1043 ty: InEnvironment { value: ty, environment },
1037 }) 1044 })
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index a7e2e0982..c6bc85e2f 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -176,6 +176,7 @@ impl ExprCollector<'_> {
176 if !self.expander.is_cfg_enabled(&expr) { 176 if !self.expander.is_cfg_enabled(&expr) {
177 return self.missing_expr(); 177 return self.missing_expr();
178 } 178 }
179
179 match expr { 180 match expr {
180 ast::Expr::IfExpr(e) => { 181 ast::Expr::IfExpr(e) => {
181 let then_branch = self.collect_block_opt(e.then_branch()); 182 let then_branch = self.collect_block_opt(e.then_branch());
@@ -218,8 +219,12 @@ impl ExprCollector<'_> {
218 let body = self.collect_block_opt(e.block_expr()); 219 let body = self.collect_block_opt(e.block_expr());
219 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) 220 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
220 } 221 }
222 ast::Effect::Unsafe(_) => {
223 let body = self.collect_block_opt(e.block_expr());
224 self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
225 }
221 // FIXME: we need to record these effects somewhere... 226 // FIXME: we need to record these effects somewhere...
222 ast::Effect::Async(_) | ast::Effect::Label(_) | ast::Effect::Unsafe(_) => { 227 ast::Effect::Async(_) | ast::Effect::Label(_) => {
223 self.collect_block_opt(e.block_expr()) 228 self.collect_block_opt(e.block_expr())
224 } 229 }
225 }, 230 },
@@ -445,7 +450,6 @@ impl ExprCollector<'_> {
445 Mutability::from_mutable(e.mut_token().is_some()) 450 Mutability::from_mutable(e.mut_token().is_some())
446 }; 451 };
447 let rawness = Rawness::from_raw(raw_tok); 452 let rawness = Rawness::from_raw(raw_tok);
448
449 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) 453 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
450 } 454 }
451 ast::Expr::PrefixExpr(e) => { 455 ast::Expr::PrefixExpr(e) => {
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index ca49b26d1..e41cfc16b 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -150,6 +150,9 @@ pub enum Expr {
150 Tuple { 150 Tuple {
151 exprs: Vec<ExprId>, 151 exprs: Vec<ExprId>,
152 }, 152 },
153 Unsafe {
154 body: ExprId,
155 },
153 Array(Array), 156 Array(Array),
154 Literal(Literal), 157 Literal(Literal),
155} 158}
@@ -247,7 +250,7 @@ impl Expr {
247 f(*expr); 250 f(*expr);
248 } 251 }
249 } 252 }
250 Expr::TryBlock { body } => f(*body), 253 Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body),
251 Expr::Loop { body, .. } => f(*body), 254 Expr::Loop { body, .. } => f(*body),
252 Expr::While { condition, body, .. } => { 255 Expr::While { condition, body, .. } => {
253 f(*condition); 256 f(*condition);
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index b50eb347c..626f9efd0 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -99,6 +99,8 @@ 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,
103 (include_str, IncludeStr) => include_str_expand,
102 (env, Env) => env_expand, 104 (env, Env) => env_expand,
103 (option_env, OptionEnv) => option_env_expand 105 (option_env, OptionEnv) => option_env_expand
104} 106}
@@ -292,11 +294,16 @@ fn concat_expand(
292 Ok((quote!(#text), FragmentKind::Expr)) 294 Ok((quote!(#text), FragmentKind::Expr))
293} 295}
294 296
295fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { 297fn relative_file(
298 db: &dyn AstDatabase,
299 call_id: MacroCallId,
300 path: &str,
301 allow_recursion: bool,
302) -> Option<FileId> {
296 let call_site = call_id.as_file().original_file(db); 303 let call_site = call_id.as_file().original_file(db);
297 let res = db.resolve_path(call_site, path)?; 304 let res = db.resolve_path(call_site, path)?;
298 // Prevent include itself 305 // Prevent include itself
299 if res == call_site { 306 if res == call_site && !allow_recursion {
300 None 307 None
301 } else { 308 } else {
302 Some(res) 309 Some(res)
@@ -319,8 +326,8 @@ fn include_expand(
319 tt: &tt::Subtree, 326 tt: &tt::Subtree,
320) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 327) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
321 let path = parse_string(tt)?; 328 let path = parse_string(tt)?;
322 let file_id = 329 let file_id = relative_file(db, arg_id.into(), &path, false)
323 relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; 330 .ok_or_else(|| mbe::ExpandError::ConversionError)?;
324 331
325 // FIXME: 332 // FIXME:
326 // Handle include as expression 333 // Handle include as expression
@@ -331,6 +338,48 @@ fn include_expand(
331 Ok((res, FragmentKind::Items)) 338 Ok((res, FragmentKind::Items))
332} 339}
333 340
341fn include_bytes_expand(
342 _db: &dyn AstDatabase,
343 _arg_id: EagerMacroId,
344 tt: &tt::Subtree,
345) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
346 let _path = parse_string(tt)?;
347
348 // FIXME: actually read the file here if the user asked for macro expansion
349 let res = tt::Subtree {
350 delimiter: None,
351 token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
352 text: r#"b"""#.into(),
353 id: tt::TokenId::unspecified(),
354 }))],
355 };
356 Ok((res, FragmentKind::Expr))
357}
358
359fn include_str_expand(
360 db: &dyn AstDatabase,
361 arg_id: EagerMacroId,
362 tt: &tt::Subtree,
363) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
364 let path = parse_string(tt)?;
365
366 // FIXME: we're not able to read excluded files (which is most of them because
367 // it's unusual to `include_str!` a Rust file), but we can return an empty string.
368 // Ideally, we'd be able to offer a precise expansion if the user asks for macro
369 // expansion.
370 let file_id = match relative_file(db, arg_id.into(), &path, true) {
371 Some(file_id) => file_id,
372 None => {
373 return Ok((quote!(""), FragmentKind::Expr));
374 }
375 };
376
377 let text = db.file_text(file_id);
378 let text = &*text;
379
380 Ok((quote!(#text), FragmentKind::Expr))
381}
382
334fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { 383fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
335 let krate = db.lookup_intern_eager_expansion(arg_id).krate; 384 let krate = db.lookup_intern_eager_expansion(arg_id).krate;
336 db.crate_graph()[krate].env.get(key) 385 db.crate_graph()[krate].env.get(key)
@@ -581,4 +630,20 @@ mod tests {
581 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),])"#
582 ); 631 );
583 } 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 }
584} 649}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 660bdfe33..1b0303685 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -191,6 +191,8 @@ pub mod known {
191 stringify, 191 stringify,
192 concat, 192 concat,
193 include, 193 include,
194 include_bytes,
195 include_str,
194 format_args, 196 format_args,
195 format_args_nl, 197 format_args_nl,
196 env, 198 env,
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 407322dc1..d6df48db2 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" }
27 27
28scoped-tls = "1" 28scoped-tls = "1"
29 29
30chalk-solve = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } 30chalk-solve = { version = "0.15.0" }
31chalk-ir = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } 31chalk-ir = { version = "0.15.0" }
32 32
33[dev-dependencies] 33[dev-dependencies]
34insta = "0.16.0" 34insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 7889b8d2c..cad553273 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -14,7 +14,7 @@ use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::CrateImplDefs,
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name; 19use hir_expand::name::Name;
20 20
@@ -65,7 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
65 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>; 65 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>;
66 66
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 67 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Substs; 68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 69
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index ebd9cb08f..a59efb347 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -169,3 +169,31 @@ impl AstDiagnostic for BreakOutsideOfLoop {
169 ast::Expr::cast(node).unwrap() 169 ast::Expr::cast(node).unwrap()
170 } 170 }
171} 171}
172
173#[derive(Debug)]
174pub struct MissingUnsafe {
175 pub file: HirFileId,
176 pub expr: AstPtr<ast::Expr>,
177}
178
179impl Diagnostic for MissingUnsafe {
180 fn message(&self) -> String {
181 format!("This operation is unsafe and requires an unsafe function or block")
182 }
183 fn source(&self) -> InFile<SyntaxNodePtr> {
184 InFile { file_id: self.file, value: self.expr.clone().into() }
185 }
186 fn as_any(&self) -> &(dyn Any + Send + 'static) {
187 self
188 }
189}
190
191impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr;
193
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap()
198 }
199}
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 a9565a58d..22884522a 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -142,6 +142,7 @@ impl<'a> InferenceContext<'a> {
142 // FIXME: Breakable block inference 142 // FIXME: Breakable block inference
143 self.infer_block(statements, *tail, expected) 143 self.infer_block(statements, *tail, expected)
144 } 144 }
145 Expr::Unsafe { body } => self.infer_expr(*body, expected),
145 Expr::TryBlock { body } => { 146 Expr::TryBlock { body } => {
146 let _inner = self.infer_expr(*body, expected); 147 let _inner = self.infer_expr(*body, expected);
147 // FIXME should be std::result::Result<{inner}, _> 148 // FIXME should be std::result::Result<{inner}, _>
@@ -784,11 +785,7 @@ impl<'a> InferenceContext<'a> {
784 for &check_closures in &[false, true] { 785 for &check_closures in &[false, true] {
785 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); 786 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
786 for (&arg, param_ty) in args.iter().zip(param_iter) { 787 for (&arg, param_ty) in args.iter().zip(param_iter) {
787 let is_closure = match &self.body[arg] { 788 let is_closure = matches!(&self.body[arg], Expr::Lambda { .. });
788 Expr::Lambda { .. } => true,
789 _ => false,
790 };
791
792 if is_closure != check_closures { 789 if is_closure != check_closures {
793 continue; 790 continue;
794 } 791 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index f22232324..c9513b752 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -37,6 +37,7 @@ pub(crate) mod utils;
37pub mod db; 37pub mod db;
38pub mod diagnostics; 38pub mod diagnostics;
39pub mod expr; 39pub mod expr;
40pub mod unsafe_validation;
40 41
41#[cfg(test)] 42#[cfg(test)]
42mod tests; 43mod tests;
@@ -619,17 +620,11 @@ pub enum GenericPredicate {
619 620
620impl GenericPredicate { 621impl GenericPredicate {
621 pub fn is_error(&self) -> bool { 622 pub fn is_error(&self) -> bool {
622 match self { 623 matches!(self, GenericPredicate::Error)
623 GenericPredicate::Error => true,
624 _ => false,
625 }
626 } 624 }
627 625
628 pub fn is_implemented(&self) -> bool { 626 pub fn is_implemented(&self) -> bool {
629 match self { 627 matches!(self, GenericPredicate::Implemented(_))
630 GenericPredicate::Implemented(_) => true,
631 _ => false,
632 }
633 } 628 }
634 629
635 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { 630 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index d5154f436..3dc154e92 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -578,11 +578,13 @@ fn substs_from_path_segment(
578 // (i.e. defaults aren't used). 578 // (i.e. defaults aren't used).
579 if !infer_args || had_explicit_args { 579 if !infer_args || had_explicit_args {
580 if let Some(def_generic) = def_generic { 580 if let Some(def_generic) = def_generic {
581 let default_substs = ctx.db.generic_defaults(def_generic); 581 let defaults = ctx.db.generic_defaults(def_generic);
582 assert_eq!(total_len, default_substs.len()); 582 assert_eq!(total_len, defaults.len());
583 583
584 for default_ty in default_substs.iter().skip(substs.len()) { 584 for default_ty in defaults.iter().skip(substs.len()) {
585 substs.push(default_ty.clone()); 585 // each default can depend on the previous parameters
586 let substs_so_far = Substs(substs.clone().into());
587 substs.push(default_ty.clone().subst(&substs_so_far));
586 } 588 }
587 } 589 }
588 } 590 }
@@ -945,17 +947,42 @@ pub(crate) fn generic_predicates_query(
945} 947}
946 948
947/// Resolve the default type params from generics 949/// Resolve the default type params from generics
948pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> Substs { 950pub(crate) fn generic_defaults_query(
951 db: &dyn HirDatabase,
952 def: GenericDefId,
953) -> Arc<[Binders<Ty>]> {
949 let resolver = def.resolver(db.upcast()); 954 let resolver = def.resolver(db.upcast());
950 let ctx = TyLoweringContext::new(db, &resolver); 955 let ctx =
956 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
951 let generic_params = generics(db.upcast(), def); 957 let generic_params = generics(db.upcast(), def);
952 958
953 let defaults = generic_params 959 let defaults = generic_params
954 .iter() 960 .iter()
955 .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t))) 961 .enumerate()
962 .map(|(idx, (_, p))| {
963 let mut ty = p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t));
964
965 // Each default can only refer to previous parameters.
966 ty.walk_mut_binders(
967 &mut |ty, binders| match ty {
968 Ty::Bound(BoundVar { debruijn, index }) if *debruijn == binders => {
969 if *index >= idx {
970 // type variable default referring to parameter coming
971 // after it. This is forbidden (FIXME: report
972 // diagnostic)
973 *ty = Ty::Unknown;
974 }
975 }
976 _ => {}
977 },
978 DebruijnIndex::INNERMOST,
979 );
980
981 Binders::new(idx, ty)
982 })
956 .collect(); 983 .collect();
957 984
958 Substs(defaults) 985 defaults
959} 986}
960 987
961fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { 988fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index ad04e3e0f..0481a7b12 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -11,7 +11,10 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDataba
11use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
12use stdx::format_to; 12use stdx::format_to;
13 13
14use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; 14use crate::{
15 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
16 unsafe_validation::UnsafeValidator,
17};
15 18
16#[salsa::database( 19#[salsa::database(
17 ra_db::SourceDatabaseExtStorage, 20 ra_db::SourceDatabaseExtStorage,
@@ -119,7 +122,9 @@ impl TestDB {
119 let infer = self.infer(f.into()); 122 let infer = self.infer(f.into());
120 let mut sink = DiagnosticSink::new(&mut cb); 123 let mut sink = DiagnosticSink::new(&mut cb);
121 infer.add_diagnostics(self, f, &mut sink); 124 infer.add_diagnostics(self, f, &mut sink);
122 let mut validator = ExprValidator::new(f, infer, &mut sink); 125 let mut validator = ExprValidator::new(f, infer.clone(), &mut sink);
126 validator.validate_body(self);
127 let mut validator = UnsafeValidator::new(f, infer, &mut sink);
123 validator.validate_body(self); 128 validator.validate_body(self);
124 } 129 }
125 } 130 }
@@ -149,6 +154,19 @@ impl TestDB {
149 }); 154 });
150 (buf, count) 155 (buf, count)
151 } 156 }
157
158 pub fn all_files(&self) -> Vec<FileId> {
159 let mut res = Vec::new();
160 let crate_graph = self.crate_graph();
161 for krate in crate_graph.iter() {
162 let crate_def_map = self.crate_def_map(krate);
163 for (module_id, _) in crate_def_map.modules.iter() {
164 let file_id = crate_def_map[module_id].origin.file_id();
165 res.extend(file_id)
166 }
167 }
168 res
169 }
152} 170}
153 171
154impl TestDB { 172impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 85ff26a36..5424e6bb1 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -17,17 +17,18 @@ use hir_def::{
17 item_scope::ItemScope, 17 item_scope::ItemScope,
18 keys, 18 keys,
19 nameres::CrateDefMap, 19 nameres::CrateDefMap,
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId, 20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 21};
22use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 23use insta::assert_snapshot;
24use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 24use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
25use ra_syntax::{ 25use ra_syntax::{
26 algo, 26 algo,
27 ast::{self, AstNode}, 27 ast::{self, AstNode},
28 SyntaxNode, 28 SyntaxNode,
29}; 29};
30use stdx::format_to; 30use stdx::format_to;
31use test_utils::extract_annotations;
31 32
32use crate::{ 33use crate::{
33 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, 34 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
@@ -37,21 +38,38 @@ use crate::{
37// against snapshots of the expected results using insta. Use cargo-insta to 38// against snapshots of the expected results using insta. Use cargo-insta to
38// update the snapshots. 39// update the snapshots.
39 40
40fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 41fn check_types(ra_fixture: &str) {
41 type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string()) 42 check_types_impl(ra_fixture, false)
42} 43}
43 44
44fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { 45fn 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()) 46 check_types_impl(ra_fixture, true)
46} 47}
47 48
48fn type_at_pos_displayed( 49fn check_types_impl(ra_fixture: &str, display_source: bool) {
49 db: &TestDB, 50 let db = TestDB::with_files(ra_fixture);
50 pos: FilePosition, 51 let mut checked_one = false;
51 display_fn: impl FnOnce(&Ty, ModuleId) -> String, 52 for file_id in db.all_files() {
52) -> String { 53 let text = db.parse(file_id).syntax_node().to_string();
54 let annotations = extract_annotations(&text);
55 for (range, expected) in annotations {
56 let ty = type_at_range(&db, FileRange { file_id, range });
57 let actual = if display_source {
58 let module = db.module_for_file(file_id);
59 ty.display_source_code(&db, module).unwrap()
60 } else {
61 ty.display(&db).to_string()
62 };
63 assert_eq!(expected, actual);
64 checked_one = true;
65 }
66 }
67 assert!(checked_one, "no `//^` annotations found");
68}
69
70fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
53 let file = db.parse(pos.file_id).ok().unwrap(); 71 let file = db.parse(pos.file_id).ok().unwrap();
54 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 72 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(); 73 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
56 let module = db.module_for_file(pos.file_id); 74 let module = db.module_for_file(pos.file_id);
57 let func = *module.child_by_source(db)[keys::FUNCTION] 75 let func = *module.child_by_source(db)[keys::FUNCTION]
@@ -61,17 +79,11 @@ fn type_at_pos_displayed(
61 let (_body, source_map) = db.body_with_source_map(func.into()); 79 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)) { 80 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
63 let infer = db.infer(func.into()); 81 let infer = db.infer(func.into());
64 let ty = &infer[expr_id]; 82 return infer[expr_id].clone();
65 return display_fn(ty, module);
66 } 83 }
67 panic!("Can't find expression") 84 panic!("Can't find expression")
68} 85}
69 86
70fn type_at(ra_fixture: &str) -> String {
71 let (db, file_pos) = TestDB::with_position(ra_fixture);
72 type_at_pos(&db, file_pos)
73}
74
75fn infer(ra_fixture: &str) -> String { 87fn infer(ra_fixture: &str) -> String {
76 infer_with_mismatches(ra_fixture, false) 88 infer_with_mismatches(ra_fixture, false)
77} 89}
@@ -539,6 +551,155 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
539} 551}
540 552
541#[test] 553#[test]
554fn missing_unsafe_diagnostic_with_raw_ptr() {
555 let diagnostics = TestDB::with_files(
556 r"
557//- /lib.rs
558fn missing_unsafe() {
559 let x = &5 as *const usize;
560 let y = *x;
561}
562",
563 )
564 .diagnostics()
565 .0;
566
567 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
568}
569
570#[test]
571fn missing_unsafe_diagnostic_with_unsafe_call() {
572 let diagnostics = TestDB::with_files(
573 r"
574//- /lib.rs
575unsafe fn unsafe_fn() {
576 let x = &5 as *const usize;
577 let y = *x;
578}
579
580fn missing_unsafe() {
581 unsafe_fn();
582}
583",
584 )
585 .diagnostics()
586 .0;
587
588 assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
589}
590
591#[test]
592fn missing_unsafe_diagnostic_with_unsafe_method_call() {
593 let diagnostics = TestDB::with_files(
594 r"
595struct HasUnsafe;
596
597impl HasUnsafe {
598 unsafe fn unsafe_fn(&self) {
599 let x = &5 as *const usize;
600 let y = *x;
601 }
602}
603
604fn missing_unsafe() {
605 HasUnsafe.unsafe_fn();
606}
607
608",
609 )
610 .diagnostics()
611 .0;
612
613 assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
614}
615
616#[test]
617fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
618 let diagnostics = TestDB::with_files(
619 r"
620fn nothing_to_see_move_along() {
621 let x = &5 as *const usize;
622 unsafe {
623 let y = *x;
624 }
625}
626",
627 )
628 .diagnostics()
629 .0;
630
631 assert_snapshot!(diagnostics, @"");
632}
633
634#[test]
635fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
636 let diagnostics = TestDB::with_files(
637 r"
638fn nothing_to_see_move_along() {
639 let x = &5 as *const usize;
640 unsafe {
641 let y = *x;
642 }
643 let z = *x;
644}
645",
646 )
647 .diagnostics()
648 .0;
649
650 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
651}
652
653#[test]
654fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
655 let diagnostics = TestDB::with_files(
656 r"
657unsafe fn unsafe_fn() {
658 let x = &5 as *const usize;
659 let y = *x;
660}
661
662fn nothing_to_see_move_along() {
663 unsafe {
664 unsafe_fn();
665 }
666}
667",
668 )
669 .diagnostics()
670 .0;
671
672 assert_snapshot!(diagnostics, @"");
673}
674
675#[test]
676fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
677 let diagnostics = TestDB::with_files(
678 r"
679struct HasUnsafe;
680
681impl HasUnsafe {
682 unsafe fn unsafe_fn() {
683 let x = &5 as *const usize;
684 let y = *x;
685 }
686}
687
688fn nothing_to_see_move_along() {
689 unsafe {
690 HasUnsafe.unsafe_fn();
691 }
692}
693
694",
695 )
696 .diagnostics()
697 .0;
698
699 assert_snapshot!(diagnostics, @"");
700}
701
702#[test]
542fn break_outside_of_loop() { 703fn break_outside_of_loop() {
543 let diagnostics = TestDB::with_files( 704 let diagnostics = TestDB::with_files(
544 r" 705 r"
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 5a1c6ccc3..136d28a91 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,7 +1,8 @@
1use super::infer_with_mismatches;
2use insta::assert_snapshot; 1use insta::assert_snapshot;
3use test_utils::mark; 2use test_utils::mark;
4 3
4use super::infer_with_mismatches;
5
5// Infer with some common definitions and impls. 6// Infer with some common definitions and impls.
6fn infer(source: &str) -> String { 7fn infer(source: &str) -> String {
7 let defs = r#" 8 let defs = r#"
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
index 5dfa0a014..b502135d8 100644
--- a/crates/ra_hir_ty/src/tests/display_source_code.rs
+++ b/crates/ra_hir_ty/src/tests/display_source_code.rs
@@ -1,50 +1,41 @@
1use super::displayed_source_at_pos; 1use super::check_types_source_code;
2use crate::test_db::TestDB;
3use ra_db::fixture::WithFixture;
4 2
5#[test] 3#[test]
6fn qualify_path_to_submodule() { 4fn qualify_path_to_submodule() {
7 let (db, pos) = TestDB::with_position( 5 check_types_source_code(
8 r#" 6 r#"
9//- /main.rs
10
11mod foo { 7mod foo {
12 pub struct Foo; 8 pub struct Foo;
13} 9}
14 10
15fn bar() { 11fn bar() {
16 let foo: foo::Foo = foo::Foo; 12 let foo: foo::Foo = foo::Foo;
17 foo<|> 13 foo
18} 14} //^ foo::Foo
19 15
20"#, 16"#,
21 ); 17 );
22 assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
23} 18}
24 19
25#[test] 20#[test]
26fn omit_default_type_parameters() { 21fn omit_default_type_parameters() {
27 let (db, pos) = TestDB::with_position( 22 check_types_source_code(
28 r" 23 r#"
29 //- /main.rs 24struct Foo<T = u8> { t: T }
30 struct Foo<T = u8> { t: T } 25fn main() {
31 fn main() { 26 let foo = Foo { t: 5u8 };
32 let foo = Foo { t: 5u8 }; 27 foo;
33 foo<|>; 28} //^ Foo
34 } 29"#,
35 ",
36 ); 30 );
37 assert_eq!("Foo", displayed_source_at_pos(&db, pos));
38 31
39 let (db, pos) = TestDB::with_position( 32 check_types_source_code(
40 r" 33 r#"
41 //- /main.rs 34struct Foo<K, T = u8> { k: K, t: T }
42 struct Foo<K, T = u8> { k: K, t: T } 35fn main() {
43 fn main() { 36 let foo = Foo { k: 400, t: 5u8 };
44 let foo = Foo { k: 400, t: 5u8 }; 37 foo;
45 foo<|>; 38} //^ Foo<i32>
46 } 39"#,
47 ",
48 ); 40 );
49 assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
50} 41}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index be2b48dcc..45c4e309e 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,16 +1,13 @@
1use std::fs; 1use std::fs;
2 2
3use insta::assert_snapshot; 3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5use test_utils::project_dir; 4use test_utils::project_dir;
6 5
7use crate::test_db::TestDB; 6use super::{check_types, infer};
8
9use super::{infer, type_at, type_at_pos};
10 7
11#[test] 8#[test]
12fn cfg_impl_def() { 9fn cfg_impl_def() {
13 let (db, pos) = TestDB::with_position( 10 check_types(
14 r#" 11 r#"
15//- /main.rs crate:main deps:foo cfg:test 12//- /main.rs crate:main deps:foo cfg:test
16use foo::S as T; 13use foo::S as T;
@@ -28,8 +25,8 @@ impl S {
28 25
29fn test() { 26fn test() {
30 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); 27 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
31 t<|>; 28 t;
32} 29} //^ (i32, {unknown}, i32, {unknown})
33 30
34//- /foo.rs crate:foo 31//- /foo.rs crate:foo
35struct S; 32struct S;
@@ -45,7 +42,6 @@ impl S {
45} 42}
46"#, 43"#,
47 ); 44 );
48 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
49} 45}
50 46
51#[test] 47#[test]
@@ -253,26 +249,24 @@ fn foo() {
253 249
254#[test] 250#[test]
255fn processes_impls_generated_by_macros() { 251fn processes_impls_generated_by_macros() {
256 let t = type_at( 252 check_types(
257 r#" 253 r#"
258//- /main.rs
259macro_rules! m { 254macro_rules! m {
260 ($ident:ident) => (impl Trait for $ident {}) 255 ($ident:ident) => (impl Trait for $ident {})
261} 256}
262trait Trait { fn foo(self) -> u128 {} } 257trait Trait { fn foo(self) -> u128 {} }
263struct S; 258struct S;
264m!(S); 259m!(S);
265fn test() { S.foo()<|>; } 260fn test() { S.foo(); }
261 //^ u128
266"#, 262"#,
267 ); 263 );
268 assert_eq!(t, "u128");
269} 264}
270 265
271#[test] 266#[test]
272fn infer_assoc_items_generated_by_macros() { 267fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 268 check_types(
274 r#" 269 r#"
275//- /main.rs
276macro_rules! m { 270macro_rules! m {
277 () => (fn foo(&self) -> u128 {0}) 271 () => (fn foo(&self) -> u128 {0})
278} 272}
@@ -281,17 +275,16 @@ impl S {
281 m!(); 275 m!();
282} 276}
283 277
284fn test() { S.foo()<|>; } 278fn test() { S.foo(); }
279 //^ u128
285"#, 280"#,
286 ); 281 );
287 assert_eq!(t, "u128");
288} 282}
289 283
290#[test] 284#[test]
291fn infer_assoc_items_generated_by_macros_chain() { 285fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 286 check_types(
293 r#" 287 r#"
294//- /main.rs
295macro_rules! m_inner { 288macro_rules! m_inner {
296 () => {fn foo(&self) -> u128 {0}} 289 () => {fn foo(&self) -> u128 {0}}
297} 290}
@@ -304,21 +297,21 @@ impl S {
304 m!(); 297 m!();
305} 298}
306 299
307fn test() { S.foo()<|>; } 300fn test() { S.foo(); }
301 //^ u128
308"#, 302"#,
309 ); 303 );
310 assert_eq!(t, "u128");
311} 304}
312 305
313#[test] 306#[test]
314fn infer_macro_with_dollar_crate_is_correct_in_expr() { 307fn infer_macro_with_dollar_crate_is_correct_in_expr() {
315 let (db, pos) = TestDB::with_position( 308 check_types(
316 r#" 309 r#"
317//- /main.rs crate:main deps:foo 310//- /main.rs crate:main deps:foo
318fn test() { 311fn test() {
319 let x = (foo::foo!(1), foo::foo!(2)); 312 let x = (foo::foo!(1), foo::foo!(2));
320 x<|>; 313 x;
321} 314} //^ (i32, usize)
322 315
323//- /lib.rs crate:foo 316//- /lib.rs crate:foo
324#[macro_export] 317#[macro_export]
@@ -335,12 +328,11 @@ macro_rules! bar {
335pub fn baz() -> usize { 31usize } 328pub fn baz() -> usize { 31usize }
336"#, 329"#,
337 ); 330 );
338 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
339} 331}
340 332
341#[test] 333#[test]
342fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { 334fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
343 let (db, pos) = TestDB::with_position( 335 check_types(
344 r#" 336 r#"
345//- /main.rs crate:main deps:foo 337//- /main.rs crate:main deps:foo
346use foo::Trait; 338use foo::Trait;
@@ -348,7 +340,8 @@ use foo::Trait;
348fn test() { 340fn test() {
349 let msg = foo::Message(foo::MessageRef); 341 let msg = foo::Message(foo::MessageRef);
350 let r = msg.deref(); 342 let r = msg.deref();
351 r<|>; 343 r;
344 //^ &MessageRef
352} 345}
353 346
354//- /lib.rs crate:foo 347//- /lib.rs crate:foo
@@ -375,7 +368,6 @@ macro_rules! expand {
375expand!(); 368expand!();
376"#, 369"#,
377 ); 370 );
378 assert_eq!("&MessageRef", type_at_pos(&db, pos));
379} 371}
380 372
381#[test] 373#[test]
@@ -429,13 +421,13 @@ fn main() {
429 421
430#[test] 422#[test]
431fn infer_local_inner_macros() { 423fn infer_local_inner_macros() {
432 let (db, pos) = TestDB::with_position( 424 check_types(
433 r#" 425 r#"
434//- /main.rs crate:main deps:foo 426//- /main.rs crate:main deps:foo
435fn test() { 427fn test() {
436 let x = foo::foo!(1); 428 let x = foo::foo!(1);
437 x<|>; 429 x;
438} 430} //^ i32
439 431
440//- /lib.rs crate:foo 432//- /lib.rs crate:foo
441#[macro_export(local_inner_macros)] 433#[macro_export(local_inner_macros)]
@@ -450,7 +442,6 @@ macro_rules! bar {
450 442
451"#, 443"#,
452 ); 444 );
453 assert_eq!("i32", type_at_pos(&db, pos));
454} 445}
455 446
456#[test] 447#[test]
@@ -531,7 +522,7 @@ fn main() {
531 522
532#[test] 523#[test]
533fn infer_builtin_macros_include() { 524fn infer_builtin_macros_include() {
534 let (db, pos) = TestDB::with_position( 525 check_types(
535 r#" 526 r#"
536//- /main.rs 527//- /main.rs
537#[rustc_builtin_macro] 528#[rustc_builtin_macro]
@@ -540,14 +531,13 @@ macro_rules! include {() => {}}
540include!("foo.rs"); 531include!("foo.rs");
541 532
542fn main() { 533fn main() {
543 bar()<|>; 534 bar();
544} 535} //^ u32
545 536
546//- /foo.rs 537//- /foo.rs
547fn bar() -> u32 {0} 538fn bar() -> u32 {0}
548"#, 539"#,
549 ); 540 );
550 assert_eq!("u32", type_at_pos(&db, pos));
551} 541}
552 542
553#[test] 543#[test]
@@ -565,18 +555,17 @@ macro_rules! include {() => {}}
565include!("foo.rs"); 555include!("foo.rs");
566 556
567fn main() { 557fn main() {
568 RegisterBlock { }<|>; 558 RegisterBlock { };
559 //^ RegisterBlock
569} 560}
570 "#; 561 "#;
571 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); 562 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
572 563 check_types(&fixture);
573 let (db, pos) = TestDB::with_position(&fixture);
574 assert_eq!("RegisterBlock", type_at_pos(&db, pos));
575} 564}
576 565
577#[test] 566#[test]
578fn infer_builtin_macros_include_concat() { 567fn infer_builtin_macros_include_concat() {
579 let (db, pos) = TestDB::with_position( 568 check_types(
580 r#" 569 r#"
581//- /main.rs 570//- /main.rs
582#[rustc_builtin_macro] 571#[rustc_builtin_macro]
@@ -588,19 +577,18 @@ macro_rules! concat {() => {}}
588include!(concat!("f", "oo.rs")); 577include!(concat!("f", "oo.rs"));
589 578
590fn main() { 579fn main() {
591 bar()<|>; 580 bar();
592} 581} //^ u32
593 582
594//- /foo.rs 583//- /foo.rs
595fn bar() -> u32 {0} 584fn bar() -> u32 {0}
596"#, 585"#,
597 ); 586 );
598 assert_eq!("u32", type_at_pos(&db, pos));
599} 587}
600 588
601#[test] 589#[test]
602fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { 590fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
603 let (db, pos) = TestDB::with_position( 591 check_types(
604 r#" 592 r#"
605//- /main.rs 593//- /main.rs
606#[rustc_builtin_macro] 594#[rustc_builtin_macro]
@@ -615,32 +603,29 @@ macro_rules! env {() => {}}
615include!(concat!(env!("OUT_DIR"), "/foo.rs")); 603include!(concat!(env!("OUT_DIR"), "/foo.rs"));
616 604
617fn main() { 605fn main() {
618 bar()<|>; 606 bar();
619} 607} //^ {unknown}
620 608
621//- /foo.rs 609//- /foo.rs
622fn bar() -> u32 {0} 610fn bar() -> u32 {0}
623"#, 611"#,
624 ); 612 );
625 assert_eq!("{unknown}", type_at_pos(&db, pos));
626} 613}
627 614
628#[test] 615#[test]
629fn infer_builtin_macros_include_itself_should_failed() { 616fn infer_builtin_macros_include_itself_should_failed() {
630 let (db, pos) = TestDB::with_position( 617 check_types(
631 r#" 618 r#"
632//- /main.rs
633#[rustc_builtin_macro] 619#[rustc_builtin_macro]
634macro_rules! include {() => {}} 620macro_rules! include {() => {}}
635 621
636include!("main.rs"); 622include!("main.rs");
637 623
638fn main() { 624fn main() {
639 0<|> 625 0
640} 626} //^ i32
641"#, 627"#,
642 ); 628 );
643 assert_eq!("i32", type_at_pos(&db, pos));
644} 629}
645 630
646#[test] 631#[test]
@@ -686,14 +671,14 @@ fn main() {
686 671
687#[test] 672#[test]
688fn infer_derive_clone_simple() { 673fn infer_derive_clone_simple() {
689 let (db, pos) = TestDB::with_position( 674 check_types(
690 r#" 675 r#"
691//- /main.rs crate:main deps:core 676//- /main.rs crate:main deps:core
692#[derive(Clone)] 677#[derive(Clone)]
693struct S; 678struct S;
694fn test() { 679fn test() {
695 S.clone()<|>; 680 S.clone();
696} 681} //^ S
697 682
698//- /lib.rs crate:core 683//- /lib.rs crate:core
699#[prelude_import] 684#[prelude_import]
@@ -705,12 +690,11 @@ mod clone {
705} 690}
706"#, 691"#,
707 ); 692 );
708 assert_eq!("S", type_at_pos(&db, pos));
709} 693}
710 694
711#[test] 695#[test]
712fn infer_derive_clone_in_core() { 696fn infer_derive_clone_in_core() {
713 let (db, pos) = TestDB::with_position( 697 check_types(
714 r#" 698 r#"
715//- /lib.rs crate:core 699//- /lib.rs crate:core
716#[prelude_import] 700#[prelude_import]
@@ -726,16 +710,15 @@ pub struct S;
726//- /main.rs crate:main deps:core 710//- /main.rs crate:main deps:core
727use core::S; 711use core::S;
728fn test() { 712fn test() {
729 S.clone()<|>; 713 S.clone();
730} 714} //^ S
731"#, 715"#,
732 ); 716 );
733 assert_eq!("S", type_at_pos(&db, pos));
734} 717}
735 718
736#[test] 719#[test]
737fn infer_derive_clone_with_params() { 720fn infer_derive_clone_with_params() {
738 let (db, pos) = TestDB::with_position( 721 check_types(
739 r#" 722 r#"
740//- /main.rs crate:main deps:core 723//- /main.rs crate:main deps:core
741#[derive(Clone)] 724#[derive(Clone)]
@@ -744,7 +727,8 @@ struct S;
744struct Wrapper<T>(T); 727struct Wrapper<T>(T);
745struct NonClone; 728struct NonClone;
746fn test() { 729fn test() {
747 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; 730 (Wrapper(S).clone(), Wrapper(NonClone).clone());
731 //^ (Wrapper<S>, {unknown})
748} 732}
749 733
750//- /lib.rs crate:core 734//- /lib.rs crate:core
@@ -757,13 +741,12 @@ mod clone {
757} 741}
758"#, 742"#,
759 ); 743 );
760 assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
761} 744}
762 745
763#[test] 746#[test]
764fn infer_custom_derive_simple() { 747fn infer_custom_derive_simple() {
765 // FIXME: this test current now do nothing 748 // FIXME: this test current now do nothing
766 let (db, pos) = TestDB::with_position( 749 check_types(
767 r#" 750 r#"
768//- /main.rs crate:main 751//- /main.rs crate:main
769use foo::Foo; 752use foo::Foo;
@@ -772,11 +755,10 @@ use foo::Foo;
772struct S{} 755struct S{}
773 756
774fn test() { 757fn test() {
775 S{}<|>; 758 S{};
776} 759} //^ S
777"#, 760"#,
778 ); 761 );
779 assert_eq!("S", type_at_pos(&db, pos));
780} 762}
781 763
782#[test] 764#[test]
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 20329bae4..9c8f22314 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1,7 +1,6 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
4use ra_db::fixture::WithFixture; 2
3use super::{check_types, infer};
5 4
6#[test] 5#[test]
7fn infer_slice_method() { 6fn infer_slice_method() {
@@ -246,13 +245,13 @@ fn test() {
246 245
247#[test] 246#[test]
248fn cross_crate_associated_method_call() { 247fn cross_crate_associated_method_call() {
249 let (db, pos) = TestDB::with_position( 248 check_types(
250 r#" 249 r#"
251//- /main.rs crate:main deps:other_crate 250//- /main.rs crate:main deps:other_crate
252fn test() { 251fn test() {
253 let x = other_crate::foo::S::thing(); 252 let x = other_crate::foo::S::thing();
254 x<|>; 253 x;
255} 254} //^ i128
256 255
257//- /lib.rs crate:other_crate 256//- /lib.rs crate:other_crate
258mod foo { 257mod foo {
@@ -263,7 +262,6 @@ mod foo {
263} 262}
264"#, 263"#,
265 ); 264 );
266 assert_eq!("i128", type_at_pos(&db, pos));
267} 265}
268 266
269#[test] 267#[test]
@@ -684,135 +682,127 @@ fn test() {
684 682
685#[test] 683#[test]
686fn method_resolution_unify_impl_self_type() { 684fn method_resolution_unify_impl_self_type() {
687 let t = type_at( 685 check_types(
688 r#" 686 r#"
689//- /main.rs
690struct S<T>; 687struct S<T>;
691impl S<u32> { fn foo(&self) -> u8 {} } 688impl S<u32> { fn foo(&self) -> u8 {} }
692impl S<i32> { fn foo(&self) -> i8 {} } 689impl S<i32> { fn foo(&self) -> i8 {} }
693fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; } 690fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
691 //^ (u8, i8)
694"#, 692"#,
695 ); 693 );
696 assert_eq!(t, "(u8, i8)");
697} 694}
698 695
699#[test] 696#[test]
700fn method_resolution_trait_before_autoref() { 697fn method_resolution_trait_before_autoref() {
701 let t = type_at( 698 check_types(
702 r#" 699 r#"
703//- /main.rs
704trait Trait { fn foo(self) -> u128; } 700trait Trait { fn foo(self) -> u128; }
705struct S; 701struct S;
706impl S { fn foo(&self) -> i8 { 0 } } 702impl S { fn foo(&self) -> i8 { 0 } }
707impl Trait for S { fn foo(self) -> u128 { 0 } } 703impl Trait for S { fn foo(self) -> u128 { 0 } }
708fn test() { S.foo()<|>; } 704fn test() { S.foo(); }
705 //^ u128
709"#, 706"#,
710 ); 707 );
711 assert_eq!(t, "u128");
712} 708}
713 709
714#[test] 710#[test]
715fn method_resolution_by_value_before_autoref() { 711fn method_resolution_by_value_before_autoref() {
716 let t = type_at( 712 check_types(
717 r#" 713 r#"
718//- /main.rs
719trait Clone { fn clone(&self) -> Self; } 714trait Clone { fn clone(&self) -> Self; }
720struct S; 715struct S;
721impl Clone for S {} 716impl Clone for S {}
722impl Clone for &S {} 717impl Clone for &S {}
723fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } 718fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
719 //^ (S, S, &S)
724"#, 720"#,
725 ); 721 );
726 assert_eq!(t, "(S, S, &S)");
727} 722}
728 723
729#[test] 724#[test]
730fn method_resolution_trait_before_autoderef() { 725fn method_resolution_trait_before_autoderef() {
731 let t = type_at( 726 check_types(
732 r#" 727 r#"
733//- /main.rs
734trait Trait { fn foo(self) -> u128; } 728trait Trait { fn foo(self) -> u128; }
735struct S; 729struct S;
736impl S { fn foo(self) -> i8 { 0 } } 730impl S { fn foo(self) -> i8 { 0 } }
737impl Trait for &S { fn foo(self) -> u128 { 0 } } 731impl Trait for &S { fn foo(self) -> u128 { 0 } }
738fn test() { (&S).foo()<|>; } 732fn test() { (&S).foo(); }
733 //^ u128
739"#, 734"#,
740 ); 735 );
741 assert_eq!(t, "u128");
742} 736}
743 737
744#[test] 738#[test]
745fn method_resolution_impl_before_trait() { 739fn method_resolution_impl_before_trait() {
746 let t = type_at( 740 check_types(
747 r#" 741 r#"
748//- /main.rs
749trait Trait { fn foo(self) -> u128; } 742trait Trait { fn foo(self) -> u128; }
750struct S; 743struct S;
751impl S { fn foo(self) -> i8 { 0 } } 744impl S { fn foo(self) -> i8 { 0 } }
752impl Trait for S { fn foo(self) -> u128 { 0 } } 745impl Trait for S { fn foo(self) -> u128 { 0 } }
753fn test() { S.foo()<|>; } 746fn test() { S.foo(); }
747 //^ i8
754"#, 748"#,
755 ); 749 );
756 assert_eq!(t, "i8");
757} 750}
758 751
759#[test] 752#[test]
760fn method_resolution_impl_ref_before_trait() { 753fn method_resolution_impl_ref_before_trait() {
761 let t = type_at( 754 check_types(
762 r#" 755 r#"
763//- /main.rs
764trait Trait { fn foo(self) -> u128; } 756trait Trait { fn foo(self) -> u128; }
765struct S; 757struct S;
766impl S { fn foo(&self) -> i8 { 0 } } 758impl S { fn foo(&self) -> i8 { 0 } }
767impl Trait for &S { fn foo(self) -> u128 { 0 } } 759impl Trait for &S { fn foo(self) -> u128 { 0 } }
768fn test() { S.foo()<|>; } 760fn test() { S.foo(); }
761 //^ i8
769"#, 762"#,
770 ); 763 );
771 assert_eq!(t, "i8");
772} 764}
773 765
774#[test] 766#[test]
775fn method_resolution_trait_autoderef() { 767fn method_resolution_trait_autoderef() {
776 let t = type_at( 768 check_types(
777 r#" 769 r#"
778//- /main.rs
779trait Trait { fn foo(self) -> u128; } 770trait Trait { fn foo(self) -> u128; }
780struct S; 771struct S;
781impl Trait for S { fn foo(self) -> u128 { 0 } } 772impl Trait for S { fn foo(self) -> u128 { 0 } }
782fn test() { (&S).foo()<|>; } 773fn test() { (&S).foo(); }
774 //^ u128
783"#, 775"#,
784 ); 776 );
785 assert_eq!(t, "u128");
786} 777}
787 778
788#[test] 779#[test]
789fn method_resolution_unsize_array() { 780fn method_resolution_unsize_array() {
790 let t = type_at( 781 check_types(
791 r#" 782 r#"
792//- /main.rs
793#[lang = "slice"] 783#[lang = "slice"]
794impl<T> [T] { 784impl<T> [T] {
795 fn len(&self) -> usize { loop {} } 785 fn len(&self) -> usize { loop {} }
796} 786}
797fn test() { 787fn test() {
798 let a = [1, 2, 3]; 788 let a = [1, 2, 3];
799 a.len()<|>; 789 a.len();
800} 790} //^ usize
801"#, 791"#,
802 ); 792 );
803 assert_eq!(t, "usize");
804} 793}
805 794
806#[test] 795#[test]
807fn method_resolution_trait_from_prelude() { 796fn method_resolution_trait_from_prelude() {
808 let (db, pos) = TestDB::with_position( 797 check_types(
809 r#" 798 r#"
810//- /main.rs crate:main deps:other_crate 799//- /main.rs crate:main deps:other_crate
811struct S; 800struct S;
812impl Clone for S {} 801impl Clone for S {}
813 802
814fn test() { 803fn test() {
815 S.clone()<|>; 804 S.clone();
805 //^ S
816} 806}
817 807
818//- /lib.rs crate:other_crate 808//- /lib.rs crate:other_crate
@@ -825,115 +815,107 @@ mod foo {
825} 815}
826"#, 816"#,
827 ); 817 );
828 assert_eq!("S", type_at_pos(&db, pos));
829} 818}
830 819
831#[test] 820#[test]
832fn method_resolution_where_clause_for_unknown_trait() { 821fn method_resolution_where_clause_for_unknown_trait() {
833 // The blanket impl currently applies because we ignore the unresolved where clause 822 // The blanket impl currently applies because we ignore the unresolved where clause
834 let t = type_at( 823 check_types(
835 r#" 824 r#"
836//- /main.rs
837trait Trait { fn foo(self) -> u128; } 825trait Trait { fn foo(self) -> u128; }
838struct S; 826struct S;
839impl<T> Trait for T where T: UnknownTrait {} 827impl<T> Trait for T where T: UnknownTrait {}
840fn test() { (&S).foo()<|>; } 828fn test() { (&S).foo(); }
829 //^ u128
841"#, 830"#,
842 ); 831 );
843 assert_eq!(t, "u128");
844} 832}
845 833
846#[test] 834#[test]
847fn method_resolution_where_clause_not_met() { 835fn method_resolution_where_clause_not_met() {
848 // The blanket impl shouldn't apply because we can't prove S: Clone 836 // The blanket impl shouldn't apply because we can't prove S: Clone
849 let t = type_at( 837 // This is also to make sure that we don't resolve to the foo method just
838 // because that's the only method named foo we can find, which would make
839 // the below tests not work
840 check_types(
850 r#" 841 r#"
851//- /main.rs
852trait Clone {} 842trait Clone {}
853trait Trait { fn foo(self) -> u128; } 843trait Trait { fn foo(self) -> u128; }
854struct S; 844struct S;
855impl<T> Trait for T where T: Clone {} 845impl<T> Trait for T where T: Clone {}
856fn test() { (&S).foo()<|>; } 846fn test() { (&S).foo(); }
847 //^ {unknown}
857"#, 848"#,
858 ); 849 );
859 // This is also to make sure that we don't resolve to the foo method just
860 // because that's the only method named foo we can find, which would make
861 // the below tests not work
862 assert_eq!(t, "{unknown}");
863} 850}
864 851
865#[test] 852#[test]
866fn method_resolution_where_clause_inline_not_met() { 853fn method_resolution_where_clause_inline_not_met() {
867 // The blanket impl shouldn't apply because we can't prove S: Clone 854 // The blanket impl shouldn't apply because we can't prove S: Clone
868 let t = type_at( 855 check_types(
869 r#" 856 r#"
870//- /main.rs
871trait Clone {} 857trait Clone {}
872trait Trait { fn foo(self) -> u128; } 858trait Trait { fn foo(self) -> u128; }
873struct S; 859struct S;
874impl<T: Clone> Trait for T {} 860impl<T: Clone> Trait for T {}
875fn test() { (&S).foo()<|>; } 861fn test() { (&S).foo(); }
862 //^ {unknown}
876"#, 863"#,
877 ); 864 );
878 assert_eq!(t, "{unknown}");
879} 865}
880 866
881#[test] 867#[test]
882fn method_resolution_where_clause_1() { 868fn method_resolution_where_clause_1() {
883 let t = type_at( 869 check_types(
884 r#" 870 r#"
885//- /main.rs
886trait Clone {} 871trait Clone {}
887trait Trait { fn foo(self) -> u128; } 872trait Trait { fn foo(self) -> u128; }
888struct S; 873struct S;
889impl Clone for S {} 874impl Clone for S {}
890impl<T> Trait for T where T: Clone {} 875impl<T> Trait for T where T: Clone {}
891fn test() { S.foo()<|>; } 876fn test() { S.foo(); }
877 //^ u128
892"#, 878"#,
893 ); 879 );
894 assert_eq!(t, "u128");
895} 880}
896 881
897#[test] 882#[test]
898fn method_resolution_where_clause_2() { 883fn method_resolution_where_clause_2() {
899 let t = type_at( 884 check_types(
900 r#" 885 r#"
901//- /main.rs
902trait Into<T> { fn into(self) -> T; } 886trait Into<T> { fn into(self) -> T; }
903trait From<T> { fn from(other: T) -> Self; } 887trait From<T> { fn from(other: T) -> Self; }
904struct S1; 888struct S1;
905struct S2; 889struct S2;
906impl From<S2> for S1 {} 890impl From<S2> for S1 {}
907impl<T, U> Into<U> for T where U: From<T> {} 891impl<T, U> Into<U> for T where U: From<T> {}
908fn test() { S2.into()<|>; } 892fn test() { S2.into(); }
893 //^ {unknown}
909"#, 894"#,
910 ); 895 );
911 assert_eq!(t, "{unknown}");
912} 896}
913 897
914#[test] 898#[test]
915fn method_resolution_where_clause_inline() { 899fn method_resolution_where_clause_inline() {
916 let t = type_at( 900 check_types(
917 r#" 901 r#"
918//- /main.rs
919trait Into<T> { fn into(self) -> T; } 902trait Into<T> { fn into(self) -> T; }
920trait From<T> { fn from(other: T) -> Self; } 903trait From<T> { fn from(other: T) -> Self; }
921struct S1; 904struct S1;
922struct S2; 905struct S2;
923impl From<S2> for S1 {} 906impl From<S2> for S1 {}
924impl<T, U: From<T>> Into<U> for T {} 907impl<T, U: From<T>> Into<U> for T {}
925fn test() { S2.into()<|>; } 908fn test() { S2.into(); }
909 //^ {unknown}
926"#, 910"#,
927 ); 911 );
928 assert_eq!(t, "{unknown}");
929} 912}
930 913
931#[test] 914#[test]
932fn method_resolution_overloaded_method() { 915fn method_resolution_overloaded_method() {
933 test_utils::mark::check!(impl_self_type_match_without_receiver); 916 test_utils::mark::check!(impl_self_type_match_without_receiver);
934 let t = type_at( 917 check_types(
935 r#" 918 r#"
936//- /main.rs
937struct Wrapper<T>(T); 919struct Wrapper<T>(T);
938struct Foo<T>(T); 920struct Foo<T>(T);
939struct Bar<T>(T); 921struct Bar<T>(T);
@@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> {
953fn main() { 935fn main() {
954 let a = Wrapper::<Foo<f32>>::new(1.0); 936 let a = Wrapper::<Foo<f32>>::new(1.0);
955 let b = Wrapper::<Bar<f32>>::new(1.0); 937 let b = Wrapper::<Bar<f32>>::new(1.0);
956 (a, b)<|>; 938 (a, b);
939 //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
957} 940}
958"#, 941"#,
959 ); 942 );
960 assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)")
961} 943}
962 944
963#[test] 945#[test]
964fn method_resolution_encountering_fn_type() { 946fn method_resolution_encountering_fn_type() {
965 type_at( 947 check_types(
966 r#" 948 r#"
967//- /main.rs 949//- /main.rs
968fn foo() {} 950fn foo() {}
969trait FnOnce { fn call(self); } 951trait FnOnce { fn call(self); }
970fn test() { foo.call()<|>; } 952fn test() { foo.call(); }
953 //^ {unknown}
971"#, 954"#,
972 ); 955 );
973} 956}
974 957
975#[test] 958#[test]
976fn method_resolution_non_parameter_type() { 959fn method_resolution_non_parameter_type() {
977 let t = type_at( 960 check_types(
978 r#" 961 r#"
979//- /main.rs
980mod a { 962mod a {
981 pub trait Foo { 963 pub trait Foo {
982 fn foo(&self); 964 fn foo(&self);
@@ -988,18 +970,16 @@ fn foo<T>(t: Wrapper<T>)
988where 970where
989 Wrapper<T>: a::Foo, 971 Wrapper<T>: a::Foo,
990{ 972{
991 t.foo()<|>; 973 t.foo();
992} 974} //^ {unknown}
993"#, 975"#,
994 ); 976 );
995 assert_eq!(t, "{unknown}");
996} 977}
997 978
998#[test] 979#[test]
999fn method_resolution_3373() { 980fn method_resolution_3373() {
1000 let t = type_at( 981 check_types(
1001 r#" 982 r#"
1002//- /main.rs
1003struct A<T>(T); 983struct A<T>(T);
1004 984
1005impl A<i32> { 985impl A<i32> {
@@ -1007,19 +987,17 @@ impl A<i32> {
1007} 987}
1008 988
1009fn main() { 989fn main() {
1010 A::from(3)<|>; 990 A::from(3);
1011} 991} //^ A<i32>
1012"#, 992"#,
1013 ); 993 );
1014 assert_eq!(t, "A<i32>");
1015} 994}
1016 995
1017#[test] 996#[test]
1018fn method_resolution_slow() { 997fn method_resolution_slow() {
1019 // this can get quite slow if we set the solver size limit too high 998 // this can get quite slow if we set the solver size limit too high
1020 let t = type_at( 999 check_types(
1021 r#" 1000 r#"
1022//- /main.rs
1023trait SendX {} 1001trait SendX {}
1024 1002
1025struct S1; impl SendX for S1 {} 1003struct S1; impl SendX for S1 {}
@@ -1037,10 +1015,10 @@ trait FnX {}
1037 1015
1038impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} 1016impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
1039 1017
1040fn test() { (S {}).method()<|>; } 1018fn test() { (S {}).method(); }
1019 //^ ()
1041"#, 1020"#,
1042 ); 1021 );
1043 assert_eq!(t, "()");
1044} 1022}
1045 1023
1046#[test] 1024#[test]
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index ab9a990f5..64d421d40 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,99 +1,91 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2 2
3use super::{infer_with_mismatches, type_at}; 3use super::{check_types, infer_with_mismatches};
4 4
5#[test] 5#[test]
6fn infer_never1() { 6fn infer_never1() {
7 let t = type_at( 7 check_types(
8 r#" 8 r#"
9//- /main.rs
10fn test() { 9fn test() {
11 let t = return; 10 let t = return;
12 t<|>; 11 t;
13} 12} //^ !
14"#, 13"#,
15 ); 14 );
16 assert_eq!(t, "!");
17} 15}
18 16
19#[test] 17#[test]
20fn infer_never2() { 18fn infer_never2() {
21 let t = type_at( 19 check_types(
22 r#" 20 r#"
23//- /main.rs
24fn gen<T>() -> T { loop {} } 21fn gen<T>() -> T { loop {} }
25 22
26fn test() { 23fn test() {
27 let a = gen(); 24 let a = gen();
28 if false { a } else { loop {} }; 25 if false { a } else { loop {} };
29 a<|>; 26 a;
30} 27} //^ !
31"#, 28"#,
32 ); 29 );
33 assert_eq!(t, "!");
34} 30}
35 31
36#[test] 32#[test]
37fn infer_never3() { 33fn infer_never3() {
38 let t = type_at( 34 check_types(
39 r#" 35 r#"
40//- /main.rs
41fn gen<T>() -> T { loop {} } 36fn gen<T>() -> T { loop {} }
42 37
43fn test() { 38fn test() {
44 let a = gen(); 39 let a = gen();
45 if false { loop {} } else { a }; 40 if false { loop {} } else { a };
46 a<|>; 41 a;
42 //^ !
47} 43}
48"#, 44"#,
49 ); 45 );
50 assert_eq!(t, "!");
51} 46}
52 47
53#[test] 48#[test]
54fn never_type_in_generic_args() { 49fn never_type_in_generic_args() {
55 let t = type_at( 50 check_types(
56 r#" 51 r#"
57//- /main.rs
58enum Option<T> { None, Some(T) } 52enum Option<T> { None, Some(T) }
59 53
60fn test() { 54fn test() {
61 let a = if true { Option::None } else { Option::Some(return) }; 55 let a = if true { Option::None } else { Option::Some(return) };
62 a<|>; 56 a;
63} 57} //^ Option<!>
64"#, 58"#,
65 ); 59 );
66 assert_eq!(t, "Option<!>");
67} 60}
68 61
69#[test] 62#[test]
70fn never_type_can_be_reinferred1() { 63fn never_type_can_be_reinferred1() {
71 let t = type_at( 64 check_types(
72 r#" 65 r#"
73//- /main.rs
74fn gen<T>() -> T { loop {} } 66fn gen<T>() -> T { loop {} }
75 67
76fn test() { 68fn test() {
77 let a = gen(); 69 let a = gen();
78 if false { loop {} } else { a }; 70 if false { loop {} } else { a };
79 a<|>; 71 a;
72 //^ ()
80 if false { a }; 73 if false { a };
81} 74}
82"#, 75"#,
83 ); 76 );
84 assert_eq!(t, "()");
85} 77}
86 78
87#[test] 79#[test]
88fn never_type_can_be_reinferred2() { 80fn never_type_can_be_reinferred2() {
89 let t = type_at( 81 check_types(
90 r#" 82 r#"
91//- /main.rs
92enum Option<T> { None, Some(T) } 83enum Option<T> { None, Some(T) }
93 84
94fn test() { 85fn test() {
95 let a = if true { Option::None } else { Option::Some(return) }; 86 let a = if true { Option::None } else { Option::Some(return) };
96 a<|>; 87 a;
88 //^ Option<i32>
97 match 42 { 89 match 42 {
98 42 => a, 90 42 => a,
99 _ => Option::Some(42), 91 _ => Option::Some(42),
@@ -101,19 +93,18 @@ fn test() {
101} 93}
102"#, 94"#,
103 ); 95 );
104 assert_eq!(t, "Option<i32>");
105} 96}
106 97
107#[test] 98#[test]
108fn never_type_can_be_reinferred3() { 99fn never_type_can_be_reinferred3() {
109 let t = type_at( 100 check_types(
110 r#" 101 r#"
111//- /main.rs
112enum Option<T> { None, Some(T) } 102enum Option<T> { None, Some(T) }
113 103
114fn test() { 104fn test() {
115 let a = if true { Option::None } else { Option::Some(return) }; 105 let a = if true { Option::None } else { Option::Some(return) };
116 a<|>; 106 a;
107 //^ Option<&str>
117 match 42 { 108 match 42 {
118 42 => a, 109 42 => a,
119 _ => Option::Some("str"), 110 _ => Option::Some("str"),
@@ -121,82 +112,72 @@ fn test() {
121} 112}
122"#, 113"#,
123 ); 114 );
124 assert_eq!(t, "Option<&str>");
125} 115}
126 116
127#[test] 117#[test]
128fn match_no_arm() { 118fn match_no_arm() {
129 let t = type_at( 119 check_types(
130 r#" 120 r#"
131//- /main.rs
132enum Void {} 121enum Void {}
133 122
134fn test(a: Void) { 123fn test(a: Void) {
135 let t = match a {}; 124 let t = match a {};
136 t<|>; 125 t;
137} 126} //^ !
138"#, 127"#,
139 ); 128 );
140 assert_eq!(t, "!");
141} 129}
142 130
143#[test] 131#[test]
144fn match_unknown_arm() { 132fn match_unknown_arm() {
145 let t = type_at( 133 check_types(
146 r#" 134 r#"
147//- /main.rs
148fn test(a: Option) { 135fn test(a: Option) {
149 let t = match 0 { 136 let t = match 0 {
150 _ => unknown, 137 _ => unknown,
151 }; 138 };
152 t<|>; 139 t;
153} 140} //^ {unknown}
154"#, 141"#,
155 ); 142 );
156 assert_eq!(t, "{unknown}");
157} 143}
158 144
159#[test] 145#[test]
160fn if_never() { 146fn if_never() {
161 let t = type_at( 147 check_types(
162 r#" 148 r#"
163//- /main.rs
164fn test() { 149fn test() {
165 let i = if true { 150 let i = if true {
166 loop {} 151 loop {}
167 } else { 152 } else {
168 3.0 153 3.0
169 }; 154 };
170 i<|>; 155 i;
171} 156} //^ f64
172"#, 157"#,
173 ); 158 );
174 assert_eq!(t, "f64");
175} 159}
176 160
177#[test] 161#[test]
178fn if_else_never() { 162fn if_else_never() {
179 let t = type_at( 163 check_types(
180 r#" 164 r#"
181//- /main.rs
182fn test(input: bool) { 165fn test(input: bool) {
183 let i = if input { 166 let i = if input {
184 2.0 167 2.0
185 } else { 168 } else {
186 return 169 return
187 }; 170 };
188 i<|>; 171 i;
189} 172} //^ f64
190"#, 173"#,
191 ); 174 );
192 assert_eq!(t, "f64");
193} 175}
194 176
195#[test] 177#[test]
196fn match_first_arm_never() { 178fn match_first_arm_never() {
197 let t = type_at( 179 check_types(
198 r#" 180 r#"
199//- /main.rs
200fn test(a: i32) { 181fn test(a: i32) {
201 let i = match a { 182 let i = match a {
202 1 => return, 183 1 => return,
@@ -204,18 +185,16 @@ fn test(a: i32) {
204 3 => loop {}, 185 3 => loop {},
205 _ => 3.0, 186 _ => 3.0,
206 }; 187 };
207 i<|>; 188 i;
208} 189} //^ f64
209"#, 190"#,
210 ); 191 );
211 assert_eq!(t, "f64");
212} 192}
213 193
214#[test] 194#[test]
215fn match_second_arm_never() { 195fn match_second_arm_never() {
216 let t = type_at( 196 check_types(
217 r#" 197 r#"
218//- /main.rs
219fn test(a: i32) { 198fn test(a: i32) {
220 let i = match a { 199 let i = match a {
221 1 => 3.0, 200 1 => 3.0,
@@ -223,45 +202,40 @@ fn test(a: i32) {
223 3 => 3.0, 202 3 => 3.0,
224 _ => return, 203 _ => return,
225 }; 204 };
226 i<|>; 205 i;
227} 206} //^ f64
228"#, 207"#,
229 ); 208 );
230 assert_eq!(t, "f64");
231} 209}
232 210
233#[test] 211#[test]
234fn match_all_arms_never() { 212fn match_all_arms_never() {
235 let t = type_at( 213 check_types(
236 r#" 214 r#"
237//- /main.rs
238fn test(a: i32) { 215fn test(a: i32) {
239 let i = match a { 216 let i = match a {
240 2 => return, 217 2 => return,
241 _ => loop {}, 218 _ => loop {},
242 }; 219 };
243 i<|>; 220 i;
244} 221} //^ !
245"#, 222"#,
246 ); 223 );
247 assert_eq!(t, "!");
248} 224}
249 225
250#[test] 226#[test]
251fn match_no_never_arms() { 227fn match_no_never_arms() {
252 let t = type_at( 228 check_types(
253 r#" 229 r#"
254//- /main.rs
255fn test(a: i32) { 230fn test(a: i32) {
256 let i = match a { 231 let i = match a {
257 2 => 2.0, 232 2 => 2.0,
258 _ => 3.0, 233 _ => 3.0,
259 }; 234 };
260 i<|>; 235 i;
261} 236} //^ f64
262"#, 237"#,
263 ); 238 );
264 assert_eq!(t, "f64");
265} 239}
266 240
267#[test] 241#[test]
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index aa37326df..d806e0ffb 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -1,10 +1,7 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use ra_db::fixture::WithFixture;
3use test_utils::mark; 2use test_utils::mark;
4 3
5use crate::test_db::TestDB; 4use super::{check_types, infer};
6
7use super::infer;
8 5
9#[test] 6#[test]
10fn bug_484() { 7fn bug_484() {
@@ -404,13 +401,13 @@ fn test() {
404 401
405#[test] 402#[test]
406fn issue_2683_chars_impl() { 403fn issue_2683_chars_impl() {
407 let (db, pos) = TestDB::with_position( 404 check_types(
408 r#" 405 r#"
409//- /main.rs crate:main deps:std 406//- /main.rs crate:main deps:std
410fn test() { 407fn test() {
411 let chars: std::str::Chars<'_>; 408 let chars: std::str::Chars<'_>;
412 (chars.next(), chars.nth(1))<|>; 409 (chars.next(), chars.nth(1));
413} 410} //^ (Option<char>, Option<char>)
414 411
415//- /std.rs crate:std 412//- /std.rs crate:std
416#[prelude_import] 413#[prelude_import]
@@ -449,15 +446,12 @@ pub mod str {
449} 446}
450"#, 447"#,
451 ); 448 );
452
453 assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
454} 449}
455 450
456#[test] 451#[test]
457fn issue_3642_bad_macro_stackover() { 452fn issue_3642_bad_macro_stackover() {
458 let (db, pos) = TestDB::with_position( 453 check_types(
459 r#" 454 r#"
460//- /main.rs
461#[macro_export] 455#[macro_export]
462macro_rules! match_ast { 456macro_rules! match_ast {
463 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; 457 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
@@ -472,7 +466,8 @@ macro_rules! match_ast {
472} 466}
473 467
474fn main() { 468fn main() {
475 let anchor<|> = match_ast! { 469 let anchor = match_ast! {
470 //^ ()
476 match parent { 471 match parent {
477 as => {}, 472 as => {},
478 _ => return None 473 _ => return None
@@ -480,8 +475,6 @@ fn main() {
480 }; 475 };
481}"#, 476}"#,
482 ); 477 );
483
484 assert_eq!("()", super::type_at_pos(&db, pos));
485} 478}
486 479
487#[test] 480#[test]
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 7d8197f8b..de63f4cce 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -1,19 +1,17 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
4use ra_db::fixture::WithFixture; 2
3use super::{check_types, infer};
5 4
6#[test] 5#[test]
7fn infer_box() { 6fn infer_box() {
8 let (db, pos) = TestDB::with_position( 7 check_types(
9 r#" 8 r#"
10//- /main.rs crate:main deps:std 9//- /main.rs crate:main deps:std
11
12fn test() { 10fn test() {
13 let x = box 1; 11 let x = box 1;
14 let t = (x, box x, box &1, box [1]); 12 let t = (x, box x, box &1, box [1]);
15 t<|>; 13 t;
16} 14} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)
17 15
18//- /std.rs crate:std 16//- /std.rs crate:std
19#[prelude_import] use prelude::*; 17#[prelude_import] use prelude::*;
@@ -25,29 +23,24 @@ mod boxed {
25 inner: *mut T, 23 inner: *mut T,
26 } 24 }
27} 25}
28
29"#, 26"#,
30 ); 27 );
31 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)", type_at_pos(&db, pos));
32} 28}
33 29
34#[test] 30#[test]
35fn infer_adt_self() { 31fn infer_adt_self() {
36 let (db, pos) = TestDB::with_position( 32 check_types(
37 r#" 33 r#"
38//- /main.rs
39enum Nat { Succ(Self), Demo(Nat), Zero } 34enum Nat { Succ(Self), Demo(Nat), Zero }
40 35
41fn test() { 36fn test() {
42 let foo: Nat = Nat::Zero; 37 let foo: Nat = Nat::Zero;
43 if let Nat::Succ(x) = foo { 38 if let Nat::Succ(x) = foo {
44 x<|> 39 x
45 } 40 } //^ Nat
46} 41}
47
48"#, 42"#,
49 ); 43 );
50 assert_eq!("Nat", type_at_pos(&db, pos));
51} 44}
52 45
53#[test] 46#[test]
@@ -93,7 +86,7 @@ fn foo() {
93 86
94#[test] 87#[test]
95fn infer_ranges() { 88fn infer_ranges() {
96 let (db, pos) = TestDB::with_position( 89 check_types(
97 r#" 90 r#"
98//- /main.rs crate:main deps:core 91//- /main.rs crate:main deps:core
99fn test() { 92fn test() {
@@ -105,8 +98,8 @@ fn test() {
105 let f = 'a'..='z'; 98 let f = 'a'..='z';
106 99
107 let t = (a, b, c, d, e, f); 100 let t = (a, b, c, d, e, f);
108 t<|>; 101 t;
109} 102} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
110 103
111//- /core.rs crate:core 104//- /core.rs crate:core
112#[prelude_import] use prelude::*; 105#[prelude_import] use prelude::*;
@@ -135,29 +128,22 @@ pub mod ops {
135} 128}
136"#, 129"#,
137 ); 130 );
138 assert_eq!(
139 "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
140 type_at_pos(&db, pos),
141 );
142} 131}
143 132
144#[test] 133#[test]
145fn infer_while_let() { 134fn infer_while_let() {
146 let (db, pos) = TestDB::with_position( 135 check_types(
147 r#" 136 r#"
148//- /main.rs
149enum Option<T> { Some(T), None } 137enum Option<T> { Some(T), None }
150 138
151fn test() { 139fn test() {
152 let foo: Option<f32> = None; 140 let foo: Option<f32> = None;
153 while let Option::Some(x) = foo { 141 while let Option::Some(x) = foo {
154 <|>x 142 x
155 } 143 } //^ f32
156} 144}
157
158"#, 145"#,
159 ); 146 );
160 assert_eq!("f32", type_at_pos(&db, pos));
161} 147}
162 148
163#[test] 149#[test]
@@ -1687,9 +1673,8 @@ fn test() {
1687 1673
1688#[test] 1674#[test]
1689fn shadowing_primitive() { 1675fn shadowing_primitive() {
1690 let t = type_at( 1676 check_types(
1691 r#" 1677 r#"
1692//- /main.rs
1693struct i32; 1678struct i32;
1694struct Foo; 1679struct Foo;
1695 1680
@@ -1697,15 +1682,15 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
1697 1682
1698fn main() { 1683fn main() {
1699 let x: i32 = i32; 1684 let x: i32 = i32;
1700 x.foo()<|>; 1685 x.foo();
1686 //^ Foo
1701}"#, 1687}"#,
1702 ); 1688 );
1703 assert_eq!(t, "Foo");
1704} 1689}
1705 1690
1706#[test] 1691#[test]
1707fn not_shadowing_primitive_by_module() { 1692fn not_shadowing_primitive_by_module() {
1708 let t = type_at( 1693 check_types(
1709 r#" 1694 r#"
1710//- /str.rs 1695//- /str.rs
1711fn foo() {} 1696fn foo() {}
@@ -1715,15 +1700,15 @@ mod str;
1715fn foo() -> &'static str { "" } 1700fn foo() -> &'static str { "" }
1716 1701
1717fn main() { 1702fn main() {
1718 foo()<|>; 1703 foo();
1704 //^ &str
1719}"#, 1705}"#,
1720 ); 1706 );
1721 assert_eq!(t, "&str");
1722} 1707}
1723 1708
1724#[test] 1709#[test]
1725fn not_shadowing_module_by_primitive() { 1710fn not_shadowing_module_by_primitive() {
1726 let t = type_at( 1711 check_types(
1727 r#" 1712 r#"
1728//- /str.rs 1713//- /str.rs
1729fn foo() -> u32 {0} 1714fn foo() -> u32 {0}
@@ -1733,10 +1718,10 @@ mod str;
1733fn foo() -> &'static str { "" } 1718fn foo() -> &'static str { "" }
1734 1719
1735fn main() { 1720fn main() {
1736 str::foo()<|>; 1721 str::foo();
1722 //^ u32
1737}"#, 1723}"#,
1738 ); 1724 );
1739 assert_eq!(t, "u32");
1740} 1725}
1741 1726
1742// This test is actually testing the shadowing behavior within ra_hir_def. It 1727// This test is actually testing the shadowing behavior within ra_hir_def. It
@@ -1744,27 +1729,7 @@ fn main() {
1744// capable of asserting the necessary conditions. 1729// capable of asserting the necessary conditions.
1745#[test] 1730#[test]
1746fn should_be_shadowing_imports() { 1731fn should_be_shadowing_imports() {
1747 let t = type_at( 1732 check_types(
1748 r#"
1749mod a {
1750 pub fn foo() -> i8 {0}
1751 pub struct foo { a: i8 }
1752}
1753mod b { pub fn foo () -> u8 {0} }
1754mod c { pub struct foo { a: u8 } }
1755mod d {
1756 pub use super::a::*;
1757 pub use super::c::foo;
1758 pub use super::b::foo;
1759}
1760
1761fn main() {
1762 d::foo()<|>;
1763}"#,
1764 );
1765 assert_eq!(t, "u8");
1766
1767 let t = type_at(
1768 r#" 1733 r#"
1769mod a { 1734mod a {
1770 pub fn foo() -> i8 {0} 1735 pub fn foo() -> i8 {0}
@@ -1779,10 +1744,12 @@ mod d {
1779} 1744}
1780 1745
1781fn main() { 1746fn main() {
1782 d::foo{a:0<|>}; 1747 d::foo();
1748 //^ u8
1749 d::foo{a:0};
1750 //^ u8
1783}"#, 1751}"#,
1784 ); 1752 );
1785 assert_eq!(t, "u8");
1786} 1753}
1787 1754
1788#[test] 1755#[test]
@@ -1880,6 +1847,7 @@ fn main() {
1880 @r###" 1847 @r###"
1881 10..130 '{ ...2 }; }': () 1848 10..130 '{ ...2 }; }': ()
1882 20..21 'x': i32 1849 20..21 'x': i32
1850 24..37 'unsafe { 92 }': i32
1883 31..37 '{ 92 }': i32 1851 31..37 '{ 92 }': i32
1884 33..35 '92': i32 1852 33..35 '92': i32
1885 47..48 'y': {unknown} 1853 47..48 'y': {unknown}
@@ -2151,3 +2119,48 @@ fn test() {
2151 "### 2119 "###
2152 ); 2120 );
2153} 2121}
2122
2123#[test]
2124fn generic_default_depending_on_other_type_arg() {
2125 assert_snapshot!(
2126 infer(r#"
2127struct Thing<T = u128, F = fn() -> T> { t: T }
2128
2129fn test(t1: Thing<u32>, t2: Thing) {
2130 t1;
2131 t2;
2132 Thing::<_> { t: 1u32 };
2133}
2134"#),
2135 // FIXME: the {unknown} is a bug
2136 @r###"
2137 56..58 't1': Thing<u32, fn() -> u32>
2138 72..74 't2': Thing<u128, fn() -> u128>
2139 83..130 '{ ...2 }; }': ()
2140 89..91 't1': Thing<u32, fn() -> u32>
2141 97..99 't2': Thing<u128, fn() -> u128>
2142 105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}>
2143 121..125 '1u32': u32
2144 "###
2145 );
2146}
2147
2148#[test]
2149fn generic_default_depending_on_other_type_arg_forward() {
2150 assert_snapshot!(
2151 infer(r#"
2152struct Thing<F = fn() -> T, T = u128> { t: T }
2153
2154fn test(t1: Thing) {
2155 t1;
2156}
2157"#),
2158 // the {unknown} here is intentional, as defaults are not allowed to
2159 // refer to type parameters coming later
2160 @r###"
2161 56..58 't1': Thing<fn() -> {unknown}, u128>
2162 67..78 '{ t1; }': ()
2163 73..75 't1': Thing<fn() -> {unknown}, u128>
2164 "###
2165 );
2166}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 71c0c2d27..01c919a7e 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,17 +1,13 @@
1use insta::assert_snapshot; 1use insta::assert_snapshot;
2use ra_db::fixture::WithFixture;
3use test_utils::mark; 2use test_utils::mark;
4 3
5use crate::test_db::TestDB; 4use super::{check_types, infer, infer_with_mismatches};
6
7use super::{infer, infer_with_mismatches, type_at, type_at_pos};
8 5
9#[test] 6#[test]
10fn infer_await() { 7fn infer_await() {
11 let (db, pos) = TestDB::with_position( 8 check_types(
12 r#" 9 r#"
13//- /main.rs crate:main deps:core 10//- /main.rs crate:main deps:core
14
15struct IntFuture; 11struct IntFuture;
16 12
17impl Future for IntFuture { 13impl Future for IntFuture {
@@ -21,8 +17,8 @@ impl Future for IntFuture {
21fn test() { 17fn test() {
22 let r = IntFuture; 18 let r = IntFuture;
23 let v = r.await; 19 let v = r.await;
24 v<|>; 20 v;
25} 21} //^ u64
26 22
27//- /core.rs crate:core 23//- /core.rs crate:core
28#[prelude_import] use future::*; 24#[prelude_import] use future::*;
@@ -32,18 +28,15 @@ mod future {
32 type Output; 28 type Output;
33 } 29 }
34} 30}
35
36"#, 31"#,
37 ); 32 );
38 assert_eq!("u64", type_at_pos(&db, pos));
39} 33}
40 34
41#[test] 35#[test]
42fn infer_async() { 36fn infer_async() {
43 let (db, pos) = TestDB::with_position( 37 check_types(
44 r#" 38 r#"
45//- /main.rs crate:main deps:core 39//- /main.rs crate:main deps:core
46
47async fn foo() -> u64 { 40async fn foo() -> u64 {
48 128 41 128
49} 42}
@@ -51,8 +44,8 @@ async fn foo() -> u64 {
51fn test() { 44fn test() {
52 let r = foo(); 45 let r = foo();
53 let v = r.await; 46 let v = r.await;
54 v<|>; 47 v;
55} 48} //^ u64
56 49
57//- /core.rs crate:core 50//- /core.rs crate:core
58#[prelude_import] use future::*; 51#[prelude_import] use future::*;
@@ -62,26 +55,23 @@ mod future {
62 type Output; 55 type Output;
63 } 56 }
64} 57}
65
66"#, 58"#,
67 ); 59 );
68 assert_eq!("u64", type_at_pos(&db, pos));
69} 60}
70 61
71#[test] 62#[test]
72fn infer_desugar_async() { 63fn infer_desugar_async() {
73 let (db, pos) = TestDB::with_position( 64 check_types(
74 r#" 65 r#"
75//- /main.rs crate:main deps:core 66//- /main.rs crate:main deps:core
76
77async fn foo() -> u64 { 67async fn foo() -> u64 {
78 128 68 128
79} 69}
80 70
81fn test() { 71fn test() {
82 let r = foo(); 72 let r = foo();
83 r<|>; 73 r;
84} 74} //^ impl Future<Output = u64>
85 75
86//- /core.rs crate:core 76//- /core.rs crate:core
87#[prelude_import] use future::*; 77#[prelude_import] use future::*;
@@ -93,23 +83,20 @@ mod future {
93 83
94"#, 84"#,
95 ); 85 );
96 assert_eq!("impl Future<Output = u64>", type_at_pos(&db, pos));
97} 86}
98 87
99#[test] 88#[test]
100fn infer_try() { 89fn infer_try() {
101 let (db, pos) = TestDB::with_position( 90 check_types(
102 r#" 91 r#"
103//- /main.rs crate:main deps:core 92//- /main.rs crate:main deps:core
104
105fn test() { 93fn test() {
106 let r: Result<i32, u64> = Result::Ok(1); 94 let r: Result<i32, u64> = Result::Ok(1);
107 let v = r?; 95 let v = r?;
108 v<|>; 96 v;
109} 97} //^ i32
110 98
111//- /core.rs crate:core 99//- /core.rs crate:core
112
113#[prelude_import] use ops::*; 100#[prelude_import] use ops::*;
114mod ops { 101mod ops {
115 trait Try { 102 trait Try {
@@ -130,30 +117,26 @@ mod result {
130 type Error = E; 117 type Error = E;
131 } 118 }
132} 119}
133
134"#, 120"#,
135 ); 121 );
136 assert_eq!("i32", type_at_pos(&db, pos));
137} 122}
138 123
139#[test] 124#[test]
140fn infer_for_loop() { 125fn infer_for_loop() {
141 let (db, pos) = TestDB::with_position( 126 check_types(
142 r#" 127 r#"
143//- /main.rs crate:main deps:core,alloc 128//- /main.rs crate:main deps:core,alloc
144
145use alloc::collections::Vec; 129use alloc::collections::Vec;
146 130
147fn test() { 131fn test() {
148 let v = Vec::new(); 132 let v = Vec::new();
149 v.push("foo"); 133 v.push("foo");
150 for x in v { 134 for x in v {
151 x<|>; 135 x;
152 } 136 } //^ &str
153} 137}
154 138
155//- /core.rs crate:core 139//- /core.rs crate:core
156
157#[prelude_import] use iter::*; 140#[prelude_import] use iter::*;
158mod iter { 141mod iter {
159 trait IntoIterator { 142 trait IntoIterator {
@@ -162,7 +145,6 @@ mod iter {
162} 145}
163 146
164//- /alloc.rs crate:alloc deps:core 147//- /alloc.rs crate:alloc deps:core
165
166mod collections { 148mod collections {
167 struct Vec<T> {} 149 struct Vec<T> {}
168 impl<T> Vec<T> { 150 impl<T> Vec<T> {
@@ -176,15 +158,13 @@ mod collections {
176} 158}
177"#, 159"#,
178 ); 160 );
179 assert_eq!("&str", type_at_pos(&db, pos));
180} 161}
181 162
182#[test] 163#[test]
183fn infer_ops_neg() { 164fn infer_ops_neg() {
184 let (db, pos) = TestDB::with_position( 165 check_types(
185 r#" 166 r#"
186//- /main.rs crate:main deps:std 167//- /main.rs crate:main deps:std
187
188struct Bar; 168struct Bar;
189struct Foo; 169struct Foo;
190 170
@@ -195,11 +175,10 @@ impl std::ops::Neg for Bar {
195fn test() { 175fn test() {
196 let a = Bar; 176 let a = Bar;
197 let b = -a; 177 let b = -a;
198 b<|>;