diff options
Diffstat (limited to 'crates')
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 @@ | |||
5 | use std::{ | 5 | use std::{ |
6 | fmt, | 6 | fmt, |
7 | io::{self, BufReader}, | 7 | io::{self, BufReader}, |
8 | ops, | ||
8 | path::PathBuf, | 9 | path::PathBuf, |
9 | process::{Command, Stdio}, | 10 | process::{self, Command, Stdio}, |
10 | time::Duration, | 11 | time::Duration, |
11 | }; | 12 | }; |
12 | 13 | ||
@@ -49,8 +50,8 @@ impl fmt::Display for FlycheckConfig { | |||
49 | #[derive(Debug)] | 50 | #[derive(Debug)] |
50 | pub struct FlycheckHandle { | 51 | pub struct FlycheckHandle { |
51 | // XXX: drop order is significant | 52 | // XXX: drop order is significant |
52 | cmd_send: Sender<Restart>, | 53 | sender: Sender<Restart>, |
53 | handle: jod_thread::JoinHandle, | 54 | thread: jod_thread::JoinHandle, |
54 | } | 55 | } |
55 | 56 | ||
56 | impl FlycheckHandle { | 57 | impl FlycheckHandle { |
@@ -59,16 +60,15 @@ impl FlycheckHandle { | |||
59 | config: FlycheckConfig, | 60 | config: FlycheckConfig, |
60 | workspace_root: PathBuf, | 61 | workspace_root: PathBuf, |
61 | ) -> FlycheckHandle { | 62 | ) -> FlycheckHandle { |
62 | let (cmd_send, cmd_recv) = unbounded::<Restart>(); | 63 | let actor = FlycheckActor::new(sender, config, workspace_root); |
63 | let handle = jod_thread::spawn(move || { | 64 | let (sender, receiver) = unbounded::<Restart>(); |
64 | FlycheckActor::new(sender, config, workspace_root).run(cmd_recv); | 65 | let thread = jod_thread::spawn(move || actor.run(receiver)); |
65 | }); | 66 | FlycheckHandle { sender, thread } |
66 | FlycheckHandle { cmd_send, handle } | ||
67 | } | 67 | } |
68 | 68 | ||
69 | /// Schedule a re-start of the cargo check worker. | 69 | /// Schedule a re-start of the cargo check worker. |
70 | pub fn update(&self) { | 70 | pub fn update(&self) { |
71 | self.cmd_send.send(Restart).unwrap(); | 71 | self.sender.send(Restart).unwrap(); |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
@@ -85,7 +85,7 @@ pub enum Message { | |||
85 | pub enum Progress { | 85 | pub enum Progress { |
86 | DidStart, | 86 | DidStart, |
87 | DidCheckCrate(String), | 87 | DidCheckCrate(String), |
88 | DidFinish, | 88 | DidFinish(io::Result<()>), |
89 | DidCancel, | 89 | DidCancel, |
90 | } | 90 | } |
91 | 91 | ||
@@ -100,8 +100,7 @@ struct FlycheckActor { | |||
100 | /// doesn't provide a way to read sub-process output without blocking, so we | 100 | /// doesn't provide a way to read sub-process output without blocking, so we |
101 | /// have to wrap sub-processes output handling in a thread and pass messages | 101 | /// have to wrap sub-processes output handling in a thread and pass messages |
102 | /// back over a channel. | 102 | /// back over a channel. |
103 | // XXX: drop order is significant | 103 | cargo_handle: Option<CargoHandle>, |
104 | check_process: Option<(Receiver<cargo_metadata::Message>, jod_thread::JoinHandle)>, | ||
105 | } | 104 | } |
106 | 105 | ||
107 | enum Event { | 106 | enum Event { |
@@ -115,29 +114,36 @@ impl FlycheckActor { | |||
115 | config: FlycheckConfig, | 114 | config: FlycheckConfig, |
116 | workspace_root: PathBuf, | 115 | workspace_root: PathBuf, |
117 | ) -> FlycheckActor { | 116 | ) -> FlycheckActor { |
118 | FlycheckActor { sender, config, workspace_root, check_process: None } | 117 | FlycheckActor { sender, config, workspace_root, cargo_handle: None } |
119 | } | 118 | } |
120 | fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> { | 119 | fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> { |
121 | let check_chan = self.check_process.as_ref().map(|(chan, _thread)| chan); | 120 | let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver); |
122 | select! { | 121 | select! { |
123 | recv(inbox) -> msg => msg.ok().map(Event::Restart), | 122 | recv(inbox) -> msg => msg.ok().map(Event::Restart), |
124 | recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())), | 123 | recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())), |
125 | } | 124 | } |
126 | } | 125 | } |
127 | fn run(&mut self, inbox: Receiver<Restart>) { | 126 | fn run(mut self, inbox: Receiver<Restart>) { |
128 | while let Some(event) = self.next_event(&inbox) { | 127 | while let Some(event) = self.next_event(&inbox) { |
129 | match event { | 128 | match event { |
130 | Event::Restart(Restart) => { | 129 | Event::Restart(Restart) => { |
131 | while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} | 130 | while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} |
131 | |||
132 | self.cancel_check_process(); | 132 | self.cancel_check_process(); |
133 | self.check_process = Some(self.start_check_process()); | 133 | |
134 | self.send(Message::Progress(Progress::DidStart)); | 134 | let mut command = self.check_command(); |
135 | command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); | ||
136 | if let Ok(child) = command.spawn().map(JodChild) { | ||
137 | self.cargo_handle = Some(CargoHandle::spawn(child)); | ||
138 | self.send(Message::Progress(Progress::DidStart)); | ||
139 | } | ||
135 | } | 140 | } |
136 | Event::CheckEvent(None) => { | 141 | Event::CheckEvent(None) => { |
137 | // Watcher finished, replace it with a never channel to | 142 | // Watcher finished, replace it with a never channel to |
138 | // avoid busy-waiting. | 143 | // avoid busy-waiting. |
139 | assert!(self.check_process.take().is_some()); | 144 | let cargo_handle = self.cargo_handle.take().unwrap(); |
140 | self.send(Message::Progress(Progress::DidFinish)); | 145 | let res = cargo_handle.join(); |
146 | self.send(Message::Progress(Progress::DidFinish(res))); | ||
141 | } | 147 | } |
142 | Event::CheckEvent(Some(message)) => match message { | 148 | Event::CheckEvent(Some(message)) => match message { |
143 | cargo_metadata::Message::CompilerArtifact(msg) => { | 149 | cargo_metadata::Message::CompilerArtifact(msg) => { |
@@ -162,11 +168,11 @@ impl FlycheckActor { | |||
162 | self.cancel_check_process(); | 168 | self.cancel_check_process(); |
163 | } | 169 | } |
164 | fn cancel_check_process(&mut self) { | 170 | fn cancel_check_process(&mut self) { |
165 | if self.check_process.take().is_some() { | 171 | if self.cargo_handle.take().is_some() { |
166 | self.send(Message::Progress(Progress::DidCancel)); | 172 | self.send(Message::Progress(Progress::DidCancel)); |
167 | } | 173 | } |
168 | } | 174 | } |
169 | fn start_check_process(&self) -> (Receiver<cargo_metadata::Message>, jod_thread::JoinHandle) { | 175 | fn check_command(&self) -> Command { |
170 | let mut cmd = match &self.config { | 176 | let mut cmd = match &self.config { |
171 | FlycheckConfig::CargoCommand { | 177 | FlycheckConfig::CargoCommand { |
172 | command, | 178 | command, |
@@ -198,33 +204,7 @@ impl FlycheckActor { | |||
198 | } | 204 | } |
199 | }; | 205 | }; |
200 | cmd.current_dir(&self.workspace_root); | 206 | cmd.current_dir(&self.workspace_root); |
201 | 207 | cmd | |
202 | let (message_send, message_recv) = unbounded(); | ||
203 | let thread = jod_thread::spawn(move || { | ||
204 | // If we trigger an error here, we will do so in the loop instead, | ||
205 | // which will break out of the loop, and continue the shutdown | ||
206 | let res = run_cargo(cmd, &mut |message| { | ||
207 | // Skip certain kinds of messages to only spend time on what's useful | ||
208 | match &message { | ||
209 | cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => { | ||
210 | return true | ||
211 | } | ||
212 | cargo_metadata::Message::BuildScriptExecuted(_) | ||
213 | | cargo_metadata::Message::Unknown => return true, | ||
214 | _ => {} | ||
215 | } | ||
216 | |||
217 | // if the send channel was closed, we want to shutdown | ||
218 | message_send.send(message).is_ok() | ||
219 | }); | ||
220 | |||
221 | if let Err(err) = res { | ||
222 | // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>` | ||
223 | // to display user-caused misconfiguration errors instead of just logging them here | ||
224 | log::error!("Cargo watcher failed {:?}", err); | ||
225 | } | ||
226 | }); | ||
227 | (message_recv, thread) | ||
228 | } | 208 | } |
229 | 209 | ||
230 | fn send(&self, check_task: Message) { | 210 | fn send(&self, check_task: Message) { |
@@ -232,54 +212,104 @@ impl FlycheckActor { | |||
232 | } | 212 | } |
233 | } | 213 | } |
234 | 214 | ||
235 | fn run_cargo( | 215 | struct CargoHandle { |
236 | mut command: Command, | 216 | child: JodChild, |
237 | on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, | 217 | #[allow(unused)] |
238 | ) -> io::Result<()> { | 218 | thread: jod_thread::JoinHandle<io::Result<bool>>, |
239 | let mut child = | 219 | receiver: Receiver<cargo_metadata::Message>, |
240 | command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?; | 220 | } |
241 | 221 | ||
242 | // We manually read a line at a time, instead of using serde's | 222 | impl CargoHandle { |
243 | // stream deserializers, because the deserializer cannot recover | 223 | fn spawn(mut child: JodChild) -> CargoHandle { |
244 | // from an error, resulting in it getting stuck, because we try to | 224 | let child_stdout = child.stdout.take().unwrap(); |
245 | // be resillient against failures. | 225 | let (sender, receiver) = unbounded(); |
246 | // | 226 | let actor = CargoActor::new(child_stdout, sender); |
247 | // Because cargo only outputs one JSON object per line, we can | 227 | let thread = jod_thread::spawn(move || actor.run()); |
248 | // simply skip a line if it doesn't parse, which just ignores any | 228 | CargoHandle { child, thread, receiver } |
249 | // erroneus output. | 229 | } |
250 | let stdout = BufReader::new(child.stdout.take().unwrap()); | 230 | fn join(mut self) -> io::Result<()> { |
251 | let mut read_at_least_one_message = false; | 231 | // It is okay to ignore the result, as it only errors if the process is already dead |
252 | for message in cargo_metadata::Message::parse_stream(stdout) { | 232 | let _ = self.child.kill(); |
253 | let message = match message { | 233 | let exit_status = self.child.wait()?; |
254 | Ok(message) => message, | 234 | let read_at_least_one_message = self.thread.join()?; |
255 | Err(err) => { | 235 | if !exit_status.success() && !read_at_least_one_message { |
256 | log::error!("Invalid json from cargo check, ignoring ({})", err); | 236 | // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: |
257 | continue; | 237 | // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 |
258 | } | 238 | return Err(io::Error::new( |
259 | }; | 239 | io::ErrorKind::Other, |
240 | format!( | ||
241 | "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})", | ||
242 | exit_status | ||
243 | ), | ||
244 | )); | ||
245 | } | ||
246 | Ok(()) | ||
247 | } | ||
248 | } | ||
249 | |||
250 | struct CargoActor { | ||
251 | child_stdout: process::ChildStdout, | ||
252 | sender: Sender<cargo_metadata::Message>, | ||
253 | } | ||
254 | |||
255 | impl CargoActor { | ||
256 | fn new( | ||
257 | child_stdout: process::ChildStdout, | ||
258 | sender: Sender<cargo_metadata::Message>, | ||
259 | ) -> CargoActor { | ||
260 | CargoActor { child_stdout, sender } | ||
261 | } | ||
262 | fn run(self) -> io::Result<bool> { | ||
263 | // We manually read a line at a time, instead of using serde's | ||
264 | // stream deserializers, because the deserializer cannot recover | ||
265 | // from an error, resulting in it getting stuck, because we try to | ||
266 | // be resilient against failures. | ||
267 | // | ||
268 | // Because cargo only outputs one JSON object per line, we can | ||
269 | // simply skip a line if it doesn't parse, which just ignores any | ||
270 | // erroneus output. | ||
271 | let stdout = BufReader::new(self.child_stdout); | ||
272 | let mut read_at_least_one_message = false; | ||
273 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
274 | let message = match message { | ||
275 | Ok(message) => message, | ||
276 | Err(err) => { | ||
277 | log::error!("Invalid json from cargo check, ignoring ({})", err); | ||
278 | continue; | ||
279 | } | ||
280 | }; | ||
260 | 281 | ||
261 | read_at_least_one_message = true; | 282 | read_at_least_one_message = true; |
262 | 283 | ||
263 | if !on_message(message) { | 284 | // Skip certain kinds of messages to only spend time on what's useful |
264 | break; | 285 | match &message { |
286 | cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (), | ||
287 | cargo_metadata::Message::BuildScriptExecuted(_) | ||
288 | | cargo_metadata::Message::Unknown => (), | ||
289 | _ => self.sender.send(message).unwrap(), | ||
290 | } | ||
265 | } | 291 | } |
292 | Ok(read_at_least_one_message) | ||
266 | } | 293 | } |
294 | } | ||
267 | 295 | ||
268 | // It is okay to ignore the result, as it only errors if the process is already dead | 296 | struct JodChild(process::Child); |
269 | let _ = child.kill(); | ||
270 | 297 | ||
271 | let exit_status = child.wait()?; | 298 | impl ops::Deref for JodChild { |
272 | if !exit_status.success() && !read_at_least_one_message { | 299 | type Target = process::Child; |
273 | // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: | 300 | fn deref(&self) -> &process::Child { |
274 | // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 | 301 | &self.0 |
275 | return Err(io::Error::new( | ||
276 | io::ErrorKind::Other, | ||
277 | format!( | ||
278 | "the command produced no valid metadata (exit code: {:?}): {:?}", | ||
279 | exit_status, command | ||
280 | ), | ||
281 | )); | ||
282 | } | 302 | } |
303 | } | ||
283 | 304 | ||
284 | Ok(()) | 305 | impl ops::DerefMut for JodChild { |
306 | fn deref_mut(&mut self) -> &mut process::Child { | ||
307 | &mut self.0 | ||
308 | } | ||
309 | } | ||
310 | |||
311 | impl Drop for JodChild { | ||
312 | fn drop(&mut self) { | ||
313 | let _ = self.0.kill(); | ||
314 | } | ||
285 | } | 315 | } |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index c21d75be0..157c7b665 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -1,15 +1,12 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast::{self, NameOwner, VisibilityOwner}, | 2 | ast::{self, NameOwner, VisibilityOwner}, |
3 | AstNode, | 3 | AstNode, |
4 | SyntaxKind::{ | 4 | SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY}, |
5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, | 5 | T, |
6 | WHITESPACE, | ||
7 | }, | ||
8 | SyntaxNode, TextSize, T, | ||
9 | }; | 6 | }; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | 9 | use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; |
13 | 10 | ||
14 | // Assist: change_visibility | 11 | // Assist: change_visibility |
15 | // | 12 | // |
@@ -30,9 +27,8 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
30 | } | 27 | } |
31 | 28 | ||
32 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
33 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { | 30 | let item_keyword = ctx.token_at_offset().find(|leaf| { |
34 | T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, | 31 | matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]) |
35 | _ => false, | ||
36 | }); | 32 | }); |
37 | 33 | ||
38 | let (offset, target) = if let Some(keyword) = item_keyword { | 34 | let (offset, target) = if let Some(keyword) = item_keyword { |
@@ -71,17 +67,6 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
71 | }) | 67 | }) |
72 | } | 68 | } |
73 | 69 | ||
74 | fn vis_offset(node: &SyntaxNode) -> TextSize { | ||
75 | node.children_with_tokens() | ||
76 | .skip_while(|it| match it.kind() { | ||
77 | WHITESPACE | COMMENT | ATTR => true, | ||
78 | _ => false, | ||
79 | }) | ||
80 | .next() | ||
81 | .map(|it| it.text_range().start()) | ||
82 | .unwrap_or_else(|| node.text_range().start()) | ||
83 | } | ||
84 | |||
85 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | 70 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { |
86 | if vis.syntax().text() == "pub" { | 71 | if vis.syntax().text() == "pub" { |
87 | let target = vis.syntax().text_range(); | 72 | let target = vis.syntax().text_range(); |
diff --git a/crates/ra_assists/src/handlers/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 @@ | |||
1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | 1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; |
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ast, AstNode, TextRange, TextSize}; |
4 | ast, AstNode, | ||
5 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | ||
6 | SyntaxNode, TextRange, TextSize, | ||
7 | }; | ||
8 | 4 | ||
9 | use crate::{AssistContext, AssistId, Assists}; | 5 | use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; |
10 | 6 | ||
11 | // FIXME: this really should be a fix for diagnostic, rather than an assist. | 7 | // FIXME: this really should be a fix for diagnostic, rather than an assist. |
12 | 8 | ||
@@ -177,17 +173,6 @@ fn target_data_for_def( | |||
177 | Some((offset, target, target_file, target_name)) | 173 | Some((offset, target, target_file, target_name)) |
178 | } | 174 | } |
179 | 175 | ||
180 | fn vis_offset(node: &SyntaxNode) -> TextSize { | ||
181 | node.children_with_tokens() | ||
182 | .skip_while(|it| match it.kind() { | ||
183 | WHITESPACE | COMMENT | ATTR => true, | ||
184 | _ => false, | ||
185 | }) | ||
186 | .next() | ||
187 | .map(|it| it.text_range().start()) | ||
188 | .unwrap_or_else(|| node.text_range().start()) | ||
189 | } | ||
190 | |||
191 | #[cfg(test)] | 176 | #[cfg(test)] |
192 | mod tests { | 177 | mod tests { |
193 | use crate::tests::{check_assist, check_assist_not_applicable}; | 178 | use crate::tests::{check_assist, check_assist_not_applicable}; |
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index ca04ec671..90ce66378 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -81,10 +81,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
81 | } | 81 | } |
82 | 82 | ||
83 | fn contains_placeholder(a: &ast::MatchArm) -> bool { | 83 | fn contains_placeholder(a: &ast::MatchArm) -> bool { |
84 | match a.pat() { | 84 | matches!(a.pat(), Some(ast::Pat::PlaceholderPat(..))) |
85 | Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true, | ||
86 | _ => false, | ||
87 | } | ||
88 | } | 85 | } |
89 | 86 | ||
90 | #[cfg(test)] | 87 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 897da2832..bc58ce5fe 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::collections::HashMap; | 1 | use itertools::Itertools; |
2 | use rustc_hash::FxHashMap; | ||
2 | 3 | ||
3 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | 4 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; |
4 | use itertools::Itertools; | ||
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; | 6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; |
7 | 7 | ||
@@ -87,7 +87,7 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> { | 90 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { |
91 | Some( | 91 | Some( |
92 | struct_definition(path, &ctx.sema)? | 92 | struct_definition(path, &ctx.sema)? |
93 | .fields(ctx.db) | 93 | .fields(ctx.db) |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index b7c45a619..02de902d6 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -7,7 +7,9 @@ use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; | |||
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | ast::{self, make, NameOwner}, | 9 | ast::{self, make, NameOwner}, |
10 | AstNode, SyntaxNode, T, | 10 | AstNode, |
11 | SyntaxKind::*, | ||
12 | SyntaxNode, TextSize, T, | ||
11 | }; | 13 | }; |
12 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
13 | 15 | ||
@@ -120,6 +122,13 @@ pub(crate) fn resolve_target_trait( | |||
120 | } | 122 | } |
121 | } | 123 | } |
122 | 124 | ||
125 | pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { | ||
126 | node.children_with_tokens() | ||
127 | .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) | ||
128 | .map(|it| it.text_range().start()) | ||
129 | .unwrap_or_else(|| node.text_range().start()) | ||
130 | } | ||
131 | |||
123 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | 132 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { |
124 | if let Some(expr) = invert_special_case(&expr) { | 133 | if let Some(expr) = invert_special_case(&expr) { |
125 | return expr; | 134 | return expr; |
diff --git a/crates/ra_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 | }; |
32 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 34 | use ra_db::{CrateId, CrateName, Edition, FileId}; |
33 | use ra_prof::profile; | 35 | use ra_prof::profile; |
@@ -541,7 +543,7 @@ impl_froms!(Adt: Struct, Union, Enum); | |||
541 | impl Adt { | 543 | impl 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 { | |||
771 | impl TypeAlias { | 775 | impl 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 | ||
295 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { | 297 | fn 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 | ||
341 | fn include_bytes_expand( | ||
342 | _db: &dyn AstDatabase, | ||
343 | _arg_id: EagerMacroId, | ||
344 | tt: &tt::Subtree, | ||
345 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
346 | let _path = parse_string(tt)?; | ||
347 | |||
348 | // FIXME: actually read the file here if the user asked for macro expansion | ||
349 | let res = tt::Subtree { | ||
350 | delimiter: None, | ||
351 | token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { | ||
352 | text: r#"b"""#.into(), | ||
353 | id: tt::TokenId::unspecified(), | ||
354 | }))], | ||
355 | }; | ||
356 | Ok((res, FragmentKind::Expr)) | ||
357 | } | ||
358 | |||
359 | fn 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 | |||
334 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 383 | fn 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 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } | 30 | chalk-solve = { version = "0.15.0" } |
31 | chalk-ir = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" } | 31 | chalk-ir = { version = "0.15.0" } |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | insta = "0.16.0" | 34 | insta = "0.16.0" |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 7889b8d2c..cad553273 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | method_resolution::CrateImplDefs, | 14 | method_resolution::CrateImplDefs, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::{chalk, AssocTyValue, Impl}, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, | 16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, |
17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, | 17 | ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, |
18 | }; | 18 | }; |
19 | use hir_expand::name::Name; | 19 | use hir_expand::name::Name; |
20 | 20 | ||
@@ -65,7 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
65 | fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>; | 65 | fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>; |
66 | 66 | ||
67 | #[salsa::invoke(crate::lower::generic_defaults_query)] | 67 | #[salsa::invoke(crate::lower::generic_defaults_query)] |
68 | fn generic_defaults(&self, def: GenericDefId) -> Substs; | 68 | fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; |
69 | 69 | ||
70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] | 70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] |
71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; | 71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 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)] | ||
174 | pub struct MissingUnsafe { | ||
175 | pub file: HirFileId, | ||
176 | pub expr: AstPtr<ast::Expr>, | ||
177 | } | ||
178 | |||
179 | impl 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 | |||
191 | impl 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; | |||
37 | pub mod db; | 37 | pub mod db; |
38 | pub mod diagnostics; | 38 | pub mod diagnostics; |
39 | pub mod expr; | 39 | pub mod expr; |
40 | pub mod unsafe_validation; | ||
40 | 41 | ||
41 | #[cfg(test)] | 42 | #[cfg(test)] |
42 | mod tests; | 43 | mod tests; |
@@ -619,17 +620,11 @@ pub enum GenericPredicate { | |||
619 | 620 | ||
620 | impl GenericPredicate { | 621 | impl 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 |
948 | pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> Substs { | 950 | pub(crate) fn generic_defaults_query( |
951 | db: &dyn HirDatabase, | ||
952 | def: GenericDefId, | ||
953 | ) -> Arc<[Binders<Ty>]> { | ||
949 | let resolver = def.resolver(db.upcast()); | 954 | let resolver = def.resolver(db.upcast()); |
950 | let ctx = TyLoweringContext::new(db, &resolver); | 955 | let ctx = |
956 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
951 | let generic_params = generics(db.upcast(), def); | 957 | let generic_params = generics(db.upcast(), def); |
952 | 958 | ||
953 | let defaults = generic_params | 959 | let defaults = generic_params |
954 | .iter() | 960 | .iter() |
955 | .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t))) | 961 | .enumerate() |
962 | .map(|(idx, (_, p))| { | ||
963 | let mut ty = p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t)); | ||
964 | |||
965 | // Each default can only refer to previous parameters. | ||
966 | ty.walk_mut_binders( | ||
967 | &mut |ty, binders| match ty { | ||
968 | Ty::Bound(BoundVar { debruijn, index }) if *debruijn == binders => { | ||
969 | if *index >= idx { | ||
970 | // type variable default referring to parameter coming | ||
971 | // after it. This is forbidden (FIXME: report | ||
972 | // diagnostic) | ||
973 | *ty = Ty::Unknown; | ||
974 | } | ||
975 | } | ||
976 | _ => {} | ||
977 | }, | ||
978 | DebruijnIndex::INNERMOST, | ||
979 | ); | ||
980 | |||
981 | Binders::new(idx, ty) | ||
982 | }) | ||
956 | .collect(); | 983 | .collect(); |
957 | 984 | ||
958 | Substs(defaults) | 985 | defaults |
959 | } | 986 | } |
960 | 987 | ||
961 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | 988 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 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 | |||
11 | use rustc_hash::FxHashSet; | 11 | use rustc_hash::FxHashSet; |
12 | use stdx::format_to; | 12 | use stdx::format_to; |
13 | 13 | ||
14 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | 14 | use 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 | ||
154 | impl TestDB { | 172 | impl 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 | }; |
22 | use hir_expand::{db::AstDatabase, InFile}; | 22 | use hir_expand::{db::AstDatabase, InFile}; |
23 | use insta::assert_snapshot; | 23 | use insta::assert_snapshot; |
24 | use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; | 24 | use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase}; |
25 | use ra_syntax::{ | 25 | use ra_syntax::{ |
26 | algo, | 26 | algo, |
27 | ast::{self, AstNode}, | 27 | ast::{self, AstNode}, |
28 | SyntaxNode, | 28 | SyntaxNode, |
29 | }; | 29 | }; |
30 | use stdx::format_to; | 30 | use stdx::format_to; |
31 | use test_utils::extract_annotations; | ||
31 | 32 | ||
32 | use crate::{ | 33 | use 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 | ||
40 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 41 | fn 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 | ||
44 | fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { | 45 | fn check_types_source_code(ra_fixture: &str) { |
45 | type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap()) | 46 | check_types_impl(ra_fixture, true) |
46 | } | 47 | } |
47 | 48 | ||
48 | fn type_at_pos_displayed( | 49 | fn 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 | |||
70 | fn 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 | ||
70 | fn type_at(ra_fixture: &str) -> String { | ||
71 | let (db, file_pos) = TestDB::with_position(ra_fixture); | ||
72 | type_at_pos(&db, file_pos) | ||
73 | } | ||
74 | |||
75 | fn infer(ra_fixture: &str) -> String { | 87 | fn 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] |
554 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
555 | let diagnostics = TestDB::with_files( | ||
556 | r" | ||
557 | //- /lib.rs | ||
558 | fn 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] | ||
571 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
572 | let diagnostics = TestDB::with_files( | ||
573 | r" | ||
574 | //- /lib.rs | ||
575 | unsafe fn unsafe_fn() { | ||
576 | let x = &5 as *const usize; | ||
577 | let y = *x; | ||
578 | } | ||
579 | |||
580 | fn 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] | ||
592 | fn missing_unsafe_diagnostic_with_unsafe_method_call() { | ||
593 | let diagnostics = TestDB::with_files( | ||
594 | r" | ||
595 | struct HasUnsafe; | ||
596 | |||
597 | impl HasUnsafe { | ||
598 | unsafe fn unsafe_fn(&self) { | ||
599 | let x = &5 as *const usize; | ||
600 | let y = *x; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | fn 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] | ||
617 | fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() { | ||
618 | let diagnostics = TestDB::with_files( | ||
619 | r" | ||
620 | fn 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] | ||
635 | fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() { | ||
636 | let diagnostics = TestDB::with_files( | ||
637 | r" | ||
638 | fn 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] | ||
654 | fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() { | ||
655 | let diagnostics = TestDB::with_files( | ||
656 | r" | ||
657 | unsafe fn unsafe_fn() { | ||
658 | let x = &5 as *const usize; | ||
659 | let y = *x; | ||
660 | } | ||
661 | |||
662 | fn 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] | ||
676 | fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() { | ||
677 | let diagnostics = TestDB::with_files( | ||
678 | r" | ||
679 | struct HasUnsafe; | ||
680 | |||
681 | impl HasUnsafe { | ||
682 | unsafe fn unsafe_fn() { | ||
683 | let x = &5 as *const usize; | ||
684 | let y = *x; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | fn 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] | ||
542 | fn break_outside_of_loop() { | 703 | fn 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 @@ | |||
1 | use super::infer_with_mismatches; | ||
2 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
3 | use test_utils::mark; | 2 | use test_utils::mark; |
4 | 3 | ||
4 | use super::infer_with_mismatches; | ||
5 | |||
5 | // Infer with some common definitions and impls. | 6 | // Infer with some common definitions and impls. |
6 | fn infer(source: &str) -> String { | 7 | fn infer(source: &str) -> String { |
7 | let defs = r#" | 8 | let defs = r#" |
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs index 5dfa0a014..b502135d8 100644 --- a/crates/ra_hir_ty/src/tests/display_source_code.rs +++ b/crates/ra_hir_ty/src/tests/display_source_code.rs | |||
@@ -1,50 +1,41 @@ | |||
1 | use super::displayed_source_at_pos; | 1 | use super::check_types_source_code; |
2 | use crate::test_db::TestDB; | ||
3 | use ra_db::fixture::WithFixture; | ||
4 | 2 | ||
5 | #[test] | 3 | #[test] |
6 | fn qualify_path_to_submodule() { | 4 | fn qualify_path_to_submodule() { |
7 | let (db, pos) = TestDB::with_position( | 5 | check_types_source_code( |
8 | r#" | 6 | r#" |
9 | //- /main.rs | ||
10 | |||
11 | mod foo { | 7 | mod foo { |
12 | pub struct Foo; | 8 | pub struct Foo; |
13 | } | 9 | } |
14 | 10 | ||
15 | fn bar() { | 11 | fn bar() { |
16 | let foo: foo::Foo = foo::Foo; | 12 | let foo: foo::Foo = foo::Foo; |
17 | foo<|> | 13 | foo |
18 | } | 14 | } //^ foo::Foo |
19 | 15 | ||
20 | "#, | 16 | "#, |
21 | ); | 17 | ); |
22 | assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos)); | ||
23 | } | 18 | } |
24 | 19 | ||
25 | #[test] | 20 | #[test] |
26 | fn omit_default_type_parameters() { | 21 | fn omit_default_type_parameters() { |
27 | let (db, pos) = TestDB::with_position( | 22 | check_types_source_code( |
28 | r" | 23 | r#" |
29 | //- /main.rs | 24 | struct Foo<T = u8> { t: T } |
30 | struct Foo<T = u8> { t: T } | 25 | fn main() { |
31 | fn main() { | 26 | let foo = Foo { t: 5u8 }; |
32 | let foo = Foo { t: 5u8 }; | 27 | foo; |
33 | foo<|>; | 28 | } //^ Foo |
34 | } | 29 | "#, |
35 | ", | ||
36 | ); | 30 | ); |
37 | assert_eq!("Foo", displayed_source_at_pos(&db, pos)); | ||
38 | 31 | ||
39 | let (db, pos) = TestDB::with_position( | 32 | check_types_source_code( |
40 | r" | 33 | r#" |
41 | //- /main.rs | 34 | struct Foo<K, T = u8> { k: K, t: T } |
42 | struct Foo<K, T = u8> { k: K, t: T } | 35 | fn main() { |
43 | fn main() { | 36 | let foo = Foo { k: 400, t: 5u8 }; |
44 | let foo = Foo { k: 400, t: 5u8 }; | 37 | foo; |
45 | foo<|>; | 38 | } //^ Foo<i32> |
46 | } | 39 | "#, |
47 | ", | ||
48 | ); | 40 | ); |
49 | assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos)); | ||
50 | } | 41 | } |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index be2b48dcc..45c4e309e 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -1,16 +1,13 @@ | |||
1 | use std::fs; | 1 | use std::fs; |
2 | 2 | ||
3 | use insta::assert_snapshot; | 3 | use insta::assert_snapshot; |
4 | use ra_db::fixture::WithFixture; | ||
5 | use test_utils::project_dir; | 4 | use test_utils::project_dir; |
6 | 5 | ||
7 | use crate::test_db::TestDB; | 6 | use super::{check_types, infer}; |
8 | |||
9 | use super::{infer, type_at, type_at_pos}; | ||
10 | 7 | ||
11 | #[test] | 8 | #[test] |
12 | fn cfg_impl_def() { | 9 | fn cfg_impl_def() { |
13 | let (db, pos) = TestDB::with_position( | 10 | check_types( |
14 | r#" | 11 | r#" |
15 | //- /main.rs crate:main deps:foo cfg:test | 12 | //- /main.rs crate:main deps:foo cfg:test |
16 | use foo::S as T; | 13 | use foo::S as T; |
@@ -28,8 +25,8 @@ impl S { | |||
28 | 25 | ||
29 | fn test() { | 26 | fn test() { |
30 | let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); | 27 | let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); |
31 | t<|>; | 28 | t; |
32 | } | 29 | } //^ (i32, {unknown}, i32, {unknown}) |
33 | 30 | ||
34 | //- /foo.rs crate:foo | 31 | //- /foo.rs crate:foo |
35 | struct S; | 32 | struct S; |
@@ -45,7 +42,6 @@ impl S { | |||
45 | } | 42 | } |
46 | "#, | 43 | "#, |
47 | ); | 44 | ); |
48 | assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); | ||
49 | } | 45 | } |
50 | 46 | ||
51 | #[test] | 47 | #[test] |
@@ -253,26 +249,24 @@ fn foo() { | |||
253 | 249 | ||
254 | #[test] | 250 | #[test] |
255 | fn processes_impls_generated_by_macros() { | 251 | fn processes_impls_generated_by_macros() { |
256 | let t = type_at( | 252 | check_types( |
257 | r#" | 253 | r#" |
258 | //- /main.rs | ||
259 | macro_rules! m { | 254 | macro_rules! m { |
260 | ($ident:ident) => (impl Trait for $ident {}) | 255 | ($ident:ident) => (impl Trait for $ident {}) |
261 | } | 256 | } |
262 | trait Trait { fn foo(self) -> u128 {} } | 257 | trait Trait { fn foo(self) -> u128 {} } |
263 | struct S; | 258 | struct S; |
264 | m!(S); | 259 | m!(S); |
265 | fn test() { S.foo()<|>; } | 260 | fn test() { S.foo(); } |
261 | //^ u128 | ||
266 | "#, | 262 | "#, |
267 | ); | 263 | ); |
268 | assert_eq!(t, "u128"); | ||
269 | } | 264 | } |
270 | 265 | ||
271 | #[test] | 266 | #[test] |
272 | fn infer_assoc_items_generated_by_macros() { | 267 | fn infer_assoc_items_generated_by_macros() { |
273 | let t = type_at( | 268 | check_types( |
274 | r#" | 269 | r#" |
275 | //- /main.rs | ||
276 | macro_rules! m { | 270 | macro_rules! m { |
277 | () => (fn foo(&self) -> u128 {0}) | 271 | () => (fn foo(&self) -> u128 {0}) |
278 | } | 272 | } |
@@ -281,17 +275,16 @@ impl S { | |||
281 | m!(); | 275 | m!(); |
282 | } | 276 | } |
283 | 277 | ||
284 | fn test() { S.foo()<|>; } | 278 | fn test() { S.foo(); } |
279 | //^ u128 | ||
285 | "#, | 280 | "#, |
286 | ); | 281 | ); |
287 | assert_eq!(t, "u128"); | ||
288 | } | 282 | } |
289 | 283 | ||
290 | #[test] | 284 | #[test] |
291 | fn infer_assoc_items_generated_by_macros_chain() { | 285 | fn infer_assoc_items_generated_by_macros_chain() { |
292 | let t = type_at( | 286 | check_types( |
293 | r#" | 287 | r#" |
294 | //- /main.rs | ||
295 | macro_rules! m_inner { | 288 | macro_rules! m_inner { |
296 | () => {fn foo(&self) -> u128 {0}} | 289 | () => {fn foo(&self) -> u128 {0}} |
297 | } | 290 | } |
@@ -304,21 +297,21 @@ impl S { | |||
304 | m!(); | 297 | m!(); |
305 | } | 298 | } |
306 | 299 | ||
307 | fn test() { S.foo()<|>; } | 300 | fn test() { S.foo(); } |
301 | //^ u128 | ||
308 | "#, | 302 | "#, |
309 | ); | 303 | ); |
310 | assert_eq!(t, "u128"); | ||
311 | } | 304 | } |
312 | 305 | ||
313 | #[test] | 306 | #[test] |
314 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | 307 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { |
315 | let (db, pos) = TestDB::with_position( | 308 | check_types( |
316 | r#" | 309 | r#" |
317 | //- /main.rs crate:main deps:foo | 310 | //- /main.rs crate:main deps:foo |
318 | fn test() { | 311 | fn test() { |
319 | let x = (foo::foo!(1), foo::foo!(2)); | 312 | let x = (foo::foo!(1), foo::foo!(2)); |
320 | x<|>; | 313 | x; |
321 | } | 314 | } //^ (i32, usize) |
322 | 315 | ||
323 | //- /lib.rs crate:foo | 316 | //- /lib.rs crate:foo |
324 | #[macro_export] | 317 | #[macro_export] |
@@ -335,12 +328,11 @@ macro_rules! bar { | |||
335 | pub fn baz() -> usize { 31usize } | 328 | pub fn baz() -> usize { 31usize } |
336 | "#, | 329 | "#, |
337 | ); | 330 | ); |
338 | assert_eq!("(i32, usize)", type_at_pos(&db, pos)); | ||
339 | } | 331 | } |
340 | 332 | ||
341 | #[test] | 333 | #[test] |
342 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { | 334 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { |
343 | let (db, pos) = TestDB::with_position( | 335 | check_types( |
344 | r#" | 336 | r#" |
345 | //- /main.rs crate:main deps:foo | 337 | //- /main.rs crate:main deps:foo |
346 | use foo::Trait; | 338 | use foo::Trait; |
@@ -348,7 +340,8 @@ use foo::Trait; | |||
348 | fn test() { | 340 | fn test() { |
349 | let msg = foo::Message(foo::MessageRef); | 341 | let msg = foo::Message(foo::MessageRef); |
350 | let r = msg.deref(); | 342 | let r = msg.deref(); |
351 | r<|>; | 343 | r; |
344 | //^ &MessageRef | ||
352 | } | 345 | } |
353 | 346 | ||
354 | //- /lib.rs crate:foo | 347 | //- /lib.rs crate:foo |
@@ -375,7 +368,6 @@ macro_rules! expand { | |||
375 | expand!(); | 368 | expand!(); |
376 | "#, | 369 | "#, |
377 | ); | 370 | ); |
378 | assert_eq!("&MessageRef", type_at_pos(&db, pos)); | ||
379 | } | 371 | } |
380 | 372 | ||
381 | #[test] | 373 | #[test] |
@@ -429,13 +421,13 @@ fn main() { | |||
429 | 421 | ||
430 | #[test] | 422 | #[test] |
431 | fn infer_local_inner_macros() { | 423 | fn infer_local_inner_macros() { |
432 | let (db, pos) = TestDB::with_position( | 424 | check_types( |
433 | r#" | 425 | r#" |
434 | //- /main.rs crate:main deps:foo | 426 | //- /main.rs crate:main deps:foo |
435 | fn test() { | 427 | fn test() { |
436 | let x = foo::foo!(1); | 428 | let x = foo::foo!(1); |
437 | x<|>; | 429 | x; |
438 | } | 430 | } //^ i32 |
439 | 431 | ||
440 | //- /lib.rs crate:foo | 432 | //- /lib.rs crate:foo |
441 | #[macro_export(local_inner_macros)] | 433 | #[macro_export(local_inner_macros)] |
@@ -450,7 +442,6 @@ macro_rules! bar { | |||
450 | 442 | ||
451 | "#, | 443 | "#, |
452 | ); | 444 | ); |
453 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
454 | } | 445 | } |
455 | 446 | ||
456 | #[test] | 447 | #[test] |
@@ -531,7 +522,7 @@ fn main() { | |||
531 | 522 | ||
532 | #[test] | 523 | #[test] |
533 | fn infer_builtin_macros_include() { | 524 | fn infer_builtin_macros_include() { |
534 | let (db, pos) = TestDB::with_position( | 525 | check_types( |
535 | r#" | 526 | r#" |
536 | //- /main.rs | 527 | //- /main.rs |
537 | #[rustc_builtin_macro] | 528 | #[rustc_builtin_macro] |
@@ -540,14 +531,13 @@ macro_rules! include {() => {}} | |||
540 | include!("foo.rs"); | 531 | include!("foo.rs"); |
541 | 532 | ||
542 | fn main() { | 533 | fn main() { |
543 | bar()<|>; | 534 | bar(); |
544 | } | 535 | } //^ u32 |
545 | 536 | ||
546 | //- /foo.rs | 537 | //- /foo.rs |
547 | fn bar() -> u32 {0} | 538 | fn bar() -> u32 {0} |
548 | "#, | 539 | "#, |
549 | ); | 540 | ); |
550 | assert_eq!("u32", type_at_pos(&db, pos)); | ||
551 | } | 541 | } |
552 | 542 | ||
553 | #[test] | 543 | #[test] |
@@ -565,18 +555,17 @@ macro_rules! include {() => {}} | |||
565 | include!("foo.rs"); | 555 | include!("foo.rs"); |
566 | 556 | ||
567 | fn main() { | 557 | fn main() { |
568 | RegisterBlock { }<|>; | 558 | RegisterBlock { }; |
559 | //^ RegisterBlock | ||
569 | } | 560 | } |
570 | "#; | 561 | "#; |
571 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); | 562 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); |
572 | 563 | check_types(&fixture); | |
573 | let (db, pos) = TestDB::with_position(&fixture); | ||
574 | assert_eq!("RegisterBlock", type_at_pos(&db, pos)); | ||
575 | } | 564 | } |
576 | 565 | ||
577 | #[test] | 566 | #[test] |
578 | fn infer_builtin_macros_include_concat() { | 567 | fn infer_builtin_macros_include_concat() { |
579 | let (db, pos) = TestDB::with_position( | 568 | check_types( |
580 | r#" | 569 | r#" |
581 | //- /main.rs | 570 | //- /main.rs |
582 | #[rustc_builtin_macro] | 571 | #[rustc_builtin_macro] |
@@ -588,19 +577,18 @@ macro_rules! concat {() => {}} | |||
588 | include!(concat!("f", "oo.rs")); | 577 | include!(concat!("f", "oo.rs")); |
589 | 578 | ||
590 | fn main() { | 579 | fn main() { |
591 | bar()<|>; | 580 | bar(); |
592 | } | 581 | } //^ u32 |
593 | 582 | ||
594 | //- /foo.rs | 583 | //- /foo.rs |
595 | fn bar() -> u32 {0} | 584 | fn bar() -> u32 {0} |
596 | "#, | 585 | "#, |
597 | ); | 586 | ); |
598 | assert_eq!("u32", type_at_pos(&db, pos)); | ||
599 | } | 587 | } |
600 | 588 | ||
601 | #[test] | 589 | #[test] |
602 | fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { | 590 | fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { |
603 | let (db, pos) = TestDB::with_position( | 591 | check_types( |
604 | r#" | 592 | r#" |
605 | //- /main.rs | 593 | //- /main.rs |
606 | #[rustc_builtin_macro] | 594 | #[rustc_builtin_macro] |
@@ -615,32 +603,29 @@ macro_rules! env {() => {}} | |||
615 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); | 603 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); |
616 | 604 | ||
617 | fn main() { | 605 | fn main() { |
618 | bar()<|>; | 606 | bar(); |
619 | } | 607 | } //^ {unknown} |
620 | 608 | ||
621 | //- /foo.rs | 609 | //- /foo.rs |
622 | fn bar() -> u32 {0} | 610 | fn bar() -> u32 {0} |
623 | "#, | 611 | "#, |
624 | ); | 612 | ); |
625 | assert_eq!("{unknown}", type_at_pos(&db, pos)); | ||
626 | } | 613 | } |
627 | 614 | ||
628 | #[test] | 615 | #[test] |
629 | fn infer_builtin_macros_include_itself_should_failed() { | 616 | fn infer_builtin_macros_include_itself_should_failed() { |
630 | let (db, pos) = TestDB::with_position( | 617 | check_types( |
631 | r#" | 618 | r#" |
632 | //- /main.rs | ||
633 | #[rustc_builtin_macro] | 619 | #[rustc_builtin_macro] |
634 | macro_rules! include {() => {}} | 620 | macro_rules! include {() => {}} |
635 | 621 | ||
636 | include!("main.rs"); | 622 | include!("main.rs"); |
637 | 623 | ||
638 | fn main() { | 624 | fn main() { |
639 | 0<|> | 625 | 0 |
640 | } | 626 | } //^ i32 |
641 | "#, | 627 | "#, |
642 | ); | 628 | ); |
643 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
644 | } | 629 | } |
645 | 630 | ||
646 | #[test] | 631 | #[test] |
@@ -686,14 +671,14 @@ fn main() { | |||
686 | 671 | ||
687 | #[test] | 672 | #[test] |
688 | fn infer_derive_clone_simple() { | 673 | fn infer_derive_clone_simple() { |
689 | let (db, pos) = TestDB::with_position( | 674 | check_types( |
690 | r#" | 675 | r#" |
691 | //- /main.rs crate:main deps:core | 676 | //- /main.rs crate:main deps:core |
692 | #[derive(Clone)] | 677 | #[derive(Clone)] |
693 | struct S; | 678 | struct S; |
694 | fn test() { | 679 | fn test() { |
695 | S.clone()<|>; | 680 | S.clone(); |
696 | } | 681 | } //^ S |
697 | 682 | ||
698 | //- /lib.rs crate:core | 683 | //- /lib.rs crate:core |
699 | #[prelude_import] | 684 | #[prelude_import] |
@@ -705,12 +690,11 @@ mod clone { | |||
705 | } | 690 | } |
706 | "#, | 691 | "#, |
707 | ); | 692 | ); |
708 | assert_eq!("S", type_at_pos(&db, pos)); | ||
709 | } | 693 | } |
710 | 694 | ||
711 | #[test] | 695 | #[test] |
712 | fn infer_derive_clone_in_core() { | 696 | fn infer_derive_clone_in_core() { |
713 | let (db, pos) = TestDB::with_position( | 697 | check_types( |
714 | r#" | 698 | r#" |
715 | //- /lib.rs crate:core | 699 | //- /lib.rs crate:core |
716 | #[prelude_import] | 700 | #[prelude_import] |
@@ -726,16 +710,15 @@ pub struct S; | |||
726 | //- /main.rs crate:main deps:core | 710 | //- /main.rs crate:main deps:core |
727 | use core::S; | 711 | use core::S; |
728 | fn test() { | 712 | fn test() { |
729 | S.clone()<|>; | 713 | S.clone(); |
730 | } | 714 | } //^ S |
731 | "#, | 715 | "#, |
732 | ); | 716 | ); |
733 | assert_eq!("S", type_at_pos(&db, pos)); | ||
734 | } | 717 | } |
735 | 718 | ||
736 | #[test] | 719 | #[test] |
737 | fn infer_derive_clone_with_params() { | 720 | fn infer_derive_clone_with_params() { |
738 | let (db, pos) = TestDB::with_position( | 721 | check_types( |
739 | r#" | 722 | r#" |
740 | //- /main.rs crate:main deps:core | 723 | //- /main.rs crate:main deps:core |
741 | #[derive(Clone)] | 724 | #[derive(Clone)] |
@@ -744,7 +727,8 @@ struct S; | |||
744 | struct Wrapper<T>(T); | 727 | struct Wrapper<T>(T); |
745 | struct NonClone; | 728 | struct NonClone; |
746 | fn test() { | 729 | fn test() { |
747 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; | 730 | (Wrapper(S).clone(), Wrapper(NonClone).clone()); |
731 | //^ (Wrapper<S>, {unknown}) | ||
748 | } | 732 | } |
749 | 733 | ||
750 | //- /lib.rs crate:core | 734 | //- /lib.rs crate:core |
@@ -757,13 +741,12 @@ mod clone { | |||
757 | } | 741 | } |
758 | "#, | 742 | "#, |
759 | ); | 743 | ); |
760 | assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos)); | ||
761 | } | 744 | } |
762 | 745 | ||
763 | #[test] | 746 | #[test] |
764 | fn infer_custom_derive_simple() { | 747 | fn infer_custom_derive_simple() { |
765 | // FIXME: this test current now do nothing | 748 | // FIXME: this test current now do nothing |
766 | let (db, pos) = TestDB::with_position( | 749 | check_types( |
767 | r#" | 750 | r#" |
768 | //- /main.rs crate:main | 751 | //- /main.rs crate:main |
769 | use foo::Foo; | 752 | use foo::Foo; |
@@ -772,11 +755,10 @@ use foo::Foo; | |||
772 | struct S{} | 755 | struct S{} |
773 | 756 | ||
774 | fn test() { | 757 | fn test() { |
775 | S{}<|>; | 758 | S{}; |
776 | } | 759 | } //^ S |
777 | "#, | 760 | "#, |
778 | ); | 761 | ); |
779 | assert_eq!("S", type_at_pos(&db, pos)); | ||
780 | } | 762 | } |
781 | 763 | ||
782 | #[test] | 764 | #[test] |
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 20329bae4..9c8f22314 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use super::{infer, type_at, type_at_pos}; | ||
2 | use crate::test_db::TestDB; | ||
3 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
4 | use ra_db::fixture::WithFixture; | 2 | |
3 | use super::{check_types, infer}; | ||
5 | 4 | ||
6 | #[test] | 5 | #[test] |
7 | fn infer_slice_method() { | 6 | fn infer_slice_method() { |
@@ -246,13 +245,13 @@ fn test() { | |||
246 | 245 | ||
247 | #[test] | 246 | #[test] |
248 | fn cross_crate_associated_method_call() { | 247 | fn cross_crate_associated_method_call() { |
249 | let (db, pos) = TestDB::with_position( | 248 | check_types( |
250 | r#" | 249 | r#" |
251 | //- /main.rs crate:main deps:other_crate | 250 | //- /main.rs crate:main deps:other_crate |
252 | fn test() { | 251 | fn test() { |
253 | let x = other_crate::foo::S::thing(); | 252 | let x = other_crate::foo::S::thing(); |
254 | x<|>; | 253 | x; |
255 | } | 254 | } //^ i128 |
256 | 255 | ||
257 | //- /lib.rs crate:other_crate | 256 | //- /lib.rs crate:other_crate |
258 | mod foo { | 257 | mod foo { |
@@ -263,7 +262,6 @@ mod foo { | |||
263 | } | 262 | } |
264 | "#, | 263 | "#, |
265 | ); | 264 | ); |
266 | assert_eq!("i128", type_at_pos(&db, pos)); | ||
267 | } | 265 | } |
268 | 266 | ||
269 | #[test] | 267 | #[test] |
@@ -684,135 +682,127 @@ fn test() { | |||
684 | 682 | ||
685 | #[test] | 683 | #[test] |
686 | fn method_resolution_unify_impl_self_type() { | 684 | fn method_resolution_unify_impl_self_type() { |
687 | let t = type_at( | 685 | check_types( |
688 | r#" | 686 | r#" |
689 | //- /main.rs | ||
690 | struct S<T>; | 687 | struct S<T>; |
691 | impl S<u32> { fn foo(&self) -> u8 {} } | 688 | impl S<u32> { fn foo(&self) -> u8 {} } |
692 | impl S<i32> { fn foo(&self) -> i8 {} } | 689 | impl S<i32> { fn foo(&self) -> i8 {} } |
693 | fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; } | 690 | fn test() { (S::<u32>.foo(), S::<i32>.foo()); } |
691 | //^ (u8, i8) | ||
694 | "#, | 692 | "#, |
695 | ); | 693 | ); |
696 | assert_eq!(t, "(u8, i8)"); | ||
697 | } | 694 | } |
698 | 695 | ||
699 | #[test] | 696 | #[test] |
700 | fn method_resolution_trait_before_autoref() { | 697 | fn method_resolution_trait_before_autoref() { |
701 | let t = type_at( | 698 | check_types( |
702 | r#" | 699 | r#" |
703 | //- /main.rs | ||
704 | trait Trait { fn foo(self) -> u128; } | 700 | trait Trait { fn foo(self) -> u128; } |
705 | struct S; | 701 | struct S; |
706 | impl S { fn foo(&self) -> i8 { 0 } } | 702 | impl S { fn foo(&self) -> i8 { 0 } } |
707 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 703 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
708 | fn test() { S.foo()<|>; } | 704 | fn test() { S.foo(); } |
705 | //^ u128 | ||
709 | "#, | 706 | "#, |
710 | ); | 707 | ); |
711 | assert_eq!(t, "u128"); | ||
712 | } | 708 | } |
713 | 709 | ||
714 | #[test] | 710 | #[test] |
715 | fn method_resolution_by_value_before_autoref() { | 711 | fn method_resolution_by_value_before_autoref() { |
716 | let t = type_at( | 712 | check_types( |
717 | r#" | 713 | r#" |
718 | //- /main.rs | ||
719 | trait Clone { fn clone(&self) -> Self; } | 714 | trait Clone { fn clone(&self) -> Self; } |
720 | struct S; | 715 | struct S; |
721 | impl Clone for S {} | 716 | impl Clone for S {} |
722 | impl Clone for &S {} | 717 | impl Clone for &S {} |
723 | fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } | 718 | fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } |
719 | //^ (S, S, &S) | ||
724 | "#, | 720 | "#, |
725 | ); | 721 | ); |
726 | assert_eq!(t, "(S, S, &S)"); | ||
727 | } | 722 | } |
728 | 723 | ||
729 | #[test] | 724 | #[test] |
730 | fn method_resolution_trait_before_autoderef() { | 725 | fn method_resolution_trait_before_autoderef() { |
731 | let t = type_at( | 726 | check_types( |
732 | r#" | 727 | r#" |
733 | //- /main.rs | ||
734 | trait Trait { fn foo(self) -> u128; } | 728 | trait Trait { fn foo(self) -> u128; } |
735 | struct S; | 729 | struct S; |
736 | impl S { fn foo(self) -> i8 { 0 } } | 730 | impl S { fn foo(self) -> i8 { 0 } } |
737 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 731 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
738 | fn test() { (&S).foo()<|>; } | 732 | fn test() { (&S).foo(); } |
733 | //^ u128 | ||
739 | "#, | 734 | "#, |
740 | ); | 735 | ); |
741 | assert_eq!(t, "u128"); | ||
742 | } | 736 | } |
743 | 737 | ||
744 | #[test] | 738 | #[test] |
745 | fn method_resolution_impl_before_trait() { | 739 | fn method_resolution_impl_before_trait() { |
746 | let t = type_at( | 740 | check_types( |
747 | r#" | 741 | r#" |
748 | //- /main.rs | ||
749 | trait Trait { fn foo(self) -> u128; } | 742 | trait Trait { fn foo(self) -> u128; } |
750 | struct S; | 743 | struct S; |
751 | impl S { fn foo(self) -> i8 { 0 } } | 744 | impl S { fn foo(self) -> i8 { 0 } } |
752 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 745 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
753 | fn test() { S.foo()<|>; } | 746 | fn test() { S.foo(); } |
747 | //^ i8 | ||
754 | "#, | 748 | "#, |
755 | ); | 749 | ); |
756 | assert_eq!(t, "i8"); | ||
757 | } | 750 | } |
758 | 751 | ||
759 | #[test] | 752 | #[test] |
760 | fn method_resolution_impl_ref_before_trait() { | 753 | fn method_resolution_impl_ref_before_trait() { |
761 | let t = type_at( | 754 | check_types( |
762 | r#" | 755 | r#" |
763 | //- /main.rs | ||
764 | trait Trait { fn foo(self) -> u128; } | 756 | trait Trait { fn foo(self) -> u128; } |
765 | struct S; | 757 | struct S; |
766 | impl S { fn foo(&self) -> i8 { 0 } } | 758 | impl S { fn foo(&self) -> i8 { 0 } } |
767 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 759 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
768 | fn test() { S.foo()<|>; } | 760 | fn test() { S.foo(); } |
761 | //^ i8 | ||
769 | "#, | 762 | "#, |
770 | ); | 763 | ); |
771 | assert_eq!(t, "i8"); | ||
772 | } | 764 | } |
773 | 765 | ||
774 | #[test] | 766 | #[test] |
775 | fn method_resolution_trait_autoderef() { | 767 | fn method_resolution_trait_autoderef() { |
776 | let t = type_at( | 768 | check_types( |
777 | r#" | 769 | r#" |
778 | //- /main.rs | ||
779 | trait Trait { fn foo(self) -> u128; } | 770 | trait Trait { fn foo(self) -> u128; } |
780 | struct S; | 771 | struct S; |
781 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 772 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
782 | fn test() { (&S).foo()<|>; } | 773 | fn test() { (&S).foo(); } |
774 | //^ u128 | ||
783 | "#, | 775 | "#, |
784 | ); | 776 | ); |
785 | assert_eq!(t, "u128"); | ||
786 | } | 777 | } |
787 | 778 | ||
788 | #[test] | 779 | #[test] |
789 | fn method_resolution_unsize_array() { | 780 | fn method_resolution_unsize_array() { |
790 | let t = type_at( | 781 | check_types( |
791 | r#" | 782 | r#" |
792 | //- /main.rs | ||
793 | #[lang = "slice"] | 783 | #[lang = "slice"] |
794 | impl<T> [T] { | 784 | impl<T> [T] { |
795 | fn len(&self) -> usize { loop {} } | 785 | fn len(&self) -> usize { loop {} } |
796 | } | 786 | } |
797 | fn test() { | 787 | fn test() { |
798 | let a = [1, 2, 3]; | 788 | let a = [1, 2, 3]; |
799 | a.len()<|>; | 789 | a.len(); |
800 | } | 790 | } //^ usize |
801 | "#, | 791 | "#, |
802 | ); | 792 | ); |
803 | assert_eq!(t, "usize"); | ||
804 | } | 793 | } |
805 | 794 | ||
806 | #[test] | 795 | #[test] |
807 | fn method_resolution_trait_from_prelude() { | 796 | fn method_resolution_trait_from_prelude() { |
808 | let (db, pos) = TestDB::with_position( | 797 | check_types( |
809 | r#" | 798 | r#" |
810 | //- /main.rs crate:main deps:other_crate | 799 | //- /main.rs crate:main deps:other_crate |
811 | struct S; | 800 | struct S; |
812 | impl Clone for S {} | 801 | impl Clone for S {} |
813 | 802 | ||
814 | fn test() { | 803 | fn test() { |
815 | S.clone()<|>; | 804 | S.clone(); |
805 | //^ S | ||
816 | } | 806 | } |
817 | 807 | ||
818 | //- /lib.rs crate:other_crate | 808 | //- /lib.rs crate:other_crate |
@@ -825,115 +815,107 @@ mod foo { | |||
825 | } | 815 | } |
826 | "#, | 816 | "#, |
827 | ); | 817 | ); |
828 | assert_eq!("S", type_at_pos(&db, pos)); | ||
829 | } | 818 | } |
830 | 819 | ||
831 | #[test] | 820 | #[test] |
832 | fn method_resolution_where_clause_for_unknown_trait() { | 821 | fn method_resolution_where_clause_for_unknown_trait() { |
833 | // The blanket impl currently applies because we ignore the unresolved where clause | 822 | // The blanket impl currently applies because we ignore the unresolved where clause |
834 | let t = type_at( | 823 | check_types( |
835 | r#" | 824 | r#" |
836 | //- /main.rs | ||
837 | trait Trait { fn foo(self) -> u128; } | 825 | trait Trait { fn foo(self) -> u128; } |
838 | struct S; | 826 | struct S; |
839 | impl<T> Trait for T where T: UnknownTrait {} | 827 | impl<T> Trait for T where T: UnknownTrait {} |
840 | fn test() { (&S).foo()<|>; } | 828 | fn test() { (&S).foo(); } |
829 | //^ u128 | ||
841 | "#, | 830 | "#, |
842 | ); | 831 | ); |
843 | assert_eq!(t, "u128"); | ||
844 | } | 832 | } |
845 | 833 | ||
846 | #[test] | 834 | #[test] |
847 | fn method_resolution_where_clause_not_met() { | 835 | fn method_resolution_where_clause_not_met() { |
848 | // The blanket impl shouldn't apply because we can't prove S: Clone | 836 | // The blanket impl shouldn't apply because we can't prove S: Clone |
849 | let t = type_at( | 837 | // This is also to make sure that we don't resolve to the foo method just |
838 | // because that's the only method named foo we can find, which would make | ||
839 | // the below tests not work | ||
840 | check_types( | ||
850 | r#" | 841 | r#" |
851 | //- /main.rs | ||
852 | trait Clone {} | 842 | trait Clone {} |
853 | trait Trait { fn foo(self) -> u128; } | 843 | trait Trait { fn foo(self) -> u128; } |
854 | struct S; | 844 | struct S; |
855 | impl<T> Trait for T where T: Clone {} | 845 | impl<T> Trait for T where T: Clone {} |
856 | fn test() { (&S).foo()<|>; } | 846 | fn test() { (&S).foo(); } |
847 | //^ {unknown} | ||
857 | "#, | 848 | "#, |
858 | ); | 849 | ); |
859 | // This is also to make sure that we don't resolve to the foo method just | ||
860 | // because that's the only method named foo we can find, which would make | ||
861 | // the below tests not work | ||
862 | assert_eq!(t, "{unknown}"); | ||
863 | } | 850 | } |
864 | 851 | ||
865 | #[test] | 852 | #[test] |
866 | fn method_resolution_where_clause_inline_not_met() { | 853 | fn method_resolution_where_clause_inline_not_met() { |
867 | // The blanket impl shouldn't apply because we can't prove S: Clone | 854 | // The blanket impl shouldn't apply because we can't prove S: Clone |
868 | let t = type_at( | 855 | check_types( |
869 | r#" | 856 | r#" |
870 | //- /main.rs | ||
871 | trait Clone {} | 857 | trait Clone {} |
872 | trait Trait { fn foo(self) -> u128; } | 858 | trait Trait { fn foo(self) -> u128; } |
873 | struct S; | 859 | struct S; |
874 | impl<T: Clone> Trait for T {} | 860 | impl<T: Clone> Trait for T {} |
875 | fn test() { (&S).foo()<|>; } | 861 | fn test() { (&S).foo(); } |
862 | //^ {unknown} | ||
876 | "#, | 863 | "#, |
877 | ); | 864 | ); |
878 | assert_eq!(t, "{unknown}"); | ||
879 | } | 865 | } |
880 | 866 | ||
881 | #[test] | 867 | #[test] |
882 | fn method_resolution_where_clause_1() { | 868 | fn method_resolution_where_clause_1() { |
883 | let t = type_at( | 869 | check_types( |
884 | r#" | 870 | r#" |
885 | //- /main.rs | ||
886 | trait Clone {} | 871 | trait Clone {} |
887 | trait Trait { fn foo(self) -> u128; } | 872 | trait Trait { fn foo(self) -> u128; } |
888 | struct S; | 873 | struct S; |
889 | impl Clone for S {} | 874 | impl Clone for S {} |
890 | impl<T> Trait for T where T: Clone {} | 875 | impl<T> Trait for T where T: Clone {} |
891 | fn test() { S.foo()<|>; } | 876 | fn test() { S.foo(); } |
877 | //^ u128 | ||
892 | "#, | 878 | "#, |
893 | ); | 879 | ); |
894 | assert_eq!(t, "u128"); | ||
895 | } | 880 | } |
896 | 881 | ||
897 | #[test] | 882 | #[test] |
898 | fn method_resolution_where_clause_2() { | 883 | fn method_resolution_where_clause_2() { |
899 | let t = type_at( | 884 | check_types( |
900 | r#" | 885 | r#" |
901 | //- /main.rs | ||
902 | trait Into<T> { fn into(self) -> T; } | 886 | trait Into<T> { fn into(self) -> T; } |
903 | trait From<T> { fn from(other: T) -> Self; } | 887 | trait From<T> { fn from(other: T) -> Self; } |
904 | struct S1; | 888 | struct S1; |
905 | struct S2; | 889 | struct S2; |
906 | impl From<S2> for S1 {} | 890 | impl From<S2> for S1 {} |
907 | impl<T, U> Into<U> for T where U: From<T> {} | 891 | impl<T, U> Into<U> for T where U: From<T> {} |
908 | fn test() { S2.into()<|>; } | 892 | fn test() { S2.into(); } |
893 | //^ {unknown} | ||
909 | "#, | 894 | "#, |
910 | ); | 895 | ); |
911 | assert_eq!(t, "{unknown}"); | ||
912 | } | 896 | } |
913 | 897 | ||
914 | #[test] | 898 | #[test] |
915 | fn method_resolution_where_clause_inline() { | 899 | fn method_resolution_where_clause_inline() { |
916 | let t = type_at( | 900 | check_types( |
917 | r#" | 901 | r#" |
918 | //- /main.rs | ||
919 | trait Into<T> { fn into(self) -> T; } | 902 | trait Into<T> { fn into(self) -> T; } |
920 | trait From<T> { fn from(other: T) -> Self; } | 903 | trait From<T> { fn from(other: T) -> Self; } |
921 | struct S1; | 904 | struct S1; |
922 | struct S2; | 905 | struct S2; |
923 | impl From<S2> for S1 {} | 906 | impl From<S2> for S1 {} |
924 | impl<T, U: From<T>> Into<U> for T {} | 907 | impl<T, U: From<T>> Into<U> for T {} |
925 | fn test() { S2.into()<|>; } | 908 | fn test() { S2.into(); } |
909 | //^ {unknown} | ||
926 | "#, | 910 | "#, |
927 | ); | 911 | ); |
928 | assert_eq!(t, "{unknown}"); | ||
929 | } | 912 | } |
930 | 913 | ||
931 | #[test] | 914 | #[test] |
932 | fn method_resolution_overloaded_method() { | 915 | fn method_resolution_overloaded_method() { |
933 | test_utils::mark::check!(impl_self_type_match_without_receiver); | 916 | test_utils::mark::check!(impl_self_type_match_without_receiver); |
934 | let t = type_at( | 917 | check_types( |
935 | r#" | 918 | r#" |
936 | //- /main.rs | ||
937 | struct Wrapper<T>(T); | 919 | struct Wrapper<T>(T); |
938 | struct Foo<T>(T); | 920 | struct Foo<T>(T); |
939 | struct Bar<T>(T); | 921 | struct Bar<T>(T); |
@@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> { | |||
953 | fn main() { | 935 | fn main() { |
954 | let a = Wrapper::<Foo<f32>>::new(1.0); | 936 | let a = Wrapper::<Foo<f32>>::new(1.0); |
955 | let b = Wrapper::<Bar<f32>>::new(1.0); | 937 | let b = Wrapper::<Bar<f32>>::new(1.0); |
956 | (a, b)<|>; | 938 | (a, b); |
939 | //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) | ||
957 | } | 940 | } |
958 | "#, | 941 | "#, |
959 | ); | 942 | ); |
960 | assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)") | ||
961 | } | 943 | } |
962 | 944 | ||
963 | #[test] | 945 | #[test] |
964 | fn method_resolution_encountering_fn_type() { | 946 | fn method_resolution_encountering_fn_type() { |
965 | type_at( | 947 | check_types( |
966 | r#" | 948 | r#" |
967 | //- /main.rs | 949 | //- /main.rs |
968 | fn foo() {} | 950 | fn foo() {} |
969 | trait FnOnce { fn call(self); } | 951 | trait FnOnce { fn call(self); } |
970 | fn test() { foo.call()<|>; } | 952 | fn test() { foo.call(); } |
953 | //^ {unknown} | ||
971 | "#, | 954 | "#, |
972 | ); | 955 | ); |
973 | } | 956 | } |
974 | 957 | ||
975 | #[test] | 958 | #[test] |
976 | fn method_resolution_non_parameter_type() { | 959 | fn method_resolution_non_parameter_type() { |
977 | let t = type_at( | 960 | check_types( |
978 | r#" | 961 | r#" |
979 | //- /main.rs | ||
980 | mod a { | 962 | mod a { |
981 | pub trait Foo { | 963 | pub trait Foo { |
982 | fn foo(&self); | 964 | fn foo(&self); |
@@ -988,18 +970,16 @@ fn foo<T>(t: Wrapper<T>) | |||
988 | where | 970 | where |
989 | Wrapper<T>: a::Foo, | 971 | Wrapper<T>: a::Foo, |
990 | { | 972 | { |
991 | t.foo()<|>; | 973 | t.foo(); |
992 | } | 974 | } //^ {unknown} |
993 | "#, | 975 | "#, |
994 | ); | 976 | ); |
995 | assert_eq!(t, "{unknown}"); | ||
996 | } | 977 | } |
997 | 978 | ||
998 | #[test] | 979 | #[test] |
999 | fn method_resolution_3373() { | 980 | fn method_resolution_3373() { |
1000 | let t = type_at( | 981 | check_types( |
1001 | r#" | 982 | r#" |
1002 | //- /main.rs | ||
1003 | struct A<T>(T); | 983 | struct A<T>(T); |
1004 | 984 | ||
1005 | impl A<i32> { | 985 | impl A<i32> { |
@@ -1007,19 +987,17 @@ impl A<i32> { | |||
1007 | } | 987 | } |
1008 | 988 | ||
1009 | fn main() { | 989 | fn 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] |
1018 | fn method_resolution_slow() { | 997 | fn 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 | ||
1023 | trait SendX {} | 1001 | trait SendX {} |
1024 | 1002 | ||
1025 | struct S1; impl SendX for S1 {} | 1003 | struct S1; impl SendX for S1 {} |
@@ -1037,10 +1015,10 @@ trait FnX {} | |||
1037 | 1015 | ||
1038 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} | 1016 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} |
1039 | 1017 | ||
1040 | fn test() { (S {}).method()<|>; } | 1018 | fn 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 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | 2 | ||
3 | use super::{infer_with_mismatches, type_at}; | 3 | use super::{check_types, infer_with_mismatches}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_never1() { | 6 | fn infer_never1() { |
7 | let t = type_at( | 7 | check_types( |
8 | r#" | 8 | r#" |
9 | //- /main.rs | ||
10 | fn test() { | 9 | fn 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] |
20 | fn infer_never2() { | 18 | fn infer_never2() { |
21 | let t = type_at( | 19 | check_types( |
22 | r#" | 20 | r#" |
23 | //- /main.rs | ||
24 | fn gen<T>() -> T { loop {} } | 21 | fn gen<T>() -> T { loop {} } |
25 | 22 | ||
26 | fn test() { | 23 | fn 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] |
37 | fn infer_never3() { | 33 | fn infer_never3() { |
38 | let t = type_at( | 34 | check_types( |
39 | r#" | 35 | r#" |
40 | //- /main.rs | ||
41 | fn gen<T>() -> T { loop {} } | 36 | fn gen<T>() -> T { loop {} } |
42 | 37 | ||
43 | fn test() { | 38 | fn 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] |
54 | fn never_type_in_generic_args() { | 49 | fn never_type_in_generic_args() { |
55 | let t = type_at( | 50 | check_types( |
56 | r#" | 51 | r#" |
57 | //- /main.rs | ||
58 | enum Option<T> { None, Some(T) } | 52 | enum Option<T> { None, Some(T) } |
59 | 53 | ||
60 | fn test() { | 54 | fn 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] |
70 | fn never_type_can_be_reinferred1() { | 63 | fn never_type_can_be_reinferred1() { |
71 | let t = type_at( | 64 | check_types( |
72 | r#" | 65 | r#" |
73 | //- /main.rs | ||
74 | fn gen<T>() -> T { loop {} } | 66 | fn gen<T>() -> T { loop {} } |
75 | 67 | ||
76 | fn test() { | 68 | fn 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] |
88 | fn never_type_can_be_reinferred2() { | 80 | fn never_type_can_be_reinferred2() { |
89 | let t = type_at( | 81 | check_types( |
90 | r#" | 82 | r#" |
91 | //- /main.rs | ||
92 | enum Option<T> { None, Some(T) } | 83 | enum Option<T> { None, Some(T) } |
93 | 84 | ||
94 | fn test() { | 85 | fn 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] |
108 | fn never_type_can_be_reinferred3() { | 99 | fn never_type_can_be_reinferred3() { |
109 | let t = type_at( | 100 | check_types( |
110 | r#" | 101 | r#" |
111 | //- /main.rs | ||
112 | enum Option<T> { None, Some(T) } | 102 | enum Option<T> { None, Some(T) } |
113 | 103 | ||
114 | fn test() { | 104 | fn 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] |
128 | fn match_no_arm() { | 118 | fn match_no_arm() { |
129 | let t = type_at( | 119 | check_types( |
130 | r#" | 120 | r#" |
131 | //- /main.rs | ||
132 | enum Void {} | 121 | enum Void {} |
133 | 122 | ||
134 | fn test(a: Void) { | 123 | fn 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] |
144 | fn match_unknown_arm() { | 132 | fn match_unknown_arm() { |
145 | let t = type_at( | 133 | check_types( |
146 | r#" | 134 | r#" |
147 | //- /main.rs | ||
148 | fn test(a: Option) { | 135 | fn 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] |
160 | fn if_never() { | 146 | fn if_never() { |
161 | let t = type_at( | 147 | check_types( |
162 | r#" | 148 | r#" |
163 | //- /main.rs | ||
164 | fn test() { | 149 | fn 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] |
178 | fn if_else_never() { | 162 | fn if_else_never() { |
179 | let t = type_at( | 163 | check_types( |
180 | r#" | 164 | r#" |
181 | //- /main.rs | ||
182 | fn test(input: bool) { | 165 | fn 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] |
196 | fn match_first_arm_never() { | 178 | fn match_first_arm_never() { |
197 | let t = type_at( | 179 | check_types( |
198 | r#" | 180 | r#" |
199 | //- /main.rs | ||
200 | fn test(a: i32) { | 181 | fn 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] |
215 | fn match_second_arm_never() { | 195 | fn match_second_arm_never() { |
216 | let t = type_at( | 196 | check_types( |
217 | r#" | 197 | r#" |
218 | //- /main.rs | ||
219 | fn test(a: i32) { | 198 | fn 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] |
234 | fn match_all_arms_never() { | 212 | fn match_all_arms_never() { |
235 | let t = type_at( | 213 | check_types( |
236 | r#" | 214 | r#" |
237 | //- /main.rs | ||
238 | fn test(a: i32) { | 215 | fn 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] |
251 | fn match_no_never_arms() { | 227 | fn match_no_never_arms() { |
252 | let t = type_at( | 228 | check_types( |
253 | r#" | 229 | r#" |
254 | //- /main.rs | ||
255 | fn test(a: i32) { | 230 | fn 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 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | use ra_db::fixture::WithFixture; | ||
3 | use test_utils::mark; | 2 | use test_utils::mark; |
4 | 3 | ||
5 | use crate::test_db::TestDB; | 4 | use super::{check_types, infer}; |
6 | |||
7 | use super::infer; | ||
8 | 5 | ||
9 | #[test] | 6 | #[test] |
10 | fn bug_484() { | 7 | fn bug_484() { |
@@ -404,13 +401,13 @@ fn test() { | |||
404 | 401 | ||
405 | #[test] | 402 | #[test] |
406 | fn issue_2683_chars_impl() { | 403 | fn 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 |
410 | fn test() { | 407 | fn 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] |
457 | fn issue_3642_bad_macro_stackover() { | 452 | fn 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] |
462 | macro_rules! match_ast { | 456 | macro_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 | ||
474 | fn main() { | 468 | fn 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 @@ | |||
1 | use super::{infer, type_at, type_at_pos}; | ||
2 | use crate::test_db::TestDB; | ||
3 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
4 | use ra_db::fixture::WithFixture; | 2 | |
3 | use super::{check_types, infer}; | ||
5 | 4 | ||
6 | #[test] | 5 | #[test] |
7 | fn infer_box() { | 6 | fn 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 | |||
12 | fn test() { | 10 | fn 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] |
35 | fn infer_adt_self() { | 31 | fn infer_adt_self() { |
36 | let (db, pos) = TestDB::with_position( | 32 | check_types( |
37 | r#" | 33 | r#" |
38 | //- /main.rs | ||
39 | enum Nat { Succ(Self), Demo(Nat), Zero } | 34 | enum Nat { Succ(Self), Demo(Nat), Zero } |
40 | 35 | ||
41 | fn test() { | 36 | fn 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] |
95 | fn infer_ranges() { | 88 | fn 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 |
99 | fn test() { | 92 | fn 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] |
145 | fn infer_while_let() { | 134 | fn infer_while_let() { |
146 | let (db, pos) = TestDB::with_position( | 135 | check_types( |
147 | r#" | 136 | r#" |
148 | //- /main.rs | ||
149 | enum Option<T> { Some(T), None } | 137 | enum Option<T> { Some(T), None } |
150 | 138 | ||
151 | fn test() { | 139 | fn 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] |
1689 | fn shadowing_primitive() { | 1675 | fn shadowing_primitive() { |
1690 | let t = type_at( | 1676 | check_types( |
1691 | r#" | 1677 | r#" |
1692 | //- /main.rs | ||
1693 | struct i32; | 1678 | struct i32; |
1694 | struct Foo; | 1679 | struct Foo; |
1695 | 1680 | ||
@@ -1697,15 +1682,15 @@ impl i32 { fn foo(&self) -> Foo { Foo } } | |||
1697 | 1682 | ||
1698 | fn main() { | 1683 | fn 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] |
1707 | fn not_shadowing_primitive_by_module() { | 1692 | fn not_shadowing_primitive_by_module() { |
1708 | let t = type_at( | 1693 | check_types( |
1709 | r#" | 1694 | r#" |
1710 | //- /str.rs | 1695 | //- /str.rs |
1711 | fn foo() {} | 1696 | fn foo() {} |
@@ -1715,15 +1700,15 @@ mod str; | |||
1715 | fn foo() -> &'static str { "" } | 1700 | fn foo() -> &'static str { "" } |
1716 | 1701 | ||
1717 | fn main() { | 1702 | fn main() { |
1718 | foo()<|>; | 1703 | foo(); |
1704 | //^ &str | ||
1719 | }"#, | 1705 | }"#, |
1720 | ); | 1706 | ); |
1721 | assert_eq!(t, "&str"); | ||
1722 | } | 1707 | } |
1723 | 1708 | ||
1724 | #[test] | 1709 | #[test] |
1725 | fn not_shadowing_module_by_primitive() { | 1710 | fn not_shadowing_module_by_primitive() { |
1726 | let t = type_at( | 1711 | check_types( |
1727 | r#" | 1712 | r#" |
1728 | //- /str.rs | 1713 | //- /str.rs |
1729 | fn foo() -> u32 {0} | 1714 | fn foo() -> u32 {0} |
@@ -1733,10 +1718,10 @@ mod str; | |||
1733 | fn foo() -> &'static str { "" } | 1718 | fn foo() -> &'static str { "" } |
1734 | 1719 | ||
1735 | fn main() { | 1720 | fn 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] |
1746 | fn should_be_shadowing_imports() { | 1731 | fn should_be_shadowing_imports() { |
1747 | let t = type_at( | 1732 | check_types( |
1748 | r#" | ||
1749 | mod a { | ||
1750 | pub fn foo() -> i8 {0} | ||
1751 | pub struct foo { a: i8 } | ||
1752 | } | ||
1753 | mod b { pub fn foo () -> u8 {0} } | ||
1754 | mod c { pub struct foo { a: u8 } } | ||
1755 | mod d { | ||
1756 | pub use super::a::*; | ||
1757 | pub use super::c::foo; | ||
1758 | pub use super::b::foo; | ||
1759 | } | ||
1760 | |||
1761 | fn main() { | ||
1762 | d::foo()<|>; | ||
1763 | }"#, | ||
1764 | ); | ||
1765 | assert_eq!(t, "u8"); | ||
1766 | |||
1767 | let t = type_at( | ||
1768 | r#" | 1733 | r#" |
1769 | mod a { | 1734 | mod a { |
1770 | pub fn foo() -> i8 {0} | 1735 | pub fn foo() -> i8 {0} |
@@ -1779,10 +1744,12 @@ mod d { | |||
1779 | } | 1744 | } |
1780 | 1745 | ||
1781 | fn main() { | 1746 | fn 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] | ||
2124 | fn generic_default_depending_on_other_type_arg() { | ||
2125 | assert_snapshot!( | ||
2126 | infer(r#" | ||
2127 | struct Thing<T = u128, F = fn() -> T> { t: T } | ||
2128 | |||
2129 | fn 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] | ||
2149 | fn generic_default_depending_on_other_type_arg_forward() { | ||
2150 | assert_snapshot!( | ||
2151 | infer(r#" | ||
2152 | struct Thing<F = fn() -> T, T = u128> { t: T } | ||
2153 | |||
2154 | fn 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 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | use ra_db::fixture::WithFixture; | ||
3 | use test_utils::mark; | 2 | use test_utils::mark; |
4 | 3 | ||
5 | use crate::test_db::TestDB; | 4 | use super::{check_types, infer, infer_with_mismatches}; |
6 | |||
7 | use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | ||
8 | 5 | ||
9 | #[test] | 6 | #[test] |
10 | fn infer_await() { | 7 | fn 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 | |||
15 | struct IntFuture; | 11 | struct IntFuture; |
16 | 12 | ||
17 | impl Future for IntFuture { | 13 | impl Future for IntFuture { |
@@ -21,8 +17,8 @@ impl Future for IntFuture { | |||
21 | fn test() { | 17 | fn 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] |
42 | fn infer_async() { | 36 | fn 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 | |||
47 | async fn foo() -> u64 { | 40 | async fn foo() -> u64 { |
48 | 128 | 41 | 128 |
49 | } | 42 | } |
@@ -51,8 +44,8 @@ async fn foo() -> u64 { | |||
51 | fn test() { | 44 | fn 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] |
72 | fn infer_desugar_async() { | 63 | fn 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 | |||
77 | async fn foo() -> u64 { | 67 | async fn foo() -> u64 { |
78 | 128 | 68 | 128 |
79 | } | 69 | } |
80 | 70 | ||
81 | fn test() { | 71 | fn 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] |
100 | fn infer_try() { | 89 | fn 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 | |||
105 | fn test() { | 93 | fn 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::*; |
114 | mod ops { | 101 | mod 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] |
140 | fn infer_for_loop() { | 125 | fn 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 | |||
145 | use alloc::collections::Vec; | 129 | use alloc::collections::Vec; |
146 | 130 | ||
147 | fn test() { | 131 | fn 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::*; |
158 | mod iter { | 141 | mod 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 | |||
166 | mod collections { | 148 | mod 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] |
183 | fn infer_ops_neg() { | 164 | fn 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 | |||
188 | struct Bar; | 168 | struct Bar; |
189 | struct Foo; | 169 | struct Foo; |
190 | 170 | ||
@@ -195,11 +175,10 @@ impl std::ops::Neg for Bar { | |||
195 | fn test() { | 175 | fn 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::*; |
204 | mod ops { | 183 | mod 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] |
216 | fn infer_ops_not() { | 194 | fn 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 | |||
221 | struct Bar; | 198 | struct Bar; |
222 | struct Foo; | 199 | struct Foo; |
223 | 200 | ||
@@ -228,11 +205,10 @@ impl std::ops::Not for Bar { | |||
228 | fn test() { | 205 | fn 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::*; |
237 | mod ops { | 213 | mod 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] |
539 | fn infer_ops_index() { | 514 | fn 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 | |||
544 | struct Bar; | 518 | struct Bar; |
545 | struct Foo; | 519 | struct Foo; |
546 | 520 | ||
@@ -551,11 +525,10 @@ impl std::ops::Index<u32> for Bar { | |||
551 | fn test() { | 525 | fn 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::*; |
560 | mod ops { | 533 | mod 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] |
572 | fn infer_ops_index_autoderef() { | 544 | fn 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 |
576 | fn test() { | 548 | fn 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 |
583 | impl<T> ops::Index<u32> for [T] { | 555 | impl<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] |
600 | fn deref_trait() { | 571 | fn deref_trait() { |
601 | let t = type_at( | 572 | check_types( |
602 | r#" | 573 | r#" |
603 | //- /main.rs | ||
604 | #[lang = "deref"] | 574 | #[lang = "deref"] |
605 | trait Deref { | 575 | trait Deref { |
606 | type Target; | 576 | type Target; |
@@ -618,16 +588,15 @@ impl S { | |||
618 | } | 588 | } |
619 | 589 | ||
620 | fn test(s: Arc<S>) { | 590 | fn 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] |
629 | fn deref_trait_with_inference_var() { | 598 | fn 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 | ||
648 | fn test() { | 617 | fn 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] |
659 | fn deref_trait_infinite_recursion() { | 628 | fn 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"] |
664 | trait Deref { | 632 | trait Deref { |
665 | type Target; | 633 | type Target; |
@@ -673,18 +641,16 @@ impl Deref for S { | |||
673 | } | 641 | } |
674 | 642 | ||
675 | fn test(s: S) { | 643 | fn 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] |
684 | fn deref_trait_with_question_mark_size() { | 651 | fn 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"] |
689 | trait Deref { | 655 | trait Deref { |
690 | type Target; | 656 | type Target; |
@@ -702,18 +668,16 @@ impl S { | |||
702 | } | 668 | } |
703 | 669 | ||
704 | fn test(s: Arc<S>) { | 670 | fn 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] |
713 | fn obligation_from_function_clause() { | 678 | fn obligation_from_function_clause() { |
714 | let t = type_at( | 679 | check_types( |
715 | r#" | 680 | r#" |
716 | //- /main.rs | ||
717 | struct S; | 681 | struct S; |
718 | 682 | ||
719 | trait Trait<T> {} | 683 | trait Trait<T> {} |
@@ -722,16 +686,15 @@ impl Trait<u32> for S {} | |||
722 | fn foo<T: Trait<U>, U>(t: T) -> U {} | 686 | fn foo<T: Trait<U>, U>(t: T) -> U {} |
723 | 687 | ||
724 | fn test(s: S) { | 688 | fn 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] |
733 | fn obligation_from_method_clause() { | 696 | fn obligation_from_method_clause() { |
734 | let t = type_at( | 697 | check_types( |
735 | r#" | 698 | r#" |
736 | //- /main.rs | 699 | //- /main.rs |
737 | struct S; | 700 | struct S; |
@@ -745,18 +708,16 @@ impl O { | |||
745 | } | 708 | } |
746 | 709 | ||
747 | fn test() { | 710 | fn 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] |
756 | fn obligation_from_self_method_clause() { | 718 | fn obligation_from_self_method_clause() { |
757 | let t = type_at( | 719 | check_types( |
758 | r#" | 720 | r#" |
759 | //- /main.rs | ||
760 | struct S; | 721 | struct S; |
761 | 722 | ||
762 | trait Trait<T> {} | 723 | trait Trait<T> {} |
@@ -767,18 +728,16 @@ impl S { | |||
767 | } | 728 | } |
768 | 729 | ||
769 | fn test() { | 730 | fn 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] |
778 | fn obligation_from_impl_clause() { | 738 | fn obligation_from_impl_clause() { |
779 | let t = type_at( | 739 | check_types( |
780 | r#" | 740 | r#" |
781 | //- /main.rs | ||
782 | struct S; | 741 | struct S; |
783 | 742 | ||
784 | trait Trait<T> {} | 743 | trait Trait<T> {} |
@@ -790,32 +749,30 @@ impl<U, T: Trait<U>> O<T> { | |||
790 | } | 749 | } |
791 | 750 | ||
792 | fn test(o: O<S>) { | 751 | fn 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] |
801 | fn generic_param_env_1() { | 759 | fn generic_param_env_1() { |
802 | let t = type_at( | 760 | check_types( |
803 | r#" | 761 | r#" |
804 | //- /main.rs | ||
805 | trait Clone {} | 762 | trait Clone {} |
806 | trait Trait { fn foo(self) -> u128; } | 763 | trait Trait { fn foo(self) -> u128; } |
807 | struct S; | 764 | struct S; |
808 | impl Clone for S {} | 765 | impl Clone for S {} |
809 | impl<T> Trait for T where T: Clone {} | 766 | impl<T> Trait for T where T: Clone {} |
810 | fn test<T: Clone>(t: T) { t.foo()<|>; } | 767 | fn 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] |
817 | fn generic_param_env_1_not_met() { | 774 | fn generic_param_env_1_not_met() { |
818 | let t = type_at( | 775 | check_types( |
819 | r#" | 776 | r#" |
820 | //- /main.rs | 777 | //- /main.rs |
821 | trait Clone {} | 778 | trait Clone {} |
@@ -823,45 +780,42 @@ trait Trait { fn foo(self) -> u128; } | |||
823 | struct S; | 780 | struct S; |
824 | impl Clone for S {} | 781 | impl Clone for S {} |
825 | impl<T> Trait for T where T: Clone {} | 782 | impl<T> Trait for T where T: Clone {} |
826 | fn test<T>(t: T) { t.foo()<|>; } | 783 | fn 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] |
833 | fn generic_param_env_2() { | 790 | fn generic_param_env_2() { |
834 | let t = type_at( | 791 | check_types( |
835 | r#" | 792 | r#" |
836 | //- /main.rs | ||
837 | trait Trait { fn foo(self) -> u128; } | 793 | trait Trait { fn foo(self) -> u128; } |
838 | struct S; | 794 | struct S; |
839 | impl Trait for S {} | 795 | impl Trait for S {} |
840 | fn test<T: Trait>(t: T) { t.foo()<|>; } | 796 | fn 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] |
847 | fn generic_param_env_2_not_met() { | 803 | fn generic_param_env_2_not_met() { |
848 | let t = type_at( | 804 | check_types( |
849 | r#" | 805 | r#" |
850 | //- /main.rs | ||
851 | trait Trait { fn foo(self) -> u128; } | 806 | trait Trait { fn foo(self) -> u128; } |
852 | struct S; | 807 | struct S; |
853 | impl Trait for S {} | 808 | impl Trait for S {} |
854 | fn test<T>(t: T) { t.foo()<|>; } | 809 | fn 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] |
861 | fn generic_param_env_deref() { | 816 | fn 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"] |
866 | trait Deref { | 820 | trait Deref { |
867 | type Target; | 821 | type Target; |
@@ -870,17 +824,17 @@ trait Trait {} | |||
870 | impl<T> Deref for T where T: Trait { | 824 | impl<T> Deref for T where T: Trait { |
871 | type Target = i128; | 825 | type Target = i128; |
872 | } | 826 | } |
873 | fn test<T: Trait>(t: T) { (*t)<|>; } | 827 | fn 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] |
880 | fn associated_type_placeholder() { | 834 | fn 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 | ||
884 | pub trait ApplyL { | 838 | pub trait ApplyL { |
885 | type Out; | 839 | type Out; |
886 | } | 840 | } |
@@ -893,19 +847,16 @@ impl<T> ApplyL for RefMutL<T> { | |||
893 | 847 | ||
894 | fn test<T: ApplyL>() { | 848 | fn 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] |
905 | fn associated_type_placeholder_2() { | 857 | fn associated_type_placeholder_2() { |
906 | let t = type_at( | 858 | check_types( |
907 | r#" | 859 | r#" |
908 | //- /main.rs | ||
909 | pub trait ApplyL { | 860 | pub 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 | ||
914 | fn test<T: ApplyL>(t: T) { | 865 | fn 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] |
1400 | fn error_bound_chalk() { | 1350 | fn error_bound_chalk() { |
1401 | let t = type_at( | 1351 | check_types( |
1402 | r#" | 1352 | r#" |
1403 | //- /main.rs | ||
1404 | trait Trait { | 1353 | trait Trait { |
1405 | fn foo(&self) -> u32 {} | 1354 | fn foo(&self) -> u32 {} |
1406 | } | 1355 | } |
1407 | 1356 | ||
1408 | fn test(x: (impl Trait + UnknownTrait)) { | 1357 | fn 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] |
1482 | fn impl_trait_assoc_binding_projection_bug() { | 1430 | fn 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 |
1486 | pub trait Language { | 1434 | pub trait Language { |
@@ -1499,8 +1447,8 @@ trait Clone { | |||
1499 | 1447 | ||
1500 | fn api_walkthrough() { | 1448 | fn 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] |
1551 | fn where_clause_trait_in_scope_for_method_resolution() { | 1498 | fn where_clause_trait_in_scope_for_method_resolution() { |
1552 | let t = type_at( | 1499 | check_types( |
1553 | r#" | 1500 | r#" |
1554 | //- /main.rs | ||
1555 | mod foo { | 1501 | mod 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 | ||
1561 | fn test<T: foo::Trait>(x: T) { | 1507 | fn 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] |
2014 | fn unselected_projection_in_trait_env_1() { | 1959 | fn unselected_projection_in_trait_env_1() { |
2015 | let t = type_at( | 1960 | check_types( |
2016 | r#" | 1961 | r#" |
2017 | //- /main.rs | 1962 | //- /main.rs |
2018 | trait Trait { | 1963 | trait Trait { |
@@ -2025,18 +1970,16 @@ trait Trait2 { | |||
2025 | 1970 | ||
2026 | fn test<T: Trait>() where T::Item: Trait2 { | 1971 | fn 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] |
2036 | fn unselected_projection_in_trait_env_2() { | 1980 | fn unselected_projection_in_trait_env_2() { |
2037 | let t = type_at( | 1981 | check_types( |
2038 | r#" | 1982 | r#" |
2039 | //- /main.rs | ||
2040 | trait Trait<T> { | 1983 | trait Trait<T> { |
2041 | type Item; | 1984 | type Item; |
2042 | } | 1985 | } |
@@ -2047,11 +1990,10 @@ trait Trait2 { | |||
2047 | 1990 | ||
2048 | fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | 1991 | fn 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] |
2099 | fn unselected_projection_on_trait_self() { | 2041 | fn unselected_projection_on_trait_self() { |
2100 | let t = type_at( | 2042 | check_types( |
2101 | r#" | 2043 | r#" |
2102 | //- /main.rs | ||
2103 | trait Trait { | 2044 | trait Trait { |
2104 | type Item; | 2045 | type Item; |
2105 | 2046 | ||
@@ -2112,18 +2053,16 @@ impl Trait for S { | |||
2112 | } | 2053 | } |
2113 | 2054 | ||
2114 | fn test() { | 2055 | fn 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] |
2123 | fn unselected_projection_chalk_fold() { | 2063 | fn unselected_projection_chalk_fold() { |
2124 | let t = type_at( | 2064 | check_types( |
2125 | r#" | 2065 | r#" |
2126 | //- /main.rs | ||
2127 | trait Interner {} | 2066 | trait Interner {} |
2128 | trait Fold<I: Interner, TI = I> { | 2067 | trait Fold<I: Interner, TI = I> { |
2129 | type Result; | 2068 | type Result; |
@@ -2142,18 +2081,16 @@ where | |||
2142 | } | 2081 | } |
2143 | 2082 | ||
2144 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { | 2083 | fn 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] |
2153 | fn trait_impl_self_ty() { | 2091 | fn trait_impl_self_ty() { |
2154 | let t = type_at( | 2092 | check_types( |
2155 | r#" | 2093 | r#" |
2156 | //- /main.rs | ||
2157 | trait Trait<T> { | 2094 | trait Trait<T> { |
2158 | fn foo(&self); | 2095 | fn foo(&self); |
2159 | } | 2096 | } |
@@ -2163,18 +2100,16 @@ struct S; | |||
2163 | impl Trait<Self> for S {} | 2100 | impl Trait<Self> for S {} |
2164 | 2101 | ||
2165 | fn test() { | 2102 | fn 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] |
2174 | fn trait_impl_self_ty_cycle() { | 2110 | fn trait_impl_self_ty_cycle() { |
2175 | let t = type_at( | 2111 | check_types( |
2176 | r#" | 2112 | r#" |
2177 | //- /main.rs | ||
2178 | trait Trait { | 2113 | trait Trait { |
2179 | fn foo(&self); | 2114 | fn foo(&self); |
2180 | } | 2115 | } |
@@ -2184,18 +2119,17 @@ struct S<T>; | |||
2184 | impl Trait for S<Self> {} | 2119 | impl Trait for S<Self> {} |
2185 | 2120 | ||
2186 | fn test() { | 2121 | fn 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] |
2195 | fn unselected_projection_in_trait_env_cycle_1() { | 2129 | fn 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 | ||
2199 | trait Trait { | 2133 | trait Trait { |
2200 | type Item; | 2134 | type Item; |
2201 | } | 2135 | } |
@@ -2203,17 +2137,16 @@ trait Trait { | |||
2203 | trait Trait2<T> {} | 2137 | trait Trait2<T> {} |
2204 | 2138 | ||
2205 | fn test<T: Trait>() where T: Trait2<T::Item> { | 2139 | fn 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] |
2215 | fn unselected_projection_in_trait_env_cycle_2() { | 2147 | fn 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 |
2219 | trait Trait<T> { | 2152 | trait Trait<T> { |
@@ -2221,19 +2154,16 @@ trait Trait<T> { | |||
2221 | } | 2154 | } |
2222 | 2155 | ||
2223 | fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | 2156 | fn 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] |
2233 | fn inline_assoc_type_bounds_1() { | 2164 | fn inline_assoc_type_bounds_1() { |
2234 | let t = type_at( | 2165 | check_types( |
2235 | r#" | 2166 | r#" |
2236 | //- /main.rs | ||
2237 | trait Iterator { | 2167 | trait Iterator { |
2238 | type Item; | 2168 | type Item; |
2239 | } | 2169 | } |
@@ -2249,29 +2179,26 @@ impl<T: Iterator> Iterator for S<T> { | |||
2249 | 2179 | ||
2250 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { | 2180 | fn 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] |
2260 | fn inline_assoc_type_bounds_2() { | 2189 | fn inline_assoc_type_bounds_2() { |
2261 | let t = type_at( | 2190 | check_types( |
2262 | r#" | 2191 | r#" |
2263 | //- /main.rs | ||
2264 | trait Iterator { | 2192 | trait Iterator { |
2265 | type Item; | 2193 | type Item; |
2266 | } | 2194 | } |
2267 | 2195 | ||
2268 | fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | 2196 | fn 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] |
2447 | fn associated_type_bound() { | 2374 | fn associated_type_bound() { |
2448 | let t = type_at( | 2375 | check_types( |
2449 | r#" | 2376 | r#" |
2450 | //- /main.rs | ||
2451 | pub trait Trait { | 2377 | pub 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 | ||
2464 | fn test<T: Trait>() { | 2390 | fn 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] |
2474 | fn dyn_trait_through_chalk() { | 2399 | fn dyn_trait_through_chalk() { |
2475 | let t = type_at( | 2400 | check_types( |
2476 | r#" | 2401 | r#" |
2477 | //- /main.rs | ||
2478 | struct Box<T> {} | 2402 | struct Box<T> {} |
2479 | #[lang = "deref"] | 2403 | #[lang = "deref"] |
2480 | trait Deref { | 2404 | trait Deref { |
@@ -2488,18 +2412,16 @@ trait Trait { | |||
2488 | } | 2412 | } |
2489 | 2413 | ||
2490 | fn test(x: Box<dyn Trait>) { | 2414 | fn 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] |
2499 | fn string_to_owned() { | 2422 | fn string_to_owned() { |
2500 | let t = type_at( | 2423 | check_types( |
2501 | r#" | 2424 | r#" |
2502 | //- /main.rs | ||
2503 | struct String {} | 2425 | struct String {} |
2504 | pub trait ToOwned { | 2426 | pub 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 | } |
2511 | fn test() { | 2433 | fn 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] |
2639 | fn nested_assoc() { | 2560 | fn nested_assoc() { |
2640 | let t = type_at( | 2561 | check_types( |
2641 | r#" | 2562 | r#" |
2642 | //- /main.rs | ||
2643 | struct Bar; | 2563 | struct Bar; |
2644 | struct Foo; | 2564 | struct Foo; |
2645 | 2565 | ||
@@ -2662,11 +2582,10 @@ impl<T:A> B for T { | |||
2662 | } | 2582 | } |
2663 | 2583 | ||
2664 | fn main() { | 2584 | fn 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] |
2848 | fn integer_range_iterate() { | 2767 | fn 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 |
2852 | fn test() { | 2771 | fn 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 |
2857 | pub mod ops { | 2776 | pub 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 | |||
4 | use std::sync::Arc; | ||
5 | |||
6 | use hir_def::{ | ||
7 | body::Body, | ||
8 | expr::{Expr, ExprId, UnaryOp}, | ||
9 | DefWithBodyId, FunctionId, | ||
10 | }; | ||
11 | use hir_expand::diagnostics::DiagnosticSink; | ||
12 | |||
13 | use crate::{ | ||
14 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, | ||
15 | InferenceResult, Ty, TypeCtor, | ||
16 | }; | ||
17 | |||
18 | pub struct UnsafeValidator<'a, 'b: 'a> { | ||
19 | func: FunctionId, | ||
20 | infer: Arc<InferenceResult>, | ||
21 | sink: &'a mut DiagnosticSink<'b>, | ||
22 | } | ||
23 | |||
24 | impl<'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 | |||
58 | pub struct UnsafeExpr { | ||
59 | pub expr: ExprId, | ||
60 | pub inside_unsafe_block: bool, | ||
61 | } | ||
62 | |||
63 | pub 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 | |||
75 | fn 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 | ||
276 | fn is_argument_similar_to_param_name( | 277 | fn is_argument_similar_to_param_name( |
@@ -312,10 +313,8 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
312 | } | 313 | } |
313 | 314 | ||
314 | fn is_obvious_param(param_name: &str) -> bool { | 315 | fn 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 | ||
167 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | 167 | fn 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 | ||
348 | fn is_type(kind: SyntaxKind) -> bool { | 348 | fn 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 | ||
139 | fn is_boolean_literal(lit: &tt::Literal) -> bool { | 139 | fn 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 | ||
146 | fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> { | 143 | fn 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 | ||
171 | fn is_where_clause_end(p: &mut Parser) -> bool { | 171 | fn 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 | ||
178 | fn where_predicate(p: &mut Parser) { | 175 | fn 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 | ||
21 | impl SyntaxKind { | 21 | impl 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. |
167 | fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { | 167 | fn 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. |
13 | pub(crate) fn matches_to_edit(matches: &SsrMatches) -> TextEdit { | 13 | pub(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 | ||
17 | fn matches_to_edit_at_offset(matches: &SsrMatches, relative_start: TextSize) -> TextEdit { | 17 | fn 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 | ||
25 | fn render_replace(match_info: &Match) -> String { | 30 | fn 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] | ||
611 | fn 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] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "661.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "666.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_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 | ||
44 | pub 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 |
45 | pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> { | 49 | pub 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 | ||
460 | impl ast::TokenTree { | 460 | impl 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 | ||
4 | use rustc_lexer::{LiteralKind as LK, RawStrError}; | ||
5 | |||
4 | use std::convert::TryInto; | 6 | use std::convert::TryInto; |
5 | 7 | ||
6 | use crate::{ | 8 | use 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 | ||
122 | fn is_contextual_kw(text: &str) -> bool { | 122 | fn 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 | ||
129 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { | 126 | fn 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> {} | |||
105 | impl<'a> Cursor<'a> { | 105 | impl<'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" | |||
21 | jod-thread = "0.1.0" | 21 | jod-thread = "0.1.0" |
22 | log = "0.4.8" | 22 | log = "0.4.8" |
23 | lsp-types = { version = "0.74.0", features = ["proposed"] } | 23 | lsp-types = { version = "0.74.0", features = ["proposed"] } |
24 | parking_lot = "0.10.0" | 24 | parking_lot = "0.11.0" |
25 | pico-args = "0.3.1" | 25 | pico-args = "0.3.1" |
26 | rand = { version = "0.7.3", features = ["small_rng"] } | 26 | rand = { version = "0.7.3", features = ["small_rng"] } |
27 | rustc-hash = "1.1.0" | 27 | rustc-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 |
47 | ra_db = { path = "../ra_db" } | 47 | ra_db = { path = "../ra_db" } |
48 | ra_ide_db = { path = "../ra_ide_db" } | ||
49 | ra_ssr = { path = "../ra_ssr" } | ||
48 | hir = { path = "../ra_hir", package = "ra_hir" } | 50 | hir = { path = "../ra_hir", package = "ra_hir" } |
49 | hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } | 51 | hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } |
50 | hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } | 52 | hir_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 | ||
6 | use anyhow::{bail, Result}; | 6 | use anyhow::{bail, Result}; |
7 | use pico_args::Arguments; | 7 | use pico_args::Arguments; |
8 | use ra_ssr::SsrRule; | ||
8 | use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; | 9 | use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; |
9 | 10 | ||
10 | use std::{fmt::Write, path::PathBuf}; | 11 | use 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 | "\ | ||
281 | rust-analyzer ssr | ||
282 | |||
283 | USAGE: | ||
284 | rust-analyzer ssr [FLAGS] [RULE...] | ||
285 | |||
286 | EXAMPLE: | ||
287 | rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)' | ||
288 | |||
289 | FLAGS: | ||
290 | -h, --help Prints help information | ||
291 | |||
292 | ARGS: | ||
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; | |||
5 | mod analysis_bench; | 5 | mod analysis_bench; |
6 | mod diagnostics; | 6 | mod diagnostics; |
7 | mod progress_report; | 7 | mod progress_report; |
8 | mod ssr; | ||
8 | 9 | ||
9 | use std::io::Read; | 10 | use std::io::Read; |
10 | 11 | ||
@@ -17,6 +18,7 @@ pub use analysis_bench::{analysis_bench, BenchWhat, Position}; | |||
17 | pub use analysis_stats::analysis_stats; | 18 | pub use analysis_stats::analysis_stats; |
18 | pub use diagnostics::diagnostics; | 19 | pub use diagnostics::diagnostics; |
19 | pub use load_cargo::load_cargo; | 20 | pub use load_cargo::load_cargo; |
21 | pub use ssr::apply_ssr_rules; | ||
20 | 22 | ||
21 | #[derive(Clone, Copy)] | 23 | #[derive(Clone, Copy)] |
22 | pub enum Verbosity { | 24 | pub enum Verbosity { |
@@ -28,16 +30,10 @@ pub enum Verbosity { | |||
28 | 30 | ||
29 | impl Verbosity { | 31 | impl 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 | ||
4 | use std::{collections::HashSet, path::Path, time::Instant}; | 4 | use std::{path::Path, time::Instant}; |
5 | |||
6 | use itertools::Itertools; | ||
7 | use rand::{seq::SliceRandom, thread_rng}; | ||
8 | use rustc_hash::FxHashSet; | ||
5 | 9 | ||
6 | use hir::{ | 10 | use hir::{ |
7 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
@@ -9,10 +13,8 @@ use hir::{ | |||
9 | }; | 13 | }; |
10 | use hir_def::FunctionId; | 14 | use hir_def::FunctionId; |
11 | use hir_ty::{Ty, TypeWalk}; | 15 | use hir_ty::{Ty, TypeWalk}; |
12 | use itertools::Itertools; | ||
13 | use ra_db::SourceDatabaseExt; | 16 | use ra_db::SourceDatabaseExt; |
14 | use ra_syntax::AstNode; | 17 | use ra_syntax::AstNode; |
15 | use rand::{seq::SliceRandom, thread_rng}; | ||
16 | use stdx::format_to; | 18 | use stdx::format_to; |
17 | 19 | ||
18 | use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; | 20 | use 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 | ||
4 | use std::path::Path; | ||
5 | |||
4 | use anyhow::anyhow; | 6 | use anyhow::anyhow; |
7 | use rustc_hash::FxHashSet; | ||
8 | |||
5 | use hir::Crate; | 9 | use hir::Crate; |
6 | use ra_db::SourceDatabaseExt; | 10 | use ra_db::SourceDatabaseExt; |
7 | use ra_ide::Severity; | 11 | use ra_ide::Severity; |
8 | use std::{collections::HashSet, path::Path}; | ||
9 | 12 | ||
10 | use crate::cli::{load_cargo::load_cargo, Result}; | 13 | use 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 | |||
3 | use crate::cli::{load_cargo::load_cargo, Result}; | ||
4 | use ra_ide::SourceFileEdit; | ||
5 | use ra_ssr::{MatchFinder, SsrRule}; | ||
6 | |||
7 | pub 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. |
2 | pub(crate) mod to_proto; | 2 | pub(crate) mod to_proto; |
3 | 3 | ||
4 | use std::{collections::HashMap, mem, sync::Arc}; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use ra_ide::FileId; | 6 | use ra_ide::FileId; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::{FxHashMap, FxHashSet}; |
8 | 8 | ||
9 | use crate::lsp_ext; | 9 | use crate::lsp_ext; |
10 | 10 | ||
11 | pub(crate) type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; | 11 | pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>; |
12 | 12 | ||
13 | #[derive(Debug, Default, Clone)] | 13 | #[derive(Debug, Default, Clone)] |
14 | pub struct DiagnosticsConfig { | 14 | pub struct DiagnosticsConfig { |
@@ -18,8 +18,8 @@ pub struct DiagnosticsConfig { | |||
18 | 18 | ||
19 | #[derive(Debug, Default, Clone)] | 19 | #[derive(Debug, Default, Clone)] |
20 | pub(crate) struct DiagnosticCollection { | 20 | pub(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 | ||
18 | use serde_json::Value; | 18 | use serde_json::Value; |
19 | use stdx::lines_with_ends; | ||
19 | use text_size::{TextRange, TextSize}; | 20 | use text_size::{TextRange, TextSize}; |
20 | 21 | ||
21 | pub use difference::Changeset as __Changeset; | 22 | pub 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 | ||
164 | pub 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] | ||
181 | fn test_extract_annotations() { | ||
182 | let text = stdx::trim_indent( | ||
183 | r#" | ||
184 | fn 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 | ||
11 | use std::convert::{TryFrom, TryInto}; | 11 | use std::convert::{TryFrom, TryInto}; |
12 | 12 | ||
13 | use crossbeam_channel::{select, unbounded, Receiver}; | 13 | use crossbeam_channel::{select, unbounded, Receiver, Sender}; |
14 | use notify::{RecommendedWatcher, RecursiveMode, Watcher}; | 14 | use notify::{RecommendedWatcher, RecursiveMode, Watcher}; |
15 | use paths::{AbsPath, AbsPathBuf}; | 15 | use paths::{AbsPath, AbsPathBuf}; |
16 | use rustc_hash::FxHashSet; | 16 | use rustc_hash::FxHashSet; |
@@ -22,8 +22,8 @@ use crate::include::Include; | |||
22 | #[derive(Debug)] | 22 | #[derive(Debug)] |
23 | pub struct NotifyHandle { | 23 | pub 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() |