1use core::mem::replace;
2use core::num::NonZero;
3use core::ops::Neg;
4
5use rust_alloc::rc::Rc;
6
7use num::ToPrimitive;
8use tracing::instrument_ast;
9
10use crate::alloc::prelude::*;
11use crate::alloc::{self, HashMap, HashSet};
12use crate::ast::{self, Delimiter, Kind, NumberSize, Span, Spanned};
13use crate::compile::{meta, Error, ErrorKind, ItemId, Result, WithSpan};
14use crate::grammar::{
15 classify, object_key, Ignore, MaybeNode, NodeClass, Remaining, Stream, StreamBuf, Tree,
16};
17use crate::hash::ParametersBuilder;
18use crate::hir;
19use crate::parse::{NonZeroId, Resolve};
20use crate::query::{self, GenericsParameters, Named2, Named2Kind, Used};
21use crate::runtime::{format, ConstValue, ConstValueKind, Inline, Type, TypeCheck};
22use crate::Hash;
23
24use super::{Ctxt, Needs};
25
26use Kind::*;
27
28#[instrument_ast(span = p)]
30pub(crate) fn bare<'hir>(
31 cx: &mut Ctxt<'hir, '_, '_>,
32 p: &mut Stream<'_>,
33) -> Result<hir::ItemFn<'hir>> {
34 let body = statements(cx, None, p)?;
35
36 Ok(hir::ItemFn {
37 span: p.span(),
38 args: &[],
39 body,
40 })
41}
42
43#[instrument_ast(span = p)]
45pub(crate) fn item_fn<'hir>(
46 cx: &mut Ctxt<'hir, '_, '_>,
47 p: &mut Stream<'_>,
48 is_instance: bool,
49) -> Result<hir::ItemFn<'hir>> {
50 alloc_with!(cx, p);
51
52 p.remaining(cx, Attribute)?.ignore(cx)?;
53 p.eat(Modifiers);
54 p.expect(K![fn])?;
55 p.ast::<ast::Ident>()?;
56
57 let mut args = Vec::new();
58
59 p.expect(FnArgs)?.parse(|p| {
60 p.expect(K!['('])?;
61
62 let mut comma = Remaining::default();
63
64 while let MaybeNode::Some(pat) = p.eat(Pat) {
65 comma.exactly_one(cx)?;
66 let pat = pat.parse(|p| self::pat_binding_with(cx, p, is_instance))?;
67 args.try_push(hir::FnArg::Pat(alloc!(pat)))?;
68 comma = p.one(K![,]);
69 }
70
71 comma.at_most_one(cx)?;
72 p.expect(K![')'])?;
73 Ok(())
74 })?;
75
76 let body = p.expect(Block)?.parse(|p| block(cx, None, p))?;
77
78 Ok(hir::ItemFn {
79 span: p.span(),
80 args: iter!(args),
81 body,
82 })
83}
84
85#[instrument_ast(span = p)]
87pub(crate) fn block<'hir>(
88 cx: &mut Ctxt<'hir, '_, '_>,
89 label: Option<ast::Label>,
90 p: &mut Stream<'_>,
91) -> Result<hir::Block<'hir>> {
92 p.expect(K!['{'])?;
93 let block = p.expect(BlockBody)?.parse(|p| statements(cx, label, p))?;
94 p.expect(K!['}'])?;
95 Ok(block)
96}
97
98#[instrument_ast(span = p)]
99fn statements<'hir>(
100 cx: &mut Ctxt<'hir, '_, '_>,
101 label: Option<ast::Label>,
102 p: &mut Stream<'_>,
103) -> Result<hir::Block<'hir>> {
104 alloc_with!(cx, p);
105
106 let label = match label {
107 Some(label) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
108 None => None,
109 };
110
111 cx.scopes.push(label)?;
112
113 let at = cx.statements.len();
114
115 let mut must_be_last = None;
116
117 let mut last_item = true;
120
121 while let Some(node) = p.next() {
122 let (needs_semi, class) = classify(&node);
123
124 let span = node.span();
125
126 match node.kind() {
127 Local => {
128 let stmt = hir::Stmt::Local(alloc!(node.parse(|p| local(cx, p))?));
129 cx.statements.try_push(stmt)?;
130 }
131 Expr => {
132 let expr = node.parse(|p| expr(cx, p))?;
133 let stmt = hir::Stmt::Expr(&*alloc!(expr));
134 cx.statements.try_push(stmt)?;
135 }
136 Item => {
137 let semi = p.remaining(cx, K![;])?;
138
139 if needs_semi {
140 semi.exactly_one(cx)?;
141 } else {
142 semi.at_most_one(cx)?;
143 }
144
145 last_item = true;
146 continue;
147 }
148 _ => {
149 cx.error(node.expected("an expression or local"))?;
150 continue;
151 }
152 };
153
154 let semis = p.remaining(cx, K![;])?;
155
156 last_item = semis.is_present();
157
158 if let Some(span) = must_be_last {
159 cx.error(Error::new(
160 span,
161 ErrorKind::ExpectedBlockSemiColon {
162 #[cfg(feature = "emit")]
163 followed_span: span,
164 },
165 ))?;
166 }
167
168 if matches!(class, NodeClass::Expr) && semis.is_absent() {
169 must_be_last = Some(span);
170 }
171
172 if let Some(span) = semis.trailing() {
173 cx.error(Error::msg(span, "unused semi-colons"))?;
174 }
175
176 if needs_semi {
177 semis.at_least_one(cx)?;
178 } else {
179 semis.at_most_one(cx)?;
180 }
181 }
182
183 let value = 'out: {
184 if last_item {
185 break 'out None;
186 }
187
188 debug_assert!(
189 at < cx.statements.len(),
190 "starting point for assertions must be prior to buffer size"
191 );
192
193 match cx.statements.pop() {
194 Some(hir::Stmt::Expr(e)) => Some(e),
195 Some(stmt) => {
196 cx.statements.try_push(stmt).with_span(&*p)?;
197 None
198 }
199 None => None,
200 }
201 };
202
203 let statements = iter!(cx.statements.drain(at..));
204
205 let layer = cx.scopes.pop().with_span(&*p)?;
206
207 Ok(hir::Block {
208 span: p.span(),
209 label,
210 statements,
211 value,
212 drop: iter!(layer.into_drop_order()),
213 })
214}
215
216#[instrument_ast(span = p)]
218pub(crate) fn local<'hir>(
219 cx: &mut Ctxt<'hir, '_, '_>,
220 p: &mut Stream<'_>,
221) -> Result<hir::Local<'hir>> {
222 p.expect(K![let])?;
226 let pat = p.expect(Pat)?;
227 p.expect(K![=])?;
228 let expr = p.expect(Expr)?;
229
230 let expr = expr.parse(|p| self::expr(cx, p))?;
231 let pat = pat.parse(|p| self::pat_binding(cx, p))?;
232
233 Ok(hir::Local {
234 span: p.span(),
235 pat,
236 expr,
237 })
238}
239
240#[instrument_ast(span = p)]
242pub(crate) fn expr<'hir>(
243 cx: &mut Ctxt<'hir, '_, '_>,
244 p: &mut Stream<'_>,
245) -> Result<hir::Expr<'hir>> {
246 alloc_with!(cx, ast);
247
248 p.remaining(cx, Attribute)?.ignore(cx)?;
249 p.eat(Modifiers);
250
251 while let MaybeNode::Some(label) = p.eat_matching(|k| matches!(k, K!['label])) {
252 let label = label.ast::<ast::Label>()?;
253
254 if let Some(existing) = &cx.label {
255 cx.error(Error::new(
256 label.span(),
257 ErrorKind::ConflictingLabels {
258 existing: existing.span(),
259 },
260 ))?;
261 } else {
262 cx.label = Some(label);
263 }
264
265 p.one(K![:]).exactly_one(cx)?;
266 }
267
268 let kind = p.pump()?.parse(|p| expr_inner(cx, p))?.into_kind(cx)?;
269
270 if let Some(label) = cx.label.take() {
271 return Err(Error::msg(label, "labels are not supported for expression"));
272 };
273
274 Ok(hir::Expr {
275 span: p.span(),
276 kind,
277 })
278}
279
280#[instrument_ast(span = p)]
281fn expr_only<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Expr<'hir>> {
282 let kind = expr_inner(cx, p)?.into_kind(cx)?;
283
284 Ok(hir::Expr {
285 span: p.span(),
286 kind,
287 })
288}
289
290struct ExprInner<'hir, 'a> {
291 span: Span,
292 kind: ExprInnerKind<'hir, 'a>,
293}
294
295enum ExprInnerKind<'hir, 'a> {
296 Kind(hir::ExprKind<'hir>),
297 Path(StreamBuf<'a>),
298}
299
300impl<'hir> ExprInner<'hir, '_> {
301 fn into_call(self, cx: &mut Ctxt<'hir, '_, '_>, args: usize) -> Result<hir::Call<'hir>> {
302 match self.kind {
303 ExprInnerKind::Path(p) => {
304 let named = p.parse(|p| cx.q.convert_path2(p))?;
305 let parameters = generics_parameters(cx, &named)?;
306 let meta = cx.lookup_meta(&self.span, named.item, parameters)?;
307
308 debug_assert_eq!(meta.item_meta.item, named.item);
309
310 match &meta.kind {
311 meta::Kind::Struct {
312 fields: meta::Fields::Empty,
313 ..
314 } => {
315 if args > 0 {
316 return Err(Error::new(
317 self.span,
318 ErrorKind::BadArgumentCount {
319 expected: 0,
320 actual: args,
321 },
322 ));
323 }
324 }
325 meta::Kind::Struct {
326 fields: meta::Fields::Unnamed(expected),
327 ..
328 } => {
329 if *expected != args {
330 return Err(Error::new(
331 self.span,
332 ErrorKind::BadArgumentCount {
333 expected: *expected,
334 actual: args,
335 },
336 ));
337 }
338
339 if *expected == 0 {
340 cx.q.diagnostics.remove_tuple_call_parens(
341 cx.source_id,
342 &self.span,
343 &self.span,
344 None,
345 )?;
346 }
347 }
348 meta::Kind::Function { .. } => {
349 if let Some(message) = cx.q.lookup_deprecation(meta.hash) {
350 cx.q.diagnostics.used_deprecated(
351 cx.source_id,
352 &self.span,
353 None,
354 message.try_into()?,
355 )?;
356 };
357 }
358 meta::Kind::ConstFn => {
359 let from =
360 cx.q.item_for("lowering constant function", named.item)
361 .with_span(self.span)?;
362
363 return Ok(hir::Call::ConstFn {
364 from_module: from.module,
365 from_item: from.item,
366 id: meta.item_meta.item,
367 });
368 }
369 _ => {
370 return Err(Error::expected_meta(
371 self.span,
372 meta.info(cx.q.pool)?,
373 "something that can be called as a function",
374 ));
375 }
376 };
377
378 Ok(hir::Call::Meta { hash: meta.hash })
379 }
380 ExprInnerKind::Kind(kind) => {
381 alloc_with!(cx, &self.span);
382
383 match kind {
384 hir::ExprKind::Variable(name) => Ok(hir::Call::Var { name }),
385 hir::ExprKind::FieldAccess(&hir::ExprFieldAccess {
386 expr_field,
387 expr: target,
388 }) => {
389 let hash = match expr_field {
390 hir::ExprField::Index(index) => Hash::index(index),
391 hir::ExprField::Ident(ident) => {
392 cx.q.unit.insert_debug_ident(ident)?;
393 Hash::ident(ident)
394 }
395 hir::ExprField::IdentGenerics(ident, hash) => {
396 cx.q.unit.insert_debug_ident(ident)?;
397 Hash::ident(ident).with_function_parameters(hash)
398 }
399 };
400
401 Ok(hir::Call::Associated {
402 target: alloc!(target),
403 hash,
404 })
405 }
406 kind => Ok(hir::Call::Expr {
407 expr: alloc!(hir::Expr {
408 span: self.span,
409 kind
410 }),
411 }),
412 }
413 }
414 }
415 }
416
417 fn into_kind(self, cx: &mut Ctxt<'hir, '_, '_>) -> Result<hir::ExprKind<'hir>> {
418 match self.kind {
419 ExprInnerKind::Kind(kind) => Ok(kind),
420 ExprInnerKind::Path(p) => {
421 let named = p.parse(|p| cx.q.convert_path2(p))?;
422 let parameters = generics_parameters(cx, &named)?;
423
424 if let Some(meta) = cx.try_lookup_meta(&self.span, named.item, ¶meters)? {
425 return expr_path_meta(cx, &meta, &self.span);
426 }
427
428 if let (Needs::Value, Named2Kind::Ident(local)) = (cx.needs, named.kind) {
429 let local = local.resolve(resolve_context!(cx.q))?;
430
431 if !local.starts_with(char::is_uppercase) {
434 return Err(Error::new(
435 self.span,
436 ErrorKind::MissingLocal {
437 name: Box::<str>::try_from(local)?,
438 },
439 ));
440 }
441 }
442
443 let kind = if !parameters.parameters.is_empty() {
444 ErrorKind::MissingItemParameters {
445 item: cx.q.pool.item(named.item).try_to_owned()?,
446 parameters: parameters.parameters,
447 }
448 } else {
449 ErrorKind::MissingItem {
450 item: cx.q.pool.item(named.item).try_to_owned()?,
451 }
452 };
453
454 Err(Error::new(self.span, kind))
455 }
456 }
457 }
458}
459
460#[instrument_ast(span = p)]
461fn expr_inner<'hir, 'a>(
462 cx: &mut Ctxt<'hir, '_, '_>,
463 p: &mut Stream<'a>,
464) -> Result<ExprInner<'hir, 'a>> {
465 let kind = match p.kind() {
466 IndexedPath(..) => return expr_path(cx, p),
467 Path => return Err(p.expected("an expanded path")),
468 Block => expr_block(cx, p)?,
469 Lit => expr_lit(cx, p)?,
470 ConstBlock(item) => expr_const_block(cx, p, item)?,
471 AsyncBlock(item) => expr_async_block(cx, p, item)?,
472 Closure(item) => expr_closure(cx, p, item)?,
473 ExpandedMacro(id) => expr_expanded_macro(cx, p, id)?,
474 ExprReturn => expr_return(cx, p)?,
475 ExprYield => expr_yield(cx, p)?,
476 ExprBreak => expr_break(cx, p)?,
477 ExprContinue => expr_continue(cx, p)?,
478 ExprArray => expr_array(cx, p)?,
479 ExprTuple => expr_tuple(cx, p)?,
480 ExprGroup => expr_group(cx, p)?,
481 ExprEmptyGroup => expr_empty_group(cx, p)?,
482 ExprObject => expr_object(cx, p)?,
483 ExprChain => expr_chain(cx, p)?,
484 ExprUnary => expr_unary(cx, p)?,
485 ExprBinary => expr_binary(cx, p)?,
486 ExprAssign => expr_assign(cx, p)?,
487 ExprIf => expr_if(cx, p)?,
488 ExprMatch => expr_match(cx, p)?,
489 ExprSelect => expr_select(cx, p)?,
490 ExprWhile => expr_while(cx, p)?,
491 ExprLoop => expr_loop(cx, p)?,
492 ExprFor => expr_for(cx, p)?,
493 ExprRange => expr_range(cx, p)?,
494 ExprRangeInclusive => expr_range_inclusive(cx, p)?,
495 ExprRangeFrom => expr_range_from(cx, p)?,
496 ExprRangeFull => expr_range_full(cx, p)?,
497 ExprRangeTo => expr_range_to(cx, p)?,
498 ExprRangeToInclusive => expr_range_to_inclusive(cx, p)?,
499 _ => return Err(p.expected(Expr)),
500 };
501
502 Ok(ExprInner {
503 span: p.span(),
504 kind: ExprInnerKind::Kind(kind),
505 })
506}
507
508#[instrument_ast(span = p)]
510fn expr_block<'hir>(
511 cx: &mut Ctxt<'hir, '_, '_>,
512 p: &mut Stream<'_>,
513) -> Result<hir::ExprKind<'hir>> {
514 alloc_with!(cx, p);
515 let label = cx.label.take();
516 Ok(hir::ExprKind::Block(alloc!(block(cx, label, p)?)))
517}
518
519#[instrument_ast(span = p)]
521fn expr_const_block<'hir>(
522 cx: &mut Ctxt<'hir, '_, '_>,
523 p: &mut Stream<'_>,
524 item: ItemId,
525) -> Result<hir::ExprKind<'hir>> {
526 alloc_with!(cx, p);
527
528 if cx.const_eval {
529 return Ok(hir::ExprKind::Block(alloc!(block(cx, None, p)?)));
530 }
531
532 let item = cx.q.item_for("lowering const block", item).with_span(&*p)?;
533 let meta = cx.lookup_meta(&*p, item.item, GenericsParameters::default())?;
534
535 let meta::Kind::Const = meta.kind else {
536 return Err(Error::expected_meta(
537 &*p,
538 meta.info(cx.q.pool)?,
539 "constant block",
540 ));
541 };
542
543 p.ignore();
544 Ok(hir::ExprKind::Const(meta.hash))
545}
546
547#[instrument_ast(span = p)]
549fn expr_async_block<'hir>(
550 cx: &mut Ctxt<'hir, '_, '_>,
551 p: &mut Stream<'_>,
552 item: ItemId,
553) -> Result<hir::ExprKind<'hir>> {
554 alloc_with!(cx, p);
555
556 if cx.const_eval {
557 return Err(Error::msg(
558 &*p,
559 "async blocks are not supported in constant contexts",
560 ));
561 };
562
563 let item = cx.q.item_for("lowering async block", item).with_span(&*p)?;
564 let meta = cx.lookup_meta(&*p, item.item, GenericsParameters::default())?;
565
566 let meta::Kind::AsyncBlock { call, do_move, .. } = meta.kind else {
567 return Err(Error::expected_meta(
568 &*p,
569 meta.info(cx.q.pool)?,
570 "async block",
571 ));
572 };
573
574 cx.scopes.push_captures()?;
575 let block = alloc!(block(cx, None, p)?);
576 let layer = cx.scopes.pop().with_span(&*p)?;
577
578 cx.q.set_used(&meta.item_meta)?;
579
580 let captures = &*iter!(layer.captures().map(|(_, id)| id));
581
582 let Some(queue) = cx.secondary_builds.as_mut() else {
583 return Err(Error::new(&*p, ErrorKind::AsyncBlockInConst));
584 };
585
586 queue.try_push(query::SecondaryBuildEntry {
587 item_meta: meta.item_meta,
588 build: query::SecondaryBuild::AsyncBlock(query::AsyncBlock {
589 hir: alloc!(hir::AsyncBlock { block, captures }),
590 call,
591 }),
592 })?;
593
594 Ok(hir::ExprKind::AsyncBlock(alloc!(hir::ExprAsyncBlock {
595 hash: meta.hash,
596 do_move,
597 captures,
598 })))
599}
600
601#[instrument_ast(span = p)]
603fn expr_path<'hir, 'a>(
604 cx: &mut Ctxt<'hir, '_, '_>,
605 p: &mut Stream<'a>,
606) -> Result<ExprInner<'hir, 'a>> {
607 alloc_with!(cx, p);
608
609 fn is_self(p: &Stream<'_>) -> bool {
610 matches!(p.kinds(), Some([K![self]]))
611 }
612
613 fn try_as_ident(p: &Stream<'_>) -> Option<ast::Ident> {
614 let [node] = p.nodes()?;
615 node.ast().ok()
616 }
617
618 let kind = 'out: {
619 if is_self(p) {
620 let Some((id, _)) = cx.scopes.get(hir::Name::SelfValue)? else {
621 return Err(Error::new(&*p, ErrorKind::MissingSelf));
622 };
623
624 p.ignore();
625 break 'out ExprInnerKind::Kind(hir::ExprKind::Variable(id));
626 }
627
628 if let Needs::Value = cx.needs {
629 if let Some(name) = try_as_ident(p) {
630 let name = alloc_str!(name.resolve(resolve_context!(cx.q))?);
631
632 if let Some((name, _)) = cx.scopes.get(hir::Name::Str(name))? {
633 p.ignore();
634 break 'out ExprInnerKind::Kind(hir::ExprKind::Variable(name));
635 }
636 }
637 }
638
639 ExprInnerKind::Path(p.take_remaining())
640 };
641
642 Ok(ExprInner {
643 span: p.span(),
644 kind,
645 })
646}
647
648#[instrument_ast(span = p)]
650fn expr_expanded_macro<'hir>(
651 cx: &mut Ctxt<'hir, '_, '_>,
652 p: &mut Stream<'_>,
653 id: NonZeroId,
654) -> Result<hir::ExprKind<'hir>> {
655 alloc_with!(cx, p);
656
657 p.ignore();
658
659 let Some(expanded) = cx.q.take_expanded_macro(id) else {
660 return Err(Error::msg(
661 &*p,
662 try_format!("missing expanded macro for id {id}"),
663 ));
664 };
665
666 match expanded {
667 query::ExpandedMacro::Builtin(e) => match e {
668 query::BuiltInMacro2::File(lit) => {
669 let lit = lit.resolve_string(resolve_context!(cx.q))?;
670 let lit = alloc_str!(lit.as_ref());
671 Ok(hir::ExprKind::Lit(hir::Lit::Str(lit)))
672 }
673 query::BuiltInMacro2::Line(line) => {
674 let Some(n) = line.to_u64() else {
675 return Err(Error::new(
676 &*p,
677 ErrorKind::BadUnsignedOutOfBounds {
678 size: NumberSize::S64,
679 },
680 ));
681 };
682
683 Ok(hir::ExprKind::Lit(hir::Lit::Unsigned(n)))
684 }
685 query::BuiltInMacro2::Format(tree) => expr_format_macro(cx, p, tree),
686 query::BuiltInMacro2::Template(tree, literal) => {
687 expr_template_macro(cx, p, tree, literal)
688 }
689 },
690 query::ExpandedMacro::Tree(tree) => {
691 #[cfg(feature = "std")]
692 if cx.q.options.print_tree {
693 tree.print(&*p, format_args!("Expanded macro tree #{id}"))?;
694 }
695
696 let Some([root]) = tree.nodes() else {
697 return Err(Error::msg(&*p, "expected single root in expanded macro"));
698 };
699
700 if !matches!(root.kind(), Root) {
701 return Err(Error::expected(root, Root));
702 }
703
704 let Some([expr]) = root.nodes() else {
705 return Err(Error::msg(
706 &*p,
707 "expected single expression in expanded macro",
708 ));
709 };
710
711 if !matches!(expr.kind(), Expr) {
712 return Err(Error::expected(expr, Expr));
713 }
714
715 expr.parse(|p| Ok(self::expr(cx, p)?.kind))
716 }
717 }
718}
719
720fn expr_format_macro<'hir>(
721 cx: &mut Ctxt<'hir, '_, '_>,
722 p: &mut Stream<'_>,
723 tree: Rc<Tree>,
724) -> Result<hir::ExprKind<'hir>> {
725 alloc_with!(cx, p);
726
727 let Some([root]) = tree.nodes() else {
728 return Err(Error::msg(
729 &*p,
730 "expected single root in expanded format!()",
731 ));
732 };
733
734 if !matches!(root.kind(), Root) {
735 return Err(Error::expected(root, Root));
736 }
737
738 let mut spec = hir::BuiltInFormatSpec::default();
739
740 root.parse(|p| {
741 let expr = p.expect(Expr)?.parse(|p| self::expr(cx, p))?;
742
743 while p.eat(K![,]).is_some() {
744 let ident = p.ast::<ast::Ident>()?;
745 let key = ident.resolve(resolve_context!(cx.q))?;
746 p.expect(K![=])?;
747
748 match key {
749 "fill" => {
750 if spec.fill.is_some() {
751 return Err(Error::msg(ident, "multiple `format!(.., fill = ..)`"));
752 }
753
754 let arg = p.ast::<ast::LitChar>()?;
755 let f = arg.resolve(resolve_context!(cx.q))?;
756 spec.fill = Some(f);
757 }
758 "align" => {
759 if spec.align.is_some() {
760 return Err(Error::msg(ident, "multiple `format!(.., align = ..)`"));
761 }
762
763 let arg = p.ast::<ast::Ident>()?;
764 let value = arg.resolve(resolve_context!(cx.q))?;
765
766 let Ok(a) = str::parse::<format::Alignment>(value) else {
767 return Err(Error::unsupported(arg, "`format!(.., align = ..)`"));
768 };
769
770 spec.align = Some(a);
771 }
772 "flags" => {
773 if spec.flags.is_some() {
774 return Err(Error::unsupported(
775 ident,
776 "multiple `format!(.., flags = ..)`",
777 ));
778 }
779
780 let arg = p.ast::<ast::LitNumber>()?;
781
782 let Some(f) = arg.resolve(resolve_context!(cx.q))?.as_u32(false) else {
783 return Err(Error::unsupported(arg, "argument out-of-bounds"));
784 };
785
786 let f = format::Flags::from(f);
787 spec.flags = Some(f);
788 }
789 "width" => {
790 if spec.width.is_some() {
791 return Err(Error::unsupported(
792 ident,
793 "multiple `format!(.., width = ..)`",
794 ));
795 }
796
797 let arg = p.ast::<ast::LitNumber>()?;
798
799 let Some(f) = arg.resolve(resolve_context!(cx.q))?.as_usize(false) else {
800 return Err(Error::unsupported(arg, "argument out-of-bounds"));
801 };
802
803 spec.width = NonZero::new(f);
804 }
805 "precision" => {
806 if spec.precision.is_some() {
807 return Err(Error::unsupported(
808 ident,
809 "multiple `format!(.., precision = ..)`",
810 ));
811 }
812
813 let arg = p.ast::<ast::LitNumber>()?;
814
815 let Some(f) = arg.resolve(resolve_context!(cx.q))?.as_usize(false) else {
816 return Err(Error::unsupported(arg, "argument out-of-bounds"));
817 };
818
819 spec.precision = NonZero::new(f);
820 }
821 "type" => {
822 if spec.format_type.is_some() {
823 return Err(Error::unsupported(
824 ident,
825 "multiple `format!(.., type = ..)`",
826 ));
827 }
828
829 let arg = p.ast::<ast::Ident>()?;
830 let value = arg.resolve(resolve_context!(cx.q))?;
831
832 let Ok(format_type) = str::parse::<format::Type>(value) else {
833 return Err(Error::unsupported(arg, "`format!(.., type = ..)`"));
834 };
835
836 spec.format_type = Some(format_type);
837 }
838 _ => {
839 return Err(Error::unsupported(ident, "`format!(.., <key>)`"));
840 }
841 }
842 }
843
844 let format = alloc!(hir::BuiltInFormat {
845 spec,
846 value: alloc!(expr),
847 });
848
849 Ok(hir::ExprKind::Format(format))
850 })
851}
852
853fn expr_template_macro<'hir>(
854 cx: &mut Ctxt<'hir, '_, '_>,
855 p: &mut Stream<'_>,
856 tree: Rc<Tree>,
857 literal: query::BuiltInLiteral,
858) -> Result<hir::ExprKind<'hir>> {
859 alloc_with!(cx, p);
860
861 let Some([root]) = tree.nodes() else {
862 return Err(Error::msg(
863 &*p,
864 "expected single root in expanded template!()",
865 ));
866 };
867
868 if !matches!(root.kind(), Root) {
869 return Err(Error::expected(root, Root));
870 }
871
872 let mut exprs = Vec::new();
873
874 root.parse(|p| {
875 let mut comma = Remaining::default();
876
877 let in_template = replace(&mut cx.in_template, true);
878
879 while let MaybeNode::Some(expr) = p.eat(Expr) {
880 comma.exactly_one(cx)?;
881 exprs.try_push(expr.parse(|p| self::expr(cx, p))?)?;
882 comma = p.one(K![,]);
883 }
884
885 cx.in_template = in_template;
886
887 comma.at_most_one(cx)?;
888
889 let template = alloc!(hir::BuiltInTemplate {
890 span: p.span(),
891 from_literal: literal.is_yes(),
892 exprs: iter!(exprs),
893 });
894
895 Ok(hir::ExprKind::Template(template))
896 })
897}
898
899#[instrument_ast(span = p)]
900fn expr_return<'hir>(
901 cx: &mut Ctxt<'hir, '_, '_>,
902 p: &mut Stream<'_>,
903) -> Result<hir::ExprKind<'hir>> {
904 alloc_with!(cx, p);
905 p.expect(K![return])?;
906 let expr = p.eat(Expr).parse(|p| expr(cx, p))?;
907 Ok(hir::ExprKind::Return(option!(expr)))
908}
909
910#[instrument_ast(span = p)]
911fn expr_yield<'hir>(
912 cx: &mut Ctxt<'hir, '_, '_>,
913 p: &mut Stream<'_>,
914) -> Result<hir::ExprKind<'hir>> {
915 alloc_with!(cx, p);
916 p.expect(K![yield])?;
917 let expr = p.eat(Expr).parse(|p| expr(cx, p))?;
918 Ok(hir::ExprKind::Yield(option!(expr)))
919}
920
921#[instrument_ast(span = p)]
922fn expr_break<'hir>(
923 cx: &mut Ctxt<'hir, '_, '_>,
924 p: &mut Stream<'_>,
925) -> Result<hir::ExprKind<'hir>> {
926 alloc_with!(cx, p);
927
928 p.expect(K![break])?;
929
930 let label = p
931 .eat_matching(|k| matches!(k, K!['label]))
932 .ast::<ast::Label>()?;
933
934 let expr = p.eat(Expr).parse(|p| expr(cx, p))?;
935
936 let label = match label {
937 Some(label) => Some(label.resolve(resolve_context!(cx.q))?),
938 None => None,
939 };
940
941 let Some(drop) = cx.scopes.loop_drop(label)? else {
942 if let Some(label) = label {
943 return Err(Error::new(
944 &*p,
945 ErrorKind::MissingLabel {
946 label: label.try_into()?,
947 },
948 ));
949 } else {
950 return Err(Error::new(&*p, ErrorKind::BreakUnsupported));
951 }
952 };
953
954 Ok(hir::ExprKind::Break(alloc!(hir::ExprBreak {
955 label: match label {
956 Some(label) => Some(alloc_str!(label)),
957 None => None,
958 },
959 expr: option!(expr),
960 drop: iter!(drop),
961 })))
962}
963
964#[instrument_ast(span = p)]
965fn expr_continue<'hir>(
966 cx: &mut Ctxt<'hir, '_, '_>,
967 p: &mut Stream<'_>,
968) -> Result<hir::ExprKind<'hir>> {
969 alloc_with!(cx, p);
970
971 p.expect(K![continue])?;
972
973 let label = p
974 .eat_matching(|k| matches!(k, K!['label]))
975 .ast::<ast::Label>()?;
976
977 let label = match label {
978 Some(label) => Some(label.resolve(resolve_context!(cx.q))?),
979 None => None,
980 };
981
982 let Some(drop) = cx.scopes.loop_drop(label)? else {
983 if let Some(label) = label {
984 return Err(Error::new(
985 &*p,
986 ErrorKind::MissingLabel {
987 label: label.try_into()?,
988 },
989 ));
990 } else {
991 return Err(Error::new(&*p, ErrorKind::ContinueUnsupported));
992 }
993 };
994
995 let kind = hir::ExprContinue {
996 label: match label {
997 Some(label) => Some(alloc_str!(label)),
998 None => None,
999 },
1000 drop: iter!(drop),
1001 };
1002
1003 Ok(hir::ExprKind::Continue(alloc!(kind)))
1004}
1005
1006#[instrument_ast(span = p)]
1007fn expr_array<'hir>(
1008 cx: &mut Ctxt<'hir, '_, '_>,
1009 p: &mut Stream<'_>,
1010) -> Result<hir::ExprKind<'hir>> {
1011 alloc_with!(cx, p);
1012
1013 p.expect(K!['['])?;
1014
1015 let mut items = Vec::new();
1016 let mut comma = Remaining::default();
1017
1018 while let MaybeNode::Some(node) = p.eat(Expr) {
1019 comma.exactly_one(cx)?;
1020 items.try_push(node.parse(|p| expr(cx, p))?)?;
1021 comma = p.one(K![,]);
1022 }
1023
1024 comma.at_most_one(cx)?;
1025 p.expect(K![']'])?;
1026
1027 let seq = alloc!(hir::ExprSeq {
1028 items: iter!(items)
1029 });
1030
1031 Ok(hir::ExprKind::Vec(seq))
1032}
1033
1034#[instrument_ast(span = p)]
1036fn expr_tuple<'hir>(
1037 cx: &mut Ctxt<'hir, '_, '_>,
1038 p: &mut Stream<'_>,
1039) -> Result<hir::ExprKind<'hir>> {
1040 alloc_with!(cx, p);
1041
1042 p.expect(K!['('])?;
1043
1044 let mut items = Vec::new();
1045 let mut comma = Remaining::default();
1046
1047 while let MaybeNode::Some(node) = p.eat(Expr) {
1048 comma.exactly_one(cx)?;
1049 items.try_push(node.parse(|p| expr(cx, p))?)?;
1050 comma = p.one(K![,]);
1051 }
1052
1053 if items.len() <= 1 {
1054 comma.exactly_one(cx)?;
1055 } else {
1056 comma.at_most_one(cx)?;
1057 }
1058
1059 p.expect(K![')'])?;
1060
1061 let seq = alloc!(hir::ExprSeq {
1062 items: iter!(items)
1063 });
1064
1065 Ok(hir::ExprKind::Tuple(seq))
1066}
1067
1068#[instrument_ast(span = p)]
1069fn expr_group<'hir>(
1070 cx: &mut Ctxt<'hir, '_, '_>,
1071 p: &mut Stream<'_>,
1072) -> Result<hir::ExprKind<'hir>> {
1073 alloc_with!(cx, p);
1074
1075 p.expect(K!['('])?;
1076
1077 let expr = match p.eat(Expr).parse(|p| expr(cx, p))? {
1078 Some(expr) => expr,
1079 None => hir::Expr {
1080 span: p.span(),
1081 kind: hir::ExprKind::Tuple(&hir::ExprSeq { items: &[] }),
1082 },
1083 };
1084
1085 p.expect(K![')'])?;
1086 Ok(hir::ExprKind::Group(alloc!(expr)))
1087}
1088
1089#[instrument_ast(span = p)]
1090fn expr_empty_group<'hir>(
1091 cx: &mut Ctxt<'hir, '_, '_>,
1092 p: &mut Stream<'_>,
1093) -> Result<hir::ExprKind<'hir>> {
1094 alloc_with!(cx, p);
1095
1096 p.expect(Kind::Open(Delimiter::Empty))?;
1097 let expr = p.expect(Expr)?.parse(|p| expr(cx, p))?;
1098 p.expect(Kind::Close(Delimiter::Empty))?;
1099
1100 Ok(hir::ExprKind::Group(alloc!(expr)))
1101}
1102
1103#[instrument_ast(span = p)]
1105fn expr_object<'hir>(
1106 cx: &mut Ctxt<'hir, '_, '_>,
1107 p: &mut Stream<'_>,
1108) -> Result<hir::ExprKind<'hir>> {
1109 alloc_with!(cx, p);
1110
1111 let key = p.pump()?;
1112
1113 let mut assignments = Vec::new();
1114 let mut comma = Remaining::default();
1115 let mut keys_dup = HashMap::new();
1116
1117 p.expect(K!['{'])?;
1118
1119 while matches!(p.peek(), object_key!()) {
1120 comma.exactly_one(cx)?;
1121
1122 let (key_span, key) = match p.peek() {
1123 K![str] => {
1124 let lit = p.ast::<ast::LitStr>()?;
1125 let string = lit.resolve(resolve_context!(cx.q))?;
1126 (lit.span(), alloc_str!(string.as_ref()))
1127 }
1128 K![ident] => {
1129 let ident = p.ast::<ast::Ident>()?;
1130 let string = ident.resolve(resolve_context!(cx.q))?;
1131 (ident.span(), alloc_str!(string))
1132 }
1133 _ => {
1134 return Err(p.expected("object key"));
1135 }
1136 };
1137
1138 let assign = if p.eat(K![:]).is_some() {
1139 p.expect(Expr)?.parse(|p| expr(cx, p))?
1140 } else {
1141 let Some((name, _)) = cx.scopes.get(hir::Name::Str(key))? else {
1142 return Err(Error::new(
1143 key_span,
1144 ErrorKind::MissingLocal {
1145 name: key.try_to_string()?.try_into()?,
1146 },
1147 ));
1148 };
1149
1150 hir::Expr {
1151 span: key_span,
1152 kind: hir::ExprKind::Variable(name),
1153 }
1154 };
1155
1156 if let Some(_existing) = keys_dup.try_insert(key, key_span)? {
1157 return Err(Error::new(
1158 key_span,
1159 ErrorKind::DuplicateObjectKey {
1160 #[cfg(feature = "emit")]
1161 existing: _existing.span(),
1162 #[cfg(feature = "emit")]
1163 object: p.span(),
1164 },
1165 ));
1166 }
1167
1168 assignments.try_push(hir::FieldAssign {
1169 key: (key_span, key),
1170 assign,
1171 position: None,
1172 })?;
1173
1174 comma = p.one(K![,]);
1175 }
1176
1177 comma.at_most_one(cx)?;
1178 p.expect(K!['}'])?;
1179
1180 let mut check_object_fields = |fields: &[meta::FieldMeta], item: &crate::Item| {
1181 let mut named = HashMap::new();
1182
1183 for f in fields {
1184 named.try_insert(f.name.as_ref(), f)?;
1185 }
1186
1187 for assign in assignments.iter_mut() {
1188 let Some(meta) = named.remove(assign.key.1) else {
1189 return Err(Error::new(
1190 assign.key.0,
1191 ErrorKind::LitObjectNotField {
1192 field: assign.key.1.try_into()?,
1193 item: item.try_to_owned()?,
1194 },
1195 ));
1196 };
1197
1198 assign.position = Some(meta.position);
1199 }
1200
1201 if let Some(field) = named.into_keys().next() {
1202 return Err(Error::new(
1203 p.span(),
1204 ErrorKind::LitObjectMissingField {
1205 field: field.try_into()?,
1206 item: item.try_to_owned()?,
1207 },
1208 ));
1209 }
1210
1211 Ok(())
1212 };
1213
1214 let kind = match key.kind() {
1215 AnonymousObjectKey => hir::ExprObjectKind::Anonymous,
1216 IndexedPath(..) => {
1217 let (named, span) = key.parse(|p| Ok((cx.q.convert_path2(p)?, p.span())))?;
1218 let parameters = generics_parameters(cx, &named)?;
1219 let meta = cx.lookup_meta(&span, named.item, parameters)?;
1220 let item = cx.q.pool.item(meta.item_meta.item);
1221
1222 match &meta.kind {
1223 meta::Kind::Struct {
1224 fields: meta::Fields::Empty,
1225 constructor,
1226 ..
1227 } => {
1228 check_object_fields(&[], item)?;
1229
1230 match constructor {
1231 Some(_) => hir::ExprObjectKind::ExternalType {
1232 hash: meta.hash,
1233 args: 0,
1234 },
1235 None => hir::ExprObjectKind::Struct { hash: meta.hash },
1236 }
1237 }
1238 meta::Kind::Struct {
1239 fields: meta::Fields::Named(st),
1240 constructor,
1241 ..
1242 } => {
1243 check_object_fields(&st.fields, item)?;
1244
1245 match constructor {
1246 Some(_) => hir::ExprObjectKind::ExternalType {
1247 hash: meta.hash,
1248 args: st.fields.len(),
1249 },
1250 None => hir::ExprObjectKind::Struct { hash: meta.hash },
1251 }
1252 }
1253 _ => {
1254 return Err(Error::new(
1255 span,
1256 ErrorKind::UnsupportedLitObject {
1257 meta: meta.info(cx.q.pool)?,
1258 },
1259 ));
1260 }
1261 }
1262 }
1263 _ => {
1264 return Err(p.expected("object key"));
1265 }
1266 };
1267
1268 let object = alloc!(hir::ExprObject {
1269 kind,
1270 assignments: iter!(assignments),
1271 });
1272
1273 Ok(hir::ExprKind::Object(object))
1274}
1275
1276#[instrument_ast(span = p)]
1277fn expr_chain<'hir>(
1278 cx: &mut Ctxt<'hir, '_, '_>,
1279 p: &mut Stream<'_>,
1280) -> Result<hir::ExprKind<'hir>> {
1281 alloc_with!(cx, p);
1282
1283 let node = p.pump()?;
1284
1285 let label = cx.label.take();
1286
1287 let mut inner = node.parse(|p| expr_inner(cx, p))?;
1288
1289 let start = inner.span;
1290
1291 cx.label = label;
1292
1293 for node in p.by_ref() {
1294 let span = start.join(node.span());
1295
1296 let kind = match node.kind() {
1297 ExprCall => node.parse(|p| expr_call(cx, p, inner))?,
1298 ExprField => node.parse(|p| expr_field(cx, p, inner))?,
1299 ExprIndex => node.parse(|p| expr_index(cx, p, inner))?,
1300 ExprAwait => node.parse(|p| expr_await(cx, p, inner))?,
1301 ExprTry => node.parse(|p| expr_try(cx, p, inner))?,
1302 _ => {
1303 return Err(node.expected(ExprChain));
1304 }
1305 };
1306
1307 inner = ExprInner {
1308 span,
1309 kind: ExprInnerKind::Kind(kind),
1310 };
1311 }
1312
1313 inner.into_kind(cx)
1314}
1315
1316#[instrument_ast(span = p)]
1317fn expr_unary<'hir>(
1318 cx: &mut Ctxt<'hir, '_, '_>,
1319 p: &mut Stream<'_>,
1320) -> Result<hir::ExprKind<'hir>> {
1321 alloc_with!(cx, p);
1322
1323 let op = p.ast::<ast::UnOp>()?;
1324
1325 if let ast::UnOp::BorrowRef { .. } = op {
1326 return Err(Error::new(op, ErrorKind::UnsupportedRef));
1327 }
1328
1329 let expr = p.pump()?.parse(|p| expr_only(cx, p))?;
1330
1331 Ok(hir::ExprKind::Unary(alloc!(hir::ExprUnary { op, expr })))
1332}
1333
1334#[instrument_ast(span = p)]
1335fn expr_binary<'hir>(
1336 cx: &mut Ctxt<'hir, '_, '_>,
1337 p: &mut Stream<'_>,
1338) -> Result<hir::ExprKind<'hir>> {
1339 alloc_with!(cx, p);
1340
1341 let (mut lhs, mut lhs_span) = p
1342 .pump()?
1343 .parse(|p| Ok((expr_inner(cx, p)?.into_kind(cx)?, p.span())))?;
1344
1345 while !p.is_eof() {
1346 let node = p.expect(ExprOperator)?;
1347
1348 let Some(op) = node
1349 .tokens::<2>()
1350 .as_deref()
1351 .and_then(ast::BinOp::from_slice)
1352 else {
1353 return Err(node.expected("valid operator"));
1354 };
1355
1356 let rhs_needs = match op {
1357 ast::BinOp::As(..) | ast::BinOp::Is(..) | ast::BinOp::IsNot(..) => Needs::Type,
1358 _ => Needs::Value,
1359 };
1360
1361 let needs = replace(&mut cx.needs, rhs_needs);
1362 let (rhs, rhs_span) = p
1363 .pump()?
1364 .parse(|p| Ok((expr_inner(cx, p)?.into_kind(cx)?, p.span())))?;
1365 cx.needs = needs;
1366
1367 let span = lhs_span.join(rhs_span);
1368 let lhs_span = replace(&mut lhs_span, span);
1369
1370 lhs = hir::ExprKind::Binary(alloc!(hir::ExprBinary {
1371 lhs: hir::Expr {
1372 span: lhs_span,
1373 kind: lhs
1374 },
1375 op,
1376 rhs: hir::Expr {
1377 span: rhs_span,
1378 kind: rhs
1379 },
1380 }));
1381 }
1382
1383 Ok(lhs)
1384}
1385
1386#[instrument_ast(span = p)]
1387fn expr_lit<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::ExprKind<'hir>> {
1388 let lit = lit(cx, p)?;
1389 Ok(hir::ExprKind::Lit(lit))
1390}
1391
1392#[instrument_ast(span = p)]
1393fn expr_assign<'hir>(
1394 cx: &mut Ctxt<'hir, '_, '_>,
1395 p: &mut Stream<'_>,
1396) -> Result<hir::ExprKind<'hir>> {
1397 alloc_with!(cx, p);
1398
1399 let lhs = p.expect(Expr)?.parse(|p| expr(cx, p))?;
1400 p.expect(K![=])?;
1401 let rhs = p.expect(Expr)?.parse(|p| expr(cx, p))?;
1402
1403 Ok(hir::ExprKind::Assign(alloc!(hir::ExprAssign { lhs, rhs })))
1404}
1405
1406#[instrument_ast(span = p)]
1407fn expr_if<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::ExprKind<'hir>> {
1408 alloc_with!(cx, p);
1409
1410 let mut branches = Vec::new();
1411
1412 let start = p.expect(K![if])?;
1413
1414 cx.scopes.push_loop(None)?;
1415 let condition = p.pump()?.parse(|p| self::condition(cx, p))?;
1416 let block = p.expect(Block)?.parse(|p| self::block(cx, None, p))?;
1417 let layer = cx.scopes.pop().with_span(&*p)?;
1418
1419 branches.try_push(hir::ConditionalBranch {
1420 span: start.span().join(block.span),
1421 block,
1422 condition: alloc!(condition),
1423 drop: iter!(layer.into_drop_order()),
1424 })?;
1425
1426 let mut fallback = None;
1427
1428 while fallback.is_none() {
1429 match p.peek() {
1430 ExprElse => {
1431 p.pump()?.parse(|p| {
1432 p.expect(K![else])?;
1433 let block = p.expect(Block)?.parse(|p| self::block(cx, None, p))?;
1434 fallback = Some(alloc!(block));
1435 Ok(())
1436 })?;
1437 }
1438 ExprElseIf => {
1439 p.pump()?.parse(|p| {
1440 p.expect(K![else])?;
1441 p.expect(K![if])?;
1442
1443 cx.scopes.push_loop(None)?;
1444 let condition = p.pump()?.parse(|p| self::condition(cx, p))?;
1445 let block = p.expect(Block)?.parse(|p| self::block(cx, None, p))?;
1446 let layer = cx.scopes.pop().with_span(&*p)?;
1447
1448 branches.try_push(hir::ConditionalBranch {
1449 span: start.span().join(block.span),
1450 block,
1451 condition: alloc!(condition),
1452 drop: iter!(layer.into_drop_order()),
1453 })?;
1454
1455 Ok(())
1456 })?;
1457 }
1458 _ => {
1459 break;
1460 }
1461 }
1462 }
1463
1464 Ok(hir::ExprKind::If(alloc!(hir::Conditional {
1465 branches: iter!(branches),
1466 fallback: option!(fallback),
1467 })))
1468}
1469
1470#[instrument_ast(span = p)]
1471fn expr_match<'hir>(
1472 cx: &mut Ctxt<'hir, '_, '_>,
1473 p: &mut Stream<'_>,
1474) -> Result<hir::ExprKind<'hir>> {
1475 alloc_with!(cx, p);
1476
1477 let mut branches = Vec::new();
1478
1479 p.expect(K![match])?;
1480
1481 let expr = p.expect(Expr)?.parse(|p| expr(cx, p))?;
1482
1483 p.expect(K!['{'])?;
1484
1485 let mut comma = Remaining::default();
1486 let mut was_block = false;
1487
1488 while let MaybeNode::Some(node) = p.eat(ExprMatchArm) {
1489 if was_block {
1490 comma.at_most_one(cx)?;
1491 } else {
1492 comma.exactly_one(cx)?;
1493 }
1494
1495 was_block = node.parse(|p| {
1496 cx.scopes.push(None)?;
1497
1498 let pat = p.expect(Pat)?.parse(|p| self::pat_binding(cx, p))?;
1499
1500 let condition = if p.eat(K![if]).is_some() {
1501 let expr = p.expect(Expr)?.parse(|p| self::expr(cx, p))?;
1502 Some(&*alloc!(expr))
1503 } else {
1504 None
1505 };
1506
1507 p.expect(K![=>])?;
1508
1509 let (body, is_block) = p.expect(Expr)?.parse(|p| {
1510 let is_block = matches!(p.peek(), Block);
1511 let expr = self::expr(cx, p)?;
1512 Ok((expr, is_block))
1513 })?;
1514
1515 let layer = cx.scopes.pop().with_span(&*p)?;
1516
1517 branches.try_push(hir::ExprMatchBranch {
1518 span: p.span(),
1519 pat,
1520 condition,
1521 body,
1522 drop: iter!(layer.into_drop_order()),
1523 })?;
1524
1525 Ok(is_block)
1526 })?;
1527
1528 comma = p.remaining(cx, K![,])?;
1529 }
1530
1531 comma.at_most_one(cx)?;
1532 p.expect(K!['}'])?;
1533
1534 Ok(hir::ExprKind::Match(alloc!(hir::ExprMatch {
1535 expr: alloc!(expr),
1536 branches: iter!(branches),
1537 })))
1538}
1539
1540#[instrument_ast(span = p)]
1541fn expr_select<'hir>(
1542 cx: &mut Ctxt<'hir, '_, '_>,
1543 p: &mut Stream<'_>,
1544) -> Result<hir::ExprKind<'hir>> {
1545 alloc_with!(cx, p);
1546
1547 let mut exprs = Vec::new();
1548 let mut branches = Vec::new();
1549 let mut default = None::<hir::Expr>;
1550
1551 p.expect(K![select])?;
1552
1553 p.expect(K!['{'])?;
1554
1555 let mut comma = Remaining::default();
1556 let mut was_block = false;
1557
1558 while let MaybeNode::Some(node) = p.eat(ExprSelectArm) {
1559 if was_block {
1560 comma.at_most_one(cx)?;
1561 } else {
1562 comma.exactly_one(cx)?;
1563 }
1564
1565 was_block = node.parse(|p| {
1566 cx.scopes.push(None)?;
1567
1568 match p.peek() {
1569 K![default] => {
1570 let default_token = p.expect(K![default])?;
1571 p.expect(K![=>])?;
1572
1573 let (body, is_block) = p.expect(Expr)?.parse(|p| {
1574 let is_block = matches!(p.peek(), Block);
1575 let expr = self::expr(cx, p)?;
1576 Ok((expr, is_block))
1577 })?;
1578
1579 if let Some(existing) = &default {
1580 cx.error(Error::new(
1581 &default_token,
1582 ErrorKind::DuplicateSelectDefault {
1583 existing: existing.span(),
1584 },
1585 ))?;
1586 } else {
1587 default = Some(body);
1588 }
1589
1590 Ok(is_block)
1591 }
1592 Pat => {
1593 let pat = p.expect(Pat)?.parse(|p| self::pat_binding(cx, p))?;
1594 p.expect(K![=])?;
1595 let expr = p.expect(Expr)?.parse(|p| self::expr(cx, p))?;
1596 exprs.try_push(expr)?;
1597 p.expect(K![=>])?;
1598
1599 let (body, is_block) = p.expect(Expr)?.parse(|p| {
1600 let is_block = matches!(p.peek(), Block);
1601 let expr = self::expr(cx, p)?;
1602 Ok((expr, is_block))
1603 })?;
1604
1605 let layer = cx.scopes.pop().with_span(&*p)?;
1606
1607 branches.try_push(hir::ExprSelectBranch {
1608 pat,
1609 body,
1610 drop: iter!(layer.into_drop_order()),
1611 })?;
1612
1613 Ok(is_block)
1614 }
1615 _ => Err(p.expected(ExprSelectArm)),
1616 }
1617 })?;
1618
1619 comma = p.remaining(cx, K![,])?;
1620 }
1621
1622 comma.at_most_one(cx)?;
1623 p.expect(K!['}'])?;
1624
1625 Ok(hir::ExprKind::Select(alloc!(hir::ExprSelect {
1626 exprs: iter!(exprs),
1627 branches: iter!(branches),
1628 default: option!(default),
1629 })))
1630}
1631
1632#[instrument_ast(span = p)]
1633fn expr_while<'hir>(
1634 cx: &mut Ctxt<'hir, '_, '_>,
1635 p: &mut Stream<'_>,
1636) -> Result<hir::ExprKind<'hir>> {
1637 alloc_with!(cx, p);
1638
1639 let label = match cx.label.take() {
1640 Some(label) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
1641 None => None,
1642 };
1643
1644 cx.scopes.push_loop(label)?;
1645
1646 p.expect(K![while])?;
1647
1648 let condition = p.pump()?.parse(|p| condition(cx, p))?;
1649 let body = p.expect(Block)?.parse(|p| block(cx, None, p))?;
1650 let layer = cx.scopes.pop().with_span(&*p)?;
1651
1652 Ok(hir::ExprKind::Loop(alloc!(hir::ExprLoop {
1653 label,
1654 condition: Some(alloc!(condition)),
1655 body,
1656 drop: iter!(layer.into_drop_order()),
1657 })))
1658}
1659
1660#[instrument_ast(span = p)]
1661fn expr_loop<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::ExprKind<'hir>> {
1662 alloc_with!(cx, p);
1663
1664 let label = match cx.label.take() {
1665 Some(label) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
1666 None => None,
1667 };
1668
1669 cx.scopes.push_loop(label)?;
1670
1671 p.expect(K![loop])?;
1672 let body = p.expect(Block)?.parse(|p| block(cx, None, p))?;
1673 let layer = cx.scopes.pop().with_span(&*p)?;
1674
1675 Ok(hir::ExprKind::Loop(alloc!(hir::ExprLoop {
1676 label,
1677 condition: None,
1678 body,
1679 drop: iter!(layer.into_drop_order()),
1680 })))
1681}
1682
1683#[instrument_ast(span = p)]
1684fn expr_for<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::ExprKind<'hir>> {
1685 alloc_with!(cx, p);
1686
1687 p.expect(K![for])?;
1688 let pat = p.expect(Pat)?;
1689 p.expect(K![in])?;
1690 let iter = p.expect(Expr)?;
1691 let block = p.expect(Block)?;
1692
1693 let label = match cx.label.take() {
1694 Some(label) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
1695 None => None,
1696 };
1697
1698 let iter = iter.parse(|p| expr(cx, p))?;
1699
1700 cx.scopes.push_loop(label)?;
1701
1702 let binding = pat.parse(|p| self::pat_binding(cx, p))?;
1703 let body = block.parse(|p| self::block(cx, None, p))?;
1704
1705 let layer = cx.scopes.pop().with_span(&*p)?;
1706
1707 Ok(hir::ExprKind::For(alloc!(hir::ExprFor {
1708 label,
1709 binding,
1710 iter,
1711 body,
1712 drop: iter!(layer.into_drop_order()),
1713 })))
1714}
1715
1716#[instrument_ast(span = p)]
1717fn expr_range<'hir>(
1718 cx: &mut Ctxt<'hir, '_, '_>,
1719 p: &mut Stream<'_>,
1720) -> Result<hir::ExprKind<'hir>> {
1721 alloc_with!(cx, p);
1722
1723 let start = p.pump()?.parse(|p| expr_only(cx, p))?;
1724 p.expect(K![..])?;
1725 let end = p.pump()?.parse(|p| expr_only(cx, p))?;
1726
1727 Ok(hir::ExprKind::Range(alloc!(hir::ExprRange::Range {
1728 start,
1729 end,
1730 })))
1731}
1732
1733#[instrument_ast(span = p)]
1734fn expr_range_inclusive<'hir>(
1735 cx: &mut Ctxt<'hir, '_, '_>,
1736 p: &mut Stream<'_>,
1737) -> Result<hir::ExprKind<'hir>> {
1738 alloc_with!(cx, p);
1739
1740 let start = p.pump()?.parse(|p| expr_only(cx, p))?;
1741 p.expect(K![..=])?;
1742 let end = p.pump()?.parse(|p| expr_only(cx, p))?;
1743
1744 Ok(hir::ExprKind::Range(alloc!(
1745 hir::ExprRange::RangeInclusive { start, end }
1746 )))
1747}
1748
1749#[instrument_ast(span = p)]
1750fn expr_range_from<'hir>(
1751 cx: &mut Ctxt<'hir, '_, '_>,
1752 p: &mut Stream<'_>,
1753) -> Result<hir::ExprKind<'hir>> {
1754 alloc_with!(cx, p);
1755
1756 let start = p.pump()?.parse(|p| expr_only(cx, p))?;
1757 p.expect(K![..])?;
1758
1759 Ok(hir::ExprKind::Range(alloc!(hir::ExprRange::RangeFrom {
1760 start,
1761 })))
1762}
1763
1764#[instrument_ast(span = p)]
1765fn expr_range_full<'hir>(
1766 cx: &mut Ctxt<'hir, '_, '_>,
1767 p: &mut Stream<'_>,
1768) -> Result<hir::ExprKind<'hir>> {
1769 alloc_with!(cx, p);
1770
1771 p.expect(K![..])?;
1772
1773 Ok(hir::ExprKind::Range(alloc!(hir::ExprRange::RangeFull)))
1774}
1775
1776#[instrument_ast(span = p)]
1777fn expr_range_to<'hir>(
1778 cx: &mut Ctxt<'hir, '_, '_>,
1779 p: &mut Stream<'_>,
1780) -> Result<hir::ExprKind<'hir>> {
1781 alloc_with!(cx, p);
1782
1783 p.expect(K![..])?;
1784 let end = p.pump()?.parse(|p| expr_only(cx, p))?;
1785
1786 Ok(hir::ExprKind::Range(alloc!(hir::ExprRange::RangeTo {
1787 end,
1788 })))
1789}
1790
1791#[instrument_ast(span = p)]
1792fn expr_range_to_inclusive<'hir>(
1793 cx: &mut Ctxt<'hir, '_, '_>,
1794 p: &mut Stream<'_>,
1795) -> Result<hir::ExprKind<'hir>> {
1796 alloc_with!(cx, p);
1797
1798 p.expect(K![..=])?;
1799 let end = p.pump()?.parse(|p| expr_only(cx, p))?;
1800
1801 Ok(hir::ExprKind::Range(alloc!(
1802 hir::ExprRange::RangeToInclusive { end }
1803 )))
1804}
1805
1806#[instrument_ast(span = p)]
1807fn condition<'hir>(
1808 cx: &mut Ctxt<'hir, '_, '_>,
1809 p: &mut Stream<'_>,
1810) -> Result<hir::Condition<'hir>> {
1811 alloc_with!(cx, p);
1812
1813 match p.kind() {
1814 Condition => Ok(hir::Condition::ExprLet(alloc!(expr_let(cx, p)?))),
1815 Expr => Ok(hir::Condition::Expr(alloc!(expr(cx, p)?))),
1816 _ => Err(p.expected(Condition)),
1817 }
1818}
1819
1820#[instrument_ast(span = p)]
1821fn expr_let<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::ExprLet<'hir>> {
1822 p.expect(K![let])?;
1823 let pat = p.expect(Pat)?;
1824 p.expect(K![=])?;
1825 let expr = p.expect(Expr)?;
1826
1827 let expr = expr.parse(|p| self::expr(cx, p))?;
1828 let pat = pat.parse(|p| self::pat_binding(cx, p))?;
1829
1830 Ok(hir::ExprLet { pat, expr })
1831}
1832
1833#[instrument_ast(span = p)]
1835fn expr_closure<'hir>(
1836 cx: &mut Ctxt<'hir, '_, '_>,
1837 p: &mut Stream<'_>,
1838 item: ItemId,
1839) -> Result<hir::ExprKind<'hir>> {
1840 alloc_with!(cx, p);
1841
1842 let Some(meta) = cx.q.query_meta(&*p, item, Used::default())? else {
1843 return Err(Error::new(
1844 &*p,
1845 ErrorKind::MissingItem {
1846 item: cx.q.pool.item(item).try_to_owned()?,
1847 },
1848 ));
1849 };
1850
1851 let meta::Kind::Closure { call, do_move, .. } = meta.kind else {
1852 return Err(Error::expected_meta(
1853 &*p,
1854 meta.info(cx.q.pool)?,
1855 "a closure",
1856 ));
1857 };
1858
1859 tracing::trace!("queuing closure build entry");
1860
1861 cx.scopes.push_captures()?;
1862
1863 let args = p.expect(ClosureArguments)?.parse(|p| {
1864 if matches!(p.peek(), K![||]) {
1865 p.pump()?;
1866 return Ok(&[][..]);
1867 };
1868
1869 p.expect(K![|])?;
1870
1871 let mut args = Vec::new();
1872 let mut comma = Remaining::default();
1873
1874 while let MaybeNode::Some(pat) = p.eat(Pat) {
1875 comma.exactly_one(cx)?;
1876 let binding = pat.parse(|p| self::pat_binding(cx, p))?;
1877 comma = p.remaining(cx, K![,])?;
1878 args.try_push(hir::FnArg::Pat(alloc!(binding)))
1879 .with_span(&*p)?;
1880 }
1881
1882 comma.at_most_one(cx)?;
1883 p.expect(K![|])?;
1884 Ok(iter!(args))
1885 })?;
1886
1887 let body = p.expect(Expr)?.parse(|p| expr(cx, p))?;
1888 let body = alloc!(body);
1889
1890 let layer = cx.scopes.pop().with_span(&*p)?;
1891
1892 cx.q.set_used(&meta.item_meta)?;
1893
1894 let captures = &*iter!(layer.captures().map(|(_, id)| id));
1895
1896 let Some(queue) = cx.secondary_builds.as_mut() else {
1897 return Err(Error::new(&*p, ErrorKind::ClosureInConst));
1898 };
1899
1900 queue.try_push(query::SecondaryBuildEntry {
1901 item_meta: meta.item_meta,
1902 build: query::SecondaryBuild::Closure(query::Closure {
1903 hir: alloc!(hir::ExprClosure {
1904 args,
1905 body,
1906 captures,
1907 }),
1908 call,
1909 }),
1910 })?;
1911
1912 if captures.is_empty() {
1913 return Ok(hir::ExprKind::Fn(meta.hash));
1914 }
1915
1916 Ok(hir::ExprKind::CallClosure(alloc!(hir::ExprCallClosure {
1917 hash: meta.hash,
1918 do_move,
1919 captures,
1920 })))
1921}
1922
1923#[instrument_ast(span = p)]
1924fn expr_call<'hir>(
1925 cx: &mut Ctxt<'hir, '_, '_>,
1926 p: &mut Stream<'_>,
1927 inner: ExprInner<'hir, '_>,
1928) -> Result<hir::ExprKind<'hir>> {
1929 alloc_with!(cx, p);
1930
1931 p.expect(K!['('])?;
1932
1933 let mut comma = Remaining::default();
1934 let mut args = Vec::new();
1935
1936 while let MaybeNode::Some(node) = p.eat(Expr) {
1937 comma.exactly_one(cx)?;
1938 let expr = node.parse(|p| expr(cx, p))?;
1939 args.try_push(expr)?;
1940 comma = p.one(K![,]);
1941 }
1942
1943 comma.at_most_one(cx)?;
1944 p.expect(K![')'])?;
1945
1946 let call = inner.into_call(cx, args.len())?;
1947
1948 let kind = hir::ExprKind::Call(alloc!(hir::ExprCall {
1949 call,
1950 args: iter!(args),
1951 }));
1952
1953 Ok(kind)
1954}
1955
1956#[instrument_ast(span = p)]
1957fn expr_field<'hir>(
1958 cx: &mut Ctxt<'hir, '_, '_>,
1959 p: &mut Stream<'_>,
1960 inner: ExprInner<'hir, '_>,
1961) -> Result<hir::ExprKind<'hir>> {
1962 alloc_with!(cx, p);
1963
1964 p.expect(K![.])?;
1965
1966 let expr_field = match p.peek() {
1967 K![number] => {
1968 let number = p.ast::<ast::LitNumber>()?;
1969 let index = number.resolve(resolve_context!(cx.q))?;
1970
1971 let Some(index) = index.as_tuple_index() else {
1972 return Err(Error::new(
1973 number,
1974 ErrorKind::UnsupportedTupleIndex { number: index },
1975 ));
1976 };
1977
1978 hir::ExprField::Index(index)
1979 }
1980 IndexedPath(..) => p.pump()?.parse(|p| match p.kinds() {
1981 Some([K![ident]]) => {
1982 let base = p.ast::<ast::Ident>()?;
1983 let base = base.resolve(resolve_context!(cx.q))?;
1984 let base = alloc_str!(base);
1985 Ok(hir::ExprField::Ident(base))
1986 }
1987 None => {
1988 let base = p.ast::<ast::Ident>()?;
1989 let base = base.resolve(resolve_context!(cx.q))?;
1990 let base = alloc_str!(base);
1991
1992 if p.eat(K![::]).is_some() {
1993 let hash = p
1994 .expect(PathGenerics)?
1995 .parse(|p| generic_arguments(cx, p))?;
1996 Ok(hir::ExprField::IdentGenerics(base, hash))
1997 } else {
1998 Ok(hir::ExprField::Ident(base))
1999 }
2000 }
2001 _ => Err(p.expected_peek(Path)),
2002 })?,
2003 _ => {
2004 return Err(p.expected(ExprField));
2005 }
2006 };
2007
2008 let span = inner.span;
2009 let kind = inner.into_kind(cx)?;
2010
2011 let kind = hir::ExprKind::FieldAccess(alloc!(hir::ExprFieldAccess {
2012 expr: hir::Expr { span, kind },
2013 expr_field,
2014 }));
2015
2016 Ok(kind)
2017}
2018
2019#[instrument_ast(span = p)]
2020fn expr_index<'hir>(
2021 cx: &mut Ctxt<'hir, '_, '_>,
2022 p: &mut Stream<'_>,
2023 inner: ExprInner<'hir, '_>,
2024) -> Result<hir::ExprKind<'hir>> {
2025 alloc_with!(cx, p);
2026
2027 p.expect(K!['['])?;
2028 let index = p.expect(Expr)?.parse(|p| self::expr(cx, p))?;
2029 p.expect(K![']'])?;
2030
2031 let span = inner.span;
2032 let kind = inner.into_kind(cx)?;
2033
2034 let kind = hir::ExprKind::Index(alloc!(hir::ExprIndex {
2035 target: hir::Expr { span, kind },
2036 index,
2037 }));
2038
2039 Ok(kind)
2040}
2041
2042#[instrument_ast(span = p)]
2043fn expr_await<'hir>(
2044 cx: &mut Ctxt<'hir, '_, '_>,
2045 p: &mut Stream<'_>,
2046 inner: ExprInner<'hir, '_>,
2047) -> Result<hir::ExprKind<'hir>> {
2048 alloc_with!(cx, p);
2049
2050 p.expect(K![.])?;
2051 p.expect(K![await])?;
2052
2053 let span = inner.span;
2054 let kind = inner.into_kind(cx)?;
2055
2056 Ok(hir::ExprKind::Await(alloc!(hir::Expr { span, kind })))
2057}
2058
2059#[instrument_ast(span = p)]
2060fn expr_try<'hir>(
2061 cx: &mut Ctxt<'hir, '_, '_>,
2062 p: &mut Stream<'_>,
2063 inner: ExprInner<'hir, '_>,
2064) -> Result<hir::ExprKind<'hir>> {
2065 alloc_with!(cx, p);
2066 p.expect(K![?])?;
2067 let span = inner.span.join(p.span());
2068 let kind = inner.into_kind(cx)?;
2069 Ok(hir::ExprKind::Try(alloc!(hir::Expr { span, kind })))
2070}
2071
2072#[instrument_ast(span = span)]
2074fn expr_path_meta<'hir>(
2075 cx: &mut Ctxt<'hir, '_, '_>,
2076 meta: &meta::Meta,
2077 span: &dyn Spanned,
2078) -> Result<hir::ExprKind<'hir>> {
2079 alloc_with!(cx, span);
2080
2081 if let Needs::Value = cx.needs {
2082 match &meta.kind {
2083 meta::Kind::Struct {
2084 fields: meta::Fields::Empty | meta::Fields::Unnamed(0),
2085 ..
2086 } => Ok(hir::ExprKind::Call(alloc!(hir::ExprCall {
2087 call: hir::Call::Meta { hash: meta.hash },
2088 args: &[],
2089 }))),
2090 meta::Kind::Struct {
2091 fields: meta::Fields::Unnamed(..),
2092 ..
2093 } => Ok(hir::ExprKind::Fn(meta.hash)),
2094 meta::Kind::Function { .. } => Ok(hir::ExprKind::Fn(meta.hash)),
2095 meta::Kind::Const => Ok(hir::ExprKind::Const(meta.hash)),
2096 meta::Kind::Struct { .. } | meta::Kind::Type { .. } | meta::Kind::Enum { .. } => {
2097 Ok(hir::ExprKind::Type(Type::new(meta.hash)))
2098 }
2099 _ => Err(Error::expected_meta(
2100 span,
2101 meta.info(cx.q.pool)?,
2102 "something that can be used as a value",
2103 )),
2104 }
2105 } else {
2106 let Some(type_hash) = meta.type_hash_of() else {
2107 return Err(Error::expected_meta(
2108 span,
2109 meta.info(cx.q.pool)?,
2110 "something that has a type",
2111 ));
2112 };
2113
2114 Ok(hir::ExprKind::Type(Type::new(type_hash)))
2115 }
2116}
2117
2118fn pat_binding<'hir>(
2119 cx: &mut Ctxt<'hir, '_, '_>,
2120 p: &mut Stream<'_>,
2121) -> Result<hir::PatBinding<'hir>> {
2122 pat_binding_with(cx, p, false)
2123}
2124
2125fn pat_binding_with<'hir>(
2126 cx: &mut Ctxt<'hir, '_, '_>,
2127 p: &mut Stream<'_>,
2128 self_value: bool,
2129) -> Result<hir::PatBinding<'hir>> {
2130 alloc_with!(cx, p);
2131 let pat = p.pump()?.parse(|p| pat_inner(cx, p, self_value))?;
2132 let names = iter!(cx.pattern_bindings.drain(..));
2133 Ok(hir::PatBinding { pat, names })
2134}
2135
2136fn pat<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Pat<'hir>> {
2138 p.pump()?.parse(|p| pat_inner(cx, p, false))
2139}
2140
2141fn pat_inner<'hir>(
2142 cx: &mut Ctxt<'hir, '_, '_>,
2143 p: &mut Stream<'_>,
2144 self_value: bool,
2145) -> Result<hir::Pat<'hir>> {
2146 alloc_with!(cx, p);
2147
2148 match p.kind() {
2149 Lit => pat_lit(cx, p),
2150 PatIgnore => Ok(hir::Pat {
2151 span: p.expect(K![_])?.span(),
2152 kind: hir::PatKind::Ignore,
2153 }),
2154 IndexedPath(..) => pat_path(cx, p, self_value),
2155 PatTuple => pat_tuple(cx, p),
2156 PatObject => pat_object(cx, p),
2157 PatArray => pat_array(cx, p),
2158 _ => Err(p.expected(Pat)),
2159 }
2160}
2161
2162#[instrument_ast(span = p)]
2163fn pat_path<'hir>(
2164 cx: &mut Ctxt<'hir, '_, '_>,
2165 p: &mut Stream<'_>,
2166 self_value: bool,
2167) -> Result<hir::Pat<'hir>> {
2168 alloc_with!(cx, p);
2169
2170 let named = cx.q.convert_path2(p)?;
2171 let parameters = generics_parameters(cx, &named)?;
2172
2173 let path = 'path: {
2174 if let Some(meta) = cx.try_lookup_meta(&*p, named.item, ¶meters)? {
2175 match meta.kind {
2176 meta::Kind::Const => {
2177 let Some(const_value) = cx.q.get_const_value(meta.hash) else {
2178 return Err(Error::msg(
2179 &*p,
2180 try_format!("Missing constant for hash {}", meta.hash),
2181 ));
2182 };
2183
2184 let const_value = const_value.try_clone().with_span(&*p)?;
2185 return pat_const_value(cx, &const_value, &*p);
2186 }
2187 _ => {
2188 if let Some((0, kind)) = tuple_match_for(cx, &meta) {
2189 break 'path hir::PatPathKind::Kind(alloc!(kind));
2190 }
2191 }
2192 }
2193 };
2194
2195 match named.kind {
2196 Named2Kind::SelfValue(ast) if self_value => {
2197 let name = cx.scopes.define(hir::Name::SelfValue, &ast)?;
2198 cx.pattern_bindings.try_push(name)?;
2199 break 'path hir::PatPathKind::Ident(name);
2200 }
2201 Named2Kind::Ident(ident) => {
2202 let name = alloc_str!(ident.resolve(resolve_context!(cx.q))?);
2203 let name = cx.scopes.define(hir::Name::Str(name), &*p)?;
2204 cx.pattern_bindings.try_push(name)?;
2205 break 'path hir::PatPathKind::Ident(name);
2206 }
2207 _ => {
2208 return Err(Error::new(&*p, ErrorKind::UnsupportedBinding));
2209 }
2210 }
2211 };
2212
2213 let kind = hir::PatKind::Path(alloc!(path));
2214
2215 Ok(hir::Pat {
2216 span: p.span(),
2217 kind,
2218 })
2219}
2220
2221#[instrument_ast(span = p)]
2222fn pat_lit<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Pat<'hir>> {
2223 alloc_with!(cx, p);
2224
2225 let lit = lit(cx, p)?;
2226
2227 let expr = alloc!(hir::Expr {
2228 span: p.span(),
2229 kind: hir::ExprKind::Lit(lit),
2230 });
2231
2232 Ok(hir::Pat {
2233 span: p.span(),
2234 kind: hir::PatKind::Lit(expr),
2235 })
2236}
2237
2238#[instrument_ast(span = p)]
2239fn pat_tuple<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Pat<'hir>> {
2240 alloc_with!(cx, p);
2241
2242 let path = p.eat_matching(|kind| matches!(kind, IndexedPath(..)));
2243
2244 p.expect(K!['('])?;
2245
2246 let mut items = Vec::new();
2247 let mut comma = Remaining::default();
2248
2249 while let Some(pat) = p.eat(Pat).parse(|p| self::pat(cx, p))? {
2250 comma.exactly_one(cx)?;
2251 items.try_push(pat)?;
2252 comma = p.one(K![,]);
2253 }
2254
2255 let is_open = if p.eat(K![..]).is_some() {
2256 comma.exactly_one(cx)?;
2257 true
2258 } else {
2259 comma.at_most_one(cx)?;
2260 false
2261 };
2262
2263 p.expect(K![')'])?;
2264
2265 let items = iter!(items);
2266
2267 let kind = if let MaybeNode::Some(path) = path {
2268 let (named, span) = path.parse(|p| Ok((cx.q.convert_path2(p)?, p.span())))?;
2269 let parameters = generics_parameters(cx, &named)?;
2270 let meta = cx.lookup_meta(&span, named.item, parameters)?;
2271
2272 let Some((args, kind)) = tuple_match_for(cx, &meta) else {
2275 return Err(Error::expected_meta(
2276 span,
2277 meta.info(cx.q.pool)?,
2278 "type that can be used in a tuple pattern",
2279 ));
2280 };
2281
2282 if !(args == items.len() || items.len() < args && is_open) {
2283 cx.error(Error::new(
2284 span,
2285 ErrorKind::BadArgumentCount {
2286 expected: args,
2287 actual: items.len(),
2288 },
2289 ))?;
2290 }
2291
2292 kind
2293 } else {
2294 hir::PatSequenceKind::Anonymous {
2295 type_check: TypeCheck::Tuple,
2296 count: items.len(),
2297 is_open,
2298 }
2299 };
2300
2301 Ok(hir::Pat {
2302 span: p.span(),
2303 kind: hir::PatKind::Sequence(alloc!(hir::PatSequence { kind, items })),
2304 })
2305}
2306
2307#[instrument_ast(span = p)]
2308fn pat_object<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Pat<'hir>> {
2309 alloc_with!(cx, p);
2310
2311 let key = p.pump()?;
2312
2313 let path = match key.kind() {
2314 AnonymousObjectKey => None,
2315 IndexedPath(..) => Some(key),
2316 _ => {
2317 return Err(p.expected_peek("object kind"));
2318 }
2319 };
2320
2321 p.expect(K!['{'])?;
2322
2323 let mut bindings = Vec::new();
2324 let mut comma = Remaining::default();
2325 let mut keys_dup = HashMap::new();
2326
2327 while matches!(p.peek(), object_key!()) {
2328 comma.exactly_one(cx)?;
2329
2330 let (span, key) = match p.peek() {
2331 K![str] => {
2332 let lit = p.ast::<ast::LitStr>()?;
2333 let string = lit.resolve(resolve_context!(cx.q))?;
2334 (lit.span(), alloc_str!(string.as_ref()))
2335 }
2336 K![ident] => {
2337 let ident = p.ast::<ast::Ident>()?;
2338 let string = ident.resolve(resolve_context!(cx.q))?;
2339 (ident.span(), alloc_str!(string))
2340 }
2341 _ => {
2342 return Err(p.expected_peek("object key"));
2343 }
2344 };
2345
2346 if let Some(_existing) = keys_dup.try_insert(key, span)? {
2347 return Err(Error::new(
2348 span,
2349 ErrorKind::DuplicateObjectKey {
2350 #[cfg(feature = "emit")]
2351 existing: _existing.span(),
2352 #[cfg(feature = "emit")]
2353 object: p.span(),
2354 },
2355 ));
2356 }
2357
2358 if p.eat(K![:]).is_some() {
2359 let pat = p.expect(Pat)?.parse(|p| pat(cx, p))?;
2360 bindings.try_push(hir::Binding::Binding(p.span(), key, alloc!(pat)))?;
2361 } else {
2362 let id = cx.scopes.define(hir::Name::Str(key), &*p)?;
2363 cx.pattern_bindings.try_push(id)?;
2364 bindings.try_push(hir::Binding::Ident(p.span(), key, id))?;
2365 }
2366
2367 comma = p.one(K![,]);
2368 }
2369
2370 let is_open = if p.eat(K![..]).is_some() {
2371 comma.exactly_one(cx)?;
2372 true
2373 } else {
2374 comma.at_most_one(cx)?;
2375 false
2376 };
2377
2378 p.expect(K!['}'])?;
2379
2380 let kind = match path {
2381 Some(path) => {
2382 let (named, span) = path.parse(|p| Ok((cx.q.convert_path2(p)?, p.span())))?;
2383 let parameters = generics_parameters(cx, &named)?;
2384 let meta = cx.lookup_meta(&span, named.item, parameters)?;
2385
2386 let Some((mut fields, kind)) =
2387 struct_match_for(cx, &meta, is_open && bindings.is_empty())?
2388 else {
2389 return Err(Error::expected_meta(
2390 span,
2391 meta.info(cx.q.pool)?,
2392 "type that can be used in a struct pattern",
2393 ));
2394 };
2395
2396 for binding in bindings.iter() {
2397 if !fields.remove(binding.key()) {
2398 return Err(Error::new(
2399 span,
2400 ErrorKind::LitObjectNotField {
2401 field: binding.key().try_into()?,
2402 item: cx.q.pool.item(meta.item_meta.item).try_to_owned()?,
2403 },
2404 ));
2405 }
2406 }
2407
2408 if !is_open && !fields.is_empty() {
2409 let mut fields = fields.into_iter().try_collect::<Box<[_]>>()?;
2410 fields.sort();
2411
2412 return Err(Error::new(
2413 p.span(),
2414 ErrorKind::PatternMissingFields {
2415 item: cx.q.pool.item(meta.item_meta.item).try_to_owned()?,
2416 #[cfg(feature = "emit")]
2417 fields,
2418 },
2419 ));
2420 }
2421
2422 kind
2423 }
2424 None => hir::PatSequenceKind::Anonymous {
2425 type_check: TypeCheck::Object,
2426 count: bindings.len(),
2427 is_open,
2428 },
2429 };
2430
2431 let bindings = iter!(bindings);
2432
2433 Ok(hir::Pat {
2434 span: p.span(),
2435 kind: hir::PatKind::Object(alloc!(hir::PatObject { kind, bindings })),
2436 })
2437}
2438
2439#[instrument_ast(span = p)]
2440fn pat_array<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Pat<'hir>> {
2441 alloc_with!(cx, p);
2442
2443 p.expect(K!['['])?;
2444
2445 let mut items = Vec::new();
2446 let mut comma = Remaining::default();
2447
2448 while let Some(pat) = p.eat(Pat).parse(|p| self::pat(cx, p))? {
2449 comma.exactly_one(cx)?;
2450 items.try_push(pat)?;
2451 comma = p.one(K![,]);
2452 }
2453
2454 let is_open = if p.eat(K![..]).is_some() {
2455 comma.exactly_one(cx)?;
2456 true
2457 } else {
2458 comma.at_most_one(cx)?;
2459 false
2460 };
2461
2462 p.expect(K![']'])?;
2463
2464 let items = iter!(items);
2465
2466 let kind = hir::PatSequenceKind::Anonymous {
2467 type_check: TypeCheck::Vec,
2468 count: items.len(),
2469 is_open,
2470 };
2471
2472 Ok(hir::Pat {
2473 span: p.span(),
2474 kind: hir::PatKind::Sequence(alloc!(hir::PatSequence { kind, items })),
2475 })
2476}
2477
2478fn generics_parameters(
2479 cx: &mut Ctxt<'_, '_, '_>,
2480 named: &Named2<'_>,
2481) -> Result<GenericsParameters> {
2482 let mut parameters = GenericsParameters {
2483 trailing: named.trailing,
2484 parameters: [None, None],
2485 };
2486
2487 for (value, o) in named
2488 .parameters
2489 .iter()
2490 .zip(parameters.parameters.iter_mut())
2491 {
2492 if let Some(node) = value {
2493 let hash = node.clone().parse(|p| generic_arguments(cx, p))?;
2494 *o = Some(hash);
2495 }
2496 }
2497
2498 Ok(parameters)
2499}
2500
2501fn generic_arguments(cx: &mut Ctxt<'_, '_, '_>, p: &mut Stream<'_>) -> Result<Hash> {
2502 p.expect(K![<])?;
2503
2504 let mut comma = Remaining::default();
2505 let mut builder = ParametersBuilder::new();
2506
2507 let needs = replace(&mut cx.needs, Needs::Type);
2508
2509 while matches!(p.peek(), IndexedPath(..)) {
2510 comma.exactly_one(cx)?;
2511
2512 let hir::ExprKind::Type(ty) = p.pump()?.parse(|p| expr_path(cx, p)?.into_kind(cx))? else {
2513 return Err(Error::new(&*p, ErrorKind::UnsupportedGenerics));
2514 };
2515
2516 builder = builder.add(ty.into_hash()).with_span(&*p)?;
2517 comma = p.one(K![,]);
2518 }
2519
2520 cx.needs = needs;
2521
2522 comma.at_most_one(cx)?;
2523 p.expect(K![>])?;
2524 Ok(builder.finish())
2525}
2526
2527#[instrument_ast(span = span)]
2529fn pat_const_value<'hir>(
2530 cx: &mut Ctxt<'hir, '_, '_>,
2531 const_value: &ConstValue,
2532 span: &dyn Spanned,
2533) -> Result<hir::Pat<'hir>> {
2534 alloc_with!(cx, span);
2535
2536 let kind = 'kind: {
2537 let lit = match *const_value.as_kind() {
2538 ConstValueKind::Inline(value) => match value {
2539 Inline::Unit => {
2540 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
2541 kind: hir::PatSequenceKind::Anonymous {
2542 type_check: TypeCheck::Unit,
2543 count: 0,
2544 is_open: false,
2545 },
2546 items: &[],
2547 }));
2548 }
2549 Inline::Bool(b) => hir::Lit::Bool(b),
2550 Inline::Char(ch) => hir::Lit::Char(ch),
2551 Inline::Unsigned(value) => hir::Lit::Unsigned(value),
2552 Inline::Signed(value) => hir::Lit::Signed(value),
2553 _ => return Err(Error::msg(span, "Unsupported constant value in pattern")),
2554 },
2555 ConstValueKind::String(ref string) => hir::Lit::Str(alloc_str!(string.as_ref())),
2556 ConstValueKind::Bytes(ref bytes) => hir::Lit::ByteStr(alloc_bytes!(bytes.as_ref())),
2557 ConstValueKind::Vec(ref items) => {
2558 let items = iter!(items.iter(), items.len(), |value| pat_const_value(
2559 cx, value, span
2560 )?);
2561
2562 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
2563 kind: hir::PatSequenceKind::Anonymous {
2564 type_check: TypeCheck::Vec,
2565 count: items.len(),
2566 is_open: false,
2567 },
2568 items,
2569 }));
2570 }
2571 ConstValueKind::Tuple(ref items) => {
2572 let items = iter!(items.iter(), items.len(), |value| pat_const_value(
2573 cx, value, span
2574 )?);
2575
2576 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
2577 kind: hir::PatSequenceKind::Anonymous {
2578 type_check: TypeCheck::Vec,
2579 count: items.len(),
2580 is_open: false,
2581 },
2582 items,
2583 }));
2584 }
2585 ConstValueKind::Object(ref fields) => {
2586 let bindings = iter!(fields.iter(), fields.len(), |(key, value)| {
2587 let pat = alloc!(pat_const_value(cx, value, span)?);
2588
2589 hir::Binding::Binding(span.span(), alloc_str!(key.as_ref()), pat)
2590 });
2591
2592 break 'kind hir::PatKind::Object(alloc!(hir::PatObject {
2593 kind: hir::PatSequenceKind::Anonymous {
2594 type_check: TypeCheck::Object,
2595 count: bindings.len(),
2596 is_open: false,
2597 },
2598 bindings,
2599 }));
2600 }
2601 _ => {
2602 return Err(Error::msg(span, "Unsupported constant value in pattern"));
2603 }
2604 };
2605
2606 hir::PatKind::Lit(alloc!(hir::Expr {
2607 span: span.span(),
2608 kind: hir::ExprKind::Lit(lit),
2609 }))
2610 };
2611
2612 Ok(hir::Pat {
2613 span: span.span(),
2614 kind,
2615 })
2616}
2617
2618fn struct_match_for(
2624 cx: &Ctxt<'_, '_, '_>,
2625 meta: &meta::Meta,
2626 open: bool,
2627) -> alloc::Result<Option<(HashSet<Box<str>>, hir::PatSequenceKind)>> {
2628 let (fields, kind) = match meta.kind {
2629 meta::Kind::Struct {
2630 ref fields,
2631 enum_hash,
2632 ..
2633 } => {
2634 let kind = 'kind: {
2635 if let Some(type_check) = cx.q.context.type_check_for(meta.hash) {
2636 break 'kind hir::PatSequenceKind::BuiltInVariant { type_check };
2637 }
2638
2639 if enum_hash != Hash::EMPTY {
2640 break 'kind hir::PatSequenceKind::Variant {
2641 enum_hash,
2642 variant_hash: meta.hash,
2643 };
2644 }
2645
2646 hir::PatSequenceKind::Type { hash: meta.hash }
2647 };
2648
2649 (fields, kind)
2650 }
2651 _ => {
2652 return Ok(None);
2653 }
2654 };
2655
2656 let fields = match fields {
2657 meta::Fields::Unnamed(0) if open => HashSet::new(),
2658 meta::Fields::Empty if open => HashSet::new(),
2659 meta::Fields::Named(st) => st
2660 .fields
2661 .iter()
2662 .map(|f| f.name.try_clone())
2663 .try_collect::<alloc::Result<_>>()??,
2664 _ => return Ok(None),
2665 };
2666
2667 Ok(Some((fields, kind)))
2668}
2669
2670fn tuple_match_for(
2671 cx: &Ctxt<'_, '_, '_>,
2672 meta: &meta::Meta,
2673) -> Option<(usize, hir::PatSequenceKind)> {
2674 match meta.kind {
2675 meta::Kind::Struct {
2676 ref fields,
2677 enum_hash,
2678 ..
2679 } => {
2680 let args = fields.as_tuple()?;
2681
2682 let kind = 'kind: {
2683 if let Some(type_check) = cx.q.context.type_check_for(meta.hash) {
2684 break 'kind hir::PatSequenceKind::BuiltInVariant { type_check };
2685 }
2686
2687 if enum_hash != Hash::EMPTY {
2688 break 'kind hir::PatSequenceKind::Variant {
2689 enum_hash,
2690 variant_hash: meta.hash,
2691 };
2692 }
2693
2694 hir::PatSequenceKind::Type { hash: meta.hash }
2695 };
2696
2697 Some((args, kind))
2698 }
2699 _ => None,
2700 }
2701}
2702
2703#[instrument_ast(span = p)]
2704fn lit<'hir>(cx: &mut Ctxt<'hir, '_, '_>, p: &mut Stream<'_>) -> Result<hir::Lit<'hir>> {
2705 alloc_with!(cx, p);
2706
2707 match p.peek() {
2708 K![true] => {
2709 p.ignore();
2710 Ok(hir::Lit::Bool(true))
2711 }
2712 K![false] => {
2713 p.ignore();
2714 Ok(hir::Lit::Bool(false))
2715 }
2716 K![-] | K![number] => {
2717 let neg = p.eat(K![-]).is_some();
2718
2719 let lit = p.ast::<ast::LitNumber>()?;
2720 let n = lit.resolve(resolve_context!(cx.q))?;
2721
2722 match (n.value, n.suffix) {
2723 (ast::NumberValue::Float(n), _) => {
2724 let n = if neg { -n } else { n };
2725 Ok(hir::Lit::Float(n))
2726 }
2727 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Unsigned(_, size))) => {
2728 let int = if neg { int.neg() } else { int };
2729
2730 let Some(n) = int.to_u64() else {
2731 return Err(Error::new(lit, ErrorKind::BadUnsignedOutOfBounds { size }));
2732 };
2733
2734 if !size.unsigned_in(n) {
2735 return Err(Error::new(lit, ErrorKind::BadUnsignedOutOfBounds { size }));
2736 }
2737
2738 Ok(hir::Lit::Unsigned(n))
2739 }
2740 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Signed(_, size))) => {
2741 let int = if neg { int.neg() } else { int };
2742
2743 let Some(n) = int.to_u64() else {
2744 return Err(Error::new(lit, ErrorKind::BadUnsignedOutOfBounds { size }));
2745 };
2746
2747 if !size.unsigned_in(n) {
2748 return Err(Error::new(lit, ErrorKind::BadUnsignedOutOfBounds { size }));
2749 }
2750
2751 Ok(hir::Lit::Unsigned(n))
2752 }
2753 (ast::NumberValue::Integer(int), _) => {
2754 let int = if neg { int.neg() } else { int };
2755
2756 let Some(n) = int.to_i64() else {
2757 return Err(Error::new(
2758 lit,
2759 ErrorKind::BadSignedOutOfBounds {
2760 size: NumberSize::S64,
2761 },
2762 ));
2763 };
2764
2765 Ok(hir::Lit::Signed(n))
2766 }
2767 }
2768 }
2769 K![byte] => {
2770 let lit = p.ast::<ast::LitByte>()?;
2771 let b = lit.resolve(resolve_context!(cx.q))?;
2772 Ok(hir::Lit::Unsigned(b as u64))
2773 }
2774 K![char] => {
2775 let lit = p.ast::<ast::LitChar>()?;
2776 let ch = lit.resolve(resolve_context!(cx.q))?;
2777 Ok(hir::Lit::Char(ch))
2778 }
2779 K![str] => {
2780 let lit = p.ast::<ast::LitStr>()?;
2781
2782 let string = if cx.in_template {
2783 lit.resolve_template_string(resolve_context!(cx.q))?
2784 } else {
2785 lit.resolve_string(resolve_context!(cx.q))?
2786 };
2787
2788 Ok(hir::Lit::Str(alloc_str!(string.as_ref())))
2789 }
2790 K![bytestr] => {
2791 let lit = p.ast::<ast::LitByteStr>()?;
2792 let bytes = lit.resolve(resolve_context!(cx.q))?;
2793 Ok(hir::Lit::ByteStr(alloc_bytes!(bytes.as_ref())))
2794 }
2795 _ => Err(p.expected(Lit)),
2796 }
2797}