1use core::mem::take;
2
3use tracing::instrument_ast;
4
5use crate::alloc::prelude::*;
6use crate::alloc::VecDeque;
7use crate::ast::{self, OptionSpanned, Spanned};
8use crate::compile::{
9 self, attrs, meta, Doc, DynLocation, ErrorKind, ItemMeta, Location, Visibility, WithSpan,
10};
11use crate::indexing::{self, Indexed};
12use crate::parse::{Resolve, ResolveContext};
13use crate::query::{DeferEntry, ImplItem, ImplItemKind};
14use crate::runtime::Call;
15use crate::worker::{Import, ImportKind, ImportState};
16
17use super::{ast_to_visibility, validate_call, Indexer};
18
19const MAX_MACRO_RECURSION: usize = 64;
21
22pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::Result<()> {
24 let mut p = attrs::Parser::new(&ast.attributes)?;
25
26 for doc in p.parse_all::<attrs::Doc>(resolve_context!(idx.q), &ast.attributes)? {
28 let (span, doc) = doc?;
29
30 let doc_string = doc.doc_string.resolve(resolve_context!(idx.q))?;
31
32 idx.q
33 .visitor
34 .visit_doc_comment(
35 &DynLocation::new(idx.source_id, &span),
36 idx.q.pool.module_item(idx.item.module),
37 idx.q.pool.module_item_hash(idx.item.module),
38 &doc_string,
39 )
40 .with_span(span)?;
41 }
42
43 if let Some(first) = p.remaining(&ast.attributes).next() {
44 return Err(compile::Error::msg(
45 first,
46 "File attributes are not supported",
47 ));
48 }
49
50 let mut head = VecDeque::new();
52
53 let mut queue = VecDeque::new();
56
57 for (item, semi) in ast.items.drain(..) {
58 match item {
59 i @ ast::Item::MacroCall(_) => {
60 queue.try_push_back((0, i, Vec::new(), semi))?;
61 }
62 i if !i.attributes().is_empty() => {
63 queue.try_push_back((0, i, Vec::new(), semi))?;
64 }
65 i => {
66 head.try_push_back((i, semi))?;
67 }
68 }
69 }
70
71 'uses: while !head.is_empty() || !queue.is_empty() {
72 while let Some((i, semi)) = head.pop_front() {
73 if let Some(semi) = semi {
74 if !i.needs_semi_colon() {
75 idx.q
76 .diagnostics
77 .unnecessary_semi_colon(idx.source_id, &semi)?;
78 }
79 }
80
81 item(idx, i)?;
82 }
83
84 while let Some((depth, mut item, mut skipped_attributes, semi)) = queue.pop_front() {
85 if depth >= MAX_MACRO_RECURSION {
86 return Err(compile::Error::new(
87 &item,
88 ErrorKind::MaxMacroRecursion {
89 depth,
90 max: MAX_MACRO_RECURSION,
91 },
92 ));
93 }
94
95 if let Some(mut attr) = item.remove_first_attribute() {
100 let Some(file) = idx.expand_attribute_macro::<ast::File>(&mut attr, &item)? else {
101 skipped_attributes.try_push(attr)?;
102
103 if !matches!(item, ast::Item::MacroCall(_)) && item.attributes().is_empty() {
104 *item.attributes_mut() = skipped_attributes;
107 head.try_push_front((item, semi))?;
108 } else {
109 queue.try_push_back((depth, item, skipped_attributes, semi))?;
112 }
113
114 continue;
115 };
116
117 for (item, semi) in file.items.into_iter().rev() {
118 match item {
119 item @ ast::Item::MacroCall(_) => {
120 queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?;
121 }
122 item if !item.attributes().is_empty() => {
123 queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?;
124 }
125 item => {
126 head.try_push_front((item, semi))?;
127 }
128 }
129 }
130
131 continue;
132 }
133
134 let ast::Item::MacroCall(mut macro_call) = item else {
135 return Err(compile::Error::msg(
136 &item,
137 "Expected attributes on macro call",
138 ));
139 };
140
141 macro_call.attributes = skipped_attributes;
142
143 let mut p = attrs::Parser::new(¯o_call.attributes)?;
144
145 if idx.try_expand_internal_macro(&mut p, &mut macro_call)? {
146 if let Some(attr) = p.remaining(¯o_call.attributes).next() {
147 return Err(compile::Error::msg(
148 attr,
149 "Attributes on macros are not supported",
150 ));
151 }
152
153 ast.items
155 .try_push((ast::Item::MacroCall(macro_call), semi))?;
156 } else {
157 if let Some(attr) = p.remaining(¯o_call.attributes).next() {
158 return Err(compile::Error::msg(
159 attr,
160 "Attributes on macros are not supported",
161 ));
162 }
163
164 let file = idx.expand_macro::<ast::File>(&mut macro_call)?;
165
166 for (item, semi) in file.items.into_iter().rev() {
167 match item {
168 item @ ast::Item::MacroCall(_) => {
169 queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?;
170 }
171 item if !item.attributes().is_empty() => {
172 queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?;
173 }
174 item => {
175 head.try_push_front((item, semi))?;
176 }
177 }
178 }
179 }
180
181 if !head.is_empty() {
182 continue 'uses;
183 }
184 }
185 }
186
187 Ok(())
188}
189
190#[instrument_ast(span = span)]
191pub(crate) fn empty_block_fn(
192 idx: &mut Indexer<'_, '_>,
193 mut ast: ast::EmptyBlock,
194 span: &dyn Spanned,
195) -> compile::Result<()> {
196 let item_meta = idx.insert_new_item(span, Visibility::Public, &[])?;
197 let idx_item = idx.item.replace(item_meta.item);
198
199 idx.scopes.push()?;
200
201 statements(idx, &mut ast.statements)?;
202
203 idx.item = idx_item;
204
205 let layer = idx.scopes.pop().with_span(span)?;
206
207 let call = match (layer.awaits.is_empty(), layer.yields.is_empty()) {
208 (true, true) => Call::Immediate,
209 (false, true) => Call::Async,
210 (true, false) => Call::Generator,
211 (false, false) => Call::Stream,
212 };
213
214 idx.q.index_and_build(indexing::Entry {
215 item_meta,
216 indexed: Indexed::Function(indexing::Function {
217 ast: indexing::FunctionAst::Empty(Box::try_new(ast)?, span.span()),
218 call,
219 is_instance: false,
220 is_test: false,
221 is_bench: false,
222 impl_item: None,
223 args: Vec::new(),
224 }),
225 })?;
226
227 Ok(())
228}
229
230#[instrument_ast(span = ast)]
231pub(crate) fn item_fn(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemFn) -> compile::Result<()> {
232 let name = ast.name.resolve(resolve_context!(idx.q))?;
233
234 let visibility = ast_to_visibility(&ast.visibility)?;
235
236 let mut p = attrs::Parser::new(&ast.attributes)?;
237
238 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?;
239
240 let guard = idx.items.push_name(name.as_ref())?;
241 let item_meta = idx.insert_new_item(&ast, visibility, &docs)?;
242 let idx_item = idx.item.replace(item_meta.item);
243
244 for (arg, _) in &mut ast.args {
245 if let ast::FnArg::Pat(p) = arg {
246 pat(idx, p)?;
247 }
248 }
249
250 idx.scopes.push()?;
251
252 let last = idx.nested_item.replace(ast.descriptive_span());
254 block(idx, &mut ast.body)?;
255 idx.nested_item = last;
256
257 idx.item = idx_item;
258 idx.items.pop(guard).with_span(&ast)?;
259
260 let layer = idx.scopes.pop().with_span(&ast)?;
261
262 if let (Some(const_token), Some(async_token)) = (ast.const_token, ast.async_token) {
263 return Err(compile::Error::new(
264 const_token.span().join(async_token.span()),
265 ErrorKind::FnConstAsyncConflict,
266 ));
267 };
268
269 let call = validate_call(ast.const_token.is_some(), ast.async_token.is_some(), &layer)?;
270
271 let Some(call) = call else {
272 idx.q
273 .index_const_fn(item_meta, indexing::ConstFn::Ast(Box::try_new(ast)?))?;
274 return Ok(());
275 };
276
277 let is_test = match p.try_parse::<attrs::Test>(resolve_context!(idx.q), &ast.attributes)? {
278 Some((attr, _)) => {
279 if let Some(_nested_span) = idx.nested_item {
280 return Err(compile::Error::new(
281 attr,
282 ErrorKind::NestedTest {
283 #[cfg(feature = "emit")]
284 nested_span: _nested_span,
285 },
286 ));
287 }
288
289 true
290 }
291 _ => false,
292 };
293
294 let is_bench = match p.try_parse::<attrs::Bench>(resolve_context!(idx.q), &ast.attributes)? {
295 Some((attr, _)) => {
296 if let Some(_nested_span) = idx.nested_item {
297 let span = attr.span().join(ast.descriptive_span());
298
299 return Err(compile::Error::new(
300 span,
301 ErrorKind::NestedBench {
302 #[cfg(feature = "emit")]
303 nested_span: _nested_span,
304 },
305 ));
306 }
307
308 true
309 }
310 _ => false,
311 };
312
313 if let Some(attrs) = p.remaining(&ast.attributes).next() {
314 return Err(compile::Error::msg(
315 attrs,
316 "Attributes on functions are not supported",
317 ));
318 }
319
320 if ast.output.is_some() {
321 return Err(compile::Error::msg(
322 &ast,
323 "Adding a return type in functions is not supported",
324 ));
325 }
326
327 let is_instance = ast.is_instance();
328
329 if is_instance {
330 if is_test {
331 return Err(compile::Error::msg(
332 &ast,
333 "The #[test] attribute is not supported on functions receiving `self`",
334 ));
335 }
336
337 if is_bench {
338 return Err(compile::Error::msg(
339 &ast,
340 "The #[bench] attribute is not supported on functions receiving `self`",
341 ));
342 }
343
344 if idx.item.impl_item.is_none() {
345 return Err(compile::Error::new(
346 &ast,
347 ErrorKind::InstanceFunctionOutsideImpl,
348 ));
349 };
350 }
351
352 let name = ast.name;
353 let args = ast.args.iter().map(|(a, _)| a.span()).try_collect()?;
354
355 let entry = indexing::Entry {
356 item_meta,
357 indexed: Indexed::Function(indexing::Function {
358 ast: indexing::FunctionAst::Item(Box::try_new(ast)?, name),
359 call,
360 is_instance,
361 is_test,
362 is_bench,
363 impl_item: idx.item.impl_item,
364 args,
365 }),
366 };
367
368 let is_exported = is_instance
372 || item_meta.is_public(idx.q.pool) && idx.nested_item.is_none()
373 || is_test
374 || is_bench;
375
376 if is_exported {
377 idx.q.index_and_build(entry)?;
378 } else {
379 idx.q.index(entry)?;
380 }
381
382 Ok(())
383}
384
385#[instrument_ast(span = ast)]
386fn expr_block(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprBlock) -> compile::Result<()> {
387 if let Some(span) = ast.attributes.option_span() {
388 return Err(compile::Error::msg(
389 span,
390 "Attributes on blocks are not supported",
391 ));
392 }
393
394 if ast.async_token.is_none() && ast.const_token.is_none() {
395 if let Some(span) = ast.move_token.option_span() {
396 return Err(compile::Error::msg(
397 span,
398 "The `move` modifier on blocks is not supported",
399 ));
400 }
401
402 block(idx, &mut ast.block)?;
403 return Ok(());
404 }
405
406 if ast.const_token.is_some() {
407 if let Some(async_token) = ast.async_token {
408 return Err(compile::Error::new(
409 async_token,
410 ErrorKind::BlockConstAsyncConflict,
411 ));
412 }
413
414 let item_meta = block(idx, &mut ast.block)?;
415 ast.block.id = item_meta.item;
416 idx.q.index_const_block(
417 item_meta,
418 indexing::ConstBlock::Ast(Box::try_new(ast.block.try_clone()?)?),
419 )?;
420 } else {
421 idx.scopes.push()?;
422 let item_meta = block(idx, &mut ast.block)?;
423 let layer = idx.scopes.pop().with_span(&ast)?;
424
425 let call = validate_call(ast.const_token.is_some(), ast.async_token.is_some(), &layer)?;
426
427 let Some(call) = call else {
428 return Err(compile::Error::new(ast, ErrorKind::ClosureKind));
429 };
430
431 ast.block.id = item_meta.item;
432 idx.q.index_meta(
433 &*ast,
434 item_meta,
435 meta::Kind::AsyncBlock {
436 call,
437 do_move: ast.move_token.is_some(),
438 },
439 )?;
440 }
441
442 Ok(())
443}
444
445fn statements(idx: &mut Indexer<'_, '_>, ast: &mut Vec<ast::Stmt>) -> compile::Result<()> {
446 let mut statements = Vec::new();
447
448 for stmt in ast.drain(..) {
449 match stmt {
450 ast::Stmt::Item(i, semi) => {
451 if let Some(semi) = semi {
452 if !i.needs_semi_colon() {
453 idx.q
454 .diagnostics
455 .unnecessary_semi_colon(idx.source_id, &semi)?;
456 }
457 }
458
459 item(idx, i)?;
460 }
461 stmt => {
462 statements.try_push(stmt)?;
463 }
464 }
465 }
466
467 let mut must_be_last = None;
468
469 for stmt in &mut statements {
470 if let Some(span) = must_be_last {
471 return Err(compile::Error::new(
472 span,
473 ErrorKind::ExpectedBlockSemiColon {
474 #[cfg(feature = "emit")]
475 followed_span: stmt.span(),
476 },
477 ));
478 }
479
480 match stmt {
481 ast::Stmt::Local(l) => {
482 local(idx, l)?;
483 }
484 ast::Stmt::Expr(e) => {
485 if e.needs_semi() {
486 must_be_last = Some(e.span());
487 }
488
489 expr(idx, e)?;
490 }
491 ast::Stmt::Semi(semi) => {
492 if !semi.needs_semi() {
493 idx.q
494 .diagnostics
495 .unnecessary_semi_colon(idx.source_id, semi)?;
496 }
497
498 expr(idx, &mut semi.expr)?;
499 }
500 ast::Stmt::Item(i, ..) => {
501 return Err(compile::Error::msg(i, "Unexpected item in this stage"));
502 }
503 }
504 }
505
506 *ast = statements;
507 Ok(())
508}
509
510#[instrument_ast(span = ast)]
511fn block(idx: &mut Indexer<'_, '_>, ast: &mut ast::Block) -> compile::Result<ItemMeta> {
512 let guard = idx.push_id()?;
513
514 let item_meta = idx.insert_new_item(&ast, Visibility::Inherited, &[])?;
515 let idx_item = idx.item.replace(item_meta.item);
516
517 statements(idx, &mut ast.statements)?;
518 idx.item = idx_item;
519 idx.items.pop(guard).with_span(&ast)?;
520 Ok(item_meta)
521}
522
523#[instrument_ast(span = ast)]
524fn local(idx: &mut Indexer<'_, '_>, ast: &mut ast::Local) -> compile::Result<()> {
525 if let Some(span) = ast.attributes.option_span() {
526 return Err(compile::Error::msg(
527 span,
528 "Attributes on local declarations are not supported",
529 ));
530 }
531
532 if let Some(mut_token) = ast.mut_token {
533 return Err(compile::Error::new(mut_token, ErrorKind::UnsupportedMut));
534 }
535
536 expr(idx, &mut ast.expr)?;
539 pat(idx, &mut ast.pat)?;
540 Ok(())
541}
542
543#[instrument_ast(span = ast)]
544fn expr_let(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprLet) -> compile::Result<()> {
545 if let Some(mut_token) = ast.mut_token {
546 return Err(compile::Error::new(mut_token, ErrorKind::UnsupportedMut));
547 }
548
549 pat(idx, &mut ast.pat)?;
550 expr(idx, &mut ast.expr)?;
551 Ok(())
552}
553
554#[instrument_ast(span = ast)]
555fn pat(idx: &mut Indexer<'_, '_>, ast: &mut ast::Pat) -> compile::Result<()> {
556 match ast {
557 ast::Pat::Path(pat) => {
558 path(idx, &mut pat.path)?;
559 }
560 ast::Pat::Object(pat) => {
561 pat_object(idx, pat)?;
562 }
563 ast::Pat::Vec(pat) => {
564 pat_vec(idx, pat)?;
565 }
566 ast::Pat::Tuple(pat) => {
567 pat_tuple(idx, pat)?;
568 }
569 ast::Pat::Binding(pat) => {
570 pat_binding(idx, pat)?;
571 }
572 ast::Pat::Ignore(..) => (),
573 ast::Pat::Lit(..) => (),
574 ast::Pat::Rest(..) => (),
575 }
576
577 Ok(())
578}
579
580#[instrument_ast(span = ast)]
581fn pat_tuple(idx: &mut Indexer<'_, '_>, ast: &mut ast::PatTuple) -> compile::Result<()> {
582 if let Some(p) = &mut ast.path {
583 path(idx, p)?;
584 }
585
586 for (p, _) in &mut ast.items {
587 pat(idx, p)?;
588 }
589
590 Ok(())
591}
592
593#[instrument_ast(span = ast)]
594fn pat_object(idx: &mut Indexer<'_, '_>, ast: &mut ast::PatObject) -> compile::Result<()> {
595 match &mut ast.ident {
596 ast::ObjectIdent::Anonymous(..) => (),
597 ast::ObjectIdent::Named(p) => {
598 path(idx, p)?;
599 }
600 }
601
602 for (p, _) in &mut ast.items {
603 pat(idx, p)?;
604 }
605
606 Ok(())
607}
608
609#[instrument_ast(span = ast)]
610fn pat_vec(idx: &mut Indexer<'_, '_>, ast: &mut ast::PatVec) -> compile::Result<()> {
611 for (p, _) in &mut ast.items {
612 pat(idx, p)?;
613 }
614
615 Ok(())
616}
617
618#[instrument_ast(span = ast)]
619fn pat_binding(idx: &mut Indexer<'_, '_>, ast: &mut ast::PatBinding) -> compile::Result<()> {
620 pat(idx, &mut ast.pat)?;
621 Ok(())
622}
623
624#[instrument_ast(span = ast)]
625pub(crate) fn expr(idx: &mut Indexer<'_, '_>, ast: &mut ast::Expr) -> compile::Result<()> {
626 match ast {
627 ast::Expr::Path(ast) => {
628 path(idx, ast)?;
629 }
630 ast::Expr::Let(ast) => {
631 expr_let(idx, ast)?;
632 }
633 ast::Expr::Block(ast) => {
634 expr_block(idx, ast)?;
635 }
636 ast::Expr::Group(ast) => {
637 expr(idx, &mut ast.expr)?;
638 }
639 ast::Expr::Empty(ast) => {
640 expr(idx, &mut ast.expr)?;
641 }
642 ast::Expr::If(ast) => {
643 expr_if(idx, ast)?;
644 }
645 ast::Expr::Assign(ast) => {
646 expr_assign(idx, ast)?;
647 }
648 ast::Expr::Binary(ast) => {
649 expr_binary(idx, ast)?;
650 }
651 ast::Expr::Match(ast) => {
652 expr_match(idx, ast)?;
653 }
654 ast::Expr::Closure(ast) => {
655 expr_closure(idx, ast)?;
656 }
657 ast::Expr::While(ast) => {
658 expr_while(idx, ast)?;
659 }
660 ast::Expr::Loop(ast) => {
661 expr_loop(idx, ast)?;
662 }
663 ast::Expr::For(ast) => {
664 expr_for(idx, ast)?;
665 }
666 ast::Expr::FieldAccess(ast) => {
667 expr_field_access(idx, ast)?;
668 }
669 ast::Expr::Unary(ast) => {
670 expr(idx, &mut ast.expr)?;
671 }
672 ast::Expr::Index(ast) => {
673 expr(idx, &mut ast.index)?;
674 expr(idx, &mut ast.target)?;
675 }
676 ast::Expr::Break(ast) => {
677 if let Some(ast) = &mut ast.expr {
678 expr(idx, ast)?;
679 }
680 }
681 ast::Expr::Yield(ast) => {
682 let l = idx.scopes.mark().with_span(&*ast)?;
683 l.yields.try_push(ast.span())?;
684
685 if let Some(e) = &mut ast.expr {
686 expr(idx, e)?;
687 }
688 }
689 ast::Expr::Return(ast) => {
690 if let Some(ast) = &mut ast.expr {
691 expr(idx, ast)?;
692 }
693 }
694 ast::Expr::Await(ast) => {
695 let l = idx.scopes.mark().with_span(&*ast)?;
696 l.awaits.try_push(ast.span())?;
697 expr(idx, &mut ast.expr)?;
698 }
699 ast::Expr::Try(ast) => {
700 expr(idx, &mut ast.expr)?;
701 }
702 ast::Expr::Select(e) => {
703 expr_select(idx, e)?;
704 }
705 ast::Expr::Call(e) => {
707 expr_call(idx, e)?;
708 }
709 ast::Expr::Lit(..) => {}
710 ast::Expr::Tuple(ast) => {
711 for (ast, _) in &mut ast.items {
712 expr(idx, ast)?;
713 }
714 }
715 ast::Expr::Vec(ast) => {
716 for (ast, _) in &mut ast.items {
717 expr(idx, ast)?;
718 }
719 }
720 ast::Expr::Object(ast) => {
721 expr_object(idx, ast)?;
722 }
723 ast::Expr::Range(ast) => {
724 if let Some(from) = &mut ast.start {
725 expr(idx, from)?;
726 }
727
728 if let Some(to) = &mut ast.end {
729 expr(idx, to)?;
730 }
731 }
732 ast::Expr::MacroCall(macro_call) => {
735 if let Some(id) = macro_call.id {
742 idx.q.builtin_macro_for(id).with_span(&*macro_call)?;
744 } else {
745 let mut p = attrs::Parser::new(¯o_call.attributes)?;
746
747 let expanded = idx.try_expand_internal_macro(&mut p, macro_call)?;
748
749 if let Some(span) = p.remaining(¯o_call.attributes).next() {
750 return Err(compile::Error::msg(span, "Unsupported macro attribute"));
751 }
752
753 if !expanded {
754 let out = idx.expand_macro::<ast::Expr>(macro_call)?;
755 idx.enter_macro(¯o_call)?;
756 *ast = out;
757 expr(idx, ast)?;
758 idx.leave_macro();
759 }
760 }
761
762 return Ok(());
763 }
764 ast::Expr::Continue(..) => {}
765 }
766
767 if let [first, ..] = ast.attributes() {
768 return Err(compile::Error::msg(
769 first,
770 "Attributes on expressions are not supported",
771 ));
772 }
773
774 Ok(())
775}
776
777#[instrument_ast(span = ast)]
778fn expr_if(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprIf) -> compile::Result<()> {
779 condition(idx, &mut ast.condition)?;
780 block(idx, &mut ast.block)?;
781
782 for expr_else_if in &mut ast.expr_else_ifs {
783 condition(idx, &mut expr_else_if.condition)?;
784 block(idx, &mut expr_else_if.block)?;
785 }
786
787 if let Some(expr_else) = &mut ast.expr_else {
788 block(idx, &mut expr_else.block)?;
789 }
790
791 Ok(())
792}
793
794#[instrument_ast(span = ast)]
795fn expr_assign(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprAssign) -> compile::Result<()> {
796 expr(idx, &mut ast.lhs)?;
797 expr(idx, &mut ast.rhs)?;
798 Ok(())
799}
800
801#[instrument_ast(span = ast)]
802fn expr_binary(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprBinary) -> compile::Result<()> {
803 expr(idx, &mut ast.lhs)?;
804 expr(idx, &mut ast.rhs)?;
805 Ok(())
806}
807
808#[instrument_ast(span = ast)]
809fn expr_match(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprMatch) -> compile::Result<()> {
810 expr(idx, &mut ast.expr)?;
811
812 for (branch, _) in &mut ast.branches {
813 if let Some((_, condition)) = &mut branch.condition {
814 expr(idx, condition)?;
815 }
816
817 pat(idx, &mut branch.pat)?;
818 expr(idx, &mut branch.body)?;
819 }
820
821 Ok(())
822}
823
824#[instrument_ast(span = ast)]
825fn condition(idx: &mut Indexer<'_, '_>, ast: &mut ast::Condition) -> compile::Result<()> {
826 match ast {
827 ast::Condition::Expr(e) => {
828 expr(idx, e)?;
829 }
830 ast::Condition::ExprLet(e) => {
831 expr_let(idx, e)?;
832 }
833 }
834
835 Ok(())
836}
837
838#[instrument_ast(span = ast)]
839fn item_enum(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemEnum) -> compile::Result<()> {
840 let mut p = attrs::Parser::new(&ast.attributes)?;
841
842 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?;
843
844 if let Some(first) = p.remaining(&ast.attributes).next() {
845 return Err(compile::Error::msg(
846 first,
847 "Attributes on enums are not supported",
848 ));
849 }
850
851 let name = ast.name.resolve(resolve_context!(idx.q))?;
852 let guard = idx.items.push_name(name.as_ref())?;
853
854 let visibility = ast_to_visibility(&ast.visibility)?;
855
856 let enum_item = idx.insert_new_item(&ast, visibility, &docs)?;
857 let idx_item = idx.item.replace(enum_item.item);
858
859 idx.q.index_enum(enum_item)?;
860
861 for (mut variant, _) in ast.variants.drain() {
862 let mut p = attrs::Parser::new(&variant.attributes)?;
863
864 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &variant.attributes)?;
865
866 if let Some(first) = p.remaining(&variant.attributes).next() {
867 return Err(compile::Error::msg(
868 first,
869 "Attributes on variants are not supported",
870 ));
871 }
872
873 let name = variant.name.resolve(resolve_context!(idx.q))?;
874 let guard = idx.items.push_name(name.as_ref())?;
875
876 let item_meta = idx.insert_new_item(&variant.name, Visibility::Public, &docs)?;
877 let idx_item = idx.item.replace(item_meta.item);
878
879 variant.id = item_meta.item;
880
881 let cx = resolve_context!(idx.q);
882
883 for (field, _) in variant.body.fields() {
884 let mut p = attrs::Parser::new(&field.attributes)?;
885 let docs = Doc::collect_from(cx, &mut p, &field.attributes)?;
886
887 if let Some(first) = p.remaining(&field.attributes).next() {
888 return Err(compile::Error::msg(
889 first,
890 "Attributes on variant fields are not supported",
891 ));
892 }
893
894 let name = field.name.resolve(cx)?;
895
896 for doc in docs {
897 idx.q
898 .visitor
899 .visit_field_doc_comment(
900 &DynLocation::new(idx.source_id, &doc),
901 idx.q.pool.item(item_meta.item),
902 idx.q.pool.item_type_hash(item_meta.item),
903 name,
904 doc.doc_string.resolve(cx)?.as_ref(),
905 )
906 .with_span(doc)?;
907 }
908 }
909
910 idx.item = idx_item;
911 idx.items.pop(guard).with_span(&variant)?;
912
913 idx.q.index_variant(
914 item_meta,
915 indexing::Variant {
916 enum_id: enum_item.item,
917 fields: convert_fields(resolve_context!(idx.q), variant.body)?,
918 },
919 )?;
920 }
921
922 idx.item = idx_item;
923 idx.items.pop(guard).with_span(&ast)?;
924 Ok(())
925}
926
927#[instrument_ast(span = ast)]
928fn item_struct(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemStruct) -> compile::Result<()> {
929 let mut p = attrs::Parser::new(&ast.attributes)?;
930
931 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?;
932
933 if let Some(first) = p.remaining(&ast.attributes).next() {
934 return Err(compile::Error::msg(
935 first,
936 "Attributes on structs are not supported",
937 ));
938 }
939
940 let ident = ast.ident.resolve(resolve_context!(idx.q))?;
941 let guard = idx.items.push_name(ident)?;
942
943 let visibility = ast_to_visibility(&ast.visibility)?;
944 let item_meta = idx.insert_new_item(&ast, visibility, &docs)?;
945 let idx_item = idx.item.replace(item_meta.item);
946 ast.id = item_meta.item;
947
948 let cx = resolve_context!(idx.q);
949
950 for (field, _) in ast.body.fields() {
951 let mut p = attrs::Parser::new(&field.attributes)?;
952 let docs = Doc::collect_from(cx, &mut p, &field.attributes)?;
953
954 if let Some(first) = p.remaining(&field.attributes).next() {
955 return Err(compile::Error::msg(
956 first,
957 "Attributes on fields are not supported",
958 ));
959 }
960
961 if field.ty.is_some() {
962 return Err(compile::Error::msg(
963 field,
964 "Static typing on fields is not supported",
965 ));
966 }
967
968 let name = field.name.resolve(cx)?;
969
970 for doc in docs {
971 idx.q
972 .visitor
973 .visit_field_doc_comment(
974 &DynLocation::new(idx.source_id, &doc),
975 idx.q.pool.item(item_meta.item),
976 idx.q.pool.item_type_hash(item_meta.item),
977 name,
978 doc.doc_string.resolve(cx)?.as_ref(),
979 )
980 .with_span(doc)?;
981 }
982
983 if !field.visibility.is_inherited() {
984 return Err(compile::Error::msg(
985 field,
986 "Field visibility is not supported",
987 ));
988 }
989 }
990
991 idx.item = idx_item;
992 idx.items.pop(guard).with_span(&ast)?;
993
994 let fields = convert_fields(resolve_context!(idx.q), ast.body)?;
995 idx.q.index_struct(item_meta, indexing::Struct { fields })?;
996 Ok(())
997}
998
999#[instrument_ast(span = ast)]
1000fn item_impl(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemImpl) -> compile::Result<()> {
1001 if let Some(first) = ast.attributes.first() {
1002 return Err(compile::Error::msg(
1003 first,
1004 "Attributes on impl blocks are not supported",
1005 ));
1006 }
1007
1008 path(idx, &mut ast.path)?;
1009
1010 let location = Location::new(idx.source_id, ast.path.span());
1011
1012 idx.q
1013 .inner
1014 .defer_queue
1015 .try_push_back(DeferEntry::ImplItem(ImplItem {
1016 kind: ImplItemKind::Ast {
1017 path: Box::try_new(ast.path)?,
1018 functions: take(&mut ast.functions),
1019 },
1020 location,
1021 root: idx.root.map(TryToOwned::try_to_owned).transpose()?,
1022 nested_item: idx.nested_item,
1023 macro_depth: idx.macro_depth,
1024 }))?;
1025
1026 Ok(())
1027}
1028
1029#[instrument_ast(span = ast)]
1030fn item_mod(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemMod) -> compile::Result<()> {
1031 let mut p = attrs::Parser::new(&ast.attributes)?;
1032
1033 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?;
1034
1035 if let Some(first) = p.remaining(&ast.attributes).next() {
1036 return Err(compile::Error::msg(
1037 first,
1038 "Attributes on modules are not supported",
1039 ));
1040 }
1041
1042 let name_span = ast.name_span();
1043
1044 match &mut ast.body {
1045 ast::ItemModBody::EmptyBody(..) => {
1046 idx.handle_file_mod(&mut ast, &docs)?;
1047 }
1048 ast::ItemModBody::InlineBody(body) => {
1049 let name = ast.name.resolve(resolve_context!(idx.q))?;
1050 let guard = idx.items.push_name(name.as_ref())?;
1051
1052 let visibility = ast_to_visibility(&ast.visibility)?;
1053
1054 let (mod_item, mod_item_id) = idx.q.insert_mod(
1055 &idx.items,
1056 &DynLocation::new(idx.source_id, name_span),
1057 idx.item.module,
1058 visibility,
1059 &docs,
1060 )?;
1061
1062 ast.id = mod_item_id;
1063
1064 let idx_item = idx.item.replace_module(mod_item, mod_item_id);
1065 file(idx, &mut body.file)?;
1066 idx.item = idx_item;
1067
1068 idx.items.pop(guard).with_span(&ast)?;
1069 }
1070 }
1071
1072 Ok(())
1073}
1074
1075#[instrument_ast(span = ast)]
1076fn item_const(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemConst) -> compile::Result<()> {
1077 let mut p = attrs::Parser::new(&ast.attributes)?;
1078
1079 let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?;
1080
1081 if let Some(first) = p.remaining(&ast.attributes).next() {
1082 return Err(compile::Error::msg(
1083 first,
1084 "Attributes on constants are not supported",
1085 ));
1086 }
1087
1088 let name = ast.name.resolve(resolve_context!(idx.q))?;
1089 let guard = idx.items.push_name(name.as_ref())?;
1090
1091 let item_meta = idx.insert_new_item(&ast, ast_to_visibility(&ast.visibility)?, &docs)?;
1092 let idx_item = idx.item.replace(item_meta.item);
1093
1094 ast.id = item_meta.item;
1095
1096 let last = idx.nested_item.replace(ast.descriptive_span());
1097 expr(idx, &mut ast.expr)?;
1098 idx.nested_item = last;
1099
1100 idx.q.index_const_expr(
1101 item_meta,
1102 indexing::ConstExpr::Ast(Box::try_new(ast.expr.try_clone()?)?),
1103 )?;
1104
1105 idx.item = idx_item;
1106 idx.items.pop(guard).with_span(&ast)?;
1107 Ok(())
1108}
1109
1110#[instrument_ast(span = ast)]
1111fn item(idx: &mut Indexer<'_, '_>, ast: ast::Item) -> compile::Result<()> {
1112 match ast {
1113 ast::Item::Enum(item) => {
1114 item_enum(idx, item)?;
1115 }
1116 ast::Item::Struct(item) => {
1117 item_struct(idx, item)?;
1118 }
1119 ast::Item::Fn(item) => {
1120 item_fn(idx, item)?;
1121 }
1122 ast::Item::Impl(item) => {
1123 item_impl(idx, item)?;
1124 }
1125 ast::Item::Mod(item) => {
1126 item_mod(idx, item)?;
1127 }
1128 ast::Item::Const(item) => {
1129 item_const(idx, item)?;
1130 }
1131 ast::Item::MacroCall(macro_call) => {
1132 let Some(id) = macro_call.id else {
1139 return Err(compile::Error::msg(
1140 ¯o_call,
1141 "macro expansion id not set",
1142 ));
1143 };
1144
1145 idx.q.builtin_macro_for(id).with_span(¯o_call)?;
1147
1148 if let Some(span) = macro_call.attributes.first() {
1149 return Err(compile::Error::msg(
1150 span,
1151 "attributes on macros are not supported",
1152 ));
1153 }
1154 }
1155 ast::Item::Use(item_use) => {
1157 if let Some(span) = item_use.attributes.first() {
1158 return Err(compile::Error::msg(
1159 span,
1160 "Attributes on uses are not supported",
1161 ));
1162 }
1163
1164 let Some(queue) = idx.queue.as_mut() else {
1165 return Err(compile::Error::msg(
1166 &item_use,
1167 "Imports are not supported in this context",
1168 ));
1169 };
1170
1171 let visibility = ast_to_visibility(&item_use.visibility)?;
1172
1173 let import = Import {
1174 state: ImportState::Ast(Box::try_new(item_use)?),
1175 kind: ImportKind::Global,
1176 visibility,
1177 module: idx.item.module,
1178 item: idx.items.item().try_to_owned()?,
1179 source_id: idx.source_id,
1180 };
1181
1182 import.process(&mut idx.q, &mut |task| {
1183 queue.try_push_back(task)?;
1184 Ok(())
1185 })?;
1186 }
1187 }
1188
1189 Ok(())
1190}
1191
1192#[instrument_ast(span = ast)]
1193fn path(idx: &mut Indexer<'_, '_>, ast: &mut ast::Path) -> compile::Result<()> {
1194 ast.id = idx.item.id;
1195
1196 path_segment(idx, &mut ast.first)?;
1197
1198 for (_, segment) in &mut ast.rest {
1199 path_segment(idx, segment)?;
1200 }
1201
1202 Ok(())
1203}
1204
1205#[instrument_ast(span = ast)]
1206fn path_segment(idx: &mut Indexer<'_, '_>, ast: &mut ast::PathSegment) -> compile::Result<()> {
1207 if let ast::PathSegment::Generics(generics) = ast {
1208 for (param, _) in generics {
1209 expr(idx, &mut param.expr)?;
1210 }
1211 }
1212
1213 Ok(())
1214}
1215
1216#[instrument_ast(span = ast)]
1217fn expr_while(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprWhile) -> compile::Result<()> {
1218 condition(idx, &mut ast.condition)?;
1219 block(idx, &mut ast.body)?;
1220 Ok(())
1221}
1222
1223#[instrument_ast(span = ast)]
1224fn expr_loop(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprLoop) -> compile::Result<()> {
1225 block(idx, &mut ast.body)?;
1226 Ok(())
1227}
1228
1229#[instrument_ast(span = ast)]
1230fn expr_for(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprFor) -> compile::Result<()> {
1231 expr(idx, &mut ast.iter)?;
1232 pat(idx, &mut ast.binding)?;
1233 block(idx, &mut ast.body)?;
1234 Ok(())
1235}
1236
1237#[instrument_ast(span = ast)]
1238fn expr_closure(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprClosure) -> compile::Result<()> {
1239 let guard = idx.push_id()?;
1240
1241 idx.scopes.push()?;
1242
1243 let item_meta = idx.insert_new_item(&*ast, Visibility::Inherited, &[])?;
1244 let idx_item = idx.item.replace(item_meta.item);
1245
1246 ast.id = item_meta.item;
1247
1248 for (arg, _) in ast.args.as_slice_mut() {
1249 match arg {
1250 ast::FnArg::SelfValue(s) => {
1251 return Err(compile::Error::new(s, ErrorKind::UnsupportedSelf));
1252 }
1253 ast::FnArg::Pat(p) => {
1254 pat(idx, p)?;
1255 }
1256 }
1257 }
1258
1259 expr(idx, &mut ast.body)?;
1260
1261 let layer = idx.scopes.pop().with_span(&*ast)?;
1262
1263 let call = validate_call(false, ast.async_token.is_some(), &layer)?;
1264
1265 let Some(call) = call else {
1266 return Err(compile::Error::new(&*ast, ErrorKind::ClosureKind));
1267 };
1268
1269 idx.q.index_meta(
1270 ast,
1271 item_meta,
1272 meta::Kind::Closure {
1273 call,
1274 do_move: ast.move_token.is_some(),
1275 },
1276 )?;
1277
1278 idx.item = idx_item;
1279 idx.items.pop(guard).with_span(&ast)?;
1280 Ok(())
1281}
1282
1283#[instrument_ast(span = ast)]
1284fn expr_field_access(
1285 idx: &mut Indexer<'_, '_>,
1286 ast: &mut ast::ExprFieldAccess,
1287) -> compile::Result<()> {
1288 expr(idx, &mut ast.expr)?;
1289
1290 if let ast::ExprField::Path(p) = &mut ast.expr_field {
1291 path(idx, p)?;
1292 }
1293
1294 Ok(())
1295}
1296
1297#[instrument_ast(span = ast)]
1298fn expr_select(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprSelect) -> compile::Result<()> {
1299 let l = idx.scopes.mark().with_span(&*ast)?;
1300 l.awaits.try_push(ast.span())?;
1301
1302 for (branch, _) in &mut ast.branches {
1303 match branch {
1304 ast::ExprSelectBranch::Pat(p) => {
1305 expr(idx, &mut p.expr)?;
1306 pat(idx, &mut p.pat)?;
1307 expr(idx, &mut p.body)?;
1308 }
1309 ast::ExprSelectBranch::Default(def) => {
1310 expr(idx, &mut def.body)?;
1311 }
1312 }
1313 }
1314
1315 Ok(())
1316}
1317
1318#[instrument_ast(span = ast)]
1319fn expr_call(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprCall) -> compile::Result<()> {
1320 ast.id = idx.item.id;
1321
1322 for (e, _) in &mut ast.args {
1323 expr(idx, e)?;
1324 }
1325
1326 expr(idx, &mut ast.expr)?;
1327 Ok(())
1328}
1329
1330#[instrument_ast(span = ast)]
1331fn expr_object(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprObject) -> compile::Result<()> {
1332 if let ast::ObjectIdent::Named(p) = &mut ast.ident {
1333 path(idx, p)?;
1335 }
1336
1337 for (assign, _) in &mut ast.assignments {
1338 if let Some((_, e)) = &mut assign.assign {
1339 expr(idx, e)?;
1340 }
1341 }
1342
1343 Ok(())
1344}
1345
1346fn convert_fields(cx: ResolveContext<'_>, body: ast::Fields) -> compile::Result<meta::Fields> {
1348 Ok(match body {
1349 ast::Fields::Empty => meta::Fields::Empty,
1350 ast::Fields::Unnamed(tuple) => meta::Fields::Unnamed(tuple.len()),
1351 ast::Fields::Named(st) => {
1352 let mut fields = Vec::try_with_capacity(st.len())?;
1353
1354 for (position, (ast::Field { name, .. }, _)) in st.iter().enumerate() {
1355 let name = name.resolve(cx)?;
1356 fields.try_push(meta::FieldMeta {
1357 name: name.try_into()?,
1358 position,
1359 })?;
1360 }
1361
1362 meta::Fields::Named(meta::FieldsNamed {
1363 fields: fields.try_into()?,
1364 })
1365 }
1366 })
1367}