1use core::mem::{replace, take};
2
3use crate::alloc::prelude::*;
4use crate::alloc::{self, Box, VecDeque};
5use crate::ast;
6use crate::ast::Spanned;
7use crate::compile::{DynLocation, Error, ErrorKind, Location, ModId, Result, Visibility};
8use crate::grammar::{Ignore, MaybeNode, NodeAt, Remaining, Stream, StreamBuf};
9use crate::parse::Resolve;
10use crate::query::{Query, QuerySource};
11use crate::worker::{ImportKind, Task, WildcardImport};
12use crate::{ItemBuf, SourceId};
13
14use ast::Kind::*;
15
16#[derive(Debug)]
18pub(crate) enum ImportState {
19 Ast(Box<ast::ItemUse>),
20 Node(NodeAt),
21 Complete,
22}
23
24#[derive(Debug)]
26pub(crate) struct Import {
27 pub(crate) state: ImportState,
28 pub(crate) kind: ImportKind,
29 pub(crate) module: ModId,
30 pub(crate) visibility: Visibility,
31 pub(crate) item: ItemBuf,
32 pub(crate) source_id: SourceId,
33}
34
35impl Import {
36 fn lookup_local(&self, query: &Query<'_, '_>, local: &str) -> alloc::Result<ItemBuf> {
38 let item = query.pool.module_item(self.module).extended(local)?;
39
40 if let ImportKind::Local = self.kind {
41 if query.contains_prefix(&item)? {
42 return Ok(item);
43 }
44 }
45
46 if query.context.contains_crate(local) {
47 return ItemBuf::with_crate(local);
48 }
49
50 Ok(item)
51 }
52
53 pub(crate) fn process(
55 mut self,
56 q: &mut Query<'_, '_>,
57 add_task: &mut dyn FnMut(Task) -> Result<()>,
58 ) -> Result<()> {
59 let mut q = q.with_source_id(self.source_id);
60
61 match replace(&mut self.state, ImportState::Complete) {
62 ImportState::Ast(ast) => {
63 self.process_ast(&mut q, add_task, Box::into_inner(ast))?;
64 }
65 ImportState::Node(node) => {
66 if !node.parse(|p| self.process_node(&mut q, p, add_task))? {
67 self.kind = ImportKind::Local;
68 self.state = ImportState::Node(node);
69
70 if let Err(error) = add_task(Task::ExpandImport(self)) {
71 q.error(error)?;
72 }
73 }
74 }
75 ImportState::Complete => {}
76 }
77
78 Ok(())
79 }
80
81 fn process_ast(
82 mut self,
83 q: &mut Query<'_, '_>,
84 add_task: &mut dyn FnMut(Task) -> Result<()>,
85 ast: ast::ItemUse,
86 ) -> Result<()> {
87 let (name, first, initial) = match self.kind {
88 ImportKind::Global => {
89 match ast.path.global {
90 Some(global) => match &ast.path.first {
91 ast::ItemUseSegment::PathSegment(ast::PathSegment::Ident(ident)) => {
92 let ident = ident.resolve(resolve_context!(q))?;
93 (ItemBuf::with_crate(ident)?, None, false)
94 }
95 _ => {
96 return Err(Error::new(global.span(), ErrorKind::UnsupportedGlobal));
97 }
98 },
99 _ => {
101 self.kind = ImportKind::Local;
102 self.state = ImportState::Ast(Box::try_new(ast)?);
103 add_task(Task::ExpandImport(self))?;
104 return Ok(());
105 }
106 }
107 }
108 ImportKind::Local => (ItemBuf::new(), Some(&ast.path.first), true),
109 };
110
111 let mut queue = VecDeque::new();
112
113 queue.try_push_back((&ast.path, name, first, initial))?;
114
115 while let Some((path, mut name, first, mut initial)) = queue.pop_front() {
116 tracing::trace!("process one");
117
118 let mut it = first
119 .into_iter()
120 .chain(path.segments.iter().map(|(_, s)| s));
121
122 let complete = loop {
123 let segment = match it.next() {
124 Some(segment) => segment,
125 None => break None,
126 };
127
128 let initial = take(&mut initial);
131
132 match segment {
133 ast::ItemUseSegment::PathSegment(segment) => match segment {
134 ast::PathSegment::Ident(ident) => {
135 let ident = ident.resolve(resolve_context!(q))?;
136
137 if !initial {
138 name.push(ident)?;
139 continue;
140 }
141
142 name = self.lookup_local(q, ident)?;
143 }
144 ast::PathSegment::SelfType(self_type) => {
145 return Err(Error::new(
146 self_type.span(),
147 ErrorKind::ExpectedLeadingPathSegment,
148 ));
149 }
150 ast::PathSegment::SelfValue(self_value) => {
151 if !initial {
152 return Err(Error::new(
153 self_value.span(),
154 ErrorKind::ExpectedLeadingPathSegment,
155 ));
156 }
157
158 name = q.pool.module_item(self.module).try_to_owned()?;
159 }
160 ast::PathSegment::Crate(crate_token) => {
161 if !initial {
162 return Err(Error::new(
163 crate_token,
164 ErrorKind::ExpectedLeadingPathSegment,
165 ));
166 }
167
168 name = ItemBuf::new();
169 }
170 ast::PathSegment::Super(super_token) => {
171 if initial {
172 name = q.pool.module_item(self.module).try_to_owned()?;
173 }
174
175 if !name.pop() {
176 return Err(Error::new(super_token, ErrorKind::UnsupportedSuper));
177 }
178 }
179 ast::PathSegment::Generics(arguments) => {
180 return Err(Error::new(arguments, ErrorKind::UnsupportedGenerics));
181 }
182 },
183 ast::ItemUseSegment::Wildcard(star_token) => {
184 let mut wildcard_import = WildcardImport {
185 visibility: self.visibility,
186 from: self.item.try_clone()?,
187 name: name.try_clone()?,
188 location: Location::new(self.source_id, star_token.span()),
189 module: self.module,
190 found: false,
191 };
192
193 wildcard_import.process_global(q)?;
194 add_task(Task::ExpandWildcardImport(wildcard_import))?;
195 break Some(star_token.span());
196 }
197 ast::ItemUseSegment::Group(group) => {
198 for (path, _) in group {
199 if let Some(global) = &path.global {
200 return Err(Error::new(
201 global.span(),
202 ErrorKind::UnsupportedGlobal,
203 ));
204 }
205
206 queue.try_push_back((
207 path,
208 name.try_clone()?,
209 Some(&path.first),
210 initial,
211 ))?;
212 }
213
214 break Some(group.span());
215 }
216 }
217 };
218
219 if let Some(segment) = it.next() {
220 return Err(Error::new(segment, ErrorKind::IllegalUseSegment));
221 }
222
223 let alias = match &path.alias {
224 Some((_, ident)) => {
225 if let Some(span) = complete {
226 return Err(Error::new(
227 span.join(ident.span()),
228 ErrorKind::UseAliasNotSupported,
229 ));
230 }
231
232 Some(*ident)
233 }
234 None => None,
235 };
236
237 if complete.is_none() {
238 q.insert_import(
239 &DynLocation::new(self.source_id, path),
240 self.module,
241 self.visibility,
242 &self.item,
243 &name,
244 alias,
245 false,
246 )?;
247 }
248 }
249
250 Ok(())
251 }
252
253 fn process_node(
254 &self,
255 q: &mut QuerySource<'_, '_>,
256 p: &mut Stream<'_>,
257 add_task: &mut dyn FnMut(Task) -> Result<()>,
258 ) -> Result<bool> {
259 p.eat(Modifiers);
260 p.expect(K![use])?;
261
262 let global = p.eat(K![::]).span();
263
264 let (item, first, has_component) = match (&self.kind, global) {
265 (ImportKind::Global, Some(global)) => match p.peek() {
266 K![ident] => {
267 let ident = p.ast::<ast::Ident>()?;
268 let ident = ident.resolve(resolve_context!(q))?;
269 (ItemBuf::with_crate(ident)?, false, true)
270 }
271 _ => {
272 return Err(Error::new(global.span(), ErrorKind::UnsupportedGlobal));
273 }
274 },
275 (ImportKind::Global, None) => {
276 p.ignore();
279 return Ok(false);
280 }
281 _ => (ItemBuf::new(), true, false),
282 };
283
284 let mut queue = VecDeque::new();
285
286 queue.try_push_back((p.take_remaining(), item, first, has_component))?;
287
288 while let Some((p, item, first, has_component)) = queue.pop_front() {
289 tracing::trace!("process one");
290
291 let result = p.parse(|p| {
292 self.handle_import(
293 q,
294 p,
295 item,
296 first,
297 has_component,
298 add_task,
299 &mut |p, name| queue.try_push_back((p, name, false, false)),
300 )
301 });
302
303 if let Err(error) = result {
304 q.diagnostics.error(self.source_id, error)?;
305 }
306 }
307
308 Ok(true)
309 }
310
311 fn handle_import<'a>(
312 &self,
313 q: &mut QuerySource<'_, '_>,
314 p: &mut Stream<'a>,
315 mut item: ItemBuf,
316 mut first: bool,
317 mut has_component: bool,
318 add_task: &mut dyn FnMut(Task) -> Result<()>,
319 enqueue: &mut dyn FnMut(StreamBuf<'a>, ItemBuf) -> alloc::Result<()>,
320 ) -> Result<()> {
321 let complete = loop {
322 if p.is_eof() {
323 break None;
324 }
325
326 let initial = take(&mut first);
329
330 if has_component {
331 if p.peek() == K![as] {
332 break None;
333 }
334
335 p.expect(K![::])?;
336 }
337
338 match p.peek() {
339 K![ident] => {
340 let ident = p.ast::<ast::Ident>()?;
341 let ident = ident.resolve(resolve_context!(q))?;
342
343 if !initial {
344 item.push(ident)?;
345 } else {
346 item = self.lookup_local(q, ident)?;
347 }
348 }
349 K![Self] => {
350 let node = p.pump()?;
351
352 return Err(Error::new(node, ErrorKind::ExpectedLeadingPathSegment));
353 }
354 K![self] => {
355 let node = p.pump()?;
356
357 if !initial {
358 return Err(Error::new(node, ErrorKind::ExpectedLeadingPathSegment));
359 }
360
361 item = q.pool.module_item(self.module).try_to_owned()?;
362 }
363 K![crate] => {
364 let node = p.pump()?;
365
366 if !initial {
367 return Err(Error::new(node, ErrorKind::ExpectedLeadingPathSegment));
368 }
369
370 item = ItemBuf::new();
371 }
372 K![super] => {
373 let node = p.pump()?;
374
375 if initial {
376 item = q.pool.module_item(self.module).try_to_owned()?;
377 }
378
379 if !item.pop() {
380 return Err(Error::new(node, ErrorKind::UnsupportedSuper));
381 }
382 }
383 PathGenerics => {
384 let node = p.pump()?;
385 return Err(Error::new(node, ErrorKind::UnsupportedGenerics));
386 }
387 K![*] => {
388 let node = p.pump()?;
389
390 let mut wildcard_import = WildcardImport {
391 visibility: self.visibility,
392 from: self.item.try_clone()?,
393 name: item.try_clone()?,
394 location: Location::new(self.source_id, node.span()),
395 module: self.module,
396 found: false,
397 };
398
399 wildcard_import.process_global(q)?;
400
401 if let Err(error) = add_task(Task::ExpandWildcardImport(wildcard_import)) {
402 q.diagnostics.error(self.source_id, error)?;
403 }
404
405 break Some(node.span());
406 }
407 ItemUseGroup => {
408 let node = p.pump()?;
409 let group = Some(node.span());
410
411 node.parse(|p| {
412 p.expect(K!['{'])?;
413
414 let mut comma = Remaining::default();
415
416 while let MaybeNode::Some(node) = p.eat(ItemUsePath) {
417 comma.exactly_one(q)?;
418
419 node.parse(|p| {
420 if let Some(global) = p.eat(K![::]).span() {
421 return Err(Error::new(global, ErrorKind::UnsupportedGlobal));
422 }
423
424 enqueue(p.take_remaining(), item.try_clone()?)?;
425 Ok(())
426 })?;
427
428 comma = p.one(K![,]);
429 }
430
431 comma.at_most_one(q)?;
432 p.expect(K!['}'])?;
433 Ok(())
434 })?;
435
436 break group;
437 }
438 _ => {
439 return Err(Error::new(p.peek_span(), ErrorKind::IllegalUseSegment));
440 }
441 }
442
443 has_component = true;
444 };
445
446 let alias = if let MaybeNode::Some(node) = p.eat(K![as]) {
447 if complete.is_some() {
448 return Err(Error::new(node, ErrorKind::UseAliasNotSupported));
449 }
450
451 Some(p.ast::<ast::Ident>()?)
452 } else {
453 None
454 };
455
456 if let Some(span) = p.remaining_span() {
457 return Err(Error::new(span, ErrorKind::IllegalUseSegment));
458 }
459
460 if complete.is_none() {
461 q.insert_import(
462 &DynLocation::new(self.source_id, p),
463 self.module,
464 self.visibility,
465 &self.item,
466 &item,
467 alias,
468 false,
469 )?;
470 }
471
472 Ok(())
473 }
474}