aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-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/Cargo.toml2
-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/lexer.rs24
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs5
-rw-r--r--crates/ra_tt/src/buffer.rs5
-rw-r--r--crates/rust-analyzer/Cargo.toml4
-rw-r--r--crates/rust-analyzer/src/bin/args.rs31
-rw-r--r--crates/rust-analyzer/src/bin/main.rs3
-rw-r--r--crates/rust-analyzer/src/cli.rs12
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs10
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs7
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs33
-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
65 files changed, 1274 insertions, 892 deletions
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<|>; 178 b;
199} 179} //^ Foo
200 180
201//- /std.rs crate:std 181//- /std.rs crate:std
202
203#[prelude_import] use ops::*; 182#[prelude_import] use ops::*;
204mod ops { 183mod ops {
205 #[lang = "neg"] 184 #[lang = "neg"]
@@ -209,15 +188,13 @@ mod ops {
209} 188}
210"#, 189"#,
211 ); 190 );
212 assert_eq!("Foo", type_at_pos(&db, pos));
213} 191}
214 192
215#[test] 193#[test]
216fn infer_ops_not() { 194fn infer_ops_not() {
217 let (db, pos) = TestDB::with_position( 195 check_types(
218 r#" 196 r#"
219//- /main.rs crate:main deps:std 197//- /main.rs crate:main deps:std
220
221struct Bar; 198struct Bar;
222struct Foo; 199struct Foo;
223 200
@@ -228,11 +205,10 @@ impl std::ops::Not for Bar {
228fn test() { 205fn test() {
229 let a = Bar; 206 let a = Bar;
230 let b = !a; 207 let b = !a;
231 b<|>; 208 b;
232} 209} //^ Foo
233 210
234//- /std.rs crate:std 211//- /std.rs crate:std
235
236#[prelude_import] use ops::*; 212#[prelude_import] use ops::*;
237mod ops { 213mod ops {
238 #[lang = "not"] 214 #[lang = "not"]
@@ -242,7 +218,6 @@ mod ops {
242} 218}
243"#, 219"#,
244 ); 220 );
245 assert_eq!("Foo", type_at_pos(&db, pos));
246} 221}
247 222
248#[test] 223#[test]
@@ -537,10 +512,9 @@ fn indexing_arrays() {
537 512
538#[test] 513#[test]
539fn infer_ops_index() { 514fn infer_ops_index() {
540 let (db, pos) = TestDB::with_position( 515 check_types(
541 r#" 516 r#"
542//- /main.rs crate:main deps:std 517//- /main.rs crate:main deps:std
543
544struct Bar; 518struct Bar;
545struct Foo; 519struct Foo;
546 520
@@ -551,11 +525,10 @@ impl std::ops::Index<u32> for Bar {
551fn test() { 525fn test() {
552 let a = Bar; 526 let a = Bar;
553 let b = a[1u32]; 527 let b = a[1u32];
554 b<|>; 528 b;
555} 529} //^ Foo
556 530
557//- /std.rs crate:std 531//- /std.rs crate:std
558
559#[prelude_import] use ops::*; 532#[prelude_import] use ops::*;
560mod ops { 533mod ops {
561 #[lang = "index"] 534 #[lang = "index"]
@@ -565,19 +538,18 @@ mod ops {
565} 538}
566"#, 539"#,
567 ); 540 );
568 assert_eq!("Foo", type_at_pos(&db, pos));
569} 541}
570 542
571#[test] 543#[test]
572fn infer_ops_index_autoderef() { 544fn infer_ops_index_autoderef() {
573 let (db, pos) = TestDB::with_position( 545 check_types(
574 r#" 546 r#"
575//- /main.rs crate:main deps:std 547//- /main.rs crate:main deps:std
576fn test() { 548fn test() {
577 let a = &[1u32, 2, 3]; 549 let a = &[1u32, 2, 3];
578 let b = a[1u32]; 550 let b = a[1u32];
579 b<|>; 551 b;
580} 552} //^ u32
581 553
582//- /std.rs crate:std 554//- /std.rs crate:std
583impl<T> ops::Index<u32> for [T] { 555impl<T> ops::Index<u32> for [T] {
@@ -593,14 +565,12 @@ mod ops {
593} 565}
594"#, 566"#,
595 ); 567 );
596 assert_eq!("u32", type_at_pos(&db, pos));
597} 568}
598 569
599#[test] 570#[test]
600fn deref_trait() { 571fn deref_trait() {
601 let t = type_at( 572 check_types(
602 r#" 573 r#"
603//- /main.rs
604#[lang = "deref"] 574#[lang = "deref"]
605trait Deref { 575trait Deref {
606 type Target; 576 type Target;
@@ -618,16 +588,15 @@ impl S {
618} 588}
619 589
620fn test(s: Arc<S>) { 590fn test(s: Arc<S>) {
621 (*s, s.foo())<|>; 591 (*s, s.foo());
622} 592} //^ (S, u128)
623"#, 593"#,
624 ); 594 );
625 assert_eq!(t, "(S, u128)");
626} 595}
627 596
628#[test] 597#[test]
629fn deref_trait_with_inference_var() { 598fn deref_trait_with_inference_var() {
630 let t = type_at( 599 check_types(
631 r#" 600 r#"
632//- /main.rs 601//- /main.rs
633#[lang = "deref"] 602#[lang = "deref"]
@@ -647,19 +616,18 @@ fn foo(a: Arc<S>) {}
647 616
648fn test() { 617fn test() {
649 let a = new_arc(); 618 let a = new_arc();
650 let b = (*a)<|>; 619 let b = (*a);
620 //^ S
651 foo(a); 621 foo(a);
652} 622}
653"#, 623"#,
654 ); 624 );
655 assert_eq!(t, "S");
656} 625}
657 626
658#[test] 627#[test]
659fn deref_trait_infinite_recursion() { 628fn deref_trait_infinite_recursion() {
660 let t = type_at( 629 check_types(
661 r#" 630 r#"
662//- /main.rs
663#[lang = "deref"] 631#[lang = "deref"]
664trait Deref { 632trait Deref {
665 type Target; 633 type Target;
@@ -673,18 +641,16 @@ impl Deref for S {
673} 641}
674 642
675fn test(s: S) { 643fn test(s: S) {
676 s.foo()<|>; 644 s.foo();
677} 645} //^ {unknown}
678"#, 646"#,
679 ); 647 );
680 assert_eq!(t, "{unknown}");
681} 648}
682 649
683#[test] 650#[test]
684fn deref_trait_with_question_mark_size() { 651fn deref_trait_with_question_mark_size() {
685 let t = type_at( 652 check_types(
686 r#" 653 r#"
687//- /main.rs
688#[lang = "deref"] 654#[lang = "deref"]
689trait Deref { 655trait Deref {
690 type Target; 656 type Target;
@@ -702,18 +668,16 @@ impl S {
702} 668}
703 669
704fn test(s: Arc<S>) { 670fn test(s: Arc<S>) {
705 (*s, s.foo())<|>; 671 (*s, s.foo());
706} 672} //^ (S, u128)
707"#, 673"#,
708 ); 674 );
709 assert_eq!(t, "(S, u128)");
710} 675}
711 676
712#[test] 677#[test]
713fn obligation_from_function_clause() { 678fn obligation_from_function_clause() {
714 let t = type_at( 679 check_types(
715 r#" 680 r#"
716//- /main.rs
717struct S; 681struct S;
718 682
719trait Trait<T> {} 683trait Trait<T> {}
@@ -722,16 +686,15 @@ impl Trait<u32> for S {}
722fn foo<T: Trait<U>, U>(t: T) -> U {} 686fn foo<T: Trait<U>, U>(t: T) -> U {}
723 687
724fn test(s: S) { 688fn test(s: S) {
725 foo(s)<|>; 689 (foo(s));
726} 690} //^ u32
727"#, 691"#,
728 ); 692 );
729 assert_eq!(t, "u32");
730} 693}
731 694
732#[test] 695#[test]
733fn obligation_from_method_clause() { 696fn obligation_from_method_clause() {
734 let t = type_at( 697 check_types(
735 r#" 698 r#"
736//- /main.rs 699//- /main.rs
737struct S; 700struct S;
@@ -745,18 +708,16 @@ impl O {
745} 708}
746 709
747fn test() { 710fn test() {
748 O.foo(S)<|>; 711 O.foo(S);
749} 712} //^ isize
750"#, 713"#,
751 ); 714 );
752 assert_eq!(t, "isize");
753} 715}
754 716
755#[test] 717#[test]
756fn obligation_from_self_method_clause() { 718fn obligation_from_self_method_clause() {
757 let t = type_at( 719 check_types(
758 r#" 720 r#"
759//- /main.rs
760struct S; 721struct S;
761 722
762trait Trait<T> {} 723trait Trait<T> {}
@@ -767,18 +728,16 @@ impl S {
767} 728}
768 729
769fn test() { 730fn test() {
770 S.foo()<|>; 731 S.foo();
771} 732} //^ i64
772"#, 733"#,
773 ); 734 );
774 assert_eq!(t, "i64");
775} 735}
776 736
777#[test] 737#[test]
778fn obligation_from_impl_clause() { 738fn obligation_from_impl_clause() {
779 let t = type_at( 739 check_types(
780 r#" 740 r#"
781//- /main.rs
782struct S; 741struct S;
783 742
784trait Trait<T> {} 743trait Trait<T> {}
@@ -790,32 +749,30 @@ impl<U, T: Trait<U>> O<T> {
790} 749}
791 750
792fn test(o: O<S>) { 751fn test(o: O<S>) {
793 o.foo()<|>; 752 o.foo();
794} 753} //^ &str
795"#, 754"#,
796 ); 755 );
797 assert_eq!(t, "&str");
798} 756}
799 757
800#[test] 758#[test]
801fn generic_param_env_1() { 759fn generic_param_env_1() {
802 let t = type_at( 760 check_types(
803 r#" 761 r#"
804//- /main.rs
805trait Clone {} 762trait Clone {}
806trait Trait { fn foo(self) -> u128; } 763trait Trait { fn foo(self) -> u128; }
807struct S; 764struct S;
808impl Clone for S {} 765impl Clone for S {}
809impl<T> Trait for T where T: Clone {} 766impl<T> Trait for T where T: Clone {}
810fn test<T: Clone>(t: T) { t.foo()<|>; } 767fn test<T: Clone>(t: T) { t.foo(); }
768 //^ u128
811"#, 769"#,
812 ); 770 );
813 assert_eq!(t, "u128");
814} 771}
815 772
816#[test] 773#[test]
817fn generic_param_env_1_not_met() { 774fn generic_param_env_1_not_met() {
818 let t = type_at( 775 check_types(
819 r#" 776 r#"
820//- /main.rs 777//- /main.rs
821trait Clone {} 778trait Clone {}
@@ -823,45 +780,42 @@ trait Trait { fn foo(self) -> u128; }
823struct S; 780struct S;
824impl Clone for S {} 781impl Clone for S {}
825impl<T> Trait for T where T: Clone {} 782impl<T> Trait for T where T: Clone {}
826fn test<T>(t: T) { t.foo()<|>; } 783fn test<T>(t: T) { t.foo(); }
784 //^ {unknown}
827"#, 785"#,
828 ); 786 );
829 assert_eq!(t, "{unknown}");
830} 787}
831 788
832#[test] 789#[test]
833fn generic_param_env_2() { 790fn generic_param_env_2() {
834 let t = type_at( 791 check_types(
835 r#" 792 r#"
836//- /main.rs
837trait Trait { fn foo(self) -> u128; } 793trait Trait { fn foo(self) -> u128; }
838struct S; 794struct S;
839impl Trait for S {} 795impl Trait for S {}
840fn test<T: Trait>(t: T) { t.foo()<|>; } 796fn test<T: Trait>(t: T) { t.foo(); }
797 //^ u128
841"#, 798"#,
842 ); 799 );
843 assert_eq!(t, "u128");
844} 800}
845 801
846#[test] 802#[test]
847fn generic_param_env_2_not_met() { 803fn generic_param_env_2_not_met() {
848 let t = type_at( 804 check_types(
849 r#" 805 r#"
850//- /main.rs
851trait Trait { fn foo(self) -> u128; } 806trait Trait { fn foo(self) -> u128; }
852struct S; 807struct S;
853impl Trait for S {} 808impl Trait for S {}
854fn test<T>(t: T) { t.foo()<|>; } 809fn test<T>(t: T) { t.foo(); }
810 //^ {unknown}
855"#, 811"#,
856 ); 812 );
857 assert_eq!(t, "{unknown}");
858} 813}
859 814
860#[test] 815#[test]
861fn generic_param_env_deref() { 816fn generic_param_env_deref() {
862 let t = type_at( 817 check_types(
863 r#" 818 r#"
864//- /main.rs
865#[lang = "deref"] 819#[lang = "deref"]
866trait Deref { 820trait Deref {
867 type Target; 821 type Target;
@@ -870,17 +824,17 @@ trait Trait {}
870impl<T> Deref for T where T: Trait { 824impl<T> Deref for T where T: Trait {
871 type Target = i128; 825 type Target = i128;
872} 826}
873fn test<T: Trait>(t: T) { (*t)<|>; } 827fn test<T: Trait>(t: T) { (*t); }
828 //^ i128
874"#, 829"#,
875 ); 830 );
876 assert_eq!(t, "i128");
877} 831}
878 832
879#[test] 833#[test]
880fn associated_type_placeholder() { 834fn associated_type_placeholder() {
881 let t = type_at( 835 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
836 check_types(
882 r#" 837 r#"
883//- /main.rs
884pub trait ApplyL { 838pub trait ApplyL {
885 type Out; 839 type Out;
886} 840}
@@ -893,19 +847,16 @@ impl<T> ApplyL for RefMutL<T> {
893 847
894fn test<T: ApplyL>() { 848fn test<T: ApplyL>() {
895 let y: <RefMutL<T> as ApplyL>::Out = no_matter; 849 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
896 y<|>; 850 y;
897} 851} //^ ApplyL::Out<T>
898"#, 852"#,
899 ); 853 );
900 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
901 assert_eq!(t, "ApplyL::Out<T>");
902} 854}
903 855
904#[test] 856#[test]
905fn associated_type_placeholder_2() { 857fn associated_type_placeholder_2() {
906 let t = type_at( 858 check_types(
907 r#" 859 r#"
908//- /main.rs
909pub trait ApplyL { 860pub trait ApplyL {
910 type Out; 861 type Out;
911} 862}
@@ -913,11 +864,10 @@ fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
913 864
914fn test<T: ApplyL>(t: T) { 865fn test<T: ApplyL>(t: T) {
915 let y = foo(t); 866 let y = foo(t);
916 y<|>; 867 y;
917} 868} //^ ApplyL::Out<T>
918"#, 869"#,
919 ); 870 );
920 assert_eq!(t, "ApplyL::Out<T>");
921} 871}
922 872
923#[test] 873#[test]
@@ -1398,19 +1348,17 @@ fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl (
1398#[test] 1348#[test]
1399#[ignore] 1349#[ignore]
1400fn error_bound_chalk() { 1350fn error_bound_chalk() {
1401 let t = type_at( 1351 check_types(
1402 r#" 1352 r#"
1403//- /main.rs
1404trait Trait { 1353trait Trait {
1405 fn foo(&self) -> u32 {} 1354 fn foo(&self) -> u32 {}
1406} 1355}
1407 1356
1408fn test(x: (impl Trait + UnknownTrait)) { 1357fn test(x: (impl Trait + UnknownTrait)) {
1409 x.foo()<|>; 1358 x.foo();
1410} 1359} //^ u32
1411"#, 1360"#,
1412 ); 1361 );
1413 assert_eq!(t, "u32");
1414} 1362}
1415 1363
1416#[test] 1364#[test]
@@ -1480,7 +1428,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
1480 1428
1481#[test] 1429#[test]
1482fn impl_trait_assoc_binding_projection_bug() { 1430fn impl_trait_assoc_binding_projection_bug() {
1483 let (db, pos) = TestDB::with_position( 1431 check_types(
1484 r#" 1432 r#"
1485//- /main.rs crate:main deps:std 1433//- /main.rs crate:main deps:std
1486pub trait Language { 1434pub trait Language {
@@ -1499,8 +1447,8 @@ trait Clone {
1499 1447
1500fn api_walkthrough() { 1448fn api_walkthrough() {
1501 for node in foo() { 1449 for node in foo() {
1502 node.clone()<|>; 1450 node.clone();
1503 } 1451 } //^ {unknown}
1504} 1452}
1505 1453
1506//- /std.rs crate:std 1454//- /std.rs crate:std
@@ -1518,7 +1466,6 @@ mod iter {
1518} 1466}
1519"#, 1467"#,
1520 ); 1468 );
1521 assert_eq!("{unknown}", type_at_pos(&db, pos));
1522} 1469}
1523 1470
1524#[test] 1471#[test]
@@ -1549,9 +1496,8 @@ fn test<T: Trait1<Type = u32>>(x: T) {
1549 1496
1550#[test] 1497#[test]
1551fn where_clause_trait_in_scope_for_method_resolution() { 1498fn where_clause_trait_in_scope_for_method_resolution() {
1552 let t = type_at( 1499 check_types(
1553 r#" 1500 r#"
1554//- /main.rs
1555mod foo { 1501mod foo {
1556 trait Trait { 1502 trait Trait {
1557 fn foo(&self) -> u32 {} 1503 fn foo(&self) -> u32 {}
@@ -1559,11 +1505,10 @@ mod foo {
1559} 1505}
1560 1506
1561fn test<T: foo::Trait>(x: T) { 1507fn test<T: foo::Trait>(x: T) {
1562 x.foo()<|>; 1508 x.foo();
1563} 1509} //^ u32
1564"#, 1510"#,
1565 ); 1511 );
1566 assert_eq!(t, "u32");
1567} 1512}
1568 1513
1569#[test] 1514#[test]
@@ -2012,7 +1957,7 @@ fn test() {
2012 1957
2013#[test] 1958#[test]
2014fn unselected_projection_in_trait_env_1() { 1959fn unselected_projection_in_trait_env_1() {
2015 let t = type_at( 1960 check_types(
2016 r#" 1961 r#"
2017//- /main.rs 1962//- /main.rs
2018trait Trait { 1963trait Trait {
@@ -2025,18 +1970,16 @@ trait Trait2 {
2025 1970
2026fn test<T: Trait>() where T::Item: Trait2 { 1971fn test<T: Trait>() where T::Item: Trait2 {
2027 let x: T::Item = no_matter; 1972 let x: T::Item = no_matter;
2028 x.foo()<|>; 1973 x.foo();
2029} 1974} //^ u32
2030"#, 1975"#,
2031 ); 1976 );
2032 assert_eq!(t, "u32");
2033} 1977}
2034 1978
2035#[test] 1979#[test]
2036fn unselected_projection_in_trait_env_2() { 1980fn unselected_projection_in_trait_env_2() {
2037 let t = type_at( 1981 check_types(
2038 r#" 1982 r#"
2039//- /main.rs
2040trait Trait<T> { 1983trait Trait<T> {
2041 type Item; 1984 type Item;
2042} 1985}
@@ -2047,11 +1990,10 @@ trait Trait2 {
2047 1990
2048fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { 1991fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
2049 let x: T::Item = no_matter; 1992 let x: T::Item = no_matter;
2050 x.foo()<|>; 1993 x.foo();
2051} 1994} //^ u32
2052"#, 1995"#,
2053 ); 1996 );
2054 assert_eq!(t, "u32");
2055} 1997}
2056 1998
2057#[test] 1999#[test]
@@ -2097,9 +2039,8 @@ impl Trait for S2 {
2097 2039
2098#[test] 2040#[test]
2099fn unselected_projection_on_trait_self() { 2041fn unselected_projection_on_trait_self() {
2100 let t = type_at( 2042 check_types(
2101 r#" 2043 r#"
2102//- /main.rs
2103trait Trait { 2044trait Trait {
2104 type Item; 2045 type Item;
2105 2046
@@ -2112,18 +2053,16 @@ impl Trait for S {
2112} 2053}
2113 2054
2114fn test() { 2055fn test() {
2115 S.f()<|>; 2056 S.f();
2116} 2057} //^ u32
2117"#, 2058"#,
2118 ); 2059 );
2119 assert_eq!(t, "u32");
2120} 2060}
2121 2061
2122#[test] 2062#[test]
2123fn unselected_projection_chalk_fold() { 2063fn unselected_projection_chalk_fold() {
2124 let t = type_at( 2064 check_types(
2125 r#" 2065 r#"
2126//- /main.rs
2127trait Interner {} 2066trait Interner {}
2128trait Fold<I: Interner, TI = I> { 2067trait Fold<I: Interner, TI = I> {
2129 type Result; 2068 type Result;
@@ -2142,18 +2081,16 @@ where
2142} 2081}
2143 2082
2144fn foo<I: Interner>(interner: &I, t: Ty<I>) { 2083fn foo<I: Interner>(interner: &I, t: Ty<I>) {
2145 fold(interner, t)<|>; 2084 fold(interner, t);
2146} 2085} //^ Ty<I>
2147"#, 2086"#,
2148 ); 2087 );
2149 assert_eq!(t, "Ty<I>");
2150} 2088}
2151 2089
2152#[test] 2090#[test]
2153fn trait_impl_self_ty() { 2091fn trait_impl_self_ty() {
2154 let t = type_at( 2092 check_types(
2155 r#" 2093 r#"
2156//- /main.rs
2157trait Trait<T> { 2094trait Trait<T> {
2158 fn foo(&self); 2095 fn foo(&self);
2159} 2096}
@@ -2163,18 +2100,16 @@ struct S;
2163impl Trait<Self> for S {} 2100impl Trait<Self> for S {}
2164 2101
2165fn test() { 2102fn test() {
2166 S.foo()<|>; 2103 S.foo();
2167} 2104} //^ ()
2168"#, 2105"#,
2169 ); 2106 );
2170 assert_eq!(t, "()");
2171} 2107}
2172 2108
2173#[test] 2109#[test]
2174fn trait_impl_self_ty_cycle() { 2110fn trait_impl_self_ty_cycle() {
2175 let t = type_at( 2111 check_types(
2176 r#" 2112 r#"
2177//- /main.rs
2178trait Trait { 2113trait Trait {
2179 fn foo(&self); 2114 fn foo(&self);
2180} 2115}
@@ -2184,18 +2119,17 @@ struct S<T>;
2184impl Trait for S<Self> {} 2119impl Trait for S<Self> {}
2185 2120
2186fn test() { 2121fn test() {
2187 S.foo()<|>; 2122 S.foo();
2188} 2123} //^ {unknown}
2189"#, 2124"#,
2190 ); 2125 );
2191 assert_eq!(t, "{unknown}");
2192} 2126}
2193 2127
2194#[test] 2128#[test]
2195fn unselected_projection_in_trait_env_cycle_1() { 2129fn unselected_projection_in_trait_env_cycle_1() {
2196 let t = type_at( 2130 // this is a legitimate cycle
2131 check_types(
2197 r#" 2132 r#"
2198//- /main.rs
2199trait Trait { 2133trait Trait {
2200 type Item; 2134 type Item;
2201} 2135}
@@ -2203,17 +2137,16 @@ trait Trait {
2203trait Trait2<T> {} 2137trait Trait2<T> {}
2204 2138
2205fn test<T: Trait>() where T: Trait2<T::Item> { 2139fn test<T: Trait>() where T: Trait2<T::Item> {
2206 let x: T::Item = no_matter<|>; 2140 let x: T::Item = no_matter;
2207} 2141} //^ {unknown}
2208"#, 2142"#,
2209 ); 2143 );
2210 // this is a legitimate cycle
2211 assert_eq!(t, "{unknown}");
2212} 2144}
2213 2145
2214#[test] 2146#[test]
2215fn unselected_projection_in_trait_env_cycle_2() { 2147fn unselected_projection_in_trait_env_cycle_2() {
2216 let t = type_at( 2148 // this is a legitimate cycle
2149 check_types(
2217 r#" 2150 r#"
2218//- /main.rs 2151//- /main.rs
2219trait Trait<T> { 2152trait Trait<T> {
@@ -2221,19 +2154,16 @@ trait Trait<T> {
2221} 2154}
2222 2155
2223fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { 2156fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
2224 let x: T::Item = no_matter<|>; 2157 let x: T::Item = no_matter;
2225} 2158} //^ {unknown}
2226"#, 2159"#,
2227 ); 2160 );
2228 // this is a legitimate cycle
2229 assert_eq!(t, "{unknown}");
2230} 2161}
2231 2162
2232#[test] 2163#[test]
2233fn inline_assoc_type_bounds_1() { 2164fn inline_assoc_type_bounds_1() {
2234 let t = type_at( 2165 check_types(
2235 r#" 2166 r#"
2236//- /main.rs
2237trait Iterator { 2167trait Iterator {
2238 type Item; 2168 type Item;
2239} 2169}
@@ -2249,29 +2179,26 @@ impl<T: Iterator> Iterator for S<T> {
2249 2179
2250fn test<I: Iterator<Item: OtherTrait<u32>>>() { 2180fn test<I: Iterator<Item: OtherTrait<u32>>>() {
2251 let x: <S<I> as Iterator>::Item; 2181 let x: <S<I> as Iterator>::Item;
2252 x.foo()<|>; 2182 x.foo();
2253} 2183} //^ u32
2254"#, 2184"#,
2255 ); 2185 );
2256 assert_eq!(t, "u32");
2257} 2186}
2258 2187
2259#[test] 2188#[test]
2260fn inline_assoc_type_bounds_2() { 2189fn inline_assoc_type_bounds_2() {
2261 let t = type_at( 2190 check_types(
2262 r#" 2191 r#"
2263//- /main.rs
2264trait Iterator { 2192trait Iterator {
2265 type Item; 2193 type Item;
2266} 2194}
2267 2195
2268fn test<I: Iterator<Item: Iterator<Item = u32>>>() { 2196fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2269 let x: <<I as Iterator>::Item as Iterator>::Item; 2197 let x: <<I as Iterator>::Item as Iterator>::Item;
2270 x<|>; 2198 x;
2271} 2199} //^ u32
2272"#, 2200"#,
2273 ); 2201 );
2274 assert_eq!(t, "u32");
2275} 2202}
2276 2203
2277#[test] 2204#[test]
@@ -2445,9 +2372,8 @@ fn main() {
2445 2372
2446#[test] 2373#[test]
2447fn associated_type_bound() { 2374fn associated_type_bound() {
2448 let t = type_at( 2375 check_types(
2449 r#" 2376 r#"
2450//- /main.rs
2451pub trait Trait { 2377pub trait Trait {
2452 type Item: OtherTrait<u32>; 2378 type Item: OtherTrait<u32>;
2453} 2379}
@@ -2463,18 +2389,16 @@ impl<T: Trait> Trait for S<T> {
2463 2389
2464fn test<T: Trait>() { 2390fn test<T: Trait>() {
2465 let y: <S<T> as Trait>::Item = no_matter; 2391 let y: <S<T> as Trait>::Item = no_matter;
2466 y.foo()<|>; 2392 y.foo();
2467} 2393} //^ u32
2468"#, 2394"#,
2469 ); 2395 );
2470 assert_eq!(t, "u32");
2471} 2396}
2472 2397
2473#[test] 2398#[test]
2474fn dyn_trait_through_chalk() { 2399fn dyn_trait_through_chalk() {
2475 let t = type_at( 2400 check_types(
2476 r#" 2401 r#"
2477//- /main.rs
2478struct Box<T> {} 2402struct Box<T> {}
2479#[lang = "deref"] 2403#[lang = "deref"]
2480trait Deref { 2404trait Deref {
@@ -2488,18 +2412,16 @@ trait Trait {
2488} 2412}
2489 2413
2490fn test(x: Box<dyn Trait>) { 2414fn test(x: Box<dyn Trait>) {
2491 x.foo()<|>; 2415 x.foo();
2492} 2416} //^ ()
2493"#, 2417"#,
2494 ); 2418 );
2495 assert_eq!(t, "()");
2496} 2419}
2497 2420
2498#[test] 2421#[test]
2499fn string_to_owned() { 2422fn string_to_owned() {
2500 let t = type_at( 2423 check_types(
2501 r#" 2424 r#"
2502//- /main.rs
2503struct String {} 2425struct String {}
2504pub trait ToOwned { 2426pub trait ToOwned {
2505 type Owned; 2427 type Owned;
@@ -2509,11 +2431,10 @@ impl ToOwned for str {
2509 type Owned = String; 2431 type Owned = String;
2510} 2432}
2511fn test() { 2433fn test() {
2512 "foo".to_owned()<|>; 2434 "foo".to_owned();
2513} 2435} //^ String
2514"#, 2436"#,
2515 ); 2437 );
2516 assert_eq!(t, "String");
2517} 2438}
2518 2439
2519#[test] 2440#[test]
@@ -2637,9 +2558,8 @@ fn main() {
2637 2558
2638#[test] 2559#[test]
2639fn nested_assoc() { 2560fn nested_assoc() {
2640 let t = type_at( 2561 check_types(
2641 r#" 2562 r#"
2642//- /main.rs
2643struct Bar; 2563struct Bar;
2644struct Foo; 2564struct Foo;
2645 2565
@@ -2662,11 +2582,10 @@ impl<T:A> B for T {
2662} 2582}
2663 2583
2664fn main() { 2584fn main() {
2665 Bar::foo()<|>; 2585 Bar::foo();
2666} 2586} //^ Foo
2667"#, 2587"#,
2668 ); 2588 );
2669 assert_eq!(t, "Foo");
2670} 2589}
2671 2590
2672#[test] 2591#[test]
@@ -2846,12 +2765,12 @@ fn test() {
2846 2765
2847#[test] 2766#[test]
2848fn integer_range_iterate() { 2767fn integer_range_iterate() {
2849 let t = type_at( 2768 check_types(
2850 r#" 2769 r#"
2851//- /main.rs crate:main deps:core 2770//- /main.rs crate:main deps:core
2852fn test() { 2771fn test() {
2853 for x in 0..100 { x<|>; } 2772 for x in 0..100 { x; }
2854} 2773} //^ i32
2855 2774
2856//- /core.rs crate:core 2775//- /core.rs crate:core
2857pub mod ops { 2776pub mod ops {
@@ -2886,7 +2805,6 @@ impl<A: Step> iter::Iterator for ops::Range<A> {
2886} 2805}
2887"#, 2806"#,
2888 ); 2807 );
2889 assert_eq!(t, "i32");
2890} 2808}
2891 2809
2892#[test] 2810#[test]
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/unsafe_validation.rs
new file mode 100644
index 000000000..c512c4f8e
--- /dev/null
+++ b/crates/ra_hir_ty/src/unsafe_validation.rs
@@ -0,0 +1,120 @@
1//! Provides validations for unsafe code. Currently checks if unsafe functions are missing
2//! unsafe blocks.
3
4use std::sync::Arc;
5
6use hir_def::{
7 body::Body,
8 expr::{Expr, ExprId, UnaryOp},
9 DefWithBodyId, FunctionId,
10};
11use hir_expand::diagnostics::DiagnosticSink;
12
13use crate::{
14 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy,
15 InferenceResult, Ty, TypeCtor,
16};
17
18pub struct UnsafeValidator<'a, 'b: 'a> {
19 func: FunctionId,
20 infer: Arc<InferenceResult>,
21 sink: &'a mut DiagnosticSink<'b>,
22}
23
24impl<'a, 'b> UnsafeValidator<'a, 'b> {
25 pub fn new(
26 func: FunctionId,
27 infer: Arc<InferenceResult>,
28 sink: &'a mut DiagnosticSink<'b>,
29 ) -> UnsafeValidator<'a, 'b> {
30 UnsafeValidator { func, infer, sink }
31 }
32
33 pub fn validate_body(&mut self, db: &dyn HirDatabase) {
34 let def = self.func.into();
35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
36 let func_data = db.function_data(self.func);
37 if func_data.is_unsafe
38 || unsafe_expressions
39 .iter()
40 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
41 .count()
42 == 0
43 {
44 return;
45 }
46
47 let (_, body_source) = db.body_with_source_map(def);
48 for unsafe_expr in unsafe_expressions {
49 if !unsafe_expr.inside_unsafe_block {
50 if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) {
51 self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value })
52 }
53 }
54 }
55 }
56}
57
58pub struct UnsafeExpr {
59 pub expr: ExprId,
60 pub inside_unsafe_block: bool,
61}
62
63pub fn unsafe_expressions(
64 db: &dyn HirDatabase,
65 infer: &InferenceResult,
66 def: DefWithBodyId,
67) -> Vec<UnsafeExpr> {
68 let mut unsafe_exprs = vec![];
69 let body = db.body(def);
70 walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false);
71
72 unsafe_exprs
73}
74
75fn walk_unsafe(
76 unsafe_exprs: &mut Vec<UnsafeExpr>,
77 db: &dyn HirDatabase,
78 infer: &InferenceResult,
79 body: &Body,
80 current: ExprId,
81 inside_unsafe_block: bool,
82) {
83 let expr = &body.exprs[current];
84 match expr {
85 Expr::Call { callee, .. } => {
86 let ty = &infer[*callee];
87 if let &Ty::Apply(ApplicationTy {
88 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)),
89 ..
90 }) = ty
91 {
92 if db.function_data(func).is_unsafe {
93 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
94 }
95 }
96 }
97 Expr::MethodCall { .. } => {
98 if infer
99 .method_resolution(current)
100 .map(|func| db.function_data(func).is_unsafe)
101 .unwrap_or(false)
102 {
103 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
104 }
105 }
106 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
107 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] {
108 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
109 }
110 }
111 Expr::Unsafe { body: child } => {
112 return walk_unsafe(unsafe_exprs, db, infer, body, *child, true);
113 }
114 _ => {}
115 }
116
117 expr.walk_child_exprs(|child| {
118 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block);
119 });
120}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 3fd08b1e8..c87652555 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -258,6 +258,7 @@ fn should_show_param_name_hint(
258 if param_name.is_empty() 258 if param_name.is_empty()
259 || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) 259 || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_'))
260 || is_argument_similar_to_param_name(sema, argument, param_name) 260 || is_argument_similar_to_param_name(sema, argument, param_name)
261 || param_name.starts_with("ra_fixture")
261 { 262 {
262 return false; 263 return false;
263 } 264 }
@@ -270,7 +271,7 @@ fn should_show_param_name_hint(
270 271
271 // avoid displaying hints for common functions like map, filter, etc. 272 // avoid displaying hints for common functions like map, filter, etc.
272 // or other obvious words used in std 273 // or other obvious words used in std
273 parameters_len != 1 || !is_obvious_param(param_name) 274 !(parameters_len == 1 && is_obvious_param(param_name))
274} 275}
275 276
276fn is_argument_similar_to_param_name( 277fn is_argument_similar_to_param_name(
@@ -312,10 +313,8 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
312} 313}
313 314
314fn is_obvious_param(param_name: &str) -> bool { 315fn is_obvious_param(param_name: &str) -> bool {
315 let is_obvious_param_name = match param_name { 316 let is_obvious_param_name =
316 "predicate" | "value" | "pat" | "rhs" | "other" => true, 317 matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
317 _ => false,
318 };
319 param_name.len() == 1 || is_obvious_param_name 318 param_name.len() == 1 || is_obvious_param_name
320} 319}
321 320
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs
index 5036c1fb0..6907c09e8 100644
--- a/crates/ra_ide/src/join_lines.rs
+++ b/crates/ra_ide/src/join_lines.rs
@@ -165,10 +165,7 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti
165} 165}
166 166
167fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { 167fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
168 match (left, right) { 168 matches!((left, right), (T![,], T![')']) | (T![,], T![']']))
169 (T![,], T![')']) | (T![,], T![']']) => true,
170 _ => false,
171 }
172} 169}
173 170
174#[cfg(test)] 171#[cfg(test)]
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index e8e251cfc..13d9dd195 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -25,7 +25,6 @@ pub enum HighlightTag {
25 EnumVariant, 25 EnumVariant,
26 EscapeSequence, 26 EscapeSequence,
27 Field, 27 Field,
28 FormatSpecifier,
29 Function, 28 Function,
30 Generic, 29 Generic,
31 Keyword, 30 Keyword,
@@ -33,7 +32,6 @@ pub enum HighlightTag {
33 Macro, 32 Macro,
34 Module, 33 Module,
35 NumericLiteral, 34 NumericLiteral,
36 Operator,
37 SelfKeyword, 35 SelfKeyword,
38 SelfType, 36 SelfType,
39 Static, 37 Static,
@@ -45,6 +43,8 @@ pub enum HighlightTag {
45 Union, 43 Union,
46 Local, 44 Local,
47 UnresolvedReference, 45 UnresolvedReference,
46 FormatSpecifier,
47 Operator,
48} 48}
49 49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index 6929055b2..5a09e7d1d 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -346,10 +346,7 @@ impl Query {
346} 346}
347 347
348fn is_type(kind: SyntaxKind) -> bool { 348fn is_type(kind: SyntaxKind) -> bool {
349 match kind { 349 matches!(kind, STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF)
350 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => true,
351 _ => false,
352 }
353} 350}
354 351
355/// The actual data that is stored in the index. It should be as compact as 352/// The actual data that is stored in the index. It should be as compact as
diff --git a/crates/ra_mbe/src/parser.rs b/crates/ra_mbe/src/parser.rs
index 034150432..1e5dafbdf 100644
--- a/crates/ra_mbe/src/parser.rs
+++ b/crates/ra_mbe/src/parser.rs
@@ -137,10 +137,7 @@ fn eat_fragment_kind<'a>(
137} 137}
138 138
139fn is_boolean_literal(lit: &tt::Literal) -> bool { 139fn is_boolean_literal(lit: &tt::Literal) -> bool {
140 match lit.text.as_str() { 140 matches!(lit.text.as_str(), "true" | "false")
141 "true" | "false" => true,
142 _ => false,
143 }
144} 141}
145 142
146fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> { 143fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> {
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 293baecf6..caedeead0 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -73,10 +73,7 @@ pub(crate) mod fragments {
73 // Parse a meta item , which excluded [], e.g : #[ MetaItem ] 73 // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
74 pub(crate) fn meta_item(p: &mut Parser) { 74 pub(crate) fn meta_item(p: &mut Parser) {
75 fn is_delimiter(p: &mut Parser) -> bool { 75 fn is_delimiter(p: &mut Parser) -> bool {
76 match p.current() { 76 matches!(p.current(), T!['{'] | T!['('] | T!['['])
77 T!['{'] | T!['('] | T!['['] => true,
78 _ => false,
79 }
80 } 77 }
81 78
82 if is_delimiter(p) { 79 if is_delimiter(p) {
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
index fd51189d5..b503af1dc 100644
--- a/crates/ra_parser/src/grammar/paths.rs
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -41,10 +41,7 @@ fn path(p: &mut Parser, mode: Mode) {
41 path_segment(p, mode, true); 41 path_segment(p, mode, true);
42 let mut qual = path.complete(p, PATH); 42 let mut qual = path.complete(p, PATH);
43 loop { 43 loop {
44 let use_tree = match p.nth(2) { 44 let use_tree = matches!(p.nth(2), T![*] | T!['{']);
45 T![*] | T!['{'] => true,
46 _ => false,
47 };
48 if p.at(T![::]) && !use_tree { 45 if p.at(T![::]) && !use_tree {
49 let path = qual.precede(p); 46 let path = qual.precede(p);
50 p.bump(T![::]); 47 p.bump(T![::]);
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index 325d566ad..d1330d4b9 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -169,10 +169,7 @@ fn is_where_predicate(p: &mut Parser) -> bool {
169} 169}
170 170
171fn is_where_clause_end(p: &mut Parser) -> bool { 171fn is_where_clause_end(p: &mut Parser) -> bool {
172 match p.current() { 172 matches!(p.current(), T!['{'] | T![;] | T![=])
173 T!['{'] | T![;] | T![=] => true,
174 _ => false,
175 }
176} 173}
177 174
178fn where_predicate(p: &mut Parser) { 175fn where_predicate(p: &mut Parser) {
diff --git a/crates/ra_parser/src/syntax_kind.rs b/crates/ra_parser/src/syntax_kind.rs
index 8d6bd057b..63204436c 100644
--- a/crates/ra_parser/src/syntax_kind.rs
+++ b/crates/ra_parser/src/syntax_kind.rs
@@ -20,9 +20,6 @@ impl From<SyntaxKind> for u16 {
20 20
21impl SyntaxKind { 21impl SyntaxKind {
22 pub fn is_trivia(self) -> bool { 22 pub fn is_trivia(self) -> bool {
23 match self { 23 matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
24 SyntaxKind::WHITESPACE | SyntaxKind::COMMENT => true,
25 _ => false,
26 }
27 } 24 }
28} 25}
diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs
index 8f149e3db..e148f4564 100644
--- a/crates/ra_ssr/src/lib.rs
+++ b/crates/ra_ssr/src/lib.rs
@@ -69,7 +69,8 @@ impl<'db> MatchFinder<'db> {
69 if matches.matches.is_empty() { 69 if matches.matches.is_empty() {
70 None 70 None
71 } else { 71 } else {
72 Some(replacing::matches_to_edit(&matches)) 72 use ra_db::SourceDatabaseExt;
73 Some(replacing::matches_to_edit(&matches, &self.sema.db.file_text(file_id)))
73 } 74 }
74 } 75 }
75 76
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index 85420ed3c..bb87bda43 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -585,7 +585,7 @@ mod tests {
585 "1+2" 585 "1+2"
586 ); 586 );
587 587
588 let edit = crate::replacing::matches_to_edit(&matches); 588 let edit = crate::replacing::matches_to_edit(&matches, input);
589 let mut after = input.to_string(); 589 let mut after = input.to_string();
590 edit.apply(&mut after); 590 edit.apply(&mut after);
591 assert_eq!(after, "fn main() { bar(1+2); }"); 591 assert_eq!(after, "fn main() { bar(1+2); }");
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs
index 90c13dbc2..1ae166d19 100644
--- a/crates/ra_ssr/src/parsing.rs
+++ b/crates/ra_ssr/src/parsing.rs
@@ -165,7 +165,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
165/// Checks for errors in a rule. e.g. the replace pattern referencing placeholders that the search 165/// Checks for errors in a rule. e.g. the replace pattern referencing placeholders that the search
166/// pattern didn't define. 166/// pattern didn't define.
167fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { 167fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
168 let mut defined_placeholders = std::collections::HashSet::new(); 168 let mut defined_placeholders = FxHashSet::default();
169 for p in &rule.pattern.raw.tokens { 169 for p in &rule.pattern.raw.tokens {
170 if let PatternElement::Placeholder(placeholder) = p { 170 if let PatternElement::Placeholder(placeholder) = p {
171 defined_placeholders.insert(&placeholder.ident); 171 defined_placeholders.insert(&placeholder.ident);
diff --git a/crates/ra_ssr/src/replacing.rs b/crates/ra_ssr/src/replacing.rs
index 5dcde82a2..70ce1c185 100644
--- a/crates/ra_ssr/src/replacing.rs
+++ b/crates/ra_ssr/src/replacing.rs
@@ -10,21 +10,25 @@ use ra_text_edit::TextEdit;
10/// Returns a text edit that will replace each match in `matches` with its corresponding replacement 10/// Returns a text edit that will replace each match in `matches` with its corresponding replacement
11/// template. Placeholders in the template will have been substituted with whatever they matched to 11/// template. Placeholders in the template will have been substituted with whatever they matched to
12/// in the original code. 12/// in the original code.
13pub(crate) fn matches_to_edit(matches: &SsrMatches) -> TextEdit { 13pub(crate) fn matches_to_edit(matches: &SsrMatches, file_src: &str) -> TextEdit {
14 matches_to_edit_at_offset(matches, 0.into()) 14 matches_to_edit_at_offset(matches, file_src, 0.into())
15} 15}
16 16
17fn matches_to_edit_at_offset(matches: &SsrMatches, relative_start: TextSize) -> TextEdit { 17fn matches_to_edit_at_offset(
18 matches: &SsrMatches,
19 file_src: &str,
20 relative_start: TextSize,
21) -> TextEdit {
18 let mut edit_builder = ra_text_edit::TextEditBuilder::default(); 22 let mut edit_builder = ra_text_edit::TextEditBuilder::default();
19 for m in &matches.matches { 23 for m in &matches.matches {
20 edit_builder.replace(m.range.checked_sub(relative_start).unwrap(), render_replace(m)); 24 edit_builder
25 .replace(m.range.checked_sub(relative_start).unwrap(), render_replace(m, file_src));
21 } 26 }
22 edit_builder.finish() 27 edit_builder.finish()
23} 28}
24 29
25fn render_replace(match_info: &Match) -> String { 30fn render_replace(match_info: &Match, file_src: &str) -> String {
26 let mut out = String::new(); 31 let mut out = String::new();
27 let match_start = match_info.matched_node.text_range().start();
28 for r in &match_info.template.tokens { 32 for r in &match_info.template.tokens {
29 match r { 33 match r {
30 PatternElement::Token(t) => out.push_str(t.text.as_str()), 34 PatternElement::Token(t) => out.push_str(t.text.as_str()),
@@ -33,16 +37,13 @@ fn render_replace(match_info: &Match) -> String {
33 match_info.placeholder_values.get(&Var(p.ident.to_string())) 37 match_info.placeholder_values.get(&Var(p.ident.to_string()))
34 { 38 {
35 let range = &placeholder_value.range.range; 39 let range = &placeholder_value.range.range;
36 let mut matched_text = if let Some(node) = &placeholder_value.node { 40 let mut matched_text =
37 node.text().to_string() 41 file_src[usize::from(range.start())..usize::from(range.end())].to_owned();
38 } else { 42 let edit = matches_to_edit_at_offset(
39 let relative_range = range.checked_sub(match_start).unwrap(); 43 &placeholder_value.inner_matches,
40 match_info.matched_node.text().to_string() 44 file_src,
41 [usize::from(relative_range.start())..usize::from(relative_range.end())] 45 range.start(),
42 .to_string() 46 );
43 };
44 let edit =
45 matches_to_edit_at_offset(&placeholder_value.inner_matches, range.start());
46 edit.apply(&mut matched_text); 47 edit.apply(&mut matched_text);
47 out.push_str(&matched_text); 48 out.push_str(&matched_text);
48 } else { 49 } else {
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index 7a3141be8..8be60c293 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -606,3 +606,20 @@ fn replace_within_macro_expansion() {
606 fn f() {macro1!(bar(5.x()).o2())}"#, 606 fn f() {macro1!(bar(5.x()).o2())}"#,
607 ) 607 )
608} 608}
609
610#[test]
611fn preserves_whitespace_within_macro_expansion() {
612 assert_ssr_transform(
613 "$a + $b ==>> $b - $a",
614 r#"
615 macro_rules! macro1 {
616 ($a:expr) => {$a}
617 }
618 fn f() {macro1!(1 * 2 + 3 + 4}"#,
619 r#"
620 macro_rules! macro1 {
621 ($a:expr) => {$a}
622 }
623 fn f() {macro1!(4 - 3 - 1 * 2}"#,
624 )
625}
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index a8ff2e74f..49696ce75 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "661.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "666.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index f7a885eb3..26b3c813a 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -41,6 +41,10 @@ pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextSize) ->
41 ancestors_at_offset(syntax, offset).find_map(N::cast) 41 ancestors_at_offset(syntax, offset).find_map(N::cast)
42} 42}
43 43
44pub fn find_node_at_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
45 find_covering_element(syntax, range).ancestors().find_map(N::cast)
46}
47
44/// Skip to next non `trivia` token 48/// Skip to next non `trivia` token
45pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> { 49pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> {
46 while token.kind().is_trivia() { 50 while token.kind().is_trivia() {
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 7771d6759..db5438d68 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -399,10 +399,7 @@ impl ast::BlockExpr {
399 Some(it) => it, 399 Some(it) => it,
400 None => return true, 400 None => return true,
401 }; 401 };
402 match parent.kind() { 402 !matches!(parent.kind(), FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR)
403 FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR => false,
404 _ => true,
405 }
406 } 403 }
407} 404}
408 405
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 98c38d009..662c6f73e 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -459,16 +459,16 @@ impl ast::RangePat {
459 459
460impl ast::TokenTree { 460impl ast::TokenTree {
461 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> { 461 pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
462 self.syntax().first_child_or_token()?.into_token().filter(|it| match it.kind() { 462 self.syntax()
463 T!['{'] | T!['('] | T!['['] => true, 463 .first_child_or_token()?
464 _ => false, 464 .into_token()
465 }) 465 .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
466 } 466 }
467 467
468 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> { 468 pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
469 self.syntax().last_child_or_token()?.into_token().filter(|it| match it.kind() { 469 self.syntax()
470 T!['}'] | T![')'] | T![']'] => true, 470 .last_child_or_token()?
471 _ => false, 471 .into_token()
472 }) 472 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
473 } 473 }
474} 474}
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs
index 1a5a6dc06..fa3be1016 100644
--- a/crates/ra_syntax/src/parsing/lexer.rs
+++ b/crates/ra_syntax/src/parsing/lexer.rs
@@ -1,6 +1,8 @@
1//! Lexer analyzes raw input string and produces lexemes (tokens). 1//! Lexer analyzes raw input string and produces lexemes (tokens).
2//! It is just a bridge to `rustc_lexer`. 2//! It is just a bridge to `rustc_lexer`.
3 3
4use rustc_lexer::{LiteralKind as LK, RawStrError};
5
4use std::convert::TryInto; 6use std::convert::TryInto;
5 7
6use crate::{ 8use crate::{
@@ -180,8 +182,6 @@ fn rustc_token_kind_to_syntax_kind(
180 return (syntax_kind, None); 182 return (syntax_kind, None);
181 183
182 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<&'static str>) { 184 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<&'static str>) {
183 use rustc_lexer::{LexRawStrError, LiteralKind as LK};
184
185 #[rustfmt::skip] 185 #[rustfmt::skip]
186 let syntax_kind = match *kind { 186 let syntax_kind = match *kind {
187 LK::Int { empty_int: false, .. } => INT_NUMBER, 187 LK::Int { empty_int: false, .. } => INT_NUMBER,
@@ -215,27 +215,27 @@ fn rustc_token_kind_to_syntax_kind(
215 return (BYTE_STRING, Some("Missing trailing `\"` symbol to terminate the byte string literal")) 215 return (BYTE_STRING, Some("Missing trailing `\"` symbol to terminate the byte string literal"))
216 } 216 }
217 217
218 LK::RawStr(str) => match str.validate() { 218 LK::RawStr { err, .. } => match err {
219 Ok(_) => RAW_STRING, 219 None => RAW_STRING,
220 Err(LexRawStrError::InvalidStarter) => return (RAW_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw string literal")), 220 Some(RawStrError::InvalidStarter { .. }) => return (RAW_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw string literal")),
221 Err(LexRawStrError::NoTerminator { expected, found, .. }) => if expected == found { 221 Some(RawStrError::NoTerminator { expected, found, .. }) => if expected == found {
222 return (RAW_STRING, Some("Missing trailing `\"` to terminate the raw string literal")) 222 return (RAW_STRING, Some("Missing trailing `\"` to terminate the raw string literal"))
223 } else { 223 } else {
224 return (RAW_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw string literal")) 224 return (RAW_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw string literal"))
225 225
226 }, 226 },
227 Err(LexRawStrError::TooManyDelimiters { .. }) => return (RAW_STRING, Some("Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols")), 227 Some(RawStrError::TooManyDelimiters { .. }) => return (RAW_STRING, Some("Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols")),
228 }, 228 },
229 LK::RawByteStr(str) => match str.validate() { 229 LK::RawByteStr { err, .. } => match err {
230 Ok(_) => RAW_BYTE_STRING, 230 None => RAW_BYTE_STRING,
231 Err(LexRawStrError::InvalidStarter) => return (RAW_BYTE_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw byte string literal")), 231 Some(RawStrError::InvalidStarter { .. }) => return (RAW_BYTE_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw byte string literal")),
232 Err(LexRawStrError::NoTerminator { expected, found, .. }) => if expected == found { 232 Some(RawStrError::NoTerminator { expected, found, .. }) => if expected == found {
233 return (RAW_BYTE_STRING, Some("Missing trailing `\"` to terminate the raw byte string literal")) 233 return (RAW_BYTE_STRING, Some("Missing trailing `\"` to terminate the raw byte string literal"))
234 } else { 234 } else {
235 return (RAW_BYTE_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw byte string literal")) 235 return (RAW_BYTE_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"))
236 236
237 }, 237 },
238 Err(LexRawStrError::TooManyDelimiters { .. }) => return (RAW_BYTE_STRING, Some("Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols")), 238 Some(RawStrError::TooManyDelimiters { .. }) => return (RAW_BYTE_STRING, Some("Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols")),
239 }, 239 },
240 }; 240 };
241 241
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index edbc190f8..ed5a42ea3 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -120,10 +120,7 @@ fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
120} 120}
121 121
122fn is_contextual_kw(text: &str) -> bool { 122fn is_contextual_kw(text: &str) -> bool {
123 match text { 123 matches!(text, "auto" | "default" | "union")
124 "auto" | "default" | "union" => true,
125 _ => false,
126 }
127} 124}
128 125
129fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { 126fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
diff --git a/crates/ra_tt/src/buffer.rs b/crates/ra_tt/src/buffer.rs
index 5967f44cd..02c771f70 100644
--- a/crates/ra_tt/src/buffer.rs
+++ b/crates/ra_tt/src/buffer.rs
@@ -105,10 +105,7 @@ impl<'a> Eq for Cursor<'a> {}
105impl<'a> Cursor<'a> { 105impl<'a> Cursor<'a> {
106 /// Check whether it is eof 106 /// Check whether it is eof
107 pub fn eof(self) -> bool { 107 pub fn eof(self) -> bool {
108 match self.buffer.entry(&self.ptr) { 108 matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None)))
109 None | Some(Entry::End(None)) => true,
110 _ => false,
111 }
112 } 109 }
113 110
114 /// If the cursor is pointing at the end of a subtree, returns 111 /// If the cursor is pointing at the end of a subtree, returns
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 122a1605f..803755106 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -21,7 +21,7 @@ itertools = "0.9.0"
21jod-thread = "0.1.0" 21jod-thread = "0.1.0"
22log = "0.4.8" 22log = "0.4.8"
23lsp-types = { version = "0.74.0", features = ["proposed"] } 23lsp-types = { version = "0.74.0", features = ["proposed"] }
24parking_lot = "0.10.0" 24parking_lot = "0.11.0"
25pico-args = "0.3.1" 25pico-args = "0.3.1"
26rand = { version = "0.7.3", features = ["small_rng"] } 26rand = { version = "0.7.3", features = ["small_rng"] }
27rustc-hash = "1.1.0" 27rustc-hash = "1.1.0"
@@ -45,6 +45,8 @@ ra_toolchain = { path = "../ra_toolchain" }
45 45
46# This should only be used in CLI 46# This should only be used in CLI
47ra_db = { path = "../ra_db" } 47ra_db = { path = "../ra_db" }
48ra_ide_db = { path = "../ra_ide_db" }
49ra_ssr = { path = "../ra_ssr" }
48hir = { path = "../ra_hir", package = "ra_hir" } 50hir = { path = "../ra_hir", package = "ra_hir" }
49hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 51hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
50hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } 52hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 8e3ca9343..3f0bb3865 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -5,6 +5,7 @@
5 5
6use anyhow::{bail, Result}; 6use anyhow::{bail, Result};
7use pico_args::Arguments; 7use pico_args::Arguments;
8use ra_ssr::SsrRule;
8use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 9use rust_analyzer::cli::{BenchWhat, Position, Verbosity};
9 10
10use std::{fmt::Write, path::PathBuf}; 11use std::{fmt::Write, path::PathBuf};
@@ -45,6 +46,9 @@ pub(crate) enum Command {
45 /// this would include the parser test files. 46 /// this would include the parser test files.
46 all: bool, 47 all: bool,
47 }, 48 },
49 Ssr {
50 rules: Vec<SsrRule>,
51 },
48 ProcMacro, 52 ProcMacro,
49 RunServer, 53 RunServer,
50 Version, 54 Version,
@@ -270,6 +274,32 @@ ARGS:
270 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } 274 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all }
271 } 275 }
272 "proc-macro" => Command::ProcMacro, 276 "proc-macro" => Command::ProcMacro,
277 "ssr" => {
278 if matches.contains(["-h", "--help"]) {
279 eprintln!(
280 "\
281rust-analyzer ssr
282
283USAGE:
284 rust-analyzer ssr [FLAGS] [RULE...]
285
286EXAMPLE:
287 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
288
289FLAGS:
290 -h, --help Prints help information
291
292ARGS:
293 <RULE> A structured search replace rule"
294 );
295 return Ok(Err(HelpPrinted));
296 }
297 let mut rules = Vec::new();
298 while let Some(rule) = matches.free_from_str()? {
299 rules.push(rule);
300 }
301 Command::Ssr { rules }
302 }
273 _ => { 303 _ => {
274 print_subcommands(); 304 print_subcommands();
275 return Ok(Err(HelpPrinted)); 305 return Ok(Err(HelpPrinted));
@@ -297,6 +327,7 @@ SUBCOMMANDS:
297 diagnostics 327 diagnostics
298 proc-macro 328 proc-macro
299 parse 329 parse
330 ssr
300 symbols" 331 symbols"
301 ) 332 )
302} 333}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 45204d1a3..16882fc13 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -60,6 +60,9 @@ fn main() -> Result<()> {
60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
62 } 62 }
63 args::Command::Ssr { rules } => {
64 cli::apply_ssr_rules(rules)?;
65 }
63 args::Command::Version => println!("rust-analyzer {}", env!("REV")), 66 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
64 } 67 }
65 Ok(()) 68 Ok(())
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index 39ce77900..13e3d75be 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -5,6 +5,7 @@ mod analysis_stats;
5mod analysis_bench; 5mod analysis_bench;
6mod diagnostics; 6mod diagnostics;
7mod progress_report; 7mod progress_report;
8mod ssr;
8 9
9use std::io::Read; 10use std::io::Read;
10 11
@@ -17,6 +18,7 @@ pub use analysis_bench::{analysis_bench, BenchWhat, Position};
17pub use analysis_stats::analysis_stats; 18pub use analysis_stats::analysis_stats;
18pub use diagnostics::diagnostics; 19pub use diagnostics::diagnostics;
19pub use load_cargo::load_cargo; 20pub use load_cargo::load_cargo;
21pub use ssr::apply_ssr_rules;
20 22
21#[derive(Clone, Copy)] 23#[derive(Clone, Copy)]
22pub enum Verbosity { 24pub enum Verbosity {
@@ -28,16 +30,10 @@ pub enum Verbosity {
28 30
29impl Verbosity { 31impl Verbosity {
30 pub fn is_verbose(self) -> bool { 32 pub fn is_verbose(self) -> bool {
31 match self { 33 matches!(self, Verbosity::Verbose | Verbosity::Spammy)
32 Verbosity::Verbose | Verbosity::Spammy => true,
33 _ => false,
34 }
35 } 34 }
36 pub fn is_spammy(self) -> bool { 35 pub fn is_spammy(self) -> bool {
37 match self { 36 matches!(self, Verbosity::Spammy)
38 Verbosity::Spammy => true,
39 _ => false,
40 }
41 } 37 }
42} 38}
43 39
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 4fe99ff68..930375d3e 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -78,10 +78,7 @@ pub fn analysis_bench(
78 } 78 }
79 } 79 }
80 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => { 80 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
81 let is_completion = match what { 81 let is_completion = matches!(what, BenchWhat::Complete(..));
82 BenchWhat::Complete(..) => true,
83 _ => false,
84 };
85 82
86 let offset = host 83 let offset = host
87 .analysis() 84 .analysis()
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2f4c29e06..9d09501cd 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -1,7 +1,11 @@
1//! Fully type-check project and print various stats, like the number of type 1//! Fully type-check project and print various stats, like the number of type
2//! errors. 2//! errors.
3 3
4use std::{collections::HashSet, path::Path, time::Instant}; 4use std::{path::Path, time::Instant};
5
6use itertools::Itertools;
7use rand::{seq::SliceRandom, thread_rng};
8use rustc_hash::FxHashSet;
5 9
6use hir::{ 10use hir::{
7 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
@@ -9,10 +13,8 @@ use hir::{
9}; 13};
10use hir_def::FunctionId; 14use hir_def::FunctionId;
11use hir_ty::{Ty, TypeWalk}; 15use hir_ty::{Ty, TypeWalk};
12use itertools::Itertools;
13use ra_db::SourceDatabaseExt; 16use ra_db::SourceDatabaseExt;
14use ra_syntax::AstNode; 17use ra_syntax::AstNode;
15use rand::{seq::SliceRandom, thread_rng};
16use stdx::format_to; 18use stdx::format_to;
17 19
18use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; 20use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity};
@@ -33,7 +35,7 @@ pub fn analysis_stats(
33 println!("Database loaded {:?}", db_load_time.elapsed()); 35 println!("Database loaded {:?}", db_load_time.elapsed());
34 let analysis_time = Instant::now(); 36 let analysis_time = Instant::now();
35 let mut num_crates = 0; 37 let mut num_crates = 0;
36 let mut visited_modules = HashSet::new(); 38 let mut visited_modules = FxHashSet::default();
37 let mut visit_queue = Vec::new(); 39 let mut visit_queue = Vec::new();
38 40
39 let mut krates = Crate::all(db); 41 let mut krates = Crate::all(db);
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 82b3a8a53..6f3c1c1f9 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -1,11 +1,14 @@
1//! Analyze all modules in a project for diagnostics. Exits with a non-zero status 1//! Analyze all modules in a project for diagnostics. Exits with a non-zero status
2//! code if any errors are found. 2//! code if any errors are found.
3 3
4use std::path::Path;
5
4use anyhow::anyhow; 6use anyhow::anyhow;
7use rustc_hash::FxHashSet;
8
5use hir::Crate; 9use hir::Crate;
6use ra_db::SourceDatabaseExt; 10use ra_db::SourceDatabaseExt;
7use ra_ide::Severity; 11use ra_ide::Severity;
8use std::{collections::HashSet, path::Path};
9 12
10use crate::cli::{load_cargo::load_cargo, Result}; 13use crate::cli::{load_cargo::load_cargo, Result};
11 14
@@ -20,7 +23,7 @@ pub fn diagnostics(
20 let analysis = host.analysis(); 23 let analysis = host.analysis();
21 24
22 let mut found_error = false; 25 let mut found_error = false;
23 let mut visited_files = HashSet::new(); 26 let mut visited_files = FxHashSet::default();
24 27
25 let mut work = Vec::new(); 28 let mut work = Vec::new();
26 let krates = Crate::all(db); 29 let krates = Crate::all(db);
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
new file mode 100644
index 000000000..a5265ac15
--- /dev/null
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -0,0 +1,33 @@
1//! Applies structured search replace rules from the command line.
2
3use crate::cli::{load_cargo::load_cargo, Result};
4use ra_ide::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrRule};
6
7pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
8 use ra_db::SourceDatabaseExt;
9 use ra_ide_db::symbol_index::SymbolsDatabase;
10 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
11 let db = host.raw_database();
12 let mut match_finder = MatchFinder::new(db);
13 for rule in rules {
14 match_finder.add_rule(rule);
15 }
16 let mut edits = Vec::new();
17 for &root in db.local_roots().iter() {
18 let sr = db.source_root(root);
19 for file_id in sr.iter() {
20 if let Some(edit) = match_finder.edits_for_file(file_id) {
21 edits.push(SourceFileEdit { file_id, edit });
22 }
23 }
24 }
25 for edit in edits {
26 if let Some(path) = vfs.file_path(edit.file_id).as_path() {
27 let mut contents = db.file_text(edit.file_id).to_string();
28 edit.edit.apply(&mut contents);
29 std::fs::write(path, contents)?;
30 }
31 }
32 Ok(())
33}
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index 1cf50b677..b46281c98 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -1,14 +1,14 @@
1//! Book keeping for keeping diagnostics easily in sync with the client. 1//! Book keeping for keeping diagnostics easily in sync with the client.
2pub(crate) mod to_proto; 2pub(crate) mod to_proto;
3 3
4use std::{collections::HashMap, mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use ra_ide::FileId; 6use ra_ide::FileId;
7use rustc_hash::FxHashSet; 7use rustc_hash::{FxHashMap, FxHashSet};
8 8
9use crate::lsp_ext; 9use crate::lsp_ext;
10 10
11pub(crate) type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; 11pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>;
12 12
13#[derive(Debug, Default, Clone)] 13#[derive(Debug, Default, Clone)]
14pub struct DiagnosticsConfig { 14pub struct DiagnosticsConfig {
@@ -18,8 +18,8 @@ pub struct DiagnosticsConfig {
18 18
19#[derive(Debug, Default, Clone)] 19#[derive(Debug, Default, Clone)]
20pub(crate) struct DiagnosticCollection { 20pub(crate) struct DiagnosticCollection {
21 pub(crate) native: HashMap<FileId, Vec<lsp_types::Diagnostic>>, 21 pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
22 pub(crate) check: HashMap<FileId, Vec<lsp_types::Diagnostic>>, 22 pub(crate) check: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
23 pub(crate) check_fixes: CheckFixes, 23 pub(crate) check_fixes: CheckFixes,
24 changes: FxHashSet<FileId>, 24 changes: FxHashSet<FileId>,
25} 25}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 615aa2eb0..0940fcc28 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1300,7 +1300,7 @@ fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>)
1300 RunnableKind::Bin => { 1300 RunnableKind::Bin => {
1301 // Do not suggest binary run on other target than binary 1301 // Do not suggest binary run on other target than binary
1302 match &cargo_spec { 1302 match &cargo_spec {
1303 Some(spec) => spec.target_kind != TargetKind::Bin, 1303 Some(spec) => !matches!(spec.target_kind, TargetKind::Bin | TargetKind::Example),
1304 None => true, 1304 None => true,
1305 } 1305 }
1306 } 1306 }
diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs
index 7e6db954e..9f892f32e 100644
--- a/crates/rust-analyzer/src/line_endings.rs
+++ b/crates/rust-analyzer/src/line_endings.rs
@@ -46,19 +46,7 @@ impl LineEndings {
46 return (src, LineEndings::Dos); 46 return (src, LineEndings::Dos);
47 47
48 fn find_crlf(src: &[u8]) -> Option<usize> { 48 fn find_crlf(src: &[u8]) -> Option<usize> {
49 let mut search_idx = 0; 49 src.iter().zip(src.iter().skip(1)).position(|it| it == (&b'\r', &b'\n'))
50 while let Some(idx) = find_cr(&src[search_idx..]) {
51 if src[search_idx..].get(idx + 1) != Some(&b'\n') {
52 search_idx += idx + 1;
53 continue;
54 }
55 return Some(search_idx + idx);
56 }
57 None
58 }
59
60 fn find_cr(src: &[u8]) -> Option<usize> {
61 src.iter().enumerate().find_map(|(idx, &b)| if b == b'\r' { Some(idx) } else { None })
62 } 50 }
63 } 51 }
64} 52}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e5194fe41..9fd16ef3b 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -216,7 +216,11 @@ impl GlobalState {
216 flycheck::Progress::DidCheckCrate(target) => { 216 flycheck::Progress::DidCheckCrate(target) => {
217 (Progress::Report, Some(target)) 217 (Progress::Report, Some(target))
218 } 218 }
219 flycheck::Progress::DidFinish | flycheck::Progress::DidCancel => { 219 flycheck::Progress::DidCancel => (Progress::End, None),
220 flycheck::Progress::DidFinish(result) => {
221 if let Err(err) = result {
222 log::error!("cargo check failed: {}", err)
223 }
220 (Progress::End, None) 224 (Progress::End, None)
221 } 225 }
222 }; 226 };
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index 58839b14a..cc079790e 100644
--- a/crates/rust-analyzer/tests/heavy_tests/main.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/main.rs
@@ -494,6 +494,7 @@ fn main() {
494} 494}
495//- /src/main.rs 495//- /src/main.rs
496#[rustc_builtin_macro] macro_rules! include {} 496#[rustc_builtin_macro] macro_rules! include {}
497#[rustc_builtin_macro] macro_rules! include_str {}
497#[rustc_builtin_macro] macro_rules! concat {} 498#[rustc_builtin_macro] macro_rules! concat {}
498#[rustc_builtin_macro] macro_rules! env {} 499#[rustc_builtin_macro] macro_rules! env {}
499 500
@@ -512,6 +513,7 @@ fn main() {
512 let va = A; 513 let va = A;
513 let vb = B; 514 let vb = B;
514 let should_be_str = message(); 515 let should_be_str = message();
516 let another_str = include_str!("main.rs");
515} 517}
516"###, 518"###,
517 ) 519 )
@@ -523,7 +525,15 @@ fn main() {
523 let res = server.send_request::<HoverRequest>(HoverParams { 525 let res = server.send_request::<HoverRequest>(HoverParams {
524 text_document_position_params: TextDocumentPositionParams::new( 526 text_document_position_params: TextDocumentPositionParams::new(
525 server.doc_id("src/main.rs"), 527 server.doc_id("src/main.rs"),
526 Position::new(18, 10), 528 Position::new(19, 10),
529 ),
530 work_done_progress_params: Default::default(),
531 });
532 assert!(res.to_string().contains("&str"));
533 let res = server.send_request::<HoverRequest>(HoverParams {
534 text_document_position_params: TextDocumentPositionParams::new(
535 server.doc_id("src/main.rs"),
536 Position::new(20, 10),
527 ), 537 ),
528 work_done_progress_params: Default::default(), 538 work_done_progress_params: Default::default(),
529 }); 539 });
@@ -532,23 +542,23 @@ fn main() {
532 GotoDefinitionParams { 542 GotoDefinitionParams {
533 text_document_position_params: TextDocumentPositionParams::new( 543 text_document_position_params: TextDocumentPositionParams::new(
534 server.doc_id("src/main.rs"), 544 server.doc_id("src/main.rs"),
535 Position::new(16, 9), 545 Position::new(17, 9),
536 ), 546 ),
537 work_done_progress_params: Default::default(), 547 work_done_progress_params: Default::default(),
538 partial_result_params: Default::default(), 548 partial_result_params: Default::default(),
539 }, 549 },
540 json!([{ 550 json!([{
541 "originSelectionRange": { 551 "originSelectionRange": {
542 "end": { "character": 10, "line": 16 }, 552 "end": { "character": 10, "line": 17 },
543 "start": { "character": 8, "line": 16 } 553 "start": { "character": 8, "line": 17 }
544 }, 554 },
545 "targetRange": { 555 "targetRange": {
546 "end": { "character": 9, "line": 7 }, 556 "end": { "character": 9, "line": 8 },
547 "start": { "character": 0, "line": 6 } 557 "start": { "character": 0, "line": 7 }
548 }, 558 },
549 "targetSelectionRange": { 559 "targetSelectionRange": {
550 "end": { "character": 8, "line": 7 }, 560 "end": { "character": 8, "line": 8 },
551 "start": { "character": 7, "line": 7 } 561 "start": { "character": 7, "line": 8 }
552 }, 562 },
553 "targetUri": "file:///[..]src/main.rs" 563 "targetUri": "file:///[..]src/main.rs"
554 }]), 564 }]),
@@ -557,23 +567,23 @@ fn main() {
557 GotoDefinitionParams { 567 GotoDefinitionParams {
558 text_document_position_params: TextDocumentPositionParams::new( 568 text_document_position_params: TextDocumentPositionParams::new(
559 server.doc_id("src/main.rs"), 569 server.doc_id("src/main.rs"),
560 Position::new(17, 9), 570 Position::new(18, 9),
561 ), 571 ),
562 work_done_progress_params: Default::default(), 572 work_done_progress_params: Default::default(),
563 partial_result_params: Default::default(), 573 partial_result_params: Default::default(),
564 }, 574 },
565 json!([{ 575 json!([{
566 "originSelectionRange": { 576 "originSelectionRange": {
567 "end": { "character": 10, "line": 17 }, 577 "end": { "character": 10, "line": 18 },
568 "start": { "character": 8, "line": 17 } 578 "start": { "character": 8, "line": 18 }
569 }, 579 },
570 "targetRange": { 580 "targetRange": {
571 "end": { "character": 9, "line": 11 }, 581 "end": { "character": 9, "line": 12 },
572 "start": { "character": 0, "line":10 } 582 "start": { "character": 0, "line":11 }
573 }, 583 },
574 "targetSelectionRange": { 584 "targetSelectionRange": {
575 "end": { "character": 8, "line": 11 }, 585 "end": { "character": 8, "line": 12 },
576 "start": { "character": 7, "line": 11 } 586 "start": { "character": 7, "line": 12 }
577 }, 587 },
578 "targetUri": "file:///[..]src/main.rs" 588 "targetUri": "file:///[..]src/main.rs"
579 }]), 589 }]),
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index eaeeeb97b..caf847273 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -16,6 +16,7 @@ use std::{
16}; 16};
17 17
18use serde_json::Value; 18use serde_json::Value;
19use stdx::lines_with_ends;
19use text_size::{TextRange, TextSize}; 20use text_size::{TextRange, TextSize};
20 21
21pub use difference::Changeset as __Changeset; 22pub use difference::Changeset as __Changeset;
@@ -159,6 +160,41 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
159 res 160 res
160} 161}
161 162
163/// Extracts `//^ some text` annotations
164pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
165 let mut res = Vec::new();
166 let mut prev_line_start: Option<TextSize> = None;
167 let mut line_start: TextSize = 0.into();
168 for line in lines_with_ends(text) {
169 if let Some(idx) = line.find("//^") {
170 let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
171 let data = line[idx + "//^".len()..].trim().to_string();
172 res.push((TextRange::at(offset, 1.into()), data))
173 }
174 prev_line_start = Some(line_start);
175 line_start += TextSize::of(line);
176 }
177 res
178}
179
180#[test]
181fn test_extract_annotations() {
182 let text = stdx::trim_indent(
183 r#"
184fn main() {
185 let x = 92;
186 //^ def
187 z + 1
188} //^ i32
189 "#,
190 );
191 let res = extract_annotations(&text)
192 .into_iter()
193 .map(|(range, ann)| (&text[range], ann))
194 .collect::<Vec<_>>();
195 assert_eq!(res, vec![("x", "def".into()), ("z", "i32".into()),]);
196}
197
162// Comparison functionality borrowed from cargo: 198// Comparison functionality borrowed from cargo:
163 199
164/// Compare a line with an expected pattern. 200/// Compare a line with an expected pattern.
diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs
index 25ba8d798..b1ea298ae 100644
--- a/crates/vfs-notify/src/lib.rs
+++ b/crates/vfs-notify/src/lib.rs
@@ -10,7 +10,7 @@ mod include;
10 10
11use std::convert::{TryFrom, TryInto}; 11use std::convert::{TryFrom, TryInto};
12 12
13use crossbeam_channel::{select, unbounded, Receiver}; 13use crossbeam_channel::{select, unbounded, Receiver, Sender};
14use notify::{RecommendedWatcher, RecursiveMode, Watcher}; 14use notify::{RecommendedWatcher, RecursiveMode, Watcher};
15use paths::{AbsPath, AbsPathBuf}; 15use paths::{AbsPath, AbsPathBuf};
16use rustc_hash::FxHashSet; 16use rustc_hash::FxHashSet;
@@ -22,8 +22,8 @@ use crate::include::Include;
22#[derive(Debug)] 22#[derive(Debug)]
23pub struct NotifyHandle { 23pub struct NotifyHandle {
24 // Relative order of fields below is significant. 24 // Relative order of fields below is significant.
25 sender: crossbeam_channel::Sender<Message>, 25 sender: Sender<Message>,
26 _thread: jod_thread::JoinHandle, 26 thread: jod_thread::JoinHandle,
27} 27}
28 28
29#[derive(Debug)] 29#[derive(Debug)]
@@ -37,7 +37,7 @@ impl loader::Handle for NotifyHandle {
37 let actor = NotifyActor::new(sender); 37 let actor = NotifyActor::new(sender);
38 let (sender, receiver) = unbounded::<Message>(); 38 let (sender, receiver) = unbounded::<Message>();
39 let thread = jod_thread::spawn(move || actor.run(receiver)); 39 let thread = jod_thread::spawn(move || actor.run(receiver));
40 NotifyHandle { sender, _thread: thread } 40 NotifyHandle { sender, thread }
41 } 41 }
42 fn set_config(&mut self, config: loader::Config) { 42 fn set_config(&mut self, config: loader::Config) {
43 self.sender.send(Message::Config(config)).unwrap() 43 self.sender.send(Message::Config(config)).unwrap()