aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/flycheck/Cargo.toml (renamed from crates/ra_flycheck/Cargo.toml)2
-rw-r--r--crates/flycheck/src/lib.rs (renamed from crates/ra_flycheck/src/lib.rs)247
-rw-r--r--crates/paths/src/lib.rs26
-rw-r--r--crates/ra_arena/src/lib.rs3
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs57
-rw-r--r--crates/ra_db/src/fixture.rs40
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs10
-rw-r--r--crates/ra_hir/src/db.rs2
-rw-r--r--crates/ra_hir_def/Cargo.toml1
-rw-r--r--crates/ra_hir_def/src/adt.rs94
-rw-r--r--crates/ra_hir_def/src/attr.rs49
-rw-r--r--crates/ra_hir_def/src/body/lower.rs151
-rw-r--r--crates/ra_hir_def/src/body/scope.rs33
-rw-r--r--crates/ra_hir_def/src/data.rs382
-rw-r--r--crates/ra_hir_def/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/generics.rs62
-rw-r--r--crates/ra_hir_def/src/item_scope.rs31
-rw-r--r--crates/ra_hir_def/src/item_tree.rs753
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs698
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs435
-rw-r--r--crates/ra_hir_def/src/lib.rs99
-rw-r--r--crates/ra_hir_def/src/nameres.rs1
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs386
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs482
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs47
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs38
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs28
-rw-r--r--crates/ra_hir_def/src/src.rs31
-rw-r--r--crates/ra_hir_def/src/visibility.rs21
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs13
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs42
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs130
-rw-r--r--crates/ra_hir_ty/src/tests.rs16
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs82
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs2
-rw-r--r--crates/ra_ide/src/call_info.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs312
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs116
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs12
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs28
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs220
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs68
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs314
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs16
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs44
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs262
-rw-r--r--crates/ra_ide/src/completion/presentation.rs217
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs6
-rw-r--r--crates/ra_ide/src/diagnostics.rs46
-rw-r--r--crates/ra_ide/src/extend_selection.rs12
-rw-r--r--crates/ra_ide/src/hover.rs50
-rw-r--r--crates/ra_ide/src/inlay_hints.rs178
-rw-r--r--crates/ra_ide/src/matching_brace.rs33
-rw-r--r--crates/ra_ide/src/mock_analysis.rs178
-rw-r--r--crates/ra_ide/src/parent_module.rs12
-rw-r--r--crates/ra_ide/src/references.rs490
-rw-r--r--crates/ra_ide/src/references/rename.rs14
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs24
-rw-r--r--crates/ra_ide/src/syntax_tree.rs12
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs15
-rw-r--r--crates/ra_ide_db/src/change.rs2
-rw-r--r--crates/ra_project_model/Cargo.toml2
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs44
-rw-r--r--crates/ra_project_model/src/json_project.rs95
-rw-r--r--crates/ra_project_model/src/lib.rs122
-rw-r--r--crates/ra_project_model/src/project_json.rs117
-rw-r--r--crates/ra_project_model/src/sysroot.rs23
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/bin/main.rs37
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs7
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs23
-rw-r--r--crates/rust-analyzer/src/config.rs50
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs66
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs25
-rw-r--r--crates/rust-analyzer/src/dispatch.rs170
-rw-r--r--crates/rust-analyzer/src/from_proto.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs366
-rw-r--r--crates/rust-analyzer/src/handlers.rs (renamed from crates/rust-analyzer/src/main_loop/handlers.rs)237
-rw-r--r--crates/rust-analyzer/src/lib.rs43
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs195
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1271
-rw-r--r--crates/rust-analyzer/src/reload.rs243
-rw-r--r--crates/rust-analyzer/src/request_metrics.rs (renamed from crates/rust-analyzer/src/main_loop/request_metrics.rs)0
-rw-r--r--crates/rust-analyzer/src/thread_pool.rs35
-rw-r--r--crates/rust-analyzer/src/to_proto.rs10
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs22
-rw-r--r--crates/test_utils/src/fixture.rs8
-rw-r--r--crates/vfs-notify/src/lib.rs56
-rw-r--r--crates/vfs/src/file_set.rs2
-rw-r--r--crates/vfs/src/loader.rs12
-rw-r--r--crates/vfs/src/vfs_path.rs35
93 files changed, 6163 insertions, 4351 deletions
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 1aa39bade..dc26b8ce7 100644
--- a/crates/ra_flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2edition = "2018" 2edition = "2018"
3name = "ra_flycheck" 3name = "flycheck"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 6c4170529..92ec4f92e 100644
--- a/crates/ra_flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -3,14 +3,14 @@
3//! LSP diagnostics based on the output of the command. 3//! LSP diagnostics based on the output of the command.
4 4
5use std::{ 5use std::{
6 fmt,
6 io::{self, BufReader}, 7 io::{self, BufReader},
7 path::PathBuf, 8 path::PathBuf,
8 process::{Command, Stdio}, 9 process::{Command, Stdio},
9 time::Instant, 10 time::Duration,
10}; 11};
11 12
12use cargo_metadata::Message; 13use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
13use crossbeam_channel::{never, select, unbounded, Receiver, RecvError, Sender};
14 14
15pub use cargo_metadata::diagnostic::{ 15pub use cargo_metadata::diagnostic::{
16 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, 16 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
@@ -31,171 +31,142 @@ pub enum FlycheckConfig {
31 }, 31 },
32} 32}
33 33
34impl fmt::Display for FlycheckConfig {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
38 FlycheckConfig::CustomCommand { command, args } => {
39 write!(f, "{} {}", command, args.join(" "))
40 }
41 }
42 }
43}
44
34/// Flycheck wraps the shared state and communication machinery used for 45/// Flycheck wraps the shared state and communication machinery used for
35/// running `cargo check` (or other compatible command) and providing 46/// running `cargo check` (or other compatible command) and providing
36/// diagnostics based on the output. 47/// diagnostics based on the output.
37/// The spawned thread is shut down when this struct is dropped. 48/// The spawned thread is shut down when this struct is dropped.
38#[derive(Debug)] 49#[derive(Debug)]
39pub struct Flycheck { 50pub struct FlycheckHandle {
40 // XXX: drop order is significant 51 // XXX: drop order is significant
41 cmd_send: Sender<CheckCommand>, 52 cmd_send: Sender<Restart>,
42 handle: jod_thread::JoinHandle<()>, 53 handle: jod_thread::JoinHandle,
43 pub task_recv: Receiver<CheckTask>,
44} 54}
45 55
46impl Flycheck { 56impl FlycheckHandle {
47 pub fn new(config: FlycheckConfig, workspace_root: PathBuf) -> Flycheck { 57 pub fn spawn(
48 let (task_send, task_recv) = unbounded::<CheckTask>(); 58 sender: Box<dyn Fn(Message) + Send>,
49 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 59 config: FlycheckConfig,
60 workspace_root: PathBuf,
61 ) -> FlycheckHandle {
62 let (cmd_send, cmd_recv) = unbounded::<Restart>();
50 let handle = jod_thread::spawn(move || { 63 let handle = jod_thread::spawn(move || {
51 FlycheckThread::new(config, workspace_root).run(&task_send, &cmd_recv); 64 FlycheckActor::new(sender, config, workspace_root).run(cmd_recv);
52 }); 65 });
53 Flycheck { task_recv, cmd_send, handle } 66 FlycheckHandle { cmd_send, handle }
54 } 67 }
55 68
56 /// Schedule a re-start of the cargo check worker. 69 /// Schedule a re-start of the cargo check worker.
57 pub fn update(&self) { 70 pub fn update(&self) {
58 self.cmd_send.send(CheckCommand::Update).unwrap(); 71 self.cmd_send.send(Restart).unwrap();
59 } 72 }
60} 73}
61 74
62#[derive(Debug)] 75#[derive(Debug)]
63pub enum CheckTask { 76pub enum Message {
64 /// Request a clearing of all cached diagnostics from the check watcher
65 ClearDiagnostics,
66
67 /// Request adding a diagnostic with fixes included to a file 77 /// Request adding a diagnostic with fixes included to a file
68 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic }, 78 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
69 79
70 /// Request check progress notification to client 80 /// Request check progress notification to client
71 Status(Status), 81 Progress(Progress),
72} 82}
73 83
74#[derive(Debug)] 84#[derive(Debug)]
75pub enum Status { 85pub enum Progress {
76 Being, 86 DidStart,
77 Progress(String), 87 DidCheckCrate(String),
78 End, 88 DidFinish,
89 DidCancel,
79} 90}
80 91
81pub enum CheckCommand { 92struct Restart;
82 /// Request re-start of check thread
83 Update,
84}
85 93
86struct FlycheckThread { 94struct FlycheckActor {
95 sender: Box<dyn Fn(Message) + Send>,
87 config: FlycheckConfig, 96 config: FlycheckConfig,
88 workspace_root: PathBuf, 97 workspace_root: PathBuf,
89 last_update_req: Option<Instant>,
90 // XXX: drop order is significant
91 message_recv: Receiver<CheckEvent>,
92 /// WatchThread exists to wrap around the communication needed to be able to 98 /// WatchThread exists to wrap around the communication needed to be able to
93 /// run `cargo check` without blocking. Currently the Rust standard library 99 /// run `cargo check` without blocking. Currently the Rust standard library
94 /// 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
95 /// 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
96 /// back over a channel. 102 /// back over a channel.
97 check_process: Option<jod_thread::JoinHandle<()>>, 103 // XXX: drop order is significant
104 check_process: Option<(Receiver<cargo_metadata::Message>, jod_thread::JoinHandle)>,
98} 105}
99 106
100impl FlycheckThread { 107enum Event {
101 fn new(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckThread { 108 Restart(Restart),
102 FlycheckThread { 109 CheckEvent(Option<cargo_metadata::Message>),
103 config, 110}
104 workspace_root,
105 last_update_req: None,
106 message_recv: never(),
107 check_process: None,
108 }
109 }
110
111 fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) {
112 // If we rerun the thread, we need to discard the previous check results first
113 self.clean_previous_results(task_send);
114
115 loop {
116 select! {
117 recv(&cmd_recv) -> cmd => match cmd {
118 Ok(cmd) => self.handle_command(cmd),
119 Err(RecvError) => {
120 // Command channel has closed, so shut down
121 break;
122 },
123 },
124 recv(self.message_recv) -> msg => match msg {
125 Ok(msg) => self.handle_message(msg, task_send),
126 Err(RecvError) => {
127 // Watcher finished, replace it with a never channel to
128 // avoid busy-waiting.
129 self.message_recv = never();
130 self.check_process = None;
131 },
132 }
133 };
134
135 if self.should_recheck() {
136 self.last_update_req = None;
137 task_send.send(CheckTask::ClearDiagnostics).unwrap();
138 self.restart_check_process();
139 }
140 }
141 }
142 111
143 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) { 112impl FlycheckActor {
144 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 113 fn new(
145 task_send.send(CheckTask::Status(Status::End)).unwrap(); 114 sender: Box<dyn Fn(Message) + Send>,
115 config: FlycheckConfig,
116 workspace_root: PathBuf,
117 ) -> FlycheckActor {
118 FlycheckActor { sender, config, workspace_root, check_process: None }
146 } 119 }
147 120 fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
148 fn should_recheck(&mut self) -> bool { 121 let check_chan = self.check_process.as_ref().map(|(chan, _thread)| chan);
149 if let Some(_last_update_req) = &self.last_update_req { 122 select! {
150 // We currently only request an update on save, as we need up to 123 recv(inbox) -> msg => msg.ok().map(Event::Restart),
151 // date source on disk for cargo check to do it's magic, so we 124 recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
152 // don't really need to debounce the requests at this point.
153 return true;
154 } 125 }
155 false
156 } 126 }
157 127 fn run(&mut self, inbox: Receiver<Restart>) {
158 fn handle_command(&mut self, cmd: CheckCommand) { 128 while let Some(event) = self.next_event(&inbox) {
159 match cmd { 129 match event {
160 CheckCommand::Update => self.last_update_req = Some(Instant::now()), 130 Event::Restart(Restart) => {
131 while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {}
132 self.cancel_check_process();
133 self.check_process = Some(self.start_check_process());
134 self.send(Message::Progress(Progress::DidStart));
135 }
136 Event::CheckEvent(None) => {
137 // Watcher finished, replace it with a never channel to
138 // avoid busy-waiting.
139 assert!(self.check_process.take().is_some());
140 self.send(Message::Progress(Progress::DidFinish));
141 }
142 Event::CheckEvent(Some(message)) => match message {
143 cargo_metadata::Message::CompilerArtifact(msg) => {
144 self.send(Message::Progress(Progress::DidCheckCrate(msg.target.name)));
145 }
146
147 cargo_metadata::Message::CompilerMessage(msg) => {
148 self.send(Message::AddDiagnostic {
149 workspace_root: self.workspace_root.clone(),
150 diagnostic: msg.message,
151 });
152 }
153
154 cargo_metadata::Message::BuildScriptExecuted(_)
155 | cargo_metadata::Message::BuildFinished(_)
156 | cargo_metadata::Message::TextLine(_)
157 | cargo_metadata::Message::Unknown => {}
158 },
159 }
161 } 160 }
161 // If we rerun the thread, we need to discard the previous check results first
162 self.cancel_check_process();
162 } 163 }
163 164 fn cancel_check_process(&mut self) {
164 fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) { 165 if self.check_process.take().is_some() {
165 match msg { 166 self.send(Message::Progress(Progress::DidCancel));
166 CheckEvent::Begin => {
167 task_send.send(CheckTask::Status(Status::Being)).unwrap();
168 }
169
170 CheckEvent::End => {
171 task_send.send(CheckTask::Status(Status::End)).unwrap();
172 }
173
174 CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
175 task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap();
176 }
177
178 CheckEvent::Msg(Message::CompilerMessage(msg)) => {
179 task_send
180 .send(CheckTask::AddDiagnostic {
181 workspace_root: self.workspace_root.clone(),
182 diagnostic: msg.message,
183 })
184 .unwrap();
185 }
186
187 CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
188 CheckEvent::Msg(Message::BuildFinished(_)) => {}
189 CheckEvent::Msg(Message::TextLine(_)) => {}
190 CheckEvent::Msg(Message::Unknown) => {}
191 } 167 }
192 } 168 }
193 169 fn start_check_process(&self) -> (Receiver<cargo_metadata::Message>, jod_thread::JoinHandle) {
194 fn restart_check_process(&mut self) {
195 // First, clear and cancel the old thread
196 self.message_recv = never();
197 self.check_process = None;
198
199 let mut cmd = match &self.config { 170 let mut cmd = match &self.config {
200 FlycheckConfig::CargoCommand { 171 FlycheckConfig::CargoCommand {
201 command, 172 command,
@@ -229,23 +200,22 @@ impl FlycheckThread {
229 cmd.current_dir(&self.workspace_root); 200 cmd.current_dir(&self.workspace_root);
230 201
231 let (message_send, message_recv) = unbounded(); 202 let (message_send, message_recv) = unbounded();
232 self.message_recv = message_recv; 203 let thread = jod_thread::spawn(move || {
233 self.check_process = Some(jod_thread::spawn(move || {
234 // If we trigger an error here, we will do so in the loop instead, 204 // If we trigger an error here, we will do so in the loop instead,
235 // which will break out of the loop, and continue the shutdown 205 // which will break out of the loop, and continue the shutdown
236 let _ = message_send.send(CheckEvent::Begin);
237
238 let res = run_cargo(cmd, &mut |message| { 206 let res = run_cargo(cmd, &mut |message| {
239 // Skip certain kinds of messages to only spend time on what's useful 207 // Skip certain kinds of messages to only spend time on what's useful
240 match &message { 208 match &message {
241 Message::CompilerArtifact(artifact) if artifact.fresh => return true, 209 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
242 Message::BuildScriptExecuted(_) => return true, 210 return true
243 Message::Unknown => return true, 211 }
212 cargo_metadata::Message::BuildScriptExecuted(_)
213 | cargo_metadata::Message::Unknown => return true,
244 _ => {} 214 _ => {}
245 } 215 }
246 216
247 // if the send channel was closed, we want to shutdown 217 // if the send channel was closed, we want to shutdown
248 message_send.send(CheckEvent::Msg(message)).is_ok() 218 message_send.send(message).is_ok()
249 }); 219 });
250 220
251 if let Err(err) = res { 221 if let Err(err) = res {
@@ -253,18 +223,13 @@ impl FlycheckThread {
253 // to display user-caused misconfiguration errors instead of just logging them here 223 // to display user-caused misconfiguration errors instead of just logging them here
254 log::error!("Cargo watcher failed {:?}", err); 224 log::error!("Cargo watcher failed {:?}", err);
255 } 225 }
256 226 });
257 // We can ignore any error here, as we are already in the progress 227 (message_recv, thread)
258 // of shutting down.
259 let _ = message_send.send(CheckEvent::End);
260 }))
261 } 228 }
262}
263 229
264enum CheckEvent { 230 fn send(&self, check_task: Message) {
265 Begin, 231 (self.sender)(check_task)
266 Msg(cargo_metadata::Message), 232 }
267 End,
268} 233}
269 234
270fn run_cargo( 235fn run_cargo(
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index 45b19c45a..1b259682d 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -28,6 +28,12 @@ impl AsRef<Path> for AbsPathBuf {
28 } 28 }
29} 29}
30 30
31impl AsRef<AbsPath> for AbsPathBuf {
32 fn as_ref(&self) -> &AbsPath {
33 self.as_path()
34 }
35}
36
31impl TryFrom<PathBuf> for AbsPathBuf { 37impl TryFrom<PathBuf> for AbsPathBuf {
32 type Error = PathBuf; 38 type Error = PathBuf;
33 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { 39 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
@@ -45,9 +51,19 @@ impl TryFrom<&str> for AbsPathBuf {
45 } 51 }
46} 52}
47 53
54impl PartialEq<AbsPath> for AbsPathBuf {
55 fn eq(&self, other: &AbsPath) -> bool {
56 self.as_path() == other
57 }
58}
59
48impl AbsPathBuf { 60impl AbsPathBuf {
61 pub fn assert(path: PathBuf) -> AbsPathBuf {
62 AbsPathBuf::try_from(path)
63 .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
64 }
49 pub fn as_path(&self) -> &AbsPath { 65 pub fn as_path(&self) -> &AbsPath {
50 AbsPath::new_unchecked(self.0.as_path()) 66 AbsPath::assert(self.0.as_path())
51 } 67 }
52 pub fn pop(&mut self) -> bool { 68 pub fn pop(&mut self) -> bool {
53 self.0.pop() 69 self.0.pop()
@@ -77,15 +93,19 @@ impl<'a> TryFrom<&'a Path> for &'a AbsPath {
77 if !path.is_absolute() { 93 if !path.is_absolute() {
78 return Err(path); 94 return Err(path);
79 } 95 }
80 Ok(AbsPath::new_unchecked(path)) 96 Ok(AbsPath::assert(path))
81 } 97 }
82} 98}
83 99
84impl AbsPath { 100impl AbsPath {
85 fn new_unchecked(path: &Path) -> &AbsPath { 101 pub fn assert(path: &Path) -> &AbsPath {
102 assert!(path.is_absolute());
86 unsafe { &*(path as *const Path as *const AbsPath) } 103 unsafe { &*(path as *const Path as *const AbsPath) }
87 } 104 }
88 105
106 pub fn parent(&self) -> Option<&AbsPath> {
107 self.0.parent().map(AbsPath::assert)
108 }
89 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { 109 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
90 self.as_ref().join(path).try_into().unwrap() 110 self.as_ref().join(path).try_into().unwrap()
91 } 111 }
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index 441fbb3cb..3169aa5b8 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -116,6 +116,9 @@ impl<T> Arena<T> {
116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { 116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator {
117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) 117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value))
118 } 118 }
119 pub fn shrink_to_fit(&mut self) {
120 self.data.shrink_to_fit();
121 }
119} 122}
120 123
121impl<T> Default for Arena<T> { 124impl<T> Default for Arena<T> {
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index 88b62278f..96affe49d 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -44,12 +44,26 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
44 } 44 }
45 let target = expr.syntax().text_range(); 45 let target = expr.syntax().text_range();
46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { 46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| {
47 let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) {
48 Some(field) => field.name_ref(),
49 None => None,
50 };
51
47 let mut buf = String::new(); 52 let mut buf = String::new();
48 53
54 let var_name = match &field_shorthand {
55 Some(it) => it.to_string(),
56 None => "var_name".to_string(),
57 };
58 let expr_range = match &field_shorthand {
59 Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()),
60 None => expr.syntax().text_range(),
61 };
62
49 if wrap_in_block { 63 if wrap_in_block {
50 buf.push_str("{ let var_name = "); 64 format_to!(buf, "{{ let {} = ", var_name);
51 } else { 65 } else {
52 buf.push_str("let var_name = "); 66 format_to!(buf, "let {} = ", var_name);
53 }; 67 };
54 format_to!(buf, "{}", expr.syntax()); 68 format_to!(buf, "{}", expr.syntax());
55 69
@@ -64,13 +78,13 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
64 if full_stmt.unwrap().semicolon_token().is_none() { 78 if full_stmt.unwrap().semicolon_token().is_none() {
65 buf.push_str(";"); 79 buf.push_str(";");
66 } 80 }
67 let offset = expr.syntax().text_range();
68 match ctx.config.snippet_cap { 81 match ctx.config.snippet_cap {
69 Some(cap) => { 82 Some(cap) => {
70 let snip = buf.replace("let var_name", "let $0var_name"); 83 let snip =
71 edit.replace_snippet(cap, offset, snip) 84 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
85 edit.replace_snippet(cap, expr_range, snip)
72 } 86 }
73 None => edit.replace(offset, buf), 87 None => edit.replace(expr_range, buf),
74 } 88 }
75 return; 89 return;
76 } 90 }
@@ -88,11 +102,12 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
88 buf.push_str(text); 102 buf.push_str(text);
89 } 103 }
90 104
91 edit.replace(expr.syntax().text_range(), "var_name".to_string()); 105 edit.replace(expr_range, var_name.clone());
92 let offset = anchor_stmt.text_range().start(); 106 let offset = anchor_stmt.text_range().start();
93 match ctx.config.snippet_cap { 107 match ctx.config.snippet_cap {
94 Some(cap) => { 108 Some(cap) => {
95 let snip = buf.replace("let var_name", "let $0var_name"); 109 let snip =
110 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
96 edit.insert_snippet(cap, offset, snip) 111 edit.insert_snippet(cap, offset, snip)
97 } 112 }
98 None => edit.insert(offset, buf), 113 None => edit.insert(offset, buf),
@@ -504,6 +519,32 @@ fn main() {
504 } 519 }
505 520
506 #[test] 521 #[test]
522 fn introduce_var_field_shorthand() {
523 check_assist(
524 introduce_variable,
525 r#"
526struct S {
527 foo: i32
528}
529
530fn main() {
531 S { foo: <|>1 + 1<|> }
532}
533"#,
534 r#"
535struct S {
536 foo: i32
537}
538
539fn main() {
540 let $0foo = 1 + 1;
541 S { foo }
542}
543"#,
544 )
545 }
546
547 #[test]
507 fn test_introduce_var_for_return_not_applicable() { 548 fn test_introduce_var_for_return_not_applicable() {
508 check_assist_not_applicable(introduce_variable, "fn foo() { <|>return<|>; } "); 549 check_assist_not_applicable(introduce_variable, "fn foo() { <|>return<|>; } ");
509 } 550 }
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index ddf46e6c4..4f4fb4494 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -132,10 +132,17 @@ fn with_files(
132 132
133 let mut file_position = None; 133 let mut file_position = None;
134 134
135 for entry in fixture.iter() { 135 for entry in fixture {
136 let meta = match ParsedMeta::from(entry) { 136 let text = if entry.text.contains(CURSOR_MARKER) {
137 ParsedMeta::File(it) => it, 137 let (range_or_offset, text) = extract_range_or_offset(&entry.text);
138 assert!(file_position.is_none());
139 file_position = Some((file_id, range_or_offset));
140 text.to_string()
141 } else {
142 entry.text.clone()
138 }; 143 };
144
145 let meta = FileMeta::from(entry);
139 assert!(meta.path.starts_with(&source_root_prefix)); 146 assert!(meta.path.starts_with(&source_root_prefix));
140 147
141 if let Some(krate) = meta.krate { 148 if let Some(krate) = meta.krate {
@@ -157,15 +164,6 @@ fn with_files(
157 default_crate_root = Some(file_id); 164 default_crate_root = Some(file_id);
158 } 165 }
159 166
160 let text = if entry.text.contains(CURSOR_MARKER) {
161 let (range_or_offset, text) = extract_range_or_offset(&entry.text);
162 assert!(file_position.is_none());
163 file_position = Some((file_id, range_or_offset));
164 text.to_string()
165 } else {
166 entry.text.to_string()
167 };
168
169 db.set_file_text(file_id, Arc::new(text)); 167 db.set_file_text(file_id, Arc::new(text));
170 db.set_file_source_root(file_id, source_root_id); 168 db.set_file_source_root(file_id, source_root_id);
171 let path = VfsPath::new_virtual_path(meta.path); 169 let path = VfsPath::new_virtual_path(meta.path);
@@ -198,10 +196,6 @@ fn with_files(
198 (file_position, files) 196 (file_position, files)
199} 197}
200 198
201enum ParsedMeta {
202 File(FileMeta),
203}
204
205struct FileMeta { 199struct FileMeta {
206 path: String, 200 path: String,
207 krate: Option<String>, 201 krate: Option<String>,
@@ -211,22 +205,22 @@ struct FileMeta {
211 env: Env, 205 env: Env,
212} 206}
213 207
214impl From<&Fixture> for ParsedMeta { 208impl From<Fixture> for FileMeta {
215 fn from(f: &Fixture) -> Self { 209 fn from(f: Fixture) -> FileMeta {
216 let mut cfg = CfgOptions::default(); 210 let mut cfg = CfgOptions::default();
217 f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); 211 f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into()));
218 f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); 212 f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into()));
219 213
220 Self::File(FileMeta { 214 FileMeta {
221 path: f.path.to_owned(), 215 path: f.path,
222 krate: f.crate_name.to_owned(), 216 krate: f.krate,
223 deps: f.deps.to_owned(), 217 deps: f.deps,
224 cfg, 218 cfg,
225 edition: f 219 edition: f
226 .edition 220 .edition
227 .as_ref() 221 .as_ref()
228 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), 222 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()),
229 env: Env::from(f.env.iter()), 223 env: Env::from(f.env.iter()),
230 }) 224 }
231 } 225 }
232} 226}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 875290259..4a3ba57da 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -114,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
114} 114}
115 115
116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { 116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
117 let _p = profile("parse_query"); 117 let _p = profile("parse_query").detail(|| format!("{:?}", file_id));
118 let text = db.file_text(file_id); 118 let text = db.file_text(file_id);
119 SourceFile::parse(&*text) 119 SourceFile::parse(&*text)
120} 120}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index ffd5278ec..a379b9f49 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -31,10 +31,7 @@ use hir_ty::{
31}; 31};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 33use ra_prof::profile;
34use ra_syntax::{ 34use ra_syntax::ast::{self, AttrsOwner, NameOwner};
35 ast::{self, AttrsOwner, NameOwner},
36 AstNode,
37};
38use rustc_hash::FxHashSet; 35use rustc_hash::FxHashSet;
39 36
40use crate::{ 37use crate::{
@@ -205,7 +202,8 @@ impl ModuleDef {
205} 202}
206 203
207pub use hir_def::{ 204pub use hir_def::{
208 attr::Attrs, item_scope::ItemInNs, visibility::Visibility, AssocItemId, AssocItemLoc, 205 attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility,
206 AssocItemId, AssocItemLoc,
209}; 207};
210 208
211impl Module { 209impl Module {
@@ -872,7 +870,7 @@ where
872 ID: Lookup<Data = AssocItemLoc<AST>>, 870 ID: Lookup<Data = AssocItemLoc<AST>>,
873 DEF: From<ID>, 871 DEF: From<ID>,
874 CTOR: FnOnce(DEF) -> AssocItem, 872 CTOR: FnOnce(DEF) -> AssocItem,
875 AST: AstNode, 873 AST: ItemTreeNode,
876{ 874{
877 match id.lookup(db.upcast()).container { 875 match id.lookup(db.upcast()).container {
878 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), 876 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index b25dac28e..bb67952de 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -6,7 +6,7 @@ pub use hir_def::db::{
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, 7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, 8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, 9 InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery,
10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, 10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index ef1f65ee0..6d43924e3 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -17,6 +17,7 @@ drop_bomb = "0.1.4"
17fst = { version = "0.4", default-features = false } 17fst = { version = "0.4", default-features = false }
18itertools = "0.9.0" 18itertools = "0.9.0"
19indexmap = "1.4.0" 19indexmap = "1.4.0"
20smallvec = "1.4.0"
20 21
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx" }
22 23
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 2bc34d449..4994a2125 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,12 +8,12 @@ use hir_expand::{
8 InFile, 8 InFile,
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_prof::profile;
12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
13 12
14use crate::{ 13use crate::{
15 body::{CfgExpander, LowerCtx}, 14 body::{CfgExpander, LowerCtx},
16 db::DefDatabase, 15 db::DefDatabase,
16 item_tree::{Field, Fields, ItemTree},
17 src::HasChildSource, 17 src::HasChildSource,
18 src::HasSource, 18 src::HasSource,
19 trace::Trace, 19 trace::Trace,
@@ -22,6 +22,7 @@ use crate::{
22 EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, 22 EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId,
23 VariantId, 23 VariantId,
24}; 24};
25use ra_cfg::CfgOptions;
25 26
26/// Note that we use `StructData` for unions as well! 27/// Note that we use `StructData` for unions as well!
27#[derive(Debug, Clone, PartialEq, Eq)] 28#[derive(Debug, Clone, PartialEq, Eq)]
@@ -59,39 +60,48 @@ pub struct FieldData {
59 60
60impl StructData { 61impl StructData {
61 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 62 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
62 let src = id.lookup(db).source(db); 63 let loc = id.lookup(db);
64 let item_tree = db.item_tree(loc.id.file_id);
65 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
63 66
64 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 67 let strukt = &item_tree[loc.id.value];
65 let variant_data = 68 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);
66 VariantData::new(db, src.map(|s| s.kind()), id.lookup(db).container.module(db)); 69
67 let variant_data = Arc::new(variant_data); 70 Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) })
68 Arc::new(StructData { name, variant_data })
69 } 71 }
70 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 72 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
71 let src = id.lookup(db).source(db); 73 let loc = id.lookup(db);
72 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 74 let item_tree = db.item_tree(loc.id.file_id);
73 let variant_data = VariantData::new( 75 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
74 db, 76
75 src.map(|s| { 77 let union = &item_tree[loc.id.value];
76 s.record_field_def_list() 78 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);
77 .map(ast::StructKind::Record) 79
78 .unwrap_or(ast::StructKind::Unit) 80 Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) })
79 }),
80 id.lookup(db).container.module(db),
81 );
82 let variant_data = Arc::new(variant_data);
83 Arc::new(StructData { name, variant_data })
84 } 81 }
85} 82}
86 83
87impl EnumData { 84impl EnumData {
88 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { 85 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
89 let _p = profile("enum_data_query"); 86 let loc = e.lookup(db);
90 let src = e.lookup(db).source(db); 87 let item_tree = db.item_tree(loc.id.file_id);
91 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 88 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
92 let mut trace = Trace::new_for_arena(); 89
93 lower_enum(db, &mut trace, &src, e.lookup(db).container.module(db)); 90 let enum_ = &item_tree[loc.id.value];
94 Arc::new(EnumData { name, variants: trace.into_arena() }) 91 let mut variants = Arena::new();
92 for var_id in enum_.variants.clone() {
93 if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) {
94 let var = &item_tree[var_id];
95 let var_data = lower_fields(&item_tree, &cfg_options, &var.fields);
96
97 variants.alloc(EnumVariantData {
98 name: var.name.clone(),
99 variant_data: Arc::new(var_data),
100 });
101 }
102 }
103
104 Arc::new(EnumData { name: enum_.name.clone(), variants })
95 } 105 }
96 106
97 pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 107 pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
@@ -251,3 +261,35 @@ fn lower_struct(
251 ast::StructKind::Unit => StructKind::Unit, 261 ast::StructKind::Unit => StructKind::Unit,
252 } 262 }
253} 263}
264
265fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData {
266 match fields {
267 Fields::Record(flds) => {
268 let mut arena = Arena::new();
269 for field_id in flds.clone() {
270 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
271 arena.alloc(lower_field(item_tree, &item_tree[field_id]));
272 }
273 }
274 VariantData::Record(arena)
275 }
276 Fields::Tuple(flds) => {
277 let mut arena = Arena::new();
278 for field_id in flds.clone() {
279 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
280 arena.alloc(lower_field(item_tree, &item_tree[field_id]));
281 }
282 }
283 VariantData::Tuple(arena)
284 }
285 Fields::Unit => VariantData::Unit,
286 }
287}
288
289fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData {
290 FieldData {
291 name: field.name.clone(),
292 type_ref: field.type_ref.clone(),
293 visibility: item_tree[field.visibility].clone(),
294 }
295}
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 2eeba0572..e228e2145 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -13,7 +13,11 @@ use ra_syntax::{
13use tt::Subtree; 13use tt::Subtree;
14 14
15use crate::{ 15use crate::{
16 db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, 16 db::DefDatabase,
17 item_tree::{ItemTreeId, ItemTreeNode},
18 nameres::ModuleSource,
19 path::ModPath,
20 src::HasChildSource,
17 AdtId, AttrDefId, Lookup, 21 AdtId, AttrDefId, Lookup,
18}; 22};
19 23
@@ -34,6 +38,8 @@ impl ops::Deref for Attrs {
34} 38}
35 39
36impl Attrs { 40impl Attrs {
41 pub const EMPTY: Attrs = Attrs { entries: None };
42
37 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 43 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
38 match def { 44 match def {
39 AttrDefId::ModuleId(module) => { 45 AttrDefId::ModuleId(module) => {
@@ -65,19 +71,19 @@ impl Attrs {
65 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 71 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
66 } 72 }
67 AttrDefId::AdtId(it) => match it { 73 AttrDefId::AdtId(it) => match it {
68 AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), 74 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
69 AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), 75 AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
70 AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), 76 AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
71 }, 77 },
72 AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), 78 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
73 AttrDefId::MacroDefId(it) => { 79 AttrDefId::MacroDefId(it) => {
74 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) 80 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
75 } 81 }
76 AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), 82 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
77 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 83 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
78 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), 84 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
79 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 85 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
80 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), 86 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
81 } 87 }
82 } 88 }
83 89
@@ -103,6 +109,18 @@ impl Attrs {
103 Attrs { entries } 109 Attrs { entries }
104 } 110 }
105 111
112 pub fn merge(&self, other: Attrs) -> Attrs {
113 match (&self.entries, &other.entries) {
114 (None, None) => Attrs { entries: None },
115 (Some(entries), None) | (None, Some(entries)) => {
116 Attrs { entries: Some(entries.clone()) }
117 }
118 (Some(a), Some(b)) => {
119 Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
120 }
121 }
122 }
123
106 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 124 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
107 AttrQuery { attrs: self, key } 125 AttrQuery { attrs: self, key }
108 } 126 }
@@ -187,11 +205,8 @@ where
187 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 205 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
188} 206}
189 207
190fn attrs_from_loc<T>(node: T, db: &dyn DefDatabase) -> Attrs 208fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
191where 209 let tree = db.item_tree(id.file_id);
192 T: HasSource, 210 let mod_item = N::id_to_mod_item(id.value);
193 T::Value: ast::AttrsOwner, 211 tree.attrs(mod_item.into()).clone()
194{
195 let src = node.source(db);
196 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
197} 212}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index f159f80af..a7e2e0982 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -27,6 +27,7 @@ use crate::{
27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, 27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
28 }, 28 },
29 item_scope::BuiltinShadowMode, 29 item_scope::BuiltinShadowMode,
30 item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
30 path::{GenericArgs, Path}, 31 path::{GenericArgs, Path},
31 type_ref::{Mutability, Rawness, TypeRef}, 32 type_ref::{Mutability, Rawness, TypeRef},
32 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 33 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
@@ -35,6 +36,8 @@ use crate::{
35 36
36use super::{ExprSource, PatSource}; 37use super::{ExprSource, PatSource};
37use ast::AstChildren; 38use ast::AstChildren;
39use rustc_hash::FxHashMap;
40use std::{any::type_name, sync::Arc};
38 41
39pub(crate) struct LowerCtx { 42pub(crate) struct LowerCtx {
40 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -60,10 +63,10 @@ pub(super) fn lower(
60 params: Option<ast::ParamList>, 63 params: Option<ast::ParamList>,
61 body: Option<ast::Expr>, 64 body: Option<ast::Expr>,
62) -> (Body, BodySourceMap) { 65) -> (Body, BodySourceMap) {
66 let item_tree = db.item_tree(expander.current_file_id);
63 ExprCollector { 67 ExprCollector {
64 db, 68 db,
65 def, 69 def,
66 expander,
67 source_map: BodySourceMap::default(), 70 source_map: BodySourceMap::default(),
68 body: Body { 71 body: Body {
69 exprs: Arena::default(), 72 exprs: Arena::default(),
@@ -72,6 +75,12 @@ pub(super) fn lower(
72 body_expr: dummy_expr_id(), 75 body_expr: dummy_expr_id(),
73 item_scope: Default::default(), 76 item_scope: Default::default(),
74 }, 77 },
78 item_trees: {
79 let mut map = FxHashMap::default();
80 map.insert(expander.current_file_id, item_tree);
81 map
82 },
83 expander,
75 } 84 }
76 .collect(params, body) 85 .collect(params, body)
77} 86}
@@ -82,6 +91,8 @@ struct ExprCollector<'a> {
82 expander: Expander, 91 expander: Expander,
83 body: Body, 92 body: Body,
84 source_map: BodySourceMap, 93 source_map: BodySourceMap,
94
95 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
85} 96}
86 97
87impl ExprCollector<'_> { 98impl ExprCollector<'_> {
@@ -533,6 +544,9 @@ impl ExprCollector<'_> {
533 self.source_map 544 self.source_map
534 .expansions 545 .expansions
535 .insert(macro_call, self.expander.current_file_id); 546 .insert(macro_call, self.expander.current_file_id);
547
548 let item_tree = self.db.item_tree(self.expander.current_file_id);
549 self.item_trees.insert(self.expander.current_file_id, item_tree);
536 let id = self.collect_expr(expansion); 550 let id = self.collect_expr(expansion);
537 self.expander.exit(self.db, mark); 551 self.expander.exit(self.db, mark);
538 id 552 id
@@ -547,6 +561,32 @@ impl ExprCollector<'_> {
547 } 561 }
548 } 562 }
549 563
564 fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
565 let id = self.expander.ast_id(ast);
566 let tree = &self.item_trees[&id.file_id];
567
568 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
569
570 // Root file (non-macro).
571 let item_tree_id = tree
572 .all_inner_items()
573 .chain(tree.top_level_items().iter().copied())
574 .filter_map(|mod_item| mod_item.downcast::<N>())
575 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
576 .or_else(|| {
577 log::debug!(
578 "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
579 type_name::<N>(),
580 id,
581 ast.syntax(),
582 ast.syntax(),
583 );
584 None
585 })?;
586
587 Some(ItemTreeId::new(id.file_id, item_tree_id))
588 }
589
550 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 590 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
551 if let Some(expr) = expr { 591 if let Some(expr) = expr {
552 self.collect_expr(expr) 592 self.collect_expr(expr)
@@ -578,56 +618,65 @@ impl ExprCollector<'_> {
578 618
579 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 619 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
580 let container = ContainerId::DefWithBodyId(self.def); 620 let container = ContainerId::DefWithBodyId(self.def);
581 for item in block.items() { 621
582 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 622 let items = block
583 ast::ModuleItem::FnDef(def) => { 623 .items()
584 let ast_id = self.expander.ast_id(&def); 624 .filter_map(|item| {
585 ( 625 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
586 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), 626 ast::ModuleItem::FnDef(def) => {
587 def.name(), 627 let id = self.find_inner_item(&def)?;
588 ) 628 (
589 } 629 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
590 ast::ModuleItem::TypeAliasDef(def) => { 630 def.name(),
591 let ast_id = self.expander.ast_id(&def); 631 )
592 ( 632 }
593 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), 633 ast::ModuleItem::TypeAliasDef(def) => {
594 def.name(), 634 let id = self.find_inner_item(&def)?;
595 ) 635 (
596 } 636 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
597 ast::ModuleItem::ConstDef(def) => { 637 def.name(),
598 let ast_id = self.expander.ast_id(&def); 638 )
599 ( 639 }
600 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), 640 ast::ModuleItem::ConstDef(def) => {
601 def.name(), 641 let id = self.find_inner_item(&def)?;
602 ) 642 (
603 } 643 ConstLoc { container: container.into(), id }.intern(self.db).into(),
604 ast::ModuleItem::StaticDef(def) => { 644 def.name(),
605 let ast_id = self.expander.ast_id(&def); 645 )
606 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) 646 }
607 } 647 ast::ModuleItem::StaticDef(def) => {
608 ast::ModuleItem::StructDef(def) => { 648 let id = self.find_inner_item(&def)?;
609 let ast_id = self.expander.ast_id(&def); 649 (StaticLoc { container, id }.intern(self.db).into(), def.name())
610 (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) 650 }
611 } 651 ast::ModuleItem::StructDef(def) => {
612 ast::ModuleItem::EnumDef(def) => { 652 let id = self.find_inner_item(&def)?;
613 let ast_id = self.expander.ast_id(&def); 653 (StructLoc { container, id }.intern(self.db).into(), def.name())
614 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) 654 }
615 } 655 ast::ModuleItem::EnumDef(def) => {
616 ast::ModuleItem::UnionDef(def) => { 656 let id = self.find_inner_item(&def)?;
617 let ast_id = self.expander.ast_id(&def); 657 (EnumLoc { container, id }.intern(self.db).into(), def.name())
618 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) 658 }
619 } 659 ast::ModuleItem::UnionDef(def) => {
620 ast::ModuleItem::TraitDef(def) => { 660 let id = self.find_inner_item(&def)?;
621 let ast_id = self.expander.ast_id(&def); 661 (UnionLoc { container, id }.intern(self.db).into(), def.name())
622 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) 662 }
623 } 663 ast::ModuleItem::TraitDef(def) => {
624 ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks 664 let id = self.find_inner_item(&def)?;
625 ast::ModuleItem::ImplDef(_) 665 (TraitLoc { container, id }.intern(self.db).into(), def.name())
626 | ast::ModuleItem::UseItem(_) 666 }
627 | ast::ModuleItem::ExternCrateItem(_) 667 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks
628 | ast::ModuleItem::Module(_) 668 ast::ModuleItem::ImplDef(_)
629 | ast::ModuleItem::MacroCall(_) => continue, 669 | ast::ModuleItem::UseItem(_)
630 }; 670 | ast::ModuleItem::ExternCrateItem(_)
671 | ast::ModuleItem::Module(_)
672 | ast::ModuleItem::MacroCall(_) => return None,
673 };
674
675 Some((def, name))
676 })
677 .collect::<Vec<_>>();
678
679 for (def, name) in items {
631 self.body.item_scope.define_def(def); 680 self.body.item_scope.define_def(def);
632 if let Some(name) = name { 681 if let Some(name) = name {
633 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 682 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 0b74199d9..99e876683 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -317,6 +317,39 @@ fn foo() {
317 ); 317 );
318 } 318 }
319 319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
339
340 #[test]
341 fn broken_inner_item() {
342 do_check(
343 r"
344 fn foo() {
345 trait {}
346 <|>
347 }
348 ",
349 &[],
350 );
351 }
352
320 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { 353 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
321 let (db, position) = TestDB::with_position(ra_fixture); 354 let (db, position) = TestDB::with_position(ra_fixture);
322 let file_id = position.file_id; 355 let file_id = position.file_id;
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 53599e74a..282ade2a3 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -2,27 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{name::Name, InFile};
6 hygiene::Hygiene,
7 name::{name, AsName, Name},
8 AstId, InFile,
9};
10use ra_prof::profile; 6use ra_prof::profile;
11use ra_syntax::ast::{ 7use ra_syntax::ast;
12 self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner,
13 VisibilityOwner,
14};
15 8
16use crate::{ 9use crate::{
17 attr::Attrs, 10 attr::Attrs,
18 body::LowerCtx, 11 body::Expander,
19 db::DefDatabase, 12 db::DefDatabase,
20 path::{path, AssociatedTypeBinding, GenericArgs, Path}, 13 item_tree::{AssocItem, ItemTreeId, ModItem},
21 src::HasSource, 14 type_ref::{TypeBound, TypeRef},
22 type_ref::{Mutability, TypeBound, TypeRef},
23 visibility::RawVisibility, 15 visibility::RawVisibility,
24 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
25 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 17 Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
26}; 18};
27 19
28#[derive(Debug, Clone, PartialEq, Eq)] 20#[derive(Debug, Clone, PartialEq, Eq)]
@@ -41,82 +33,27 @@ pub struct FunctionData {
41impl FunctionData { 33impl FunctionData {
42 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { 34 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
43 let loc = func.lookup(db); 35 let loc = func.lookup(db);
44 let src = loc.source(db); 36 let item_tree = db.item_tree(loc.id.file_id);
45 let ctx = LowerCtx::new(db, src.file_id); 37 let func = &item_tree[loc.id.value];
46 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); 38
47 let mut params = Vec::new(); 39 Arc::new(FunctionData {
48 let mut has_self_param = false; 40 name: func.name.clone(),
49 if let Some(param_list) = src.value.param_list() { 41 params: func.params.to_vec(),
50 if let Some(self_param) = param_list.self_param() { 42 ret_type: func.ret_type.clone(),
51 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 43 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
52 TypeRef::from_ast(&ctx, type_ref) 44 has_self_param: func.has_self_param,
53 } else { 45 is_unsafe: func.is_unsafe,
54 let self_type = TypeRef::Path(name![Self].into()); 46 visibility: item_tree[func.visibility].clone(),
55 match self_param.kind() { 47 })
56 ast::SelfParamKind::Owned => self_type,
57 ast::SelfParamKind::Ref => {
58 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
59 }
60 ast::SelfParamKind::MutRef => {
61 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
62 }
63 }
64 };
65 params.push(self_type);
66 has_self_param = true;
67 }
68 for param in param_list.params() {
69 let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type());
70 params.push(type_ref);
71 }
72 }
73 let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
74
75 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
76 TypeRef::from_ast(&ctx, type_ref)
77 } else {
78 TypeRef::unit()
79 };
80
81 let ret_type = if src.value.async_token().is_some() {
82 let future_impl = desugar_future_path(ret_type);
83 let ty_bound = TypeBound::Path(future_impl);
84 TypeRef::ImplTrait(vec![ty_bound])
85 } else {
86 ret_type
87 };
88
89 let is_unsafe = src.value.unsafe_token().is_some();
90
91 let vis_default = RawVisibility::default_for_container(loc.container);
92 let visibility =
93 RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
94
95 let sig =
96 FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs };
97 Arc::new(sig)
98 } 48 }
99} 49}
100 50
101fn desugar_future_path(orig: TypeRef) -> Path {
102 let path = path![core::future::Future];
103 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
104 let mut last = GenericArgs::empty();
105 last.bindings.push(AssociatedTypeBinding {
106 name: name![Output],
107 type_ref: Some(orig),
108 bounds: Vec::new(),
109 });
110 generic_args.push(Some(Arc::new(last)));
111
112 Path::from_known_path(path, generic_args)
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)] 51#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct TypeAliasData { 52pub struct TypeAliasData {
117 pub name: Name, 53 pub name: Name,
118 pub type_ref: Option<TypeRef>, 54 pub type_ref: Option<TypeRef>,
119 pub visibility: RawVisibility, 55 pub visibility: RawVisibility,
56 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
120 pub bounds: Vec<TypeBound>, 57 pub bounds: Vec<TypeBound>,
121} 58}
122 59
@@ -126,22 +63,15 @@ impl TypeAliasData {
126 typ: TypeAliasId, 63 typ: TypeAliasId,
127 ) -> Arc<TypeAliasData> { 64 ) -> Arc<TypeAliasData> {
128 let loc = typ.lookup(db); 65 let loc = typ.lookup(db);
129 let node = loc.source(db); 66 let item_tree = db.item_tree(loc.id.file_id);
130 let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); 67 let typ = &item_tree[loc.id.value];
131 let lower_ctx = LowerCtx::new(db, node.file_id); 68
132 let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); 69 Arc::new(TypeAliasData {
133 let vis_default = RawVisibility::default_for_container(loc.container); 70 name: typ.name.clone(),
134 let visibility = RawVisibility::from_ast_with_default( 71 type_ref: typ.type_ref.clone(),
135 db, 72 visibility: item_tree[typ.visibility].clone(),
136 vis_default, 73 bounds: typ.bounds.to_vec(),
137 node.as_ref().map(|n| n.visibility()), 74 })
138 );
139 let bounds = if let Some(bound_list) = node.value.type_bound_list() {
140 bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect()
141 } else {
142 Vec::new()
143 };
144 Arc::new(TypeAliasData { name, type_ref, visibility, bounds })
145 } 75 }
146} 76}
147 77
@@ -155,30 +85,24 @@ pub struct TraitData {
155impl TraitData { 85impl TraitData {
156 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { 86 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
157 let tr_loc = tr.lookup(db); 87 let tr_loc = tr.lookup(db);
158 let src = tr_loc.source(db); 88 let item_tree = db.item_tree(tr_loc.id.file_id);
159 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 89 let tr_def = &item_tree[tr_loc.id.value];
160 let auto = src.value.auto_token().is_some(); 90 let name = tr_def.name.clone();
91 let auto = tr_def.auto;
161 let module_id = tr_loc.container.module(db); 92 let module_id = tr_loc.container.module(db);
162
163 let container = AssocContainerId::TraitId(tr); 93 let container = AssocContainerId::TraitId(tr);
164 let mut items = Vec::new(); 94 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
165 95
166 if let Some(item_list) = src.value.item_list() { 96 let items = collect_items(
167 let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); 97 db,
168 items.extend(collect_items( 98 module_id,
169 db, 99 &mut expander,
170 &mut expander, 100 tr_def.items.iter().copied(),
171 item_list.assoc_items(), 101 tr_loc.id.file_id,
172 src.file_id, 102 container,
173 container, 103 100,
174 )); 104 );
175 items.extend(collect_items_in_macros( 105
176 db,
177 &mut expander,
178 &src.with_value(item_list),
179 container,
180 ));
181 }
182 Arc::new(TraitData { name, items, auto }) 106 Arc::new(TraitData { name, items, auto })
183 } 107 }
184 108
@@ -209,33 +133,28 @@ impl ImplData {
209 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { 133 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
210 let _p = profile("impl_data_query"); 134 let _p = profile("impl_data_query");
211 let impl_loc = id.lookup(db); 135 let impl_loc = id.lookup(db);
212 let src = impl_loc.source(db);
213 let lower_ctx = LowerCtx::new(db, src.file_id);
214 136
215 let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); 137 let item_tree = db.item_tree(impl_loc.id.file_id);
216 let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); 138 let impl_def = &item_tree[impl_loc.id.value];
217 let is_negative = src.value.excl_token().is_some(); 139 let target_trait = impl_def.target_trait.clone();
140 let target_type = impl_def.target_type.clone();
141 let is_negative = impl_def.is_negative;
218 let module_id = impl_loc.container.module(db); 142 let module_id = impl_loc.container.module(db);
219 let container = AssocContainerId::ImplId(id); 143 let container = AssocContainerId::ImplId(id);
144 let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
220 145
221 let mut items: Vec<AssocItemId> = Vec::new(); 146 let items = collect_items(
222 147 db,
223 if let Some(item_list) = src.value.item_list() { 148 module_id,
224 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); 149 &mut expander,
225 items.extend( 150 impl_def.items.iter().copied(),
226 collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) 151 impl_loc.id.file_id,
227 .into_iter() 152 container,
228 .map(|(_, item)| item), 153 100,
229 ); 154 );
230 items.extend( 155 let items = items.into_iter().map(|(_, item)| item).collect();
231 collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container)
232 .into_iter()
233 .map(|(_, item)| item),
234 );
235 }
236 156
237 let res = ImplData { target_trait, target_type, items, is_negative }; 157 Arc::new(ImplData { target_trait, target_type, items, is_negative })
238 Arc::new(res)
239 } 158 }
240} 159}
241 160
@@ -250,22 +169,14 @@ pub struct ConstData {
250impl ConstData { 169impl ConstData {
251 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { 170 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
252 let loc = konst.lookup(db); 171 let loc = konst.lookup(db);
253 let node = loc.source(db); 172 let item_tree = db.item_tree(loc.id.file_id);
254 let vis_default = RawVisibility::default_for_container(loc.container); 173 let konst = &item_tree[loc.id.value];
255 Arc::new(ConstData::new(db, vis_default, node))
256 }
257 174
258 fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( 175 Arc::new(ConstData {
259 db: &dyn DefDatabase, 176 name: konst.name.clone(),
260 vis_default: RawVisibility, 177 type_ref: konst.type_ref.clone(),
261 node: InFile<N>, 178 visibility: item_tree[konst.visibility].clone(),
262 ) -> ConstData { 179 })
263 let ctx = LowerCtx::new(db, node.file_id);
264 let name = node.value.name().map(|n| n.as_name());
265 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type());
266 let visibility =
267 RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
268 ConstData { name, type_ref, visibility }
269 } 180 }
270} 181}
271 182
@@ -279,44 +190,25 @@ pub struct StaticData {
279 190
280impl StaticData { 191impl StaticData {
281 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { 192 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
282 let node = konst.lookup(db).source(db); 193 let node = konst.lookup(db);
283 let ctx = LowerCtx::new(db, node.file_id); 194 let item_tree = db.item_tree(node.id.file_id);
284 195 let statik = &item_tree[node.id.value];
285 let name = node.value.name().map(|n| n.as_name()); 196
286 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); 197 Arc::new(StaticData {
287 let mutable = node.value.mut_token().is_some(); 198 name: Some(statik.name.clone()),
288 let visibility = RawVisibility::from_ast_with_default( 199 type_ref: statik.type_ref.clone(),
289 db, 200 visibility: item_tree[statik.visibility].clone(),
290 RawVisibility::private(), 201 mutable: statik.mutable,
291 node.map(|n| n.visibility()), 202 })
292 );
293
294 Arc::new(StaticData { name, type_ref, visibility, mutable })
295 }
296}
297
298fn collect_items_in_macros(
299 db: &dyn DefDatabase,
300 expander: &mut Expander,
301 impl_def: &InFile<ast::ItemList>,
302 container: AssocContainerId,
303) -> Vec<(Name, AssocItemId)> {
304 let mut res = Vec::new();
305
306 // We set a limit to protect against infinite recursion
307 let limit = 100;
308
309 for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
310 res.extend(collect_items_in_macro(db, expander, m, container, limit))
311 } 203 }
312
313 res
314} 204}
315 205
316fn collect_items_in_macro( 206fn collect_items(
317 db: &dyn DefDatabase, 207 db: &dyn DefDatabase,
208 module: ModuleId,
318 expander: &mut Expander, 209 expander: &mut Expander,
319 m: ast::MacroCall, 210 assoc_items: impl Iterator<Item = AssocItem>,
211 file_id: crate::HirFileId,
320 container: AssocContainerId, 212 container: AssocContainerId,
321 limit: usize, 213 limit: usize,
322) -> Vec<(Name, AssocItemId)> { 214) -> Vec<(Name, AssocItemId)> {
@@ -324,62 +216,62 @@ fn collect_items_in_macro(
324 return Vec::new(); 216 return Vec::new();
325 } 217 }
326 218
327 if let Some((mark, items)) = expander.enter_expand(db, None, m) { 219 let item_tree = db.item_tree(file_id);
328 let items: InFile<ast::MacroItems> = expander.to_source(items); 220 let cfg_options = db.crate_graph()[module.krate].cfg_options.clone();
329 let mut res = collect_items( 221
330 db, 222 let mut items = Vec::new();
331 expander, 223 for item in assoc_items {
332 items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), 224 match item {
333 items.file_id, 225 AssocItem::Function(id) => {
334 container, 226 let item = &item_tree[id];
335 ); 227 let attrs = item_tree.attrs(ModItem::from(id).into());
336 228 if !attrs.is_cfg_enabled(&cfg_options) {
337 // Recursive collect macros 229 continue;
338 // Note that ast::ModuleItem do not include ast::MacroCall
339 // We cannot use ModuleItemOwner::items here
340 for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
341 res.extend(collect_items_in_macro(db, expander, it, container, limit - 1))
342 }
343 expander.exit(db, mark);
344 res
345 } else {
346 Vec::new()
347 }
348}
349
350fn collect_items(
351 db: &dyn DefDatabase,
352 expander: &mut Expander,
353 assoc_items: impl Iterator<Item = AssocItem>,
354 file_id: crate::HirFileId,
355 container: AssocContainerId,
356) -> Vec<(Name, AssocItemId)> {
357 let items = db.ast_id_map(file_id);
358
359 assoc_items
360 .filter_map(|item_node| match item_node {
361 ast::AssocItem::FnDef(it) => {
362 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
363 if !expander.is_cfg_enabled(&it) {
364 return None;
365 } 230 }
366 let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 231 let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
367 .intern(db); 232 items.push((item.name.clone(), def.into()));
368 Some((name, def.into()))
369 } 233 }
370 ast::AssocItem::ConstDef(it) => { 234 // FIXME: cfg?
371 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 235 AssocItem::Const(id) => {
372 let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 236 let item = &item_tree[id];
373 .intern(db); 237 let name = match item.name.clone() {
374 Some((name, def.into())) 238 Some(name) => name,
239 None => continue,
240 };
241 let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
242 items.push((name, def.into()));
375 } 243 }
376 ast::AssocItem::TypeAliasDef(it) => { 244 AssocItem::TypeAlias(id) => {
377 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 245 let item = &item_tree[id];
378 let def = 246 let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
379 TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 247 items.push((item.name.clone(), def.into()));
380 .intern(db);
381 Some((name, def.into()))
382 } 248 }
383 }) 249 AssocItem::MacroCall(call) => {
384 .collect() 250 let call = &item_tree[call];
251 let ast_id_map = db.ast_id_map(file_id);
252 let root = db.parse_or_expand(file_id).unwrap();
253 let call = ast_id_map.get(call.ast_id).to_node(&root);
254
255 if let Some((mark, mac)) = expander.enter_expand(db, None, call) {
256 let src: InFile<ast::MacroItems> = expander.to_source(mac);
257 let item_tree = db.item_tree(src.file_id);
258 let iter =
259 item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
260 items.extend(collect_items(
261 db,
262 module,
263 expander,
264 iter,
265 src.file_id,
266 container,
267 limit - 1,
268 ));
269
270 expander.exit(db, mark);
271 }
272 }
273 }
274 }
275
276 items
385} 277}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 10cc26480..9c3ede2d7 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -14,8 +14,9 @@ use crate::{
14 docs::Documentation, 14 docs::Documentation,
15 generics::GenericParams, 15 generics::GenericParams,
16 import_map::ImportMap, 16 import_map::ImportMap,
17 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 18 lang_item::{LangItemTarget, LangItems},
18 nameres::{raw::RawItems, CrateDefMap}, 19 nameres::CrateDefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
20 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, 21 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
21 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, 22 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
@@ -45,8 +46,8 @@ pub trait InternDatabase: SourceDatabase {
45 46
46#[salsa::query_group(DefDatabaseStorage)] 47#[salsa::query_group(DefDatabaseStorage)]
47pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { 48pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
48 #[salsa::invoke(RawItems::raw_items_query)] 49 #[salsa::invoke(ItemTree::item_tree_query)]
49 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 50 fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
50 51
51 #[salsa::invoke(crate_def_map_wait)] 52 #[salsa::invoke(crate_def_map_wait)]
52 #[salsa::transparent] 53 #[salsa::transparent]
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 09a5241f7..6a0f493a7 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -42,7 +42,7 @@ pub enum TypeParamProvenance {
42} 42}
43 43
44/// Data about the generic parameters of a function, struct, impl, etc. 44/// Data about the generic parameters of a function, struct, impl, etc.
45#[derive(Clone, PartialEq, Eq, Debug)] 45#[derive(Clone, PartialEq, Eq, Debug, Default)]
46pub struct GenericParams { 46pub struct GenericParams {
47 pub types: Arena<TypeParamData>, 47 pub types: Arena<TypeParamData>,
48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, 48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
@@ -74,8 +74,53 @@ impl GenericParams {
74 def: GenericDefId, 74 def: GenericDefId,
75 ) -> Arc<GenericParams> { 75 ) -> Arc<GenericParams> {
76 let _p = profile("generic_params_query"); 76 let _p = profile("generic_params_query");
77 let (params, _source_map) = GenericParams::new(db, def); 77
78 Arc::new(params) 78 let generics = match def {
79 GenericDefId::FunctionId(id) => {
80 let id = id.lookup(db).id;
81 let tree = db.item_tree(id.file_id);
82 let item = &tree[id.value];
83 tree[item.generic_params].clone()
84 }
85 GenericDefId::AdtId(AdtId::StructId(id)) => {
86 let id = id.lookup(db).id;
87 let tree = db.item_tree(id.file_id);
88 let item = &tree[id.value];
89 tree[item.generic_params].clone()
90 }
91 GenericDefId::AdtId(AdtId::EnumId(id)) => {
92 let id = id.lookup(db).id;
93 let tree = db.item_tree(id.file_id);
94 let item = &tree[id.value];
95 tree[item.generic_params].clone()
96 }
97 GenericDefId::AdtId(AdtId::UnionId(id)) => {
98 let id = id.lookup(db).id;
99 let tree = db.item_tree(id.file_id);
100 let item = &tree[id.value];
101 tree[item.generic_params].clone()
102 }
103 GenericDefId::TraitId(id) => {
104 let id = id.lookup(db).id;
105 let tree = db.item_tree(id.file_id);
106 let item = &tree[id.value];
107 tree[item.generic_params].clone()
108 }
109 GenericDefId::TypeAliasId(id) => {
110 let id = id.lookup(db).id;
111 let tree = db.item_tree(id.file_id);
112 let item = &tree[id.value];
113 tree[item.generic_params].clone()
114 }
115 GenericDefId::ImplId(id) => {
116 let id = id.lookup(db).id;
117 let tree = db.item_tree(id.file_id);
118 let item = &tree[id.value];
119 tree[item.generic_params].clone()
120 }
121 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
122 };
123 Arc::new(generics)
79 } 124 }
80 125
81 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 126 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
@@ -156,7 +201,12 @@ impl GenericParams {
156 (generics, InFile::new(file_id, sm)) 201 (generics, InFile::new(file_id, sm))
157 } 202 }
158 203
159 fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { 204 pub(crate) fn fill(
205 &mut self,
206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap,
208 node: &dyn TypeParamsOwner,
209 ) {
160 if let Some(params) = node.type_param_list() { 210 if let Some(params) = node.type_param_list() {
161 self.fill_params(lower_ctx, sm, params) 211 self.fill_params(lower_ctx, sm, params)
162 } 212 }
@@ -165,7 +215,7 @@ impl GenericParams {
165 } 215 }
166 } 216 }
167 217
168 fn fill_bounds( 218 pub(crate) fn fill_bounds(
169 &mut self, 219 &mut self,
170 lower_ctx: &LowerCtx, 220 lower_ctx: &LowerCtx,
171 node: &dyn ast::TypeBoundsOwner, 221 node: &dyn ast::TypeBoundsOwner,
@@ -229,7 +279,7 @@ impl GenericParams {
229 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); 279 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
230 } 280 }
231 281
232 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { 282 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
233 type_ref.walk(&mut |type_ref| { 283 type_ref.walk(&mut |type_ref| {
234 if let TypeRef::ImplTrait(bounds) = type_ref { 284 if let TypeRef::ImplTrait(bounds) = type_ref {
235 let param = TypeParamData { 285 let param = TypeParamData {
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index b03ba939a..c81b966c3 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -5,6 +5,7 @@ use hir_expand::name::Name;
5use once_cell::sync::Lazy; 5use once_cell::sync::Lazy;
6use ra_db::CrateId; 6use ra_db::CrateId;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use test_utils::mark;
8 9
9use crate::{ 10use crate::{
10 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, 11 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
@@ -126,19 +127,27 @@ impl ItemScope {
126 let mut changed = false; 127 let mut changed = false;
127 let existing = self.visible.entry(name).or_default(); 128 let existing = self.visible.entry(name).or_default();
128 129
129 if existing.types.is_none() && def.types.is_some() { 130 macro_rules! check_changed {
130 existing.types = def.types; 131 ($changed:ident, $existing:expr, $def:expr) => {
131 changed = true; 132 match ($existing, $def) {
132 } 133 (None, Some(_)) => {
133 if existing.values.is_none() && def.values.is_some() { 134 $existing = $def;
134 existing.values = def.values; 135 $changed = true;
135 changed = true; 136 }
136 } 137 (Some(e), Some(d)) if e.0 != d.0 => {
137 if existing.macros.is_none() && def.macros.is_some() { 138 mark::hit!(import_shadowed);
138 existing.macros = def.macros; 139 $existing = $def;
139 changed = true; 140 $changed = true;
141 }
142 _ => {}
143 }
144 };
140 } 145 }
141 146
147 check_changed!(changed, existing.types, def.types);
148 check_changed!(changed, existing.values, def.values);
149 check_changed!(changed, existing.macros, def.macros);
150
142 changed 151 changed
143 } 152 }
144 153
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
new file mode 100644
index 000000000..3e603bd55
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -0,0 +1,753 @@
1//! A simplified AST that only contains items.
2
3mod lower;
4#[cfg(test)]
5mod tests;
6
7use std::{
8 any::type_name,
9 fmt::{self, Debug},
10 hash::{Hash, Hasher},
11 marker::PhantomData,
12 ops::{Index, Range},
13 sync::Arc,
14};
15
16use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner};
17use either::Either;
18use hir_expand::{
19 ast_id_map::FileAstId,
20 hygiene::Hygiene,
21 name::{name, AsName, Name},
22 HirFileId, InFile,
23};
24use ra_arena::{Arena, Idx, RawId};
25use ra_syntax::{ast, match_ast};
26use rustc_hash::FxHashMap;
27use smallvec::SmallVec;
28use test_utils::mark;
29
30use crate::{
31 attr::Attrs,
32 db::DefDatabase,
33 generics::GenericParams,
34 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
35 type_ref::{Mutability, TypeBound, TypeRef},
36 visibility::RawVisibility,
37};
38
39#[derive(Copy, Clone, Eq, PartialEq)]
40pub struct RawVisibilityId(u32);
41
42impl RawVisibilityId {
43 pub const PUB: Self = RawVisibilityId(u32::max_value());
44 pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
45 pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
46}
47
48impl fmt::Debug for RawVisibilityId {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 let mut f = f.debug_tuple("RawVisibilityId");
51 match *self {
52 Self::PUB => f.field(&"pub"),
53 Self::PRIV => f.field(&"pub(self)"),
54 Self::PUB_CRATE => f.field(&"pub(crate)"),
55 _ => f.field(&self.0),
56 };
57 f.finish()
58 }
59}
60
61#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62pub struct GenericParamsId(u32);
63
64impl GenericParamsId {
65 pub const EMPTY: Self = GenericParamsId(u32::max_value());
66}
67
68/// The item tree of a source file.
69#[derive(Debug, Eq, PartialEq)]
70pub struct ItemTree {
71 top_level: SmallVec<[ModItem; 1]>,
72 attrs: FxHashMap<AttrOwner, Attrs>,
73 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
74
75 data: Option<Box<ItemTreeData>>,
76}
77
78impl ItemTree {
79 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
80 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
81 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
82 node
83 } else {
84 return Arc::new(Self::empty());
85 };
86
87 let hygiene = Hygiene::new(db.upcast(), file_id);
88 let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
89 let mut top_attrs = None;
90 let mut item_tree = match_ast! {
91 match syntax {
92 ast::SourceFile(file) => {
93 top_attrs = Some(Attrs::new(&file, &hygiene));
94 ctx.lower_module_items(&file)
95 },
96 ast::MacroItems(items) => {
97 ctx.lower_module_items(&items)
98 },
99 // Macros can expand to expressions. We return an empty item tree in this case, but
100 // still need to collect inner items.
101 ast::Expr(e) => {
102 ctx.lower_inner_items(e.syntax())
103 },
104 _ => {
105 panic!("cannot create item tree from {:?}", syntax);
106 },
107 }
108 };
109
110 if let Some(attrs) = top_attrs {
111 item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
112 }
113 item_tree.shrink_to_fit();
114 Arc::new(item_tree)
115 }
116
117 fn empty() -> Self {
118 Self {
119 top_level: Default::default(),
120 attrs: Default::default(),
121 inner_items: Default::default(),
122 data: Default::default(),
123 }
124 }
125
126 fn shrink_to_fit(&mut self) {
127 if let Some(data) = &mut self.data {
128 let ItemTreeData {
129 imports,
130 extern_crates,
131 functions,
132 structs,
133 fields,
134 unions,
135 enums,
136 variants,
137 consts,
138 statics,
139 traits,
140 impls,
141 type_aliases,
142 mods,
143 macro_calls,
144 exprs,
145 vis,
146 generics,
147 } = &mut **data;
148
149 imports.shrink_to_fit();
150 extern_crates.shrink_to_fit();
151 functions.shrink_to_fit();
152 structs.shrink_to_fit();
153 fields.shrink_to_fit();
154 unions.shrink_to_fit();
155 enums.shrink_to_fit();
156 variants.shrink_to_fit();
157 consts.shrink_to_fit();
158 statics.shrink_to_fit();
159 traits.shrink_to_fit();
160 impls.shrink_to_fit();
161 type_aliases.shrink_to_fit();
162 mods.shrink_to_fit();
163 macro_calls.shrink_to_fit();
164 exprs.shrink_to_fit();
165
166 vis.arena.shrink_to_fit();
167 generics.arena.shrink_to_fit();
168 }
169 }
170
171 /// Returns an iterator over all items located at the top level of the `HirFileId` this
172 /// `ItemTree` was created from.
173 pub fn top_level_items(&self) -> &[ModItem] {
174 &self.top_level
175 }
176
177 /// Returns the inner attributes of the source file.
178 pub fn top_level_attrs(&self) -> &Attrs {
179 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
180 }
181
182 pub fn attrs(&self, of: AttrOwner) -> &Attrs {
183 self.attrs.get(&of).unwrap_or(&Attrs::EMPTY)
184 }
185
186 /// Returns the lowered inner items that `ast` corresponds to.
187 ///
188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
189 /// to multiple items in the `ItemTree`.
190 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] {
191 &self.inner_items[&ast]
192 }
193
194 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
195 self.inner_items.values().flatten().copied()
196 }
197
198 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
199 // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
200 // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).
201 let root =
202 db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree");
203
204 let id = self[of.value].ast_id();
205 let map = db.ast_id_map(of.file_id);
206 let ptr = map.get(id);
207 ptr.to_node(&root)
208 }
209
210 fn data(&self) -> &ItemTreeData {
211 self.data.as_ref().expect("attempted to access data of empty ItemTree")
212 }
213
214 fn data_mut(&mut self) -> &mut ItemTreeData {
215 self.data.get_or_insert_with(Box::default)
216 }
217}
218
219#[derive(Default, Debug, Eq, PartialEq)]
220struct ItemVisibilities {
221 arena: Arena<RawVisibility>,
222}
223
224impl ItemVisibilities {
225 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
226 match &vis {
227 RawVisibility::Public => RawVisibilityId::PUB,
228 RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind {
229 PathKind::Super(0) => RawVisibilityId::PRIV,
230 PathKind::Crate => RawVisibilityId::PUB_CRATE,
231 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
232 },
233 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
234 }
235 }
236}
237
238static VIS_PUB: RawVisibility = RawVisibility::Public;
239static VIS_PRIV: RawVisibility =
240 RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() });
241static VIS_PUB_CRATE: RawVisibility =
242 RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
243
244#[derive(Default, Debug, Eq, PartialEq)]
245struct GenericParamsStorage {
246 arena: Arena<GenericParams>,
247}
248
249impl GenericParamsStorage {
250 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
251 if params.types.is_empty() && params.where_predicates.is_empty() {
252 return GenericParamsId::EMPTY;
253 }
254
255 GenericParamsId(self.arena.alloc(params).into_raw().into())
256 }
257}
258
259static EMPTY_GENERICS: GenericParams =
260 GenericParams { types: Arena::new(), where_predicates: Vec::new() };
261
262#[derive(Default, Debug, Eq, PartialEq)]
263struct ItemTreeData {
264 imports: Arena<Import>,
265 extern_crates: Arena<ExternCrate>,
266 functions: Arena<Function>,
267 structs: Arena<Struct>,
268 fields: Arena<Field>,
269 unions: Arena<Union>,
270 enums: Arena<Enum>,
271 variants: Arena<Variant>,
272 consts: Arena<Const>,
273 statics: Arena<Static>,
274 traits: Arena<Trait>,
275 impls: Arena<Impl>,
276 type_aliases: Arena<TypeAlias>,
277 mods: Arena<Mod>,
278 macro_calls: Arena<MacroCall>,
279 exprs: Arena<Expr>,
280
281 vis: ItemVisibilities,
282 generics: GenericParamsStorage,
283}
284
285#[derive(Debug, Eq, PartialEq, Hash)]
286pub enum AttrOwner {
287 /// Attributes on an item.
288 ModItem(ModItem),
289 /// Inner attributes of the source file.
290 TopLevel,
291
292 Variant(Idx<Variant>),
293 Field(Idx<Field>),
294 // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
295}
296
297macro_rules! from_attrs {
298 ( $( $var:ident($t:ty) ),+ ) => {
299 $(
300 impl From<$t> for AttrOwner {
301 fn from(t: $t) -> AttrOwner {
302 AttrOwner::$var(t)
303 }
304 }
305 )+
306 };
307}
308
309from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
310
311/// Trait implemented by all item nodes in the item tree.
312pub trait ItemTreeNode: Clone {
313 type Source: AstNode + Into<ast::ModuleItem>;
314
315 fn ast_id(&self) -> FileAstId<Self::Source>;
316
317 /// Looks up an instance of `Self` in an item tree.
318 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
319
320 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
321 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
322
323 /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
324 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
325}
326
327pub struct FileItemTreeId<N: ItemTreeNode> {
328 index: Idx<N>,
329 _p: PhantomData<N>,
330}
331
332impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
333 fn clone(&self) -> Self {
334 Self { index: self.index, _p: PhantomData }
335 }
336}
337impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
338
339impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
340 fn eq(&self, other: &FileItemTreeId<N>) -> bool {
341 self.index == other.index
342 }
343}
344impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
345
346impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
347 fn hash<H: Hasher>(&self, state: &mut H) {
348 self.index.hash(state)
349 }
350}
351
352impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 self.index.fmt(f)
355 }
356}
357
358pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>;
359
360macro_rules! mod_items {
361 ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
362 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
363 pub enum ModItem {
364 $(
365 $typ(FileItemTreeId<$typ>),
366 )+
367 }
368
369 $(
370 impl From<FileItemTreeId<$typ>> for ModItem {
371 fn from(id: FileItemTreeId<$typ>) -> ModItem {
372 ModItem::$typ(id)
373 }
374 }
375 )+
376
377 $(
378 impl ItemTreeNode for $typ {
379 type Source = $ast;
380
381 fn ast_id(&self) -> FileAstId<Self::Source> {
382 self.ast_id
383 }
384
385 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
386 &tree.data().$fld[index]
387 }
388
389 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
390 if let ModItem::$typ(id) = mod_item {
391 Some(id)
392 } else {
393 None
394 }
395 }
396
397 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
398 ModItem::$typ(id)
399 }
400 }
401
402 impl Index<Idx<$typ>> for ItemTree {
403 type Output = $typ;
404
405 fn index(&self, index: Idx<$typ>) -> &Self::Output {
406 &self.data().$fld[index]
407 }
408 }
409 )+
410 };
411}
412
413mod_items! {
414 Import in imports -> ast::UseItem,
415 ExternCrate in extern_crates -> ast::ExternCrateItem,
416 Function in functions -> ast::FnDef,
417 Struct in structs -> ast::StructDef,
418 Union in unions -> ast::UnionDef,
419 Enum in enums -> ast::EnumDef,
420 Const in consts -> ast::ConstDef,
421 Static in statics -> ast::StaticDef,
422 Trait in traits -> ast::TraitDef,
423 Impl in impls -> ast::ImplDef,
424 TypeAlias in type_aliases -> ast::TypeAliasDef,
425 Mod in mods -> ast::Module,
426 MacroCall in macro_calls -> ast::MacroCall,
427}
428
429macro_rules! impl_index {
430 ( $($fld:ident: $t:ty),+ $(,)? ) => {
431 $(
432 impl Index<Idx<$t>> for ItemTree {
433 type Output = $t;
434
435 fn index(&self, index: Idx<$t>) -> &Self::Output {
436 &self.data().$fld[index]
437 }
438 }
439 )+
440 };
441}
442
443impl_index!(fields: Field, variants: Variant, exprs: Expr);
444
445impl Index<RawVisibilityId> for ItemTree {
446 type Output = RawVisibility;
447 fn index(&self, index: RawVisibilityId) -> &Self::Output {
448 match index {
449 RawVisibilityId::PRIV => &VIS_PRIV,
450 RawVisibilityId::PUB => &VIS_PUB,
451 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
452 _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
453 }
454 }
455}
456
457impl Index<GenericParamsId> for ItemTree {
458 type Output = GenericParams;
459
460 fn index(&self, index: GenericParamsId) -> &Self::Output {
461 match index {
462 GenericParamsId::EMPTY => &EMPTY_GENERICS,
463 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
464 }
465 }
466}
467
468impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
469 type Output = N;
470 fn index(&self, id: FileItemTreeId<N>) -> &N {
471 N::lookup(self, id.index)
472 }
473}
474
475/// A desugared `use` import.
476#[derive(Debug, Clone, Eq, PartialEq)]
477pub struct Import {
478 pub path: ModPath,
479 pub alias: Option<ImportAlias>,
480 pub visibility: RawVisibilityId,
481 pub is_glob: bool,
482 pub is_prelude: bool,
483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
484 /// `Import`s can map to the same `use` item.
485 pub ast_id: FileAstId<ast::UseItem>,
486}
487
488#[derive(Debug, Clone, Eq, PartialEq)]
489pub struct ExternCrate {
490 pub path: ModPath,
491 pub alias: Option<ImportAlias>,
492 pub visibility: RawVisibilityId,
493 /// Whether this is a `#[macro_use] extern crate ...`.
494 pub is_macro_use: bool,
495 pub ast_id: FileAstId<ast::ExternCrateItem>,
496}
497
498#[derive(Debug, Clone, Eq, PartialEq)]
499pub struct Function {
500 pub name: Name,
501 pub visibility: RawVisibilityId,
502 pub generic_params: GenericParamsId,
503 pub has_self_param: bool,
504 pub is_unsafe: bool,
505 pub params: Box<[TypeRef]>,
506 pub ret_type: TypeRef,
507 pub ast_id: FileAstId<ast::FnDef>,
508}
509
510#[derive(Debug, Clone, Eq, PartialEq)]
511pub struct Struct {
512 pub name: Name,
513 pub visibility: RawVisibilityId,
514 pub generic_params: GenericParamsId,
515 pub fields: Fields,
516 pub ast_id: FileAstId<ast::StructDef>,
517 pub kind: StructDefKind,
518}
519
520#[derive(Debug, Clone, Eq, PartialEq)]
521pub enum StructDefKind {
522 /// `struct S { ... }` - type namespace only.
523 Record,
524 /// `struct S(...);`
525 Tuple,
526 /// `struct S;`
527 Unit,
528}
529
530#[derive(Debug, Clone, Eq, PartialEq)]
531pub struct Union {
532 pub name: Name,
533 pub visibility: RawVisibilityId,
534 pub generic_params: GenericParamsId,
535 pub fields: Fields,
536 pub ast_id: FileAstId<ast::UnionDef>,
537}
538
539#[derive(Debug, Clone, Eq, PartialEq)]
540pub struct Enum {
541 pub name: Name,
542 pub visibility: RawVisibilityId,
543 pub generic_params: GenericParamsId,
544 pub variants: IdRange<Variant>,
545 pub ast_id: FileAstId<ast::EnumDef>,
546}
547
548#[derive(Debug, Clone, Eq, PartialEq)]
549pub struct Const {
550 /// const _: () = ();
551 pub name: Option<Name>,
552 pub visibility: RawVisibilityId,
553 pub type_ref: TypeRef,
554 pub ast_id: FileAstId<ast::ConstDef>,
555}
556
557#[derive(Debug, Clone, Eq, PartialEq)]
558pub struct Static {
559 pub name: Name,
560 pub visibility: RawVisibilityId,
561 pub mutable: bool,
562 pub type_ref: TypeRef,
563 pub ast_id: FileAstId<ast::StaticDef>,
564}
565
566#[derive(Debug, Clone, Eq, PartialEq)]
567pub struct Trait {
568 pub name: Name,
569 pub visibility: RawVisibilityId,
570 pub generic_params: GenericParamsId,
571 pub auto: bool,
572 pub items: Box<[AssocItem]>,
573 pub ast_id: FileAstId<ast::TraitDef>,
574}
575
576#[derive(Debug, Clone, Eq, PartialEq)]
577pub struct Impl {
578 pub generic_params: GenericParamsId,
579 pub target_trait: Option<TypeRef>,
580 pub target_type: TypeRef,
581 pub is_negative: bool,
582 pub items: Box<[AssocItem]>,
583 pub ast_id: FileAstId<ast::ImplDef>,
584}
585
586#[derive(Debug, Clone, PartialEq, Eq)]
587pub struct TypeAlias {
588 pub name: Name,
589 pub visibility: RawVisibilityId,
590 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
591 pub bounds: Box<[TypeBound]>,
592 pub generic_params: GenericParamsId,
593 pub type_ref: Option<TypeRef>,
594 pub ast_id: FileAstId<ast::TypeAliasDef>,
595}
596
597#[derive(Debug, Clone, Eq, PartialEq)]
598pub struct Mod {
599 pub name: Name,
600 pub visibility: RawVisibilityId,
601 pub kind: ModKind,
602 pub ast_id: FileAstId<ast::Module>,
603}
604
605#[derive(Debug, Clone, Eq, PartialEq)]
606pub enum ModKind {
607 /// `mod m { ... }`
608 Inline { items: Box<[ModItem]> },
609
610 /// `mod m;`
611 Outline {},
612}
613
614#[derive(Debug, Clone, Eq, PartialEq)]
615pub struct MacroCall {
616 /// For `macro_rules!` declarations, this is the name of the declared macro.
617 pub name: Option<Name>,
618 /// Path to the called macro.
619 pub path: ModPath,
620 /// Has `#[macro_export]`.
621 pub is_export: bool,
622 /// Has `#[macro_export(local_inner_macros)]`.
623 pub is_local_inner: bool,
624 /// Has `#[rustc_builtin_macro]`.
625 pub is_builtin: bool,
626 pub ast_id: FileAstId<ast::MacroCall>,
627}
628
629// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
630// lengths, but we don't do much with them yet.
631#[derive(Debug, Clone, Eq, PartialEq)]
632pub struct Expr;
633
634macro_rules! impl_froms {
635 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
636 $(
637 impl From<$t> for $e {
638 fn from(it: $t) -> $e {
639 $e::$v(it)
640 }
641 }
642 )*
643 }
644}
645
646impl ModItem {
647 pub fn as_assoc_item(&self) -> Option<AssocItem> {
648 match self {
649 ModItem::Import(_)
650 | ModItem::ExternCrate(_)
651 | ModItem::Struct(_)
652 | ModItem::Union(_)
653 | ModItem::Enum(_)
654 | ModItem::Static(_)
655 | ModItem::Trait(_)
656 | ModItem::Impl(_)
657 | ModItem::Mod(_) => None,
658 ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
659 ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
660 ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
661 ModItem::Function(func) => Some(AssocItem::Function(*func)),
662 }
663 }
664
665 pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
666 N::id_from_mod_item(self)
667 }
668}
669
670#[derive(Debug, Copy, Clone, Eq, PartialEq)]
671pub enum AssocItem {
672 Function(FileItemTreeId<Function>),
673 TypeAlias(FileItemTreeId<TypeAlias>),
674 Const(FileItemTreeId<Const>),
675 MacroCall(FileItemTreeId<MacroCall>),
676}
677
678impl_froms!(AssocItem {
679 Function(FileItemTreeId<Function>),
680 TypeAlias(FileItemTreeId<TypeAlias>),
681 Const(FileItemTreeId<Const>),
682 MacroCall(FileItemTreeId<MacroCall>),
683});
684
685impl From<AssocItem> for ModItem {
686 fn from(item: AssocItem) -> Self {
687 match item {
688 AssocItem::Function(it) => it.into(),
689 AssocItem::TypeAlias(it) => it.into(),
690 AssocItem::Const(it) => it.into(),
691 AssocItem::MacroCall(it) => it.into(),
692 }
693 }
694}
695
696#[derive(Debug, Eq, PartialEq)]
697pub struct Variant {
698 pub name: Name,
699 pub fields: Fields,
700}
701
702pub struct IdRange<T> {
703 range: Range<u32>,
704 _p: PhantomData<T>,
705}
706
707impl<T> IdRange<T> {
708 fn new(range: Range<Idx<T>>) -> Self {
709 Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
710 }
711}
712
713impl<T> Iterator for IdRange<T> {
714 type Item = Idx<T>;
715 fn next(&mut self) -> Option<Self::Item> {
716 self.range.next().map(|raw| Idx::from_raw(raw.into()))
717 }
718}
719
720impl<T> fmt::Debug for IdRange<T> {
721 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
722 f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
723 }
724}
725
726impl<T> Clone for IdRange<T> {
727 fn clone(&self) -> Self {
728 Self { range: self.range.clone(), _p: PhantomData }
729 }
730}
731
732impl<T> PartialEq for IdRange<T> {
733 fn eq(&self, other: &Self) -> bool {
734 self.range == other.range
735 }
736}
737
738impl<T> Eq for IdRange<T> {}
739
740#[derive(Debug, Clone, PartialEq, Eq)]
741pub enum Fields {
742 Record(IdRange<Field>),
743 Tuple(IdRange<Field>),
744 Unit,
745}
746
747/// A single field of an enum variant or struct
748#[derive(Debug, Clone, PartialEq, Eq)]
749pub struct Field {
750 pub name: Name,
751 pub type_ref: TypeRef,
752 pub visibility: RawVisibilityId,
753}
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
new file mode 100644
index 000000000..5149dd141
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -0,0 +1,698 @@
1//! AST -> `ItemTree` lowering code.
2
3use super::*;
4use crate::{
5 attr::Attrs,
6 generics::{GenericParams, TypeParamData, TypeParamProvenance},
7};
8use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
9use ra_arena::map::ArenaMap;
10use ra_syntax::{
11 ast::{self, ModuleItemOwner},
12 SyntaxNode,
13};
14use smallvec::SmallVec;
15use std::{collections::hash_map::Entry, mem, sync::Arc};
16
17fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
18 FileItemTreeId { index, _p: PhantomData }
19}
20
21struct ModItems(SmallVec<[ModItem; 1]>);
22
23impl<T> From<T> for ModItems
24where
25 T: Into<ModItem>,
26{
27 fn from(t: T) -> Self {
28 ModItems(SmallVec::from_buf([t.into(); 1]))
29 }
30}
31
32pub(super) struct Ctx {
33 tree: ItemTree,
34 hygiene: Hygiene,
35 file: HirFileId,
36 source_ast_id_map: Arc<AstIdMap>,
37 body_ctx: crate::body::LowerCtx,
38 inner_items: Vec<ModItem>,
39 forced_visibility: Option<RawVisibilityId>,
40}
41
42impl Ctx {
43 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
44 Self {
45 tree: ItemTree::empty(),
46 hygiene,
47 file,
48 source_ast_id_map: db.ast_id_map(file),
49 body_ctx: crate::body::LowerCtx::new(db, file),
50 inner_items: Vec::new(),
51 forced_visibility: None,
52 }
53 }
54
55 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
56 self.tree.top_level = item_owner
57 .items()
58 .flat_map(|item| self.lower_mod_item(&item, false))
59 .flat_map(|items| items.0)
60 .collect();
61 self.tree
62 }
63
64 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
65 self.collect_inner_items(within);
66 self.tree
67 }
68
69 fn data(&mut self) -> &mut ItemTreeData {
70 self.tree.data_mut()
71 }
72
73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
74 assert!(inner || self.inner_items.is_empty());
75
76 // Collect inner items for 1-to-1-lowered items.
77 match item {
78 ast::ModuleItem::StructDef(_)
79 | ast::ModuleItem::UnionDef(_)
80 | ast::ModuleItem::EnumDef(_)
81 | ast::ModuleItem::FnDef(_)
82 | ast::ModuleItem::TypeAliasDef(_)
83 | ast::ModuleItem::ConstDef(_)
84 | ast::ModuleItem::StaticDef(_)
85 | ast::ModuleItem::MacroCall(_) => {
86 // Skip this if we're already collecting inner items. We'll descend into all nodes
87 // already.
88 if !inner {
89 self.collect_inner_items(item.syntax());
90 }
91 }
92
93 // These are handled in their respective `lower_X` method (since we can't just blindly
94 // walk them).
95 ast::ModuleItem::TraitDef(_)
96 | ast::ModuleItem::ImplDef(_)
97 | ast::ModuleItem::ExternBlock(_) => {}
98
99 // These don't have inner items.
100 ast::ModuleItem::Module(_)
101 | ast::ModuleItem::ExternCrateItem(_)
102 | ast::ModuleItem::UseItem(_) => {}
103 };
104
105 let attrs = Attrs::new(item, &self.hygiene);
106 let items = match item {
107 ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into),
108 ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into),
109 ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into),
110 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
111 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
112 ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into),
113 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
114 ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into),
115 ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into),
116 ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into),
117 ast::ModuleItem::UseItem(ast) => Some(ModItems(
118 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
119 )),
120 ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into),
121 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
122 ast::ModuleItem::ExternBlock(ast) => {
123 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
124 }
125 };
126
127 if !attrs.is_empty() {
128 for item in items.iter().flat_map(|items| &items.0) {
129 self.add_attrs((*item).into(), attrs.clone());
130 }
131 }
132
133 items
134 }
135
136 fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) {
137 match self.tree.attrs.entry(item) {
138 Entry::Occupied(mut entry) => {
139 *entry.get_mut() = entry.get().merge(attrs);
140 }
141 Entry::Vacant(entry) => {
142 entry.insert(attrs);
143 }
144 }
145 }
146
147 fn collect_inner_items(&mut self, container: &SyntaxNode) {
148 let forced_vis = self.forced_visibility.take();
149 let mut inner_items = mem::take(&mut self.tree.inner_items);
150 inner_items.extend(
151 container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| {
152 let ast_id = self.source_ast_id_map.ast_id(&item);
153 Some((ast_id, self.lower_mod_item(&item, true)?.0))
154 }),
155 );
156 self.tree.inner_items = inner_items;
157 self.forced_visibility = forced_vis;
158 }
159
160 fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> {
161 match item {
162 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
163 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
164 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
165 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
166 _ => None,
167 }
168 }
169
170 fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> {
171 let visibility = self.lower_visibility(strukt);
172 let name = strukt.name()?.as_name();
173 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
174 let fields = self.lower_fields(&strukt.kind());
175 let ast_id = self.source_ast_id_map.ast_id(strukt);
176 let kind = match strukt.kind() {
177 ast::StructKind::Record(_) => StructDefKind::Record,
178 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
179 ast::StructKind::Unit => StructDefKind::Unit,
180 };
181 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
182 Some(id(self.data().structs.alloc(res)))
183 }
184
185 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
186 match strukt_kind {
187 ast::StructKind::Record(it) => {
188 let range = self.lower_record_fields(it);
189 Fields::Record(range)
190 }
191 ast::StructKind::Tuple(it) => {
192 let range = self.lower_tuple_fields(it);
193 Fields::Tuple(range)
194 }
195 ast::StructKind::Unit => Fields::Unit,
196 }
197 }
198
199 fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> IdRange<Field> {
200 let start = self.next_field_idx();
201 for field in fields.fields() {
202 if let Some(data) = self.lower_record_field(&field) {
203 let idx = self.data().fields.alloc(data);
204 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
205 }
206 }
207 let end = self.next_field_idx();
208 IdRange::new(start..end)
209 }
210
211 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
212 let name = field.name()?.as_name();
213 let visibility = self.lower_visibility(field);
214 let type_ref = self.lower_type_ref(&field.ascribed_type()?);
215 let res = Field { name, type_ref, visibility };
216 Some(res)
217 }
218
219 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> IdRange<Field> {
220 let start = self.next_field_idx();
221 for (i, field) in fields.fields().enumerate() {
222 if let Some(data) = self.lower_tuple_field(i, &field) {
223 let idx = self.data().fields.alloc(data);
224 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
225 }
226 }
227 let end = self.next_field_idx();
228 IdRange::new(start..end)
229 }
230
231 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> {
232 let name = Name::new_tuple_field(idx);
233 let visibility = self.lower_visibility(field);
234 let type_ref = self.lower_type_ref(&field.type_ref()?);
235 let res = Field { name, type_ref, visibility };
236 Some(res)
237 }
238
239 fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> {
240 let visibility = self.lower_visibility(union);
241 let name = union.name()?.as_name();
242 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
243 let fields = match union.record_field_def_list() {
244 Some(record_field_def_list) => {
245 self.lower_fields(&StructKind::Record(record_field_def_list))
246 }
247 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())),
248 };
249 let ast_id = self.source_ast_id_map.ast_id(union);
250 let res = Union { name, visibility, generic_params, fields, ast_id };
251 Some(id(self.data().unions.alloc(res)))
252 }
253
254 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> {
255 let visibility = self.lower_visibility(enum_);
256 let name = enum_.name()?.as_name();
257 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
258 let variants = match &enum_.variant_list() {
259 Some(variant_list) => self.lower_variants(variant_list),
260 None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()),
261 };
262 let ast_id = self.source_ast_id_map.ast_id(enum_);
263 let res = Enum { name, visibility, generic_params, variants, ast_id };
264 Some(id(self.data().enums.alloc(res)))
265 }
266
267 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> IdRange<Variant> {
268 let start = self.next_variant_idx();
269 for variant in variants.variants() {
270 if let Some(data) = self.lower_variant(&variant) {
271 let idx = self.data().variants.alloc(data);
272 self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene));
273 }
274 }
275 let end = self.next_variant_idx();
276 IdRange::new(start..end)
277 }
278
279 fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> {
280 let name = variant.name()?.as_name();
281 let fields = self.lower_fields(&variant.kind());
282 let res = Variant { name, fields };
283 Some(res)
284 }
285
286 fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> {
287 let visibility = self.lower_visibility(func);
288 let name = func.name()?.as_name();
289
290 let mut params = Vec::new();
291 let mut has_self_param = false;
292 if let Some(param_list) = func.param_list() {
293 if let Some(self_param) = param_list.self_param() {
294 let self_type = match self_param.ascribed_type() {
295 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
296 None => {
297 let self_type = TypeRef::Path(name![Self].into());
298 match self_param.kind() {
299 ast::SelfParamKind::Owned => self_type,
300 ast::SelfParamKind::Ref => {
301 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
302 }
303 ast::SelfParamKind::MutRef => {
304 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
305 }
306 }
307 }
308 };
309 params.push(self_type);
310 has_self_param = true;
311 }
312 for param in param_list.params() {
313 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type());
314 params.push(type_ref);
315 }
316 }
317 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) {
318 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
319 _ => TypeRef::unit(),
320 };
321
322 let ret_type = if func.async_token().is_some() {
323 let future_impl = desugar_future_path(ret_type);
324 let ty_bound = TypeBound::Path(future_impl);
325 TypeRef::ImplTrait(vec![ty_bound])
326 } else {
327 ret_type
328 };
329
330 let ast_id = self.source_ast_id_map.ast_id(func);
331 let mut res = Function {
332 name,
333 visibility,
334 generic_params: GenericParamsId::EMPTY,
335 has_self_param,
336 is_unsafe: func.unsafe_token().is_some(),
337 params: params.into_boxed_slice(),
338 ret_type,
339 ast_id,
340 };
341 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
342
343 Some(id(self.data().functions.alloc(res)))
344 }
345
346 fn lower_type_alias(
347 &mut self,
348 type_alias: &ast::TypeAliasDef,
349 ) -> Option<FileItemTreeId<TypeAlias>> {
350 let name = type_alias.name()?.as_name();
351 let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it));
352 let visibility = self.lower_visibility(type_alias);
353 let bounds = self.lower_type_bounds(type_alias);
354 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
355 let ast_id = self.source_ast_id_map.ast_id(type_alias);
356 let res = TypeAlias {
357 name,
358 visibility,
359 bounds: bounds.into_boxed_slice(),
360 generic_params,
361 type_ref,
362 ast_id,
363 };
364 Some(id(self.data().type_aliases.alloc(res)))
365 }
366
367 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> {
368 let name = static_.name()?.as_name();
369 let type_ref = self.lower_type_ref_opt(static_.ascribed_type());
370 let visibility = self.lower_visibility(static_);
371 let mutable = static_.mut_token().is_some();
372 let ast_id = self.source_ast_id_map.ast_id(static_);
373 let res = Static { name, visibility, mutable, type_ref, ast_id };
374 Some(id(self.data().statics.alloc(res)))
375 }
376
377 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> {
378 let name = konst.name().map(|it| it.as_name());
379 let type_ref = self.lower_type_ref_opt(konst.ascribed_type());
380 let visibility = self.lower_visibility(konst);
381 let ast_id = self.source_ast_id_map.ast_id(konst);
382 let res = Const { name, visibility, type_ref, ast_id };
383 id(self.data().consts.alloc(res))
384 }
385
386 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
387 let name = module.name()?.as_name();
388 let visibility = self.lower_visibility(module);
389 let kind = if module.semicolon_token().is_some() {
390 ModKind::Outline {}
391 } else {
392 ModKind::Inline {
393 items: module
394 .item_list()
395 .map(|list| {
396 list.items()
397 .flat_map(|item| self.lower_mod_item(&item, false))
398 .flat_map(|items| items.0)
399 .collect()
400 })
401 .unwrap_or_else(|| {
402 mark::hit!(name_res_works_for_broken_modules);
403 Box::new([]) as Box<[_]>
404 }),
405 }
406 };
407 let ast_id = self.source_ast_id_map.ast_id(module);
408 let res = Mod { name, visibility, kind, ast_id };
409 Some(id(self.data().mods.alloc(res)))
410 }
411
412 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> {
413 let name = trait_def.name()?.as_name();
414 let visibility = self.lower_visibility(trait_def);
415 let generic_params =
416 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
417 let auto = trait_def.auto_token().is_some();
418 let items = trait_def.item_list().map(|list| {
419 self.with_inherited_visibility(visibility, |this| {
420 list.items()
421 .filter_map(|item| {
422 let attrs = Attrs::new(&item, &this.hygiene);
423 this.collect_inner_items(item.syntax());
424 this.lower_assoc_item(&item).map(|item| {
425 this.add_attrs(ModItem::from(item).into(), attrs);
426 item
427 })
428 })
429 .collect()
430 })
431 });
432 let ast_id = self.source_ast_id_map.ast_id(trait_def);
433 let res = Trait {
434 name,
435 visibility,
436 generic_params,
437 auto,
438 items: items.unwrap_or_default(),
439 ast_id,
440 };
441 Some(id(self.data().traits.alloc(res)))
442 }
443
444 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> {
445 let generic_params =
446 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
447 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr));
448 let target_type = self.lower_type_ref(&impl_def.target_type()?);
449 let is_negative = impl_def.excl_token().is_some();
450
451 // We cannot use `assoc_items()` here as that does not include macro calls.
452 let items = impl_def
453 .item_list()?
454 .items()
455 .filter_map(|item| {
456 self.collect_inner_items(item.syntax());
457 let assoc = self.lower_assoc_item(&item)?;
458 let attrs = Attrs::new(&item, &self.hygiene);
459 self.add_attrs(ModItem::from(assoc).into(), attrs);
460 Some(assoc)
461 })
462 .collect();
463 let ast_id = self.source_ast_id_map.ast_id(impl_def);
464 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id };
465 Some(id(self.data().impls.alloc(res)))
466 }
467
468 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
469 // FIXME: cfg_attr
470 let is_prelude = use_item.has_atom_attr("prelude_import");
471 let visibility = self.lower_visibility(use_item);
472 let ast_id = self.source_ast_id_map.ast_id(use_item);
473
474 // Every use item can expand to many `Import`s.
475 let mut imports = Vec::new();
476 let tree = self.tree.data_mut();
477 ModPath::expand_use_item(
478 InFile::new(self.file, use_item.clone()),
479 &self.hygiene,
480 |path, _tree, is_glob, alias| {
481 imports.push(id(tree.imports.alloc(Import {
482 path,
483 alias,
484 visibility,
485 is_glob,
486 is_prelude,
487 ast_id,
488 })));
489 },
490 );
491
492 imports
493 }
494
495 fn lower_extern_crate(
496 &mut self,
497 extern_crate: &ast::ExternCrateItem,
498 ) -> Option<FileItemTreeId<ExternCrate>> {
499 let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
500 let alias = extern_crate.alias().map(|a| {
501 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
502 });
503 let visibility = self.lower_visibility(extern_crate);
504 let ast_id = self.source_ast_id_map.ast_id(extern_crate);
505 // FIXME: cfg_attr
506 let is_macro_use = extern_crate.has_atom_attr("macro_use");
507
508 let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
509 Some(id(self.data().extern_crates.alloc(res)))
510 }
511
512 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
513 let name = m.name().map(|it| it.as_name());
514 let attrs = Attrs::new(m, &self.hygiene);
515 let path = ModPath::from_src(m.path()?, &self.hygiene)?;
516
517 let ast_id = self.source_ast_id_map.ast_id(m);
518
519 // FIXME: cfg_attr
520 let export_attr = attrs.by_key("macro_export");
521
522 let is_export = export_attr.exists();
523 let is_local_inner = if is_export {
524 export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
525 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
526 ident.text.contains("local_inner_macros")
527 }
528 _ => false,
529 })
530 } else {
531 false
532 };
533
534 let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
535 let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
536 Some(id(self.data().macro_calls.alloc(res)))
537 }
538
539 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
540 block.extern_item_list().map_or(Vec::new(), |list| {
541 list.extern_items()
542 .filter_map(|item| {
543 self.collect_inner_items(item.syntax());
544 let attrs = Attrs::new(&item, &self.hygiene);
545 let id: ModItem = match item {
546 ast::ExternItem::FnDef(ast) => {
547 let func = self.lower_function(&ast)?;
548 func.into()
549 }
550 ast::ExternItem::StaticDef(ast) => {
551 let statik = self.lower_static(&ast)?;
552 statik.into()
553 }
554 };
555 self.add_attrs(id.into(), attrs);
556 Some(id)
557 })
558 .collect()
559 })
560 }
561
562 /// Lowers generics defined on `node` and collects inner items defined within.
563 fn lower_generic_params_and_inner_items(
564 &mut self,
565 owner: GenericsOwner<'_>,
566 node: &impl ast::TypeParamsOwner,
567 ) -> GenericParamsId {
568 // Generics are part of item headers and may contain inner items we need to collect.
569 if let Some(params) = node.type_param_list() {
570 self.collect_inner_items(params.syntax());
571 }
572 if let Some(clause) = node.where_clause() {
573 self.collect_inner_items(clause.syntax());
574 }
575
576 self.lower_generic_params(owner, node)
577 }
578
579 fn lower_generic_params(
580 &mut self,
581 owner: GenericsOwner<'_>,
582 node: &impl ast::TypeParamsOwner,
583 ) -> GenericParamsId {
584 let mut sm = &mut ArenaMap::default();
585 let mut generics = GenericParams::default();
586 match owner {
587 GenericsOwner::Function(func) => {
588 generics.fill(&self.body_ctx, sm, node);
589 // lower `impl Trait` in arguments
590 for param in &*func.params {
591 generics.fill_implicit_impl_trait_args(param);
592 }
593 }
594 GenericsOwner::Struct
595 | GenericsOwner::Enum
596 | GenericsOwner::Union
597 | GenericsOwner::TypeAlias => {
598 generics.fill(&self.body_ctx, sm, node);
599 }
600 GenericsOwner::Trait(trait_def) => {
601 // traits get the Self type as an implicit first type parameter
602 let self_param_id = generics.types.alloc(TypeParamData {
603 name: Some(name![Self]),
604 default: None,
605 provenance: TypeParamProvenance::TraitSelf,
606 });
607 sm.insert(self_param_id, Either::Left(trait_def.clone()));
608 // add super traits as bounds on Self
609 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
610 let self_param = TypeRef::Path(name![Self].into());
611 generics.fill_bounds(&self.body_ctx, trait_def, self_param);
612
613 generics.fill(&self.body_ctx, &mut sm, node);
614 }
615 GenericsOwner::Impl => {
616 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
617 // type-parameter, but rather is a type-alias for impl's target
618 // type, so this is handled by the resolver.
619 generics.fill(&self.body_ctx, &mut sm, node);
620 }
621 }
622
623 self.data().generics.alloc(generics)
624 }
625
626 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {
627 match node.type_bound_list() {
628 Some(bound_list) => {
629 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect()
630 }
631 None => Vec::new(),
632 }
633 }
634
635 fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
636 let vis = match self.forced_visibility {
637 Some(vis) => return vis,
638 None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene),
639 };
640
641 self.data().vis.alloc(vis)
642 }
643
644 fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef {
645 TypeRef::from_ast(&self.body_ctx, type_ref.clone())
646 }
647 fn lower_type_ref_opt(&self, type_ref: Option<ast::TypeRef>) -> TypeRef {
648 type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error)
649 }
650
651 /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.
652 fn with_inherited_visibility<R>(
653 &mut self,
654 vis: RawVisibilityId,
655 f: impl FnOnce(&mut Self) -> R,
656 ) -> R {
657 let old = mem::replace(&mut self.forced_visibility, Some(vis));
658 let res = f(self);
659 self.forced_visibility = old;
660 res
661 }
662
663 fn next_field_idx(&self) -> Idx<Field> {
664 Idx::from_raw(RawId::from(
665 self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
666 ))
667 }
668 fn next_variant_idx(&self) -> Idx<Variant> {
669 Idx::from_raw(RawId::from(
670 self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
671 ))
672 }
673}
674
675fn desugar_future_path(orig: TypeRef) -> Path {
676 let path = path![core::future::Future];
677 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
678 let mut last = GenericArgs::empty();
679 let binding =
680 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
681 last.bindings.push(binding);
682 generic_args.push(Some(Arc::new(last)));