rune/hir/
lowering2.rs

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/// Lower a bare function.
29#[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/// Lower a function item.
44#[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/// Lower a block.
86#[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    // NB: This must start as true to avoid the last statement from being
118    // included if none exists.
119    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/// Lower a local.
217#[instrument_ast(span = p)]
218pub(crate) fn local<'hir>(
219    cx: &mut Ctxt<'hir, '_, '_>,
220    p: &mut Stream<'_>,
221) -> Result<hir::Local<'hir>> {
222    // Note: expression needs to be assembled before pattern, otherwise the
223    // expression will see declarations in the pattern.
224
225    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/// Lower an expression.
241#[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, &parameters)? {
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                    // light heuristics, treat it as a type error in case the first
432                    // character is uppercase.
433                    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/// Lower the given block expression.
509#[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/// Lower the given async block expression.
520#[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/// Lower the given async block expression.
548#[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/// Lower the given path.
602#[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/// Lower the given path.
649#[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/// Lower the given tuple.
1035#[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/// Lower the given tuple.
1104#[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/// Assemble a closure expression.
1834#[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/// Compile an item.
2073#[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
2136/// Parses a pattern inside of a binding.
2137fn 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, &parameters)? {
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        // Treat the current meta as a tuple and get the number of arguments it
2273        // should receive and the type check that applies to it.
2274        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/// Construct a pattern from a constant value.
2528#[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
2618/// Generate a legal struct match for the given meta which indicates the type of
2619/// sequence and the fields that it expects.
2620///
2621/// For `open` matches (i.e. `{ .. }`), `Unnamed` and `Empty` structs are also
2622/// supported and they report empty fields.
2623fn 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}