1use core::mem::replace;
2
3use crate::alloc;
4use crate::alloc::prelude::*;
5use crate::ast::{self, Kind, Span, Spanned};
6use crate::compile::{
7 meta, Doc, DynLocation, Error, ErrorKind, Location, Result, Visibility, WithSpan,
8};
9use crate::grammar::{Ignore, MaybeNode, Node, NodeId, Remaining, Stream, StreamBuf};
10use crate::indexing;
11use crate::parse::Resolve;
12use crate::query::{Attrs, BuiltInLiteral, DeferEntry, ExpandMacroBuiltin, ImplItem, ImplItemKind};
13use crate::runtime::Call;
14use crate::worker::{self, Import, ImportKind, ImportState};
15
16use super::items::Guard;
17use super::{validate_call, IndexItem, Indexed, Indexer};
18
19use Kind::*;
20
21#[derive(Debug, Clone, Copy, PartialEq)]
23#[non_exhaustive]
24pub(crate) enum ExprBlockKind {
25 Default,
26 Async,
27 Const,
28}
29
30#[derive(Default, Debug)]
31enum ExprSupport {
32 Yes,
33 #[default]
34 No,
35}
36
37struct Function<'a> {
38 node: Node<'a>,
39 name: Option<ast::Ident>,
40 attrs: Attrs,
41 mods: Mods,
42}
43
44fn is_instance(node: &Node<'_>) -> alloc::Result<(bool, Vec<Span>)> {
45 fn is_self(node: Node<'_>) -> bool {
46 let Some([node]) = node.nodes::<1>() else {
47 return false;
48 };
49
50 matches!(
51 (node.kind(), node.kinds()),
52 (IndexedPath(..), Some([K![self]]))
53 )
54 }
55
56 let mut is_instance = false;
57 let mut args = Vec::new();
58
59 let Some(node) = node.find(FnArgs) else {
60 return Ok((is_instance, args));
61 };
62
63 for node in node.children() {
64 if matches!(node.kind(), Pat) {
65 args.try_push(node.span())?;
66 is_instance |= is_self(node);
67 }
68 }
69
70 Ok((is_instance, args))
71}
72
73#[derive(Debug)]
75enum State<'a> {
76 Stream(StreamBuf<'a>),
77 Expr(Mods, Attrs),
78 Block(Guard, IndexItem),
79 ConstBlock(Guard, IndexItem, Node<'a>),
80 AsyncBlock(Guard, IndexItem, Span, Option<ast::Move>),
81 Bare(IndexItem, NodeId),
82 Function(Guard, IndexItem, usize, Option<Span>, ExprSupport),
83 Module(Guard, IndexItem),
84 Closure(Guard, IndexItem, Option<ast::Async>, Option<ast::Move>),
85 Const(Guard, IndexItem, Option<Span>, Node<'a>, ExprSupport),
86}
87
88struct Processor<'a> {
89 span: Span,
90 fns: Vec<Function<'a>>,
91 stack: Vec<State<'a>>,
92 expr: ExprSupport,
93}
94
95impl<'a> Processor<'a> {
96 fn new(span: Span) -> Self {
97 Self {
98 span,
99 fns: Vec::new(),
100 stack: Vec::new(),
101 expr: ExprSupport::No,
102 }
103 }
104
105 fn with_expr(mut self, expr: ExprSupport) -> Self {
106 self.expr = expr;
107 self
108 }
109
110 fn process(mut self, idx: &mut Indexer<'_, '_>) -> Result<()> {
111 loop {
112 if let Some(State::Stream(p)) = self.stack.last_mut() {
113 let Some(node) = p.next() else {
114 self.stack.pop();
115 continue;
116 };
117
118 tracing::trace!(?node, stack = self.stack.len());
119 self.node(idx, node)?;
120 continue;
121 };
122
123 let Some(state) = self.stack.pop() else {
124 break;
125 };
126
127 tracing::trace!(?state, stack = self.stack.len());
128
129 match state {
130 State::Expr(mods, attrs) => {
131 mods.deny_all(idx)?;
132 attrs.deny_any(idx)?;
133 }
134 State::Block(guard, item) => {
135 idx.item = item;
136 idx.items.pop(guard).with_span(self.span)?;
137 }
138 State::AsyncBlock(guard, item, span, move_token) => {
139 let item_meta = idx
140 .q
141 .item_for("async block", idx.item.id)
142 .with_span(self.span)?;
143 let layer = idx.scopes.pop().with_span(self.span)?;
144 let call = validate_call(false, true, &layer)?;
145
146 if let Some(call) = call {
147 idx.q.index_meta(
148 &span,
149 item_meta,
150 meta::Kind::AsyncBlock {
151 call,
152 do_move: move_token.is_some(),
153 },
154 )?;
155 } else {
156 idx.error(Error::new(span, ErrorKind::ClosureKind))?;
157 }
158
159 idx.item = item;
160 idx.items.pop(guard).with_span(self.span)?;
161 }
162 State::ConstBlock(guard, item, node) => {
163 let item_meta = idx
164 .q
165 .item_for("const block", idx.item.id)
166 .with_span(self.span)?;
167
168 idx.q.index_const_block(
169 item_meta,
170 indexing::ConstBlock::Node(node.node_at(idx.source_id, idx.tree.clone())),
171 )?;
172
173 idx.item = item;
174 idx.items.pop(guard).with_span(self.span)?;
175 }
176 State::Closure(guard, item, async_token, move_token) => {
177 let layer = idx.scopes.pop().with_span(self.span)?;
178 let call = validate_call(false, async_token.is_some(), &layer)?;
179
180 let Some(call) = call else {
181 return Err(Error::new(self.span, ErrorKind::ClosureKind));
182 };
183
184 let item_meta = idx
185 .q
186 .item_for("closure", idx.item.id)
187 .with_span(self.span)?;
188
189 idx.q.index_meta(
190 &self.span,
191 item_meta,
192 meta::Kind::Closure {
193 call,
194 do_move: move_token.is_some(),
195 },
196 )?;
197
198 idx.item = item;
199 idx.items.pop(guard).with_span(self.span)?;
200 }
201 State::Bare(item, id) => {
202 self.bare(idx, id)?;
203
204 idx.item = item;
205 }
206 State::Function(guard, item, index, nested_item, expr) => {
207 self.function(idx, index, nested_item)?;
208
209 self.expr = expr;
210
211 idx.item = item;
212 idx.items.pop(guard).with_span(self.span)?;
213 idx.nested_item = nested_item;
214 }
215 State::Module(guard, item) => {
216 idx.item = item;
217 idx.items.pop(guard).with_span(self.span)?;
218 }
219 State::Const(guard, idx_item, nested_item, node, expr) => {
220 let item_meta = idx.q.item_for("const", idx.item.id).with_span(self.span)?;
221
222 idx.q.index_const_expr(
223 item_meta,
224 indexing::ConstExpr::Node(node.node_at(idx.source_id, idx.tree.clone())),
225 )?;
226
227 self.expr = expr;
228
229 idx.items.pop(guard).with_span(&node)?;
230 idx.item = idx_item;
231 idx.nested_item = nested_item;
232 }
233 State::Stream(..) => {}
234 }
235 }
236
237 Ok(())
238 }
239
240 fn node(&mut self, idx: &mut Indexer<'_, '_>, node: Node<'a>) -> Result<()> {
241 self.span = node.span();
242
243 match node.kind() {
244 Expr => {
245 if matches!(self.expr, ExprSupport::No) {
246 idx.error(Error::msg(
247 &node,
248 "expression is not supported during indexing",
249 ))?;
250 return Ok(());
251 }
252
253 let (mods, attrs, p) = node.parse(|p| {
254 let mods = p
255 .eat(Modifiers)
256 .parse(|p| Mods::parse(idx, p))?
257 .unwrap_or_default();
258 let attrs = attributes(idx, p)?;
259 Ok((mods, attrs, p.take_remaining()))
260 })?;
261
262 self.stack.try_push(State::Expr(mods, attrs))?;
263 self.stack.try_push(State::Stream(p))?;
264 return Ok(());
265 }
266 ExprMacroCall => {
267 let builtin;
268
269 if let [.., State::Expr(_, attrs), _] = &mut self.stack[..] {
270 builtin = attrs.builtin.take();
271 } else {
272 builtin = None;
273 }
274
275 let (literal, is_builtin) = match builtin {
276 Some((_, literal)) => (literal, true),
277 _ => (BuiltInLiteral::No, false),
278 };
279
280 let call = |id| {
281 Ok::<_, alloc::Error>(ExpandMacroBuiltin {
282 id,
283 node: node.node_at(idx.source_id, idx.tree.clone()),
284 location: Location::new(idx.source_id, node.span()),
285 root: idx.root.map(TryToOwned::try_to_owned).transpose()?,
286 macro_depth: idx.macro_depth,
287 item: idx.item,
288 literal,
289 })
290 };
291
292 let id = if is_builtin {
293 idx.q
294 .insert_new_macro(move |id| Ok(DeferEntry::ExpandMacroBuiltin(call(id)?)))
295 .with_span(self.span)?
296 } else {
297 for node in node.children() {
298 if node.kind() == Path {
299 node.replace(IndexedPath(idx.item.id));
300 }
301 }
302
303 idx.q
304 .insert_new_macro(move |id| Ok(DeferEntry::ExpandMacroCall(call(id)?)))
305 .with_span(self.span)?
306 };
307
308 node.replace(ExpandedMacro(id));
309 return Ok(());
310 }
311 ExprClosure => {
312 let async_token;
313 let move_token;
314
315 if let [.., State::Expr(mods, _), _] = &mut self.stack[..] {
316 async_token = mods.async_token.take();
317 move_token = mods.move_token.take();
318 } else {
319 async_token = None;
320 move_token = None;
321 }
322
323 let guard = idx.push_id()?;
324 idx.scopes.push()?;
325 let item_meta = idx.insert_new_item(&self.span, Visibility::Inherited, &[])?;
326 let item = idx.item.replace(item_meta.item);
327 self.stack
328 .try_push(State::Closure(guard, item, async_token, move_token))?;
329 node.replace(Closure(idx.item.id));
330 }
331 Path => {
332 node.replace(IndexedPath(idx.item.id));
333 }
334 Block => {
335 let async_token;
336 let const_token;
337 let move_token;
338
339 if let [.., State::Expr(mods, _), _] = &mut self.stack[..] {
340 async_token = mods.async_token.take();
341 const_token = mods.const_token.take();
342 move_token = mods.move_token.take();
343 } else {
344 async_token = None;
345 const_token = None;
346 move_token = None;
347 }
348
349 let guard = idx.push_id()?;
350 let item_meta = idx.insert_new_item(&self.span, Visibility::Inherited, &[])?;
351 let item = idx.item.replace(item_meta.item);
352
353 let kind = match (async_token, const_token) {
354 (Some(const_token), Some(async_token)) => {
355 idx.error(Error::new(
356 const_token.span.join(async_token.span),
357 ErrorKind::FnConstAsyncConflict,
358 ))?;
359
360 ExprBlockKind::Default
361 }
362 (Some(..), None) => ExprBlockKind::Async,
363 (None, Some(..)) => ExprBlockKind::Const,
364 _ => ExprBlockKind::Default,
365 };
366
367 match kind {
368 ExprBlockKind::Default => {
369 self.stack.try_push(State::Block(guard, item))?;
370 }
371 ExprBlockKind::Const => {
372 self.stack
373 .try_push(State::ConstBlock(guard, item, node.clone()))?;
374 node.replace(ConstBlock(idx.item.id));
375 }
376 ExprBlockKind::Async => {
377 idx.scopes.push()?;
378 self.stack.try_push(State::AsyncBlock(
379 guard,
380 item,
381 node.span(),
382 move_token,
383 ))?;
384 node.replace(AsyncBlock(idx.item.id));
385 }
386 }
387 }
388 ExprSelect | ExprAwait => {
389 let l = idx.scopes.mark().with_span(self.span)?;
390 l.awaits.try_push(node.span())?;
391 }
392 ExprYield => {
393 let l = idx.scopes.mark().with_span(self.span)?;
394 l.yields.try_push(node.span())?;
395 }
396 Item => {
397 let result = node.parse(|p| {
398 let attrs = attributes(idx, p)?;
399 p.pump()?.parse(|p| self.item(idx, p, attrs))?;
400 Ok(())
401 });
402
403 if let Err(error) = result {
404 idx.error(error)?;
405 }
406
407 return Ok(());
408 }
409 _ => {}
410 }
411
412 let mut p = node.into_stream();
413
414 if !p.is_eof() {
415 self.stack.try_push(State::Stream(p)).with_span(self.span)?;
416 }
417
418 Ok(())
419 }
420
421 fn bare(&mut self, idx: &mut Indexer<'_, '_>, id: NodeId) -> Result<()> {
422 let item_meta = idx
423 .q
424 .item_for("bare function", idx.item.id)
425 .with_span(self.span)?;
426 let layer = idx.scopes.pop().with_span(self.span)?;
427
428 let call = match (layer.awaits.is_empty(), layer.yields.is_empty()) {
429 (true, true) => Call::Immediate,
430 (false, true) => Call::Async,
431 (true, false) => Call::Generator,
432 (false, false) => Call::Stream,
433 };
434
435 idx.q.index_and_build(indexing::Entry {
436 item_meta,
437 indexed: Indexed::Function(indexing::Function {
438 ast: indexing::FunctionAst::Bare(idx.tree.node_at(idx.source_id, id)),
439 call,
440 is_instance: false,
441 is_test: false,
442 is_bench: false,
443 impl_item: None,
444 args: Vec::new(),
445 }),
446 })?;
447
448 Ok(())
449 }
450
451 fn function(
452 &mut self,
453 idx: &mut Indexer<'_, '_>,
454 index: usize,
455 nested_item: Option<Span>,
456 ) -> Result<(), Error> {
457 let Some(f) = self.fns.pop() else {
458 return Err(Error::msg(self.span, "missing function being indexed"));
459 };
460
461 if index != self.fns.len() {
462 return Err(Error::msg(self.span, "function indexing mismatch"));
463 }
464
465 let item_meta = idx
466 .q
467 .item_for("function", idx.item.id)
468 .with_span(self.span)?;
469
470 let Function {
471 node,
472 name,
473 attrs,
474 mods,
475 } = f;
476
477 self.span = node.span();
478
479 let (is_instance, args) = is_instance(&node).with_span(&node)?;
480 let layer = idx.scopes.pop().with_span(self.span)?;
481
482 if let (Some(const_token), Some(async_token)) = (mods.const_token, mods.async_token) {
483 idx.error(Error::new(
484 const_token.span.join(async_token.span),
485 ErrorKind::FnConstAsyncConflict,
486 ))?;
487 };
488
489 let call = validate_call(
490 mods.const_token.is_some(),
491 mods.async_token.is_some(),
492 &layer,
493 )?;
494
495 let Some(call) = call else {
496 idx.q.index_const_fn(
497 item_meta,
498 indexing::ConstFn::Node(node.node_at(idx.source_id, idx.tree.clone())),
499 )?;
500 return Ok(());
501 };
502
503 if let (Some(span), Some(_nested_span)) = (attrs.test, nested_item) {
504 idx.error(Error::new(
505 span,
506 ErrorKind::NestedTest {
507 #[cfg(feature = "emit")]
508 nested_span: _nested_span,
509 },
510 ))?;
511 }
512
513 if let (Some(span), Some(_nested_span)) = (attrs.bench, nested_item) {
514 idx.error(Error::new(
515 span,
516 ErrorKind::NestedBench {
517 #[cfg(feature = "emit")]
518 nested_span: _nested_span,
519 },
520 ))?;
521 }
522
523 let is_test = attrs.test.is_some();
524 let is_bench = attrs.bench.is_some();
525
526 if idx.item.impl_item.is_some() {
527 if is_test {
528 idx.error(Error::msg(
529 &node,
530 "the #[test] attribute is not supported on associated functions",
531 ))?;
532 }
533
534 if is_bench {
535 idx.error(Error::msg(
536 &node,
537 "the #[bench] attribute is not supported on associated functions",
538 ))?;
539 }
540 }
541
542 if is_instance && idx.item.impl_item.is_none() {
543 idx.error(Error::new(&node, ErrorKind::InstanceFunctionOutsideImpl))?;
544 };
545
546 let entry = indexing::Entry {
547 item_meta,
548 indexed: Indexed::Function(indexing::Function {
549 ast: indexing::FunctionAst::Node(
550 node.node_at(idx.source_id, idx.tree.clone()),
551 name,
552 ),
553 call,
554 is_instance,
555 is_test,
556 is_bench,
557 impl_item: idx.item.impl_item,
558 args,
559 }),
560 };
561
562 let is_exported = is_instance
563 || item_meta.is_public(idx.q.pool) && nested_item.is_none()
564 || is_test
565 || is_bench;
566
567 if is_exported {
568 idx.q.index_and_build(entry)?;
569 } else {
570 idx.q.index(entry)?;
571 }
572
573 Ok(())
574 }
575
576 fn item(&mut self, idx: &mut Indexer<'_, '_>, p: &mut Stream<'a>, attrs: Attrs) -> Result<()> {
577 let mods = p
578 .eat(Modifiers)
579 .parse(|p| Mods::parse(idx, p))?
580 .unwrap_or_default();
581
582 match p.kind() {
583 ItemFn => {
584 self.item_fn(idx, p, mods, attrs)?;
585 }
586 ItemMod => {
587 self.item_mod(idx, p, mods, attrs)?;
588 }
589 ItemFileMod => {
590 self.item_file_mod(idx, p, mods, attrs)?;
591 }
592 ItemImpl => {
593 item_impl(idx, p, mods, attrs)?;
594 }
595 ItemStruct => {
596 item_struct(idx, p, mods, attrs)?;
597 }
598 ItemEnum => {
599 item_enum(idx, p, mods, attrs)?;
600 }
601 ItemConst => {
602 self.item_const(idx, p, mods, attrs)?;
603 }
604 ItemUse => {
605 item_use(idx, p, mods, attrs)?;
606 }
607 _ => {
608 idx.error(p.expected("item"))?;
609 p.ignore();
610 }
611 }
612
613 Ok(())
614 }
615
616 fn item_fn(
617 &mut self,
618 idx: &mut Indexer<'_, '_>,
619 p: &mut Stream<'a>,
620 mods: Mods,
621 attrs: Attrs,
622 ) -> Result<(), Error> {
623 let expr = replace(&mut self.expr, ExprSupport::Yes);
624
625 p.expect(K![fn])?;
626
627 let (guard, name) = push_name(idx, p, "function")?;
628 let item_meta = idx.insert_new_item(&*p, mods.visibility, &attrs.docs)?;
629 let item = idx.item.replace(item_meta.item);
630 idx.scopes.push()?;
631
632 let nested_item = idx.nested_item.replace(p.span());
633 let index = self.fns.len();
634
635 self.fns.try_push(Function {
636 node: p.node(),
637 name,
638 attrs,
639 mods,
640 })?;
641
642 self.stack
643 .try_push(State::Function(guard, item, index, nested_item, expr))?;
644 self.stack.try_push(State::Stream(p.take_remaining()))?;
645 Ok(())
646 }
647
648 fn item_mod(
649 &mut self,
650 idx: &mut Indexer<'_, '_>,
651 p: &mut Stream<'a>,
652 mut mods: Mods,
653 attrs: Attrs,
654 ) -> Result<()> {
655 p.expect(K![mod])?;
656 let (guard, _) = push_name(idx, p, "module")?;
657
658 let MaybeNode::Some(node) = p.eat(Block) else {
659 idx.error(p.expected_peek(Block))?;
660 return Ok(());
661 };
662
663 let (mod_item, mod_item_id) = idx.q.insert_mod(
664 &idx.items,
665 &DynLocation::new(idx.source_id, &*p),
666 idx.item.module,
667 mods.visibility.take(),
668 &attrs.docs,
669 )?;
670
671 let item = idx.item.replace_module(mod_item, mod_item_id);
672
673 self.stack.try_push(State::Module(guard, item))?;
674 self.stack.try_push(State::Stream(node.into_stream()))?;
675
676 mods.deny_all(idx)?;
677 attrs.deny_non_docs(idx)?;
678 Ok(())
679 }
680
681 fn item_file_mod(
682 &mut self,
683 idx: &mut Indexer<'_, '_>,
684 p: &mut Stream<'_>,
685 mut mods: Mods,
686 attrs: Attrs,
687 ) -> Result<()> {
688 p.expect(K![mod])?;
689 let (guard, _) = push_name(idx, p, "module")?;
690
691 let (mod_item, mod_item_id) = idx.q.insert_mod(
692 &idx.items,
693 &DynLocation::new(idx.source_id, &*p),
694 idx.item.module,
695 mods.visibility.take(),
696 &attrs.docs,
697 )?;
698
699 idx.items.pop(guard).with_span(&*p)?;
700
701 let Some(root) = idx.root else {
702 return Err(Error::new(&*p, ErrorKind::UnsupportedModuleSource));
703 };
704
705 let source = idx
706 .q
707 .source_loader
708 .load(root, idx.q.pool.module_item(mod_item), &*p)?;
709
710 if let Some(loaded) = idx.loaded.as_mut() {
711 if let Some(_existing) = loaded.try_insert(mod_item, (idx.source_id, p.span()))? {
712 return Err(Error::new(
713 &*p,
714 ErrorKind::ModAlreadyLoaded {
715 item: idx.q.pool.module_item(mod_item).try_to_owned()?,
716 #[cfg(feature = "emit")]
717 existing: _existing,
718 },
719 ));
720 }
721 }
722
723 let source_id = idx.q.sources.insert(source)?;
724
725 idx.q
726 .visitor
727 .visit_mod(&DynLocation::new(source_id, &*p))
728 .with_span(&*p)?;
729
730 if let Some(queue) = idx.queue.as_mut() {
731 queue.try_push_back(worker::Task::LoadFile {
732 kind: worker::LoadFileKind::Module {
733 root: idx.root.map(|p| p.try_to_owned()).transpose()?,
734 },
735 source_id,
736 mod_item,
737 mod_item_id,
738 })?;
739 }
740
741 mods.deny_all(idx)?;
742 attrs.deny_non_docs(idx)?;
743 Ok(())
744 }
745
746 fn item_const(
747 &mut self,
748 idx: &mut Indexer<'_, '_>,
749 p: &mut Stream<'a>,
750 mut mods: Mods,
751 attrs: Attrs,
752 ) -> Result<()> {
753 let expr = replace(&mut self.expr, ExprSupport::Yes);
754
755 if mods.const_token.take().is_none() {
756 idx.error(Error::msg(&*p, "missing `const` modifier"))?;
757 }
758
759 let (guard, _) = push_name(idx, p, "constant")?;
760
761 p.expect(K![=])?;
762 let value = p.expect(Expr)?;
763
764 let item_meta = idx.insert_new_item(&value, mods.visibility.take(), &attrs.docs)?;
765
766 let idx_item = idx.item.replace(item_meta.item);
767 let last = idx.nested_item.replace(value.span());
768
769 self.stack
770 .try_push(State::Const(guard, idx_item, last, value.clone(), expr))?;
771
772 self.stack.try_push(State::Stream(value.into_stream()))?;
773
774 mods.deny_all(idx)?;
775 attrs.deny_non_docs(idx)?;
776 Ok(())
777 }
778}
779
780pub(crate) fn bare(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
782 let item_meta = idx.insert_new_item(p, Visibility::Public, &[])?;
783 let item = idx.item.replace(item_meta.item);
784
785 idx.scopes.push()?;
786
787 inner_attributes(idx, p)?;
788
789 let mut proc = Processor::new(p.span()).with_expr(ExprSupport::Yes);
790 proc.stack.try_push(State::Bare(item, p.id()))?;
791 proc.stack.try_push(State::Stream(p.take_remaining()))?;
792 proc.process(idx)?;
793 Ok(())
794}
795
796pub(crate) fn file(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
798 inner_attributes(idx, p)?;
799
800 let mut proc = Processor::new(p.span());
801 proc.stack.try_push(State::Stream(p.take_remaining()))?;
802 proc.process(idx)?;
803 Ok(())
804}
805
806pub(crate) fn item(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>, attrs: Attrs) -> Result<()> {
808 let mut proc = Processor::new(p.span());
809 proc.item(idx, p, attrs)?;
810 proc.process(idx)?;
811 Ok(())
812}
813
814pub(crate) fn any(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
816 let mut proc = Processor::new(p.span()).with_expr(ExprSupport::Yes);
817 proc.stack.try_push(State::Stream(p.take_remaining()))?;
818 proc.process(idx)?;
819 Ok(())
820}
821
822fn item_impl(
823 idx: &mut Indexer<'_, '_>,
824 p: &mut Stream<'_>,
825 mods: Mods,
826 attrs: Attrs,
827) -> Result<()> {
828 p.expect(K![impl])?;
829
830 let MaybeNode::Some(node) = p.eat(Path) else {
831 idx.error(p.expected_peek(Path))?;
832 return Ok(());
833 };
834
835 node.replace(IndexedPath(idx.item.id));
836
837 let mut functions = Vec::new();
838
839 p.eat(Block).parse(|p| {
840 p.eat(K!['{']);
841
842 p.expect(BlockBody)?.parse(|p| {
843 while let MaybeNode::Some(item) = p.eat(Item) {
844 item.parse(|p| {
845 let attrs = attributes(idx, p)?;
846
847 p.pump()?.parse(|p| {
848 let mods = p
849 .eat(Modifiers)
850 .parse(|p| Mods::parse(idx, p))?
851 .unwrap_or_default();
852
853 mods.deny_all(idx)?;
854
855 match p.kind() {
856 ItemFn => {
857 functions.try_push((p.id(), attrs)).with_span(&*p)?;
858 p.ignore();
859 }
860 _ => {
861 idx.error(p.expected(ItemFn)).with_span(&*p)?;
862 }
863 }
864
865 Ok(())
866 })?;
867
868 Ok(())
869 })?;
870 }
871
872 Ok(())
873 })?;
874
875 p.eat(K!['}']);
876 Ok(())
877 })?;
878
879 let location = Location::new(idx.source_id, p.span());
880
881 idx.q
882 .inner
883 .defer_queue
884 .try_push_back(DeferEntry::ImplItem(ImplItem {
885 kind: ImplItemKind::Node {
886 path: node.node_at(idx.source_id, idx.tree.clone()),
887 functions,
888 },
889 location,
890 root: idx.root.map(TryToOwned::try_to_owned).transpose()?,
891 nested_item: idx.nested_item,
892 macro_depth: idx.macro_depth,
893 }))?;
894
895 mods.deny_all(idx)?;
896 attrs.deny_non_docs(idx)?;
897 Ok(())
898}
899
900fn item_struct(
901 idx: &mut Indexer<'_, '_>,
902 p: &mut Stream<'_>,
903 mut mods: Mods,
904 attrs: Attrs,
905) -> Result<()> {
906 p.expect(K![struct])?;
907 let (guard, _) = push_name(idx, p, "struct")?;
908
909 let item_meta = idx.insert_new_item(&*p, mods.visibility.take(), &attrs.docs)?;
910
911 let fields = p.pump()?.parse(|p| fields(idx, p))?;
912
913 idx.q.index_struct(item_meta, indexing::Struct { fields })?;
914
915 idx.items.pop(guard).with_span(&*p)?;
916
917 mods.deny_all(idx)?;
918 attrs.deny_non_docs(idx)?;
919 Ok(())
920}
921
922fn item_enum(
923 idx: &mut Indexer<'_, '_>,
924 p: &mut Stream<'_>,
925 mut mods: Mods,
926 attrs: Attrs,
927) -> Result<()> {
928 p.expect(K![enum])?;
929 let (guard, _) = push_name(idx, p, "enum")?;
930
931 let vis = mods.visibility.take();
932
933 let enum_item_meta = idx.insert_new_item(&*p, vis, &attrs.docs)?;
934
935 idx.q.index_enum(enum_item_meta)?;
936
937 p.eat(K!['{']);
938
939 let mut comma = Remaining::default();
940
941 while let MaybeNode::Some(node) = p.eat(Variant) {
942 comma.at_most_one(idx)?;
943
944 let (item_meta, fields, attrs) = node.parse(|p| {
945 let attrs = attributes(idx, p)?;
946
947 let (guard, _) = push_name(idx, p, "variant")?;
948 let item_meta = idx.insert_new_item(&*p, vis, &attrs.docs)?;
949 let fields = p.pump()?.parse(|p| fields(idx, p))?;
950 idx.items.pop(guard).with_span(&*p)?;
951
952 Ok((item_meta, fields, attrs))
953 })?;
954
955 attrs.deny_non_docs(idx)?;
956
957 let variant = indexing::Variant {
958 enum_id: enum_item_meta.item,
959 fields,
960 };
961
962 idx.q.index_variant(item_meta, variant)?;
963
964 comma = p.remaining(idx, K![,])?;
965 }
966
967 comma.at_most_one(idx)?;
968 p.eat(K!['}']);
969 idx.items.pop(guard).with_span(&*p)?;
970
971 mods.deny_all(idx)?;
972 attrs.deny_non_docs(idx)?;
973 Ok(())
974}
975
976fn item_use(
977 idx: &mut Indexer<'_, '_>,
978 p: &mut Stream<'_>,
979 mut mods: Mods,
980 attrs: Attrs,
981) -> Result<()> {
982 let import = Import {
983 state: ImportState::Node(p.node().node_at(idx.source_id, idx.tree.clone())),
984 kind: ImportKind::Global,
985 visibility: mods.visibility.take(),
986 module: idx.item.module,
987 item: idx.items.item().try_to_owned()?,
988 source_id: idx.source_id,
989 };
990
991 let span = p.span();
992
993 import.process(&mut idx.q, &mut |task| {
994 let Some(queue) = &mut idx.queue else {
995 return Err(Error::msg(
996 span,
997 "deferred imports are not supported in this context",
998 ));
999 };
1000
1001 queue.try_push_back(task)?;
1002 Ok(())
1003 })?;
1004
1005 p.ignore();
1008
1009 mods.deny_all(idx)?;
1010 attrs.deny_any(idx)?;
1011 Ok(())
1012}
1013
1014fn push_name(
1015 idx: &mut Indexer<'_, '_>,
1016 p: &mut Stream<'_>,
1017 what: &'static str,
1018) -> Result<(Guard, Option<ast::Ident>)> {
1019 let (guard, ident) = if let Some(ident) = p.try_ast::<ast::Ident>()? {
1020 let name = ident.resolve(resolve_context!(idx.q))?;
1021 (idx.items.push_name(name.as_ref())?, Some(ident))
1022 } else {
1023 idx.error(Error::msg(
1024 p.peek_span().head(),
1025 try_format!("expected {what} name"),
1026 ))?;
1027 (idx.push_id()?, None)
1028 };
1029
1030 Ok((guard, ident))
1031}
1032
1033fn attributes(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<Attrs> {
1034 let mut attrs = Attrs::default();
1035
1036 while let MaybeNode::Some(node) = p.eat(Attribute) {
1037 node.parse(|p| {
1038 let span = p.span();
1039
1040 p.all([K![#], K!['[']])?;
1041
1042 p.expect(TokenStream)?.parse(|p| {
1043 let ident = p.ast::<ast::Ident>()?;
1044
1045 match ident.resolve(resolve_context!(idx.q))? {
1046 "test" => {
1047 if attrs.bench.is_some() {
1048 idx.error(Error::msg(ident.span, "duplicate #[test] attribute"))?;
1049 } else {
1050 attrs.test = Some(ident.span);
1051 }
1052 }
1053 "bench" => {
1054 if attrs.bench.is_some() {
1055 idx.error(Error::msg(ident.span, "duplicate #[bench] attribute"))?;
1056 } else {
1057 attrs.bench = Some(ident.span);
1058 }
1059 }
1060 "doc" => {
1061 p.expect(K![=])?;
1062 let doc_string = p.ast::<ast::LitStr>()?;
1063 attrs
1064 .docs
1065 .try_push(Doc { span, doc_string })
1066 .with_span(&*p)?;
1067 }
1068 "builtin" => {
1069 let mut literal = BuiltInLiteral::No;
1070
1071 if p.eat(K!['(']).is_some() {
1072 while matches!(p.peek(), K![ident]) {
1073 let ident = p.ast::<ast::Ident>()?;
1074
1075 match ident.resolve(resolve_context!(idx.q))? {
1076 "literal" => {
1077 literal = BuiltInLiteral::Yes(ident.span());
1078 }
1079 other => {
1080 idx.error(Error::msg(
1081 ident,
1082 try_format!("unsupported builtin option `{other}`"),
1083 ))?;
1084 }
1085 }
1086
1087 p.remaining(idx, K![,])?.ignore(idx)?;
1088 }
1089
1090 p.expect(K![')'])?;
1091 }
1092
1093 if attrs.builtin.is_some() {
1094 idx.error(Error::msg(ident.span, "duplicate #[builtin] attribute"))?;
1095 } else {
1096 attrs.builtin = Some((ident.span, literal));
1097 }
1098 }
1099 name => {
1100 idx.error(Error::msg(
1101 ident,
1102 try_format!("unsupported attribute `{name}`"),
1103 ))?;
1104 }
1105 }
1106
1107 Ok(())
1108 })?;
1109
1110 p.expect(K![']'])?;
1111 Ok(())
1112 })?;
1113 }
1114
1115 Ok(attrs)
1116}
1117
1118fn inner_attributes(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
1119 while let MaybeNode::Some(node) = p.eat(InnerAttribute) {
1120 node.parse(|p| {
1121 p.all([K![#], K![!], K!['[']])?;
1122
1123 p.expect(TokenStream)?.parse(|p| {
1124 let ident = p.ast::<ast::Ident>()?;
1125
1126 match ident.resolve(resolve_context!(idx.q))? {
1127 "doc" => {
1128 p.expect(K![=])?;
1129
1130 let str = p.ast::<ast::LitStr>()?;
1131 let str = str.resolve(resolve_context!(idx.q))?;
1132
1133 let loc = DynLocation::new(idx.source_id, &*p);
1134
1135 let item = idx.q.pool.item(idx.item.id);
1136 let hash = idx.q.pool.item_type_hash(idx.item.id);
1137
1138 idx.q
1139 .visitor
1140 .visit_doc_comment(&loc, item, hash, &str)
1141 .with_span(&*p)?;
1142 }
1143 name => {
1144 idx.error(Error::msg(
1145 ident,
1146 try_format!("unsupported attribute `{name}`"),
1147 ))?;
1148 }
1149 }
1150
1151 Ok(())
1152 })?;
1153
1154 p.expect(K![']'])?;
1155 Ok(())
1156 })?;
1157 }
1158
1159 Ok(())
1160}
1161
1162fn fields(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<meta::Fields> {
1163 match p.kind() {
1164 StructBody => {
1165 p.one(K!['{']).exactly_one(idx)?;
1166 let mut fields = Vec::new();
1167 let mut comma = Remaining::default();
1168
1169 while let MaybeNode::Some(field) = p.eat(Field) {
1170 comma.exactly_one(idx)?;
1171 let name = field.parse(|p| p.ast::<ast::Ident>())?;
1172 let name = name.resolve(resolve_context!(idx.q))?;
1173 let position = fields.len();
1174 fields.try_push(meta::FieldMeta {
1175 name: name.try_into()?,
1176 position,
1177 })?;
1178 comma = p.remaining(idx, K![,])?;
1179 }
1180
1181 comma.at_most_one(idx)?;
1182 p.one(K!['}']).exactly_one(idx)?;
1183 Ok(meta::Fields::Named(meta::FieldsNamed {
1184 fields: fields.try_into()?,
1185 }))
1186 }
1187 TupleBody => {
1188 p.one(K!['(']).exactly_one(idx)?;
1189 let mut count = 0;
1190 let mut comma = Remaining::default();
1191
1192 while p.eat(Field).is_some() {
1193 comma.exactly_one(idx)?;
1194 count += 1;
1195 comma = p.remaining(idx, K![,])?;
1196 }
1197
1198 comma.at_most_one(idx)?;
1199 p.one(K![')']).exactly_one(idx)?;
1200 Ok(meta::Fields::Unnamed(count))
1201 }
1202 EmptyBody => Ok(meta::Fields::Empty),
1203 _ => {
1204 idx.error(p.expected("struct body"))?;
1205 Ok(meta::Fields::Empty)
1206 }
1207 }
1208}
1209
1210#[derive(Default, Debug)]
1211struct Mods {
1212 span: Span,
1213 visibility: Visibility,
1214 const_token: Option<ast::Const>,
1215 async_token: Option<ast::Async>,
1216 move_token: Option<ast::Move>,
1217}
1218
1219impl Mods {
1220 fn parse(cx: &mut dyn Ignore<'_>, p: &mut Stream<'_>) -> Result<Mods> {
1222 let mut mods = Mods {
1223 span: p.span().head(),
1224 visibility: Visibility::Inherited,
1225 const_token: None,
1226 async_token: None,
1227 move_token: None,
1228 };
1229
1230 loop {
1231 match p.peek() {
1232 K![pub] => {
1233 mods.visibility = Visibility::Public;
1234 }
1235 ModifierSelf if mods.visibility == Visibility::Public => {
1236 mods.visibility = Visibility::SelfValue;
1237 }
1238 ModifierSuper if mods.visibility == Visibility::Public => {
1239 mods.visibility = Visibility::Super;
1240 }
1241 ModifierCrate if mods.visibility == Visibility::Public => {
1242 mods.visibility = Visibility::Crate;
1243 }
1244 _ => {
1245 break;
1246 }
1247 }
1248
1249 mods.span = mods.span.join(p.pump()?.span());
1250 }
1251
1252 while let Some(tok) = p.try_ast::<ast::Const>()? {
1253 if mods.const_token.is_some() {
1254 cx.error(Error::msg(tok, "duplicate `const` modifier"))?;
1255 } else {
1256 mods.const_token = Some(tok);
1257 }
1258 }
1259
1260 while let Some(tok) = p.try_ast::<ast::Async>()? {
1261 if mods.async_token.is_some() {
1262 cx.error(Error::msg(tok, "duplicate `async` modifier"))?;
1263 } else {
1264 mods.async_token = Some(tok);
1265 }
1266 }
1267
1268 while let Some(tok) = p.try_ast::<ast::Move>()? {
1269 if mods.move_token.is_some() {
1270 cx.error(Error::msg(tok, "duplicate `move` modifier"))?;
1271 } else {
1272 mods.move_token = Some(tok);
1273 }
1274 }
1275
1276 Ok(mods)
1277 }
1278
1279 fn deny_all(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
1281 if !matches!(self.visibility, Visibility::Inherited) {
1282 cx.error(Error::msg(self.span, "unsupported visibility modifier"))?;
1283 }
1284
1285 if let Some(span) = self.const_token {
1286 cx.error(Error::msg(span, "unsupported `const` modifier"))?;
1287 }
1288
1289 if let Some(span) = self.async_token {
1290 cx.error(Error::msg(span, "unsupported `async` modifier"))?;
1291 }
1292
1293 Ok(())
1294 }
1295}