flux_syntax/parser/
mod.rs

1pub(crate) mod lookahead;
2mod utils;
3use std::{collections::HashSet, str::FromStr, vec};
4
5use lookahead::{AnyLit, LAngle, NonReserved, RAngle};
6use rustc_ast::token::Lit;
7use rustc_span::{Symbol, sym::Output};
8use utils::{
9    angle, braces, brackets, delimited, opt_angle, parens, punctuated_until,
10    punctuated_with_trailing, repeat_while, sep1, until,
11};
12
13use crate::{
14    ParseCtxt, ParseError, ParseResult,
15    parser::lookahead::{AnyOf, Expected, PeekExpected},
16    surface::{
17        self, Async,
18        Attr::{self},
19        BaseSort, BaseTy, BaseTyKind, BinOp, BindKind, ConstArg, ConstArgKind, ConstructorArg,
20        DetachedInherentImpl, DetachedItem, DetachedItemKind, DetachedSpecs, DetachedTrait,
21        DetachedTraitImpl, Ensures, EnumDef, Expr, ExprKind, ExprPath, ExprPathSegment, FieldExpr,
22        FluxItem, FnInput, FnOutput, FnRetTy, FnSig, GenericArg, GenericArgKind, GenericBounds,
23        GenericParam, Generics, Ident, ImplAssocReft, Indices, LetDecl, LitKind, Mutability,
24        ParamMode, Path, PathSegment, PrimOpProp, Qualifier, QualifierKind, QuantKind, RefineArg,
25        RefineParam, RefineParams, Requires, Sort, SortDecl, SortPath, SpecFunc, Spread,
26        StaticInfo, StructDef, TraitAssocReft, TraitRef, Trusted, Ty, TyAlias, TyKind, UnOp,
27        VariantDef, VariantRet, WhereBoundPredicate,
28    },
29    symbols::{kw, sym},
30    token::{self, Comma, Delimiter::*, IdentIsRaw, Or, Token, TokenKind},
31};
32
33/// An attribute that's considered part of the *syntax* of an item.
34///
35/// This is in contrast to a [`surface::Attr`] which changes the behavior of an item. For example,
36/// a `#[refined_by(...)]` is part of the syntax of an adt: we could think of a different syntax
37/// that doesn't use an attribute. The existence of a syntax attribute in the token stream can be
38/// used to decide how to keep parsing, for example, if we see a `#[reft]` we know that the next
39/// item must be an associated refinement and not a method inside an impl or trait.
40enum SyntaxAttr {
41    /// A `#[reft]` attribute
42    Reft,
43    /// A `#[invariant]` attribute
44    Invariant(Expr),
45    /// A `#[refined_by(...)]` attribute
46    RefinedBy(RefineParams),
47    /// A `#[hide]` attribute
48    ///
49    /// NOTE(nilehmann) This should be considered a normal attribute, but we haven't implemented
50    /// attributes for flux items. If we start seeing more of these we should consider implementing
51    /// the infrastructure necesary to keep a list of attributes inside the flux item like we do
52    /// for rust items.
53    Hide,
54    /// a `#[opaque]` attribute
55    Opaque,
56    /// A `#[no_panic_if(...)]` attribute
57    NoPanicIf(Expr),
58}
59
60#[derive(Default)]
61struct ParsedAttrs {
62    normal: Vec<Attr>,
63    syntax: Vec<SyntaxAttr>,
64}
65
66impl ParsedAttrs {
67    fn is_reft(&self) -> bool {
68        self.syntax
69            .iter()
70            .any(|attr| matches!(attr, SyntaxAttr::Reft))
71    }
72
73    fn is_hide(&self) -> bool {
74        self.syntax
75            .iter()
76            .any(|attr| matches!(attr, SyntaxAttr::Hide))
77    }
78
79    fn is_opaque(&self) -> bool {
80        self.syntax
81            .iter()
82            .any(|attr| matches!(attr, SyntaxAttr::Opaque))
83    }
84
85    fn refined_by(&mut self) -> Option<RefineParams> {
86        let pos = self
87            .syntax
88            .iter()
89            .position(|x| matches!(x, SyntaxAttr::RefinedBy(_)))?;
90        if let SyntaxAttr::RefinedBy(params) = self.syntax.remove(pos) {
91            Some(params)
92        } else {
93            None
94        }
95    }
96
97    fn no_panic_if(&mut self) -> Option<Expr> {
98        let pos = self
99            .syntax
100            .iter()
101            .position(|x| matches!(x, SyntaxAttr::NoPanicIf(_)))?;
102        if let SyntaxAttr::NoPanicIf(expr) = self.syntax.remove(pos) { Some(expr) } else { None }
103    }
104
105    fn invariant(&mut self) -> Option<Expr> {
106        let pos = self
107            .syntax
108            .iter()
109            .position(|x| matches!(x, SyntaxAttr::Invariant(_)))?;
110        if let SyntaxAttr::Invariant(exp) = self.syntax.remove(pos) { Some(exp) } else { None }
111    }
112}
113
114/// ```text
115///   yes ⟨ , reason = ⟨literal⟩ ⟩?
116/// | no ⟨ , reason = ⟨literal⟩ ⟩?
117/// | reason = ⟨literal⟩
118/// ```
119pub(crate) fn parse_yes_or_no_with_reason(cx: &mut ParseCtxt) -> ParseResult<bool> {
120    let mut lookahead = cx.lookahead1();
121    if lookahead.advance_if(sym::yes) {
122        if cx.advance_if(token::Comma) {
123            parse_reason(cx)?;
124        }
125        Ok(true)
126    } else if lookahead.advance_if(sym::no) {
127        if cx.advance_if(token::Comma) {
128            parse_reason(cx)?;
129        }
130        Ok(false)
131    } else if lookahead.peek(sym::reason) {
132        parse_reason(cx)?;
133        Ok(true)
134    } else {
135        Err(lookahead.into_error())
136    }
137}
138
139/// ```text
140/// ⟨reason⟩ := reason = ⟨literal⟩
141/// ```
142fn parse_reason(cx: &mut ParseCtxt) -> ParseResult {
143    cx.expect(sym::reason)?;
144    cx.expect(token::Eq)?;
145    cx.expect(AnyLit)
146}
147
148/// ```text
149/// ⟨ident_list⟩ := ⟨ident⟩,*
150/// ```
151pub(crate) fn parse_ident_list(cx: &mut ParseCtxt) -> ParseResult<Vec<Ident>> {
152    punctuated_until(cx, Comma, token::Eof, parse_ident)
153}
154
155/// ```text
156/// ⟨flux_items⟩ := ⟨flux_item⟩*
157/// ```
158pub(crate) fn parse_flux_items(cx: &mut ParseCtxt) -> ParseResult<Vec<FluxItem>> {
159    until(cx, token::Eof, parse_flux_item)
160}
161
162/// ```text
163/// ⟨flux_item⟩ := ⟨func_def⟩
164///              | ⟨qualifier⟩
165///              | ⟨sort_decl⟩
166///              | ⟨primop_prop⟩
167/// ```
168fn parse_flux_item(cx: &mut ParseCtxt) -> ParseResult<FluxItem> {
169    let mut lookahead = cx.lookahead1();
170    if lookahead.peek(token::Pound) || lookahead.peek(kw::Fn) {
171        parse_reft_func(cx).map(FluxItem::FuncDef)
172    } else if lookahead.peek(kw::Local)
173        || lookahead.peek(kw::Invariant)
174        || lookahead.peek(kw::Qualifier)
175    {
176        parse_qualifier(cx).map(FluxItem::Qualifier)
177    } else if lookahead.peek(kw::Opaque) {
178        parse_sort_decl(cx).map(FluxItem::SortDecl)
179    } else if lookahead.peek(kw::Property) {
180        parse_primop_property(cx).map(FluxItem::PrimOpProp)
181    } else {
182        Err(lookahead.into_error())
183    }
184}
185
186///```text
187/// ⟨specs⟩ ::= ⟨specs⟩*
188/// ```
189pub(crate) fn parse_detached_specs(cx: &mut ParseCtxt) -> ParseResult<surface::DetachedSpecs> {
190    let items = until(cx, token::Eof, parse_detached_item)?;
191    Ok(surface::DetachedSpecs { items })
192}
193
194///```text
195/// ⟨specs⟩ ::= ⟨fn-spec⟩
196///           | ⟨struct-spec⟩
197///           | ⟨enum-spec⟩
198///           | ⟨mod⟩
199///           | ⟨impl⟩
200/// ```
201pub(crate) fn parse_detached_item(cx: &mut ParseCtxt) -> ParseResult<DetachedItem> {
202    let attrs = parse_attrs(cx)?;
203    let mut lookahead = cx.lookahead1();
204    if lookahead.peek(kw::Fn) {
205        Ok(parse_detached_fn_sig(cx, attrs)?.map_kind(DetachedItemKind::FnSig))
206    } else if lookahead.peek(kw::Mod) {
207        parse_detached_mod(cx)
208    } else if lookahead.peek(kw::Struct) {
209        parse_detached_struct(cx, attrs)
210    } else if lookahead.peek(kw::Enum) {
211        parse_detached_enum(cx, attrs)
212    } else if lookahead.peek(kw::Impl) {
213        parse_detached_impl(cx, attrs)
214    } else if lookahead.peek(kw::Trait) {
215        parse_detached_trait(cx, attrs)
216    } else if lookahead.peek(kw::Static) {
217        parse_detached_static(cx, attrs)
218    } else {
219        Err(lookahead.into_error())
220    }
221}
222
223///```text
224/// ⟨field⟩ ::= ⟨ident⟩ : ⟨type⟩
225/// ```
226fn parse_detached_field(cx: &mut ParseCtxt) -> ParseResult<(Ident, Ty)> {
227    let ident = parse_ident(cx)?;
228    cx.expect(token::Colon)?;
229    let ty = parse_type(cx)?;
230    Ok((ident, ty))
231}
232
233///```text
234/// ⟨enum⟩ := enum Ident ⟨refine_info⟩ { ⟨variant⟩* }
235/// ```
236fn parse_detached_enum(cx: &mut ParseCtxt, mut attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
237    cx.expect(kw::Enum)?;
238    let path = parse_expr_path(cx)?;
239    let generics = Some(parse_opt_generics(cx)?);
240    let refined_by = attrs.refined_by();
241    let invariants = attrs.invariant().into_iter().collect();
242    let variants = braces(cx, Comma, |cx| parse_variant(cx, true))?
243        .into_iter()
244        .map(Some)
245        .collect();
246    let enum_def = EnumDef { generics, refined_by, variants, invariants, reflected: false };
247    Ok(DetachedItem {
248        attrs: attrs.normal,
249        path,
250        kind: DetachedItemKind::Enum(enum_def),
251        node_id: cx.next_node_id(),
252    })
253}
254
255fn parse_detached_struct(cx: &mut ParseCtxt, mut attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
256    cx.expect(kw::Struct)?;
257    let path = parse_expr_path(cx)?;
258    let generics = Some(parse_opt_generics(cx)?);
259    let refined_by = attrs.refined_by();
260    let opaque = attrs.is_opaque();
261    let invariants = attrs.invariant().into_iter().collect();
262    let fields = if cx.peek(token::OpenBrace) {
263        braces(cx, Comma, parse_detached_field)?
264            .into_iter()
265            .map(|(_, ty)| Some(ty))
266            .collect()
267    } else if cx.peek(token::OpenParen) {
268        parens(cx, Comma, parse_type)?
269            .into_iter()
270            .map(Some)
271            .collect()
272    } else {
273        cx.expect(token::Semi)?;
274        vec![]
275    };
276    let struct_def = StructDef { generics, opaque, refined_by, invariants, fields };
277    Ok(DetachedItem {
278        attrs: attrs.normal,
279        path,
280        kind: DetachedItemKind::Struct(struct_def),
281        node_id: cx.next_node_id(),
282    })
283}
284
285fn ident_path(cx: &mut ParseCtxt, ident: Ident) -> ExprPath {
286    let span = ident.span;
287    let segments = vec![ExprPathSegment { ident, node_id: cx.next_node_id() }];
288    ExprPath { segments, span, node_id: cx.next_node_id() }
289}
290
291fn parse_detached_fn_sig(
292    cx: &mut ParseCtxt,
293    mut attrs: ParsedAttrs,
294) -> ParseResult<DetachedItem<FnSig>> {
295    let mut fn_sig = parse_fn_sig(cx, token::Semi)?;
296    fn_sig.no_panic = attrs.no_panic_if();
297    let span = fn_sig.span;
298    let ident = fn_sig
299        .ident
300        .ok_or(ParseError { kind: crate::ParseErrorKind::InvalidDetachedSpec, span })?;
301    let path = ident_path(cx, ident);
302    Ok(DetachedItem { attrs: attrs.normal, path, kind: fn_sig, node_id: cx.next_node_id() })
303}
304
305///```text
306/// ⟨static-spec⟩ ::= static ⟨ident⟩ : ⟨type⟩ ;
307/// ```
308fn parse_detached_static(cx: &mut ParseCtxt, attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
309    cx.expect(kw::Static)?;
310    let path = parse_expr_path(cx)?;
311    cx.expect(token::Colon)?;
312    let ty = parse_type(cx)?;
313    cx.expect(token::Semi)?;
314    Ok(DetachedItem {
315        attrs: attrs.normal,
316        path,
317        kind: DetachedItemKind::Static(StaticInfo { ty }),
318        node_id: cx.next_node_id(),
319    })
320}
321
322///```text
323/// ⟨mod⟩ ::= mod ⟨ident⟩ { ⟨specs⟩ }
324/// ```
325fn parse_detached_mod(cx: &mut ParseCtxt) -> ParseResult<DetachedItem> {
326    cx.expect(kw::Mod)?;
327    let path = parse_expr_path(cx)?;
328    cx.expect(TokenKind::open_delim(Brace))?;
329    let items = until(cx, TokenKind::close_delim(Brace), parse_detached_item)?;
330    cx.expect(TokenKind::close_delim(Brace))?;
331    Ok(DetachedItem {
332        attrs: vec![],
333        path,
334        kind: DetachedItemKind::Mod(DetachedSpecs { items }),
335        node_id: cx.next_node_id(),
336    })
337}
338
339///```text
340/// ⟨trait-spec⟩ ::= trait Ident { ⟨fn-spec⟩* }
341/// ```
342fn parse_detached_trait(cx: &mut ParseCtxt, attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
343    cx.expect(kw::Trait)?;
344    let path = parse_expr_path(cx)?;
345    let _generics = parse_opt_generics(cx)?;
346    cx.expect(TokenKind::open_delim(Brace))?;
347
348    let mut items = vec![];
349    let mut refts = vec![];
350    while !cx.peek(TokenKind::close_delim(Brace)) {
351        let assoc_item_attrs = parse_attrs(cx)?;
352        if assoc_item_attrs.is_reft() {
353            refts.push(parse_trait_assoc_reft(cx)?);
354        } else {
355            items.push(parse_detached_fn_sig(cx, assoc_item_attrs)?);
356        }
357    }
358    cx.expect(TokenKind::close_delim(Brace))?;
359    Ok(DetachedItem {
360        attrs: attrs.normal,
361        path,
362        kind: DetachedItemKind::Trait(DetachedTrait { items, refts }),
363        node_id: cx.next_node_id(),
364    })
365}
366
367///```text
368/// ⟨impl-spec⟩ ::= impl Ident (for Ident)? { ⟨#[assoc] impl_assoc_reft⟩* ⟨fn-spec⟩* }
369/// ```
370fn parse_detached_impl(cx: &mut ParseCtxt, attrs: ParsedAttrs) -> ParseResult<DetachedItem> {
371    let lo = cx.lo();
372    cx.expect(kw::Impl)?;
373    let hi = cx.hi();
374    let span = cx.mk_span(lo, hi);
375    let outer_path = parse_expr_path(cx)?;
376    let _generics = parse_opt_generics(cx)?;
377    let inner_path = if cx.advance_if(kw::For) {
378        let path = parse_expr_path(cx)?;
379        let _generics = parse_opt_generics(cx)?;
380        Some(path)
381    } else {
382        None
383    };
384    cx.expect(TokenKind::open_delim(Brace))?;
385
386    let mut items = vec![];
387    let mut refts = vec![];
388    while !cx.peek(TokenKind::close_delim(Brace)) {
389        // if inner_path.is_none, we are parsing an inherent impl with no associated-refts
390        let assoc_item_attrs = parse_attrs(cx)?;
391        if assoc_item_attrs.is_reft() && inner_path.is_some() {
392            refts.push(parse_impl_assoc_reft(cx)?);
393        } else {
394            items.push(parse_detached_fn_sig(cx, assoc_item_attrs)?);
395        }
396    }
397    cx.expect(TokenKind::close_delim(Brace))?;
398    if let Some(path) = inner_path {
399        Ok(DetachedItem {
400            attrs: attrs.normal,
401            path,
402            kind: DetachedItemKind::TraitImpl(DetachedTraitImpl {
403                trait_: outer_path,
404                items,
405                refts,
406                span,
407            }),
408            node_id: cx.next_node_id(),
409        })
410    } else {
411        Ok(DetachedItem {
412            attrs: attrs.normal,
413            path: outer_path,
414            kind: DetachedItemKind::InherentImpl(DetachedInherentImpl { items, span }),
415            node_id: cx.next_node_id(),
416        })
417    }
418}
419
420fn parse_attr(cx: &mut ParseCtxt, attrs: &mut ParsedAttrs) -> ParseResult {
421    cx.expect(token::Pound)?;
422    cx.expect(token::OpenBracket)?;
423    let mut lookahead = cx.lookahead1();
424    if lookahead.advance_if(kw::Trusted) {
425        if cx.advance_if(token::OpenParen) {
426            parse_reason(cx)?;
427            cx.expect(token::CloseParen)?;
428        }
429        attrs.normal.push(Attr::Trusted(Trusted::Yes));
430    } else if lookahead.advance_if(sym::hide) {
431        attrs.syntax.push(SyntaxAttr::Hide);
432    } else if lookahead.advance_if(kw::Opaque) {
433        attrs.syntax.push(SyntaxAttr::Opaque);
434    } else if lookahead.advance_if(kw::Reft) {
435        attrs.syntax.push(SyntaxAttr::Reft);
436    } else if lookahead.advance_if(kw::RefinedBy) {
437        attrs
438            .syntax
439            .push(SyntaxAttr::RefinedBy(delimited(cx, Parenthesis, parse_refined_by)?));
440    } else if lookahead.advance_if(kw::Invariant) {
441        attrs
442            .syntax
443            .push(SyntaxAttr::Invariant(delimited(cx, Parenthesis, |cx| parse_expr(cx, true))?));
444    } else if lookahead.advance_if(sym::no_panic_if) {
445        attrs
446            .syntax
447            .push(SyntaxAttr::NoPanicIf(parse_expr(cx, true)?));
448    } else {
449        return Err(lookahead.into_error());
450    };
451    cx.expect(token::CloseBracket)
452}
453
454fn parse_attrs(cx: &mut ParseCtxt) -> ParseResult<ParsedAttrs> {
455    let mut attrs = ParsedAttrs::default();
456    repeat_while(cx, token::Pound, |cx| parse_attr(cx, &mut attrs))?;
457    Ok(attrs)
458}
459
460/// ```text
461/// ⟨func_def⟩ := ⟨ # [ hide ] ⟩?
462///               fn ⟨ident⟩ ⟨ < ⟨ident⟩,* > ⟩?
463///               ( ⟨refine_param⟩,* )
464///               ->
465///               ⟨sort⟩
466/// ```
467fn parse_reft_func(cx: &mut ParseCtxt) -> ParseResult<SpecFunc> {
468    let attrs = parse_attrs(cx)?;
469    let hide = attrs.is_hide();
470    cx.expect(kw::Fn)?;
471    let name = parse_ident(cx)?;
472    let sort_vars = opt_angle(cx, Comma, parse_ident)?;
473    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
474    cx.expect(token::RArrow)?;
475    let output = parse_sort(cx)?;
476    let body = if cx.peek(token::OpenBrace) {
477        Some(parse_block(cx)?)
478    } else {
479        cx.expect(token::Semi)?;
480        None
481    };
482    Ok(SpecFunc { name, sort_vars, params, output, body, hide })
483}
484
485/// ```text
486/// ⟨qualifier_kind⟩ :=  local
487///                   |  invariant
488/// ```
489fn parse_qualifier_kind(cx: &mut ParseCtxt) -> ParseResult<QualifierKind> {
490    let mut lookahead = cx.lookahead1();
491    if lookahead.advance_if(kw::Local) {
492        Ok(QualifierKind::Local)
493    } else if lookahead.advance_if(kw::Invariant) {
494        Ok(QualifierKind::Hint)
495    } else {
496        Ok(QualifierKind::Global)
497    }
498}
499
500/// ```text
501/// ⟨qualifier⟩ :=  ⟨ qualifier_kind ⟩?
502///                 qualifier ⟨ident⟩ ( ⟨refine_param⟩,* )
503///                 ⟨block⟩
504/// ```
505fn parse_qualifier(cx: &mut ParseCtxt) -> ParseResult<Qualifier> {
506    let lo = cx.lo();
507    let kind = parse_qualifier_kind(cx)?;
508    cx.expect(kw::Qualifier)?;
509    let mut name = parse_ident(cx)?;
510    let mut params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
511    let expr = parse_block(cx)?;
512    let hi = cx.hi();
513
514    if let QualifierKind::Hint = kind {
515        let mut fvars = expr.free_vars();
516        for param in &params {
517            fvars.remove(&param.ident);
518        }
519        params.extend(fvars.into_iter().map(|ident| {
520            RefineParam {
521                ident,
522                sort: Sort::Infer,
523                mode: None,
524                span: ident.span,
525                node_id: cx.next_node_id(),
526            }
527        }));
528
529        let span = name.span;
530        let str = format!("{}_{}_{}", name.name.to_ident_string(), span.lo().0, span.hi().0);
531        name = Ident { name: Symbol::intern(&str), ..name };
532    }
533
534    Ok(Qualifier { name, params, expr, span: cx.mk_span(lo, hi), kind })
535}
536
537/// ```text
538/// ⟨sort_decl⟩ := opaque sort ⟨ident⟩ ;
539/// ```
540fn parse_sort_decl(cx: &mut ParseCtxt) -> ParseResult<SortDecl> {
541    cx.expect(kw::Opaque)?;
542    cx.expect(kw::Sort)?;
543    let name = parse_ident(cx)?;
544    let sort_vars = opt_angle(cx, Comma, parse_ident)?;
545    cx.expect(token::Semi)?;
546    Ok(SortDecl { name, sort_vars })
547}
548
549/// `⟨bin_op⟩ := ⟨ a binary operator ⟩
550fn parse_binop(cx: &mut ParseCtxt) -> ParseResult<BinOp> {
551    let (op, ntokens) = cx
552        .peek_binop()
553        .ok_or_else(|| cx.unexpected_token(vec![Expected::Str("binary operator")]))?;
554    cx.advance_by(ntokens);
555    Ok(op)
556}
557
558/// ```text
559/// ⟨primop_prop⟩ := property ⟨ident⟩ [ ⟨bin_op⟩ ] ( ⟨refine_param⟩,* ) ⟨block⟩
560/// ```
561fn parse_primop_property(cx: &mut ParseCtxt) -> ParseResult<PrimOpProp> {
562    let lo = cx.lo();
563    cx.expect(kw::Property)?;
564
565    // Parse the name
566    let name = parse_ident(cx)?;
567
568    // Parse the operator
569    cx.expect(token::OpenBracket)?;
570    let op = parse_binop(cx)?;
571    cx.expect(token::CloseBracket)?;
572
573    // Parse the args
574    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::No))?;
575
576    let body = parse_block(cx)?;
577    let hi = cx.hi();
578
579    Ok(PrimOpProp { name, op, params, body, span: cx.mk_span(lo, hi) })
580}
581
582pub(crate) fn parse_trait_assoc_refts(cx: &mut ParseCtxt) -> ParseResult<Vec<TraitAssocReft>> {
583    until(cx, token::Eof, parse_trait_assoc_reft)
584}
585
586/// ```text
587/// ⟨trait_assoc_reft⟩ := fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ;?
588///                     | fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
589///                     | final fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
590/// ```
591fn parse_trait_assoc_reft(cx: &mut ParseCtxt) -> ParseResult<TraitAssocReft> {
592    let lo = cx.lo();
593    let final_ = cx.advance_if(kw::Final);
594    cx.expect(kw::Fn)?;
595    let name = parse_ident(cx)?;
596    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
597    cx.expect(token::RArrow)?;
598    let output = parse_base_sort(cx)?;
599    let body = if cx.peek(token::OpenBrace) {
600        Some(parse_block(cx)?)
601    } else {
602        cx.advance_if(token::Semi);
603        None
604    };
605    let hi = cx.hi();
606    Ok(TraitAssocReft { name, params, output, body, span: cx.mk_span(lo, hi), final_ })
607}
608
609pub(crate) fn parse_impl_assoc_refts(cx: &mut ParseCtxt) -> ParseResult<Vec<ImplAssocReft>> {
610    until(cx, token::Eof, parse_impl_assoc_reft)
611}
612
613/// ```text
614/// ⟨impl_assoc_reft⟩ := fn ⟨ident⟩ ( ⟨refine_param⟩,* ) -> ⟨base_sort⟩ ⟨block⟩
615/// ```
616fn parse_impl_assoc_reft(cx: &mut ParseCtxt) -> ParseResult<ImplAssocReft> {
617    let lo = cx.lo();
618    cx.expect(kw::Fn)?;
619    let name = parse_ident(cx)?;
620    let params = parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?;
621    cx.expect(token::RArrow)?;
622    let output = parse_base_sort(cx)?;
623    let body = parse_block(cx)?;
624    let hi = cx.hi();
625    Ok(ImplAssocReft { name, params, output, body, span: cx.mk_span(lo, hi) })
626}
627
628/// ```text
629/// ⟨refined_by⟩ := ⟨refine_param⟩,*
630/// ```
631pub(crate) fn parse_refined_by(cx: &mut ParseCtxt) -> ParseResult<RefineParams> {
632    punctuated_until(cx, Comma, token::Eof, |cx| parse_refine_param(cx, RequireSort::Yes))
633}
634
635/// ```text
636/// ⟨variant⟩ := ⟨fields⟩ -> ⟨variant_ret⟩
637///            | ⟨fields⟩
638///            | ⟨variant_ret⟩
639/// ```
640pub(crate) fn parse_variant(cx: &mut ParseCtxt, ret_arrow: bool) -> ParseResult<VariantDef> {
641    let lo = cx.lo();
642    let mut fields = vec![];
643    let mut ret = None;
644    let ident = if ret_arrow || cx.peek2(NonReserved, token::OpenParen) {
645        Some(parse_ident(cx)?)
646    } else {
647        None
648    };
649    if cx.peek(token::OpenParen) || cx.peek(token::OpenBrace) {
650        fields = parse_fields(cx)?;
651        if cx.advance_if(token::RArrow) {
652            ret = Some(parse_variant_ret(cx)?);
653        }
654    } else {
655        if ret_arrow {
656            cx.expect(token::RArrow)?;
657        }
658        ret = Some(parse_variant_ret(cx)?);
659    };
660    let hi = cx.hi();
661    Ok(VariantDef { ident, fields, ret, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
662}
663
664/// ```text
665/// ⟨fields⟩ := ( ⟨ty⟩,* ) | { ⟨ty⟩,* }
666/// ```
667fn parse_fields(cx: &mut ParseCtxt) -> ParseResult<Vec<Ty>> {
668    let mut lookahead = cx.lookahead1();
669    if lookahead.peek(token::OpenParen) {
670        parens(cx, Comma, parse_type)
671    } else if lookahead.peek(token::OpenBrace) {
672        braces(cx, Comma, parse_type)
673    } else {
674        Err(lookahead.into_error())
675    }
676}
677
678/// ```text
679/// ⟨variant_ret⟩ := ⟨path⟩ ⟨ [ ⟨refine_arg⟩,? ] ⟩?
680/// ```
681fn parse_variant_ret(cx: &mut ParseCtxt) -> ParseResult<VariantRet> {
682    let path = parse_path(cx)?;
683    let indices = if cx.peek(token::OpenBracket) {
684        parse_indices(cx)?
685    } else {
686        let hi = cx.hi();
687        Indices { indices: vec![], span: cx.mk_span(hi, hi) }
688    };
689    Ok(VariantRet { path, indices })
690}
691
692pub(crate) fn parse_type_alias(cx: &mut ParseCtxt) -> ParseResult<TyAlias> {
693    let lo = cx.lo();
694    cx.expect(kw::Type)?;
695    let ident = parse_ident(cx)?;
696    let generics = parse_opt_generics(cx)?;
697    let params = if cx.peek(token::OpenParen) {
698        parens(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Yes))?
699    } else {
700        vec![]
701    };
702    let index = if cx.peek(token::OpenBracket) {
703        Some(delimited(cx, Bracket, |cx| parse_refine_param(cx, RequireSort::Yes))?)
704    } else {
705        None
706    };
707    cx.expect(token::Eq)?;
708    let ty = parse_type(cx)?;
709    let hi = cx.hi();
710    Ok(TyAlias {
711        ident,
712        generics,
713        params,
714        index,
715        ty,
716        node_id: cx.next_node_id(),
717        span: cx.mk_span(lo, hi),
718    })
719}
720
721fn parse_opt_generics(cx: &mut ParseCtxt) -> ParseResult<Generics> {
722    if !cx.peek(LAngle) {
723        let hi = cx.hi();
724        return Ok(Generics { params: vec![], predicates: None, span: cx.mk_span(hi, hi) });
725    }
726    let lo = cx.lo();
727    let params = angle(cx, Comma, parse_generic_param)?;
728    let hi = cx.hi();
729    Ok(Generics { params, predicates: None, span: cx.mk_span(lo, hi) })
730}
731
732fn parse_generic_param(cx: &mut ParseCtxt) -> ParseResult<GenericParam> {
733    let name = parse_ident(cx)?;
734    Ok(GenericParam { name, node_id: cx.next_node_id() })
735}
736
737fn invalid_ident_err(ident: &Ident) -> ParseError {
738    ParseError { kind: crate::ParseErrorKind::InvalidBinding, span: ident.span }
739}
740
741fn mut_as_strg(inputs: Vec<FnInput>, ensures: &[Ensures]) -> ParseResult<Vec<FnInput>> {
742    // 1. Gather ensures
743    let locs = ensures
744        .iter()
745        .filter_map(|ens| if let Ensures::Type(ident, _, _) = ens { Some(ident) } else { None })
746        .collect::<HashSet<_>>();
747    // 2. Walk over inputs and transform references mentioned in ensures
748    let mut res = vec![];
749    for input in inputs {
750        if let FnInput::Ty(Some(ident), _, _) = &input
751            && locs.contains(&ident)
752        {
753            // a known location: better be a mut or else, error!
754            let FnInput::Ty(Some(ident), ty, id) = input else {
755                return Err(invalid_ident_err(ident));
756            };
757            let TyKind::Ref(Mutability::Mut, inner_ty) = ty.kind else {
758                return Err(invalid_ident_err(&ident));
759            };
760            res.push(FnInput::StrgRef(ident, *inner_ty, id));
761        } else {
762            // not a known location, leave unchanged
763            res.push(input);
764        }
765    }
766    Ok(res)
767}
768
769/// ```text
770/// ⟨fn_sig⟩ := ⟨asyncness⟩ fn ⟨ident⟩?
771///             ⟨ [ ⟨refine_param⟩,* ] ⟩?
772///             ( ⟨fn_inputs⟩,* )
773///             ⟨-> ⟨ty⟩⟩?
774///             ⟨requires⟩ ⟨ensures⟩ ⟨where⟩
775/// ```
776pub(crate) fn parse_fn_sig<T: PeekExpected>(cx: &mut ParseCtxt, end: T) -> ParseResult<FnSig> {
777    let lo = cx.lo();
778    let asyncness = parse_asyncness(cx);
779    cx.expect(kw::Fn)?;
780    let ident = if cx.peek(NonReserved) { Some(parse_ident(cx)?) } else { None };
781    let mut generics = parse_opt_generics(cx)?;
782    let params = if cx.peek(token::OpenBracket) {
783        brackets(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?
784    } else {
785        vec![]
786    };
787    let inputs = parens(cx, Comma, parse_fn_input)?;
788    let returns = parse_fn_ret(cx)?;
789    let requires = parse_opt_requires(cx)?;
790    let ensures = parse_opt_ensures(cx)?;
791    let inputs = mut_as_strg(inputs, &ensures)?;
792    generics.predicates = parse_opt_where(cx)?;
793    cx.expect(end)?;
794    let hi = cx.hi();
795    Ok(FnSig {
796        asyncness,
797        generics,
798        params,
799        ident,
800        inputs,
801        requires,
802        output: FnOutput { returns, ensures, node_id: cx.next_node_id() },
803        node_id: cx.next_node_id(),
804        span: cx.mk_span(lo, hi),
805        no_panic: None, // We attach the `no_panic` expr later
806    })
807}
808
809/// ```text
810/// ⟨requires⟩ := ⟨ requires ⟨requires_clause⟩,* ⟩?
811/// ```
812fn parse_opt_requires(cx: &mut ParseCtxt) -> ParseResult<Vec<Requires>> {
813    if !cx.advance_if(kw::Requires) {
814        return Ok(vec![]);
815    }
816    punctuated_until(
817        cx,
818        Comma,
819        |t: TokenKind| t.is_keyword(kw::Ensures) || t.is_keyword(kw::Where) || t.is_eof(),
820        parse_requires_clause,
821    )
822}
823
824/// ```text
825/// ⟨requires_clause⟩ := ⟨ forall ⟨refine_param⟩,+ . ⟩? ⟨expr⟩
826/// ```
827fn parse_requires_clause(cx: &mut ParseCtxt) -> ParseResult<Requires> {
828    let mut params = vec![];
829    if cx.advance_if(kw::Forall) {
830        params = sep1(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
831        cx.expect(token::Dot)?;
832    }
833    let pred = parse_expr(cx, true)?;
834    Ok(Requires { params, pred })
835}
836
837/// ```text
838/// ⟨ensures⟩ := ⟨ensures ⟨ensures_clause⟩,*⟩?
839/// ```
840fn parse_opt_ensures(cx: &mut ParseCtxt) -> ParseResult<Vec<Ensures>> {
841    if !cx.advance_if(kw::Ensures) {
842        return Ok(vec![]);
843    }
844    punctuated_until(
845        cx,
846        Comma,
847        |t: TokenKind| t.is_keyword(kw::Where) || t.is_eof(),
848        parse_ensures_clause,
849    )
850}
851
852/// ```text
853/// ⟨ensures_clause⟩ :=  ⟨ident⟩ : ⟨ty⟩
854///                   |  ⟨expr⟩
855/// ```
856fn parse_ensures_clause(cx: &mut ParseCtxt) -> ParseResult<Ensures> {
857    if cx.peek2(NonReserved, token::Colon) {
858        // ⟨ident⟩ : ⟨ty⟩
859        let ident = parse_ident(cx)?;
860        cx.expect(token::Colon)?;
861        let ty = parse_type(cx)?;
862        Ok(Ensures::Type(ident, ty, cx.next_node_id()))
863    } else {
864        // ⟨expr⟩
865        Ok(Ensures::Pred(parse_expr(cx, true)?))
866    }
867}
868
869fn parse_opt_where(cx: &mut ParseCtxt) -> ParseResult<Option<Vec<WhereBoundPredicate>>> {
870    if !cx.advance_if(kw::Where) {
871        return Ok(None);
872    }
873    Ok(Some(punctuated_until(cx, Comma, token::Eof, parse_where_bound)?))
874}
875
876fn parse_where_bound(cx: &mut ParseCtxt) -> ParseResult<WhereBoundPredicate> {
877    let lo = cx.lo();
878    let bounded_ty = parse_type(cx)?;
879    cx.expect(token::Colon)?;
880    let bounds = parse_generic_bounds(cx)?;
881    let hi = cx.hi();
882    Ok(WhereBoundPredicate { span: cx.mk_span(lo, hi), bounded_ty, bounds })
883}
884
885/// ```text
886/// ⟨fn_ret⟩ := ⟨ -> ⟨ty⟩ ⟩?
887/// ```
888fn parse_fn_ret(cx: &mut ParseCtxt) -> ParseResult<FnRetTy> {
889    if cx.advance_if(token::RArrow) {
890        Ok(FnRetTy::Ty(Box::new(parse_type(cx)?)))
891    } else {
892        let hi = cx.hi();
893        Ok(FnRetTy::Default(cx.mk_span(hi, hi)))
894    }
895}
896
897/// ```text
898/// ⟨fn_input⟩ := ⟨ident⟩ : &strg ⟨ty⟩
899///             | ⟨ident⟩ : ⟨path⟩ { ⟨expr⟩ }
900///             | ⟨ident⟩ : ⟨ty⟩
901///             | ⟨ty⟩
902/// ```
903fn parse_fn_input(cx: &mut ParseCtxt) -> ParseResult<FnInput> {
904    if cx.peek2(NonReserved, token::Colon) {
905        let bind = parse_ident(cx)?;
906        cx.expect(token::Colon)?;
907        if cx.advance_if2(token::And, kw::Strg) {
908            // ⟨ident⟩ : &strg ⟨ty⟩
909            Ok(FnInput::StrgRef(bind, parse_type(cx)?, cx.next_node_id()))
910        } else if cx.peek(NonReserved) {
911            let path = parse_path(cx)?;
912            if cx.peek3(token::OpenBrace, NonReserved, token::Colon) {
913                // ⟨ident⟩ : ⟨path⟩ { ⟨ident⟩ : ⟨expr⟩ }
914                let bty = path_to_bty(path);
915                let ty = parse_bty_exists(cx, bty)?;
916                Ok(FnInput::Ty(Some(bind), ty, cx.next_node_id()))
917            } else if cx.peek(token::OpenBrace) {
918                // ⟨ident⟩ : ⟨path⟩ { ⟨expr⟩ }
919                let pred = delimited(cx, Brace, |cx| parse_expr(cx, true))?;
920                Ok(FnInput::Constr(bind, path, pred, cx.next_node_id()))
921            } else {
922                // ⟨ident⟩ : ⟨ty⟩
923                let bty = path_to_bty(path);
924                let ty = parse_bty_rhs(cx, bty)?;
925                Ok(FnInput::Ty(Some(bind), ty, cx.next_node_id()))
926            }
927        } else {
928            // ⟨ident⟩ : ⟨ty⟩
929            Ok(FnInput::Ty(Some(bind), parse_type(cx)?, cx.next_node_id()))
930        }
931    } else {
932        // ⟨ty⟩
933        Ok(FnInput::Ty(None, parse_type(cx)?, cx.next_node_id()))
934    }
935}
936
937/// ```text
938/// ⟨asyncness⟩ := async?
939/// ```
940fn parse_asyncness(cx: &mut ParseCtxt) -> Async {
941    let lo = cx.lo();
942    if cx.advance_if(kw::Async) {
943        Async::Yes { node_id: cx.next_node_id(), span: cx.mk_span(lo, cx.hi()) }
944    } else {
945        Async::No
946    }
947}
948
949enum Reft {
950    Exi(Ident, Expr),
951    Idx(Indices),
952    None,
953}
954
955fn parse_reft(cx: &mut ParseCtxt) -> ParseResult<Reft> {
956    if cx.peek(token::OpenBrace) {
957        let (bind, pred) = delimited(cx, Brace, |cx| {
958            let bind = parse_ident(cx)?;
959            cx.expect(token::Colon)?;
960            let pred = parse_block_expr(cx)?;
961            Ok((bind, pred))
962        })?;
963        Ok(Reft::Exi(bind, pred))
964    } else if cx.peek(token::OpenBracket) {
965        let indices = parse_indices(cx)?;
966        Ok(Reft::Idx(indices))
967    } else {
968        Ok(Reft::None)
969    }
970}
971
972/// ```text
973/// ⟨ty⟩ := _
974///       | { ⟨ident⟩ ⟨,⟨ident⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
975///       | ( ⟨ty⟩,* )
976///       | { ⟨ty⟩ | ⟨block_expr⟩ }
977///       | { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
978///       | & mut? ⟨ty⟩
979///       | * const ⟨ { ⟨ident⟩ : ⟨expr⟩ } ⟩? ⟨ty⟩
980///       | * mut ⟨ { ⟨ident⟩ : ⟨expr⟩ } ⟩? ⟨ty⟩
981///       | [ ⟨ty⟩ ; ⟨const_arg⟩ ]
982///       | impl ⟨path⟩
983///       | ⟨bty⟩
984///       | ⟨bty⟩ [ ⟨refine_arg⟩,* ]
985///       | ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
986///
987/// ⟨bty⟩ := ⟨path⟩ | ⟨qpath⟩ | [ ⟨ty⟩ ]
988/// ```
989pub(crate) fn parse_type(cx: &mut ParseCtxt) -> ParseResult<Ty> {
990    let lo = cx.lo();
991    let mut lookahead = cx.lookahead1();
992    let kind = if lookahead.advance_if(kw::Underscore) {
993        TyKind::Hole
994    } else if lookahead.advance_if(token::OpenParen) {
995        // ( ⟨ty⟩,* )
996        let (mut tys, trailing) =
997            punctuated_with_trailing(cx, Comma, token::CloseParen, parse_type)?;
998        cx.expect(token::CloseParen)?;
999        if tys.len() == 1 && !trailing {
1000            return Ok(tys.remove(0));
1001        } else {
1002            TyKind::Tuple(tys)
1003        }
1004    } else if lookahead.peek(token::OpenBrace) {
1005        delimited(cx, Brace, |cx| {
1006            if cx.peek2(NonReserved, AnyOf([token::Comma, token::Dot, token::Colon])) {
1007                // { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
1008                parse_general_exists(cx)
1009            } else {
1010                // { ⟨ty⟩ | ⟨block_expr⟩ }
1011                let ty = parse_type(cx)?;
1012                cx.expect(token::Or)?;
1013                let pred = parse_block_expr(cx)?;
1014                Ok(TyKind::Constr(pred, Box::new(ty)))
1015            }
1016        })?
1017    } else if lookahead.advance_if(token::And) {
1018        //  & mut? ⟨ty⟩
1019        let mutbl = if cx.advance_if(kw::Mut) { Mutability::Mut } else { Mutability::Not };
1020        TyKind::Ref(mutbl, Box::new(parse_type(cx)?))
1021    } else if lookahead.advance_if(token::Star) {
1022        //  * const ⟨ { ⟨ident⟩ : ⟨expr⟩ } ⟩? ⟨ty⟩ | * mut ⟨ { ⟨ident⟩ : ⟨expr⟩ } ⟩? ⟨ty⟩
1023        let mutbl = if cx.advance_if(kw::Mut) {
1024            Mutability::Mut
1025        } else {
1026            cx.expect(kw::Const)?;
1027            Mutability::Not
1028        };
1029        // Parse optional refinement on the pointer value: {v: pred}
1030        let reft = parse_reft(cx)?;
1031        let inner_ty = parse_type(cx)?;
1032        let bty = BaseTy {
1033            kind: BaseTyKind::Ptr(mutbl, Box::new(inner_ty)),
1034            span: cx.mk_span(lo, cx.hi()),
1035        };
1036        match reft {
1037            Reft::Exi(bind, pred) => TyKind::Exists { bind, bty, pred },
1038            Reft::Idx(indices) => TyKind::Indexed { bty, indices },
1039            Reft::None => TyKind::Base(bty),
1040        }
1041    } else if lookahead.advance_if(token::OpenBracket) {
1042        let ty = parse_type(cx)?;
1043        if cx.advance_if(token::Semi) {
1044            // [ ⟨ty⟩ ; ⟨const_arg⟩ ]
1045            let len = parse_const_arg(cx)?;
1046            cx.expect(token::CloseBracket)?;
1047            TyKind::Array(Box::new(ty), len)
1048        } else {
1049            // [ ⟨ty⟩ ] ...
1050            cx.expect(token::CloseBracket)?;
1051            let span = cx.mk_span(lo, cx.hi());
1052            let kind = BaseTyKind::Slice(Box::new(ty));
1053            return parse_bty_rhs(cx, BaseTy { kind, span });
1054        }
1055    } else if lookahead.advance_if(kw::Impl) {
1056        // impl ⟨bounds⟩
1057        TyKind::ImplTrait(cx.next_node_id(), parse_generic_bounds(cx)?)
1058    } else if lookahead.peek(NonReserved) {
1059        // ⟨path⟩ ...
1060        let path = parse_path(cx)?;
1061        let bty = path_to_bty(path);
1062        return parse_bty_rhs(cx, bty);
1063    } else if lookahead.peek(LAngle) {
1064        // ⟨qpath⟩ ...
1065        let bty = parse_qpath(cx)?;
1066        return parse_bty_rhs(cx, bty);
1067    } else {
1068        return Err(lookahead.into_error());
1069    };
1070    let hi = cx.hi();
1071    Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1072}
1073
1074/// ```text
1075/// ⟨qpath⟩ := < ⟨ty⟩ as ⟨segments⟩> :: ⟨segments⟩
1076/// ```
1077fn parse_qpath(cx: &mut ParseCtxt) -> ParseResult<BaseTy> {
1078    let lo = cx.lo();
1079    cx.expect(LAngle)?;
1080    let qself = parse_type(cx)?;
1081    cx.expect(kw::As)?;
1082    let mut segments = parse_segments(cx)?;
1083    cx.expect(RAngle)?;
1084    cx.expect(token::PathSep)?;
1085    segments.extend(parse_segments(cx)?);
1086    let hi = cx.hi();
1087
1088    let span = cx.mk_span(lo, hi);
1089    let path = Path { segments, refine: vec![], node_id: cx.next_node_id(), span };
1090    let kind = BaseTyKind::Path(Some(Box::new(qself)), path);
1091    Ok(BaseTy { kind, span })
1092}
1093
1094/// ```text
1095/// { ⟨refine_param⟩ ⟨,⟨refine_param⟩⟩* . ⟨ty⟩ | ⟨block_expr⟩ }
1096/// ```
1097fn parse_general_exists(cx: &mut ParseCtxt) -> ParseResult<TyKind> {
1098    let params = sep1(cx, Comma, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
1099    cx.expect(token::Dot)?;
1100    let ty = parse_type(cx)?;
1101    let pred = if cx.advance_if(token::Or) { Some(parse_block_expr(cx)?) } else { None };
1102    Ok(TyKind::GeneralExists { params, ty: Box::new(ty), pred })
1103}
1104
1105/// ```text
1106///    ⟨bty⟩ [ ⟨refine_arg⟩,* ]
1107/// |  ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1108/// |  ⟨bty⟩
1109/// ```
1110fn parse_bty_rhs(cx: &mut ParseCtxt, bty: BaseTy) -> ParseResult<Ty> {
1111    let lo = bty.span.lo();
1112    if cx.peek(token::OpenBracket) {
1113        // ⟨bty⟩ [ ⟨refine_arg⟩,* ]
1114        let indices = parse_indices(cx)?;
1115        let hi = cx.hi();
1116        let kind = TyKind::Indexed { bty, indices };
1117        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1118    } else if cx.peek(token::OpenBrace) {
1119        // ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1120        parse_bty_exists(cx, bty)
1121    } else {
1122        // ⟨bty⟩
1123        let hi = cx.hi();
1124        let kind = TyKind::Base(bty);
1125        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1126    }
1127}
1128
1129/// ```text
1130/// ⟨bty⟩ { ⟨ident⟩ : ⟨block_expr⟩ }
1131/// ```
1132fn parse_bty_exists(cx: &mut ParseCtxt, bty: BaseTy) -> ParseResult<Ty> {
1133    let lo = bty.span.lo();
1134    delimited(cx, Brace, |cx| {
1135        let bind = parse_ident(cx)?;
1136        cx.expect(token::Colon)?;
1137        let pred = parse_block_expr(cx)?;
1138        let hi = cx.hi();
1139        let kind = TyKind::Exists { bind, bty, pred };
1140        Ok(Ty { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1141    })
1142}
1143
1144fn path_to_bty(path: Path) -> BaseTy {
1145    let span = path.span;
1146    BaseTy { kind: BaseTyKind::Path(None, path), span }
1147}
1148
1149fn parse_indices(cx: &mut ParseCtxt) -> ParseResult<Indices> {
1150    let lo = cx.lo();
1151    let indices = brackets(cx, Comma, parse_refine_arg)?;
1152    let hi = cx.hi();
1153    Ok(Indices { indices, span: cx.mk_span(lo, hi) })
1154}
1155
1156fn parse_fn_bound_input(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1157    let lo = cx.lo();
1158    let tys = parens(cx, Comma, parse_type)?;
1159    let hi = cx.hi();
1160    let kind = TyKind::Tuple(tys);
1161    let span = cx.mk_span(lo, hi);
1162    let in_ty = Ty { kind, node_id: cx.next_node_id(), span };
1163    Ok(GenericArg { kind: GenericArgKind::Type(in_ty), node_id: cx.next_node_id() })
1164}
1165
1166fn parse_fn_bound_output(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1167    let lo = cx.lo();
1168
1169    let ty = if cx.advance_if(token::RArrow) {
1170        parse_type(cx)?
1171    } else {
1172        Ty { kind: TyKind::Tuple(vec![]), node_id: cx.next_node_id(), span: cx.mk_span(lo, lo) }
1173    };
1174    let hi = cx.hi();
1175    let ident = Ident { name: Output, span: cx.mk_span(lo, hi) };
1176    Ok(GenericArg { kind: GenericArgKind::Constraint(ident, ty), node_id: cx.next_node_id() })
1177}
1178
1179fn parse_fn_bound_path(cx: &mut ParseCtxt) -> ParseResult<Path> {
1180    let lo = cx.lo();
1181    let ident = parse_ident(cx)?;
1182    let in_arg = parse_fn_bound_input(cx)?;
1183    let out_arg = parse_fn_bound_output(cx)?;
1184    let args = vec![in_arg, out_arg];
1185    let segment = PathSegment { ident, args, node_id: cx.next_node_id() };
1186    let hi = cx.hi();
1187    Ok(Path {
1188        segments: vec![segment],
1189        refine: vec![],
1190        node_id: cx.next_node_id(),
1191        span: cx.mk_span(lo, hi),
1192    })
1193}
1194
1195fn parse_generic_bounds(cx: &mut ParseCtxt) -> ParseResult<GenericBounds> {
1196    let path = if cx.peek(sym::FnOnce) || cx.peek(sym::FnMut) || cx.peek(sym::Fn) {
1197        parse_fn_bound_path(cx)?
1198    } else {
1199        parse_path(cx)?
1200    };
1201    Ok(vec![TraitRef { path, node_id: cx.next_node_id() }])
1202}
1203
1204fn parse_const_arg(cx: &mut ParseCtxt) -> ParseResult<ConstArg> {
1205    let lo = cx.lo();
1206    let mut lookahead = cx.lookahead1();
1207    let kind = if lookahead.peek(AnyLit) {
1208        let len = parse_int(cx)?;
1209        ConstArgKind::Lit(len)
1210    } else if lookahead.advance_if(kw::Underscore) {
1211        ConstArgKind::Infer
1212    } else {
1213        return Err(lookahead.into_error());
1214    };
1215    let hi = cx.hi();
1216    Ok(ConstArg { kind, span: cx.mk_span(lo, hi) })
1217}
1218
1219/// ```text
1220/// ⟨path⟩ := ⟨segments⟩ ⟨ ( ⟨refine_arg⟩,* ) ⟩?
1221/// ```
1222fn parse_path(cx: &mut ParseCtxt) -> ParseResult<Path> {
1223    let lo = cx.lo();
1224    let segments = parse_segments(cx)?;
1225    let refine =
1226        if cx.peek(token::OpenParen) { parens(cx, Comma, parse_refine_arg)? } else { vec![] };
1227    let hi = cx.hi();
1228    Ok(Path { segments, refine, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1229}
1230
1231/// ```text
1232/// ⟨segments⟩ := ⟨segment⟩ ⟨:: ⟨segment⟩ ⟩*
1233/// ```
1234fn parse_segments(cx: &mut ParseCtxt) -> ParseResult<Vec<PathSegment>> {
1235    sep1(cx, token::PathSep, parse_segment)
1236}
1237
1238/// ```text
1239/// ⟨segment⟩ := ⟨ident⟩ ⟨ < ⟨generic_arg⟩,* > ⟩?
1240/// ```
1241fn parse_segment(cx: &mut ParseCtxt) -> ParseResult<PathSegment> {
1242    let ident = parse_ident(cx)?;
1243    let args = opt_angle(cx, Comma, parse_generic_arg)?;
1244    Ok(PathSegment { ident, node_id: cx.next_node_id(), args })
1245}
1246
1247/// ```text
1248/// ⟨generic_arg⟩ := ⟨ty⟩ | ⟨ident⟩ = ⟨ty⟩
1249/// ```
1250fn parse_generic_arg(cx: &mut ParseCtxt) -> ParseResult<GenericArg> {
1251    let kind = if cx.peek2(NonReserved, token::Eq) {
1252        let ident = parse_ident(cx)?;
1253        cx.expect(token::Eq)?;
1254        let ty = parse_type(cx)?;
1255        GenericArgKind::Constraint(ident, ty)
1256    } else {
1257        GenericArgKind::Type(parse_type(cx)?)
1258    };
1259    Ok(GenericArg { kind, node_id: cx.next_node_id() })
1260}
1261
1262/// ```text
1263/// ⟨refine_arg⟩ :=  @ ⟨ident⟩
1264///               |  # ⟨ident⟩
1265///               |  |⟨⟨refine_parm⟩,*| ⟨expr⟩
1266///               |  ⟨expr⟩
1267/// ```
1268fn parse_refine_arg(cx: &mut ParseCtxt) -> ParseResult<RefineArg> {
1269    let lo = cx.lo();
1270    let arg = if cx.advance_if(token::At) {
1271        // @ ⟨ident⟩
1272        let bind = parse_ident(cx)?;
1273        let hi = cx.hi();
1274        RefineArg::Bind(bind, BindKind::At, cx.mk_span(lo, hi), cx.next_node_id())
1275    } else if cx.peek2(token::Pound, NonReserved) {
1276        // # ⟨ident⟩
1277        cx.expect(token::Pound)?;
1278        let bind = parse_ident(cx)?;
1279        let hi = cx.hi();
1280        RefineArg::Bind(bind, BindKind::Pound, cx.mk_span(lo, hi), cx.next_node_id())
1281    } else if cx.advance_if(Or) {
1282        let params =
1283            punctuated_until(cx, Comma, Or, |cx| parse_refine_param(cx, RequireSort::Maybe))?;
1284        cx.expect(Or)?;
1285        let body = parse_expr(cx, true)?;
1286        let hi = cx.hi();
1287        RefineArg::Abs(params, body, cx.mk_span(lo, hi), cx.next_node_id())
1288    } else {
1289        // ⟨expr⟩
1290        RefineArg::Expr(parse_expr(cx, true)?)
1291    };
1292    Ok(arg)
1293}
1294
1295/// Whether a sort is required in a refinement parameter declaration.
1296enum RequireSort {
1297    /// Definitely require a sort
1298    Yes,
1299    /// Optional sort. Use [`Sort::Infer`] if not present
1300    Maybe,
1301    /// Definitely do not not require a sort. Always use [`Sort::Infer`]
1302    No,
1303}
1304
1305fn parse_sort_if_required(cx: &mut ParseCtxt, require_sort: RequireSort) -> ParseResult<Sort> {
1306    match require_sort {
1307        RequireSort::No => Ok(Sort::Infer),
1308        RequireSort::Maybe => {
1309            if cx.advance_if(token::Colon) {
1310                parse_sort(cx)
1311            } else {
1312                Ok(Sort::Infer)
1313            }
1314        }
1315        RequireSort::Yes => {
1316            cx.expect(token::Colon)?;
1317            parse_sort(cx)
1318        }
1319    }
1320}
1321
1322/// ```text
1323/// ⟨refine_param⟩ := ⟨mode⟩? ⟨ident⟩ ⟨ : ⟨sort⟩ ⟩?    if require_sort is Maybe
1324///                 | ⟨mode⟩? ⟨ident⟩ : ⟨sort⟩         if require_sort is Yes
1325///                 | ⟨mode⟩? ⟨ident⟩                  if require_sort is No
1326/// ```
1327fn parse_refine_param(cx: &mut ParseCtxt, require_sort: RequireSort) -> ParseResult<RefineParam> {
1328    let lo = cx.lo();
1329    let mode = parse_opt_param_mode(cx);
1330    let ident = parse_ident(cx)?;
1331    let sort = parse_sort_if_required(cx, require_sort)?;
1332    let hi = cx.hi();
1333    Ok(RefineParam { mode, ident, sort, span: cx.mk_span(lo, hi), node_id: cx.next_node_id() })
1334}
1335
1336/// ```text
1337/// ⟨mode⟩ := ⟨ hrn | hdl ⟩?
1338/// ```
1339fn parse_opt_param_mode(cx: &mut ParseCtxt) -> Option<ParamMode> {
1340    if cx.advance_if(kw::Hrn) {
1341        Some(ParamMode::Horn)
1342    } else if cx.advance_if(kw::Hdl) {
1343        Some(ParamMode::Hindley)
1344    } else {
1345        None
1346    }
1347}
1348
1349pub(crate) fn parse_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1350    parse_binops(cx, Precedence::MIN, allow_struct)
1351}
1352
1353fn parse_binops(cx: &mut ParseCtxt, base: Precedence, allow_struct: bool) -> ParseResult<Expr> {
1354    let mut lhs = unary_expr(cx, allow_struct)?;
1355    loop {
1356        let lo = cx.lo();
1357        let Some((op, ntokens)) = cx.peek_binop() else { break };
1358        let precedence = Precedence::of_binop(&op);
1359        if precedence < base {
1360            break;
1361        }
1362        cx.advance_by(ntokens);
1363        let next = match precedence.associativity() {
1364            Associativity::Right => precedence,
1365            Associativity::Left => precedence.next(),
1366            Associativity::None => {
1367                if let ExprKind::BinaryOp(op, ..) = &lhs.kind
1368                    && Precedence::of_binop(op) == precedence
1369                {
1370                    return Err(cx.cannot_be_chained(lo, cx.hi()));
1371                }
1372                precedence.next()
1373            }
1374        };
1375        let rhs = parse_binops(cx, next, allow_struct)?;
1376        let span = lhs.span.to(rhs.span);
1377        lhs = Expr {
1378            kind: ExprKind::BinaryOp(op, Box::new([lhs, rhs])),
1379            node_id: cx.next_node_id(),
1380            span,
1381        }
1382    }
1383    Ok(lhs)
1384}
1385
1386/// ```text
1387/// ⟨unary_expr⟩ := - ⟨unary_expr⟩ | ! ⟨unary_expr⟩ | ⟨trailer_expr⟩
1388/// ```
1389fn unary_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1390    let lo = cx.lo();
1391    let kind = if cx.advance_if(token::Minus) {
1392        ExprKind::UnaryOp(UnOp::Neg, Box::new(unary_expr(cx, allow_struct)?))
1393    } else if cx.advance_if(token::Bang) {
1394        ExprKind::UnaryOp(UnOp::Not, Box::new(unary_expr(cx, allow_struct)?))
1395    } else {
1396        return parse_trailer_expr(cx, allow_struct);
1397    };
1398    let hi = cx.hi();
1399    Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1400}
1401
1402/// ```text
1403/// ⟨trailer_expr⟩ :=  ⟨trailer_expr⟩ . ⟨ident⟩
1404///                 |  ⟨trailer_expr⟩ . ⟨integer⟩
1405///                 |  ⟨trailer_expr⟩ ( ⟨expr⟩,* )
1406///                 |  ⟨atom⟩
1407/// ```
1408fn parse_trailer_expr(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1409    let lo = cx.lo();
1410    let mut e = parse_atom(cx, allow_struct)?;
1411    loop {
1412        let kind = if cx.advance_if(token::Dot) {
1413            if let Token { kind: token::Literal(lit), lo, hi } = cx.at(0)
1414                && let Lit { kind: LitKind::Integer, symbol: name, suffix: None, .. } = lit
1415            {
1416                // ⟨trailer_expr⟩ . ⟨integer⟩
1417                cx.advance();
1418                ExprKind::Dot(Box::new(e), Ident { name, span: cx.mk_span(lo, hi) })
1419            } else {
1420                // ⟨trailer_expr⟩ . ⟨ident⟩
1421                let field = parse_ident(cx)?;
1422                ExprKind::Dot(Box::new(e), field)
1423            }
1424        } else if cx.peek(token::OpenParen) {
1425            // ⟨trailer_expr⟩ ( ⟨expr⟩,* )
1426            let args = parens(cx, Comma, |cx| parse_expr(cx, true))?;
1427            ExprKind::Call(Box::new(e), args)
1428        } else {
1429            break;
1430        };
1431        let hi = cx.hi();
1432        e = Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) };
1433    }
1434    Ok(e)
1435}
1436
1437/// ```text
1438/// ⟨atom⟩ := ⟨if_expr⟩
1439///         | ⟨lit⟩
1440///         | ( ⟨expr⟩ )
1441///         | ( ⟨expr⟩,* )
1442///         | ⟨epath⟩
1443///         | ⟨bounded_quant⟩
1444///         |  <⟨ty⟩ as ⟨path⟩> :: ⟨ident⟩
1445///         | [binop]
1446///         | ⟨epath⟩ { ⟨constructor_arg⟩,* }    if allow_struct
1447///         | { ⟨constructor_arg⟩,* }            if allow_struct
1448///         | #{ ⟨expr⟩,* }
1449/// ```
1450fn parse_atom(cx: &mut ParseCtxt, allow_struct: bool) -> ParseResult<Expr> {
1451    let lo = cx.lo();
1452    let mut lookahead = cx.lookahead1();
1453    if lookahead.peek(kw::If) {
1454        // ⟨if_expr⟩
1455        parse_if_expr(cx)
1456    } else if lookahead.peek(AnyLit) {
1457        // ⟨lit⟩
1458        parse_lit(cx)
1459    } else if lookahead.advance_if(token::OpenParen) {
1460        // ( ⟨expr⟩ ) | ( ⟨expr⟩,* )
1461        let (mut exprs, trailing) =
1462            punctuated_with_trailing(cx, Comma, token::CloseParen, |cx| parse_expr(cx, true))?;
1463        cx.expect(token::CloseParen)?;
1464        if exprs.len() == 1 && !trailing {
1465            Ok(exprs.remove(0))
1466        } else {
1467            Ok(Expr {
1468                kind: ExprKind::Tuple(exprs),
1469                node_id: cx.next_node_id(),
1470                span: cx.mk_span(lo, cx.hi()),
1471            })
1472        }
1473    } else if lookahead.advance_if(token::Pound) {
1474        // #{ ⟨expr⟩,* }
1475        let lo = cx.lo();
1476        let exprs = braces(cx, Comma, |cx| parse_expr(cx, true))?;
1477        let hi = cx.hi();
1478        let kind = ExprKind::SetLiteral(exprs);
1479        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1480    } else if lookahead.peek(NonReserved) {
1481        let path = parse_expr_path(cx)?;
1482        let kind = if allow_struct && cx.peek(token::OpenBrace) {
1483            // ⟨epath⟩ { ⟨constructor_arg⟩,* }
1484            let args = braces(cx, Comma, parse_constructor_arg)?;
1485            ExprKind::Constructor(Some(path), args)
1486        } else {
1487            // ⟨epath⟩
1488            ExprKind::Path(path)
1489        };
1490        let hi = cx.hi();
1491        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1492    } else if allow_struct && lookahead.peek(token::OpenBrace) {
1493        // { ⟨constructor_arg⟩,* }
1494        let args = braces(cx, Comma, parse_constructor_arg)?;
1495        let hi = cx.hi();
1496        Ok(Expr {
1497            kind: ExprKind::Constructor(None, args),
1498            node_id: cx.next_node_id(),
1499            span: cx.mk_span(lo, hi),
1500        })
1501    } else if lookahead.advance_if(LAngle) {
1502        // <⟨ty⟩ as ⟨path⟩> :: ⟨ident⟩
1503        let lo = cx.lo();
1504        let qself = parse_type(cx)?;
1505        cx.expect(kw::As)?;
1506        let path = parse_path(cx)?;
1507        cx.expect(RAngle)?;
1508        cx.expect(token::PathSep)?;
1509        let name = parse_ident(cx)?;
1510        let hi = cx.hi();
1511        let kind = ExprKind::AssocReft(Box::new(qself), path, name);
1512        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1513    } else if lookahead.peek(token::OpenBracket) {
1514        parse_prim_uif(cx)
1515    } else if lookahead.peek(kw::Exists) || lookahead.peek(kw::Forall) {
1516        parse_bounded_quantifier(cx)
1517    } else {
1518        Err(lookahead.into_error())
1519    }
1520}
1521
1522fn parse_prim_uif(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1523    let lo = cx.lo();
1524    cx.expect(token::OpenBracket)?;
1525    let op = parse_binop(cx)?;
1526    cx.expect(token::CloseBracket)?;
1527    let hi = cx.hi();
1528    Ok(Expr { kind: ExprKind::PrimUIF(op), node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1529}
1530
1531/// ```text
1532/// ⟨bounded_quant⟩ := forall ⟨refine_param⟩ in ⟨int⟩..⟨int⟩ ⟨block⟩
1533///                  | exists ⟨refine_param⟩ in ⟨int⟩..⟨int⟩ ⟨block⟩
1534/// ```
1535fn parse_bounded_quantifier(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1536    let lo = cx.lo();
1537    let mut lookahead = cx.lookahead1();
1538    let quant = if lookahead.advance_if(kw::Forall) {
1539        QuantKind::Forall
1540    } else if lookahead.advance_if(kw::Exists) {
1541        QuantKind::Exists
1542    } else {
1543        return Err(lookahead.into_error());
1544    };
1545    let param = parse_refine_param(cx, RequireSort::Maybe)?;
1546    cx.expect(kw::In)?;
1547    let start = parse_int(cx)?;
1548    cx.expect(token::DotDot)?;
1549    let end = parse_int(cx)?;
1550    let body = parse_block(cx)?;
1551    let hi = cx.hi();
1552    Ok(Expr {
1553        kind: ExprKind::BoundedQuant(quant, param, start..end, Box::new(body)),
1554        node_id: cx.next_node_id(),
1555        span: cx.mk_span(lo, hi),
1556    })
1557}
1558
1559/// ```text
1560/// ⟨constructor_arg⟩ :=  ⟨ident⟩ : ⟨expr⟩ |  ..
1561/// ```
1562fn parse_constructor_arg(cx: &mut ParseCtxt) -> ParseResult<ConstructorArg> {
1563    let lo = cx.lo();
1564    let mut lookahead = cx.lookahead1();
1565    if lookahead.peek(NonReserved) {
1566        let ident = parse_ident(cx)?;
1567        cx.expect(token::Colon)?;
1568        let expr = parse_expr(cx, true)?;
1569        let hi = cx.hi();
1570        Ok(ConstructorArg::FieldExpr(FieldExpr {
1571            ident,
1572            expr,
1573            node_id: cx.next_node_id(),
1574            span: cx.mk_span(lo, hi),
1575        }))
1576    } else if lookahead.advance_if(token::DotDot) {
1577        let spread = parse_expr(cx, true)?;
1578        let hi = cx.hi();
1579        Ok(ConstructorArg::Spread(Spread {
1580            expr: spread,
1581            node_id: cx.next_node_id(),
1582            span: cx.mk_span(lo, hi),
1583        }))
1584    } else {
1585        Err(lookahead.into_error())
1586    }
1587}
1588
1589/// `⟨epath⟩ := ⟨ident⟩ ⟨ :: ⟨ident⟩ ⟩*`
1590fn parse_expr_path(cx: &mut ParseCtxt) -> ParseResult<ExprPath> {
1591    let lo = cx.lo();
1592    let segments = sep1(cx, token::PathSep, parse_expr_path_segment)?;
1593    let hi = cx.hi();
1594    Ok(ExprPath { segments, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1595}
1596
1597fn parse_expr_path_segment(cx: &mut ParseCtxt) -> ParseResult<ExprPathSegment> {
1598    Ok(ExprPathSegment { ident: parse_ident(cx)?, node_id: cx.next_node_id() })
1599}
1600
1601/// `⟨if_expr⟩ := if ⟨expr⟩ ⟨block⟩ ⟨ else if ⟨expr⟩ ⟨block⟩ ⟩* else ⟨block⟩`
1602///
1603/// The `⟨expr⟩` in conditions is parsed with `allow_struct = false`
1604fn parse_if_expr(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1605    let mut branches = vec![];
1606
1607    loop {
1608        let lo = cx.lo();
1609        cx.expect(kw::If)?;
1610        let cond = parse_expr(cx, false)?;
1611        let then_ = parse_block(cx)?;
1612        branches.push((lo, cond, then_));
1613        cx.expect(kw::Else)?;
1614
1615        if !cx.peek(kw::If) {
1616            break;
1617        }
1618    }
1619    let mut else_ = parse_block(cx)?;
1620
1621    let hi = cx.hi();
1622    while let Some((lo, cond, then_)) = branches.pop() {
1623        else_ = Expr {
1624            kind: ExprKind::IfThenElse(Box::new([cond, then_, else_])),
1625            node_id: cx.next_node_id(),
1626            span: cx.mk_span(lo, hi),
1627        };
1628    }
1629    Ok(else_)
1630}
1631
1632/// `⟨block⟩ := { ⟨block_expr⟩ }`
1633fn parse_block(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1634    delimited(cx, Brace, parse_block_expr)
1635}
1636
1637/// `⟨block_expr⟩ = ⟨let_decl⟩* ⟨expr⟩`
1638fn parse_block_expr(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1639    let lo = cx.lo();
1640    let decls = repeat_while(cx, kw::Let, parse_let_decl)?;
1641    let body = parse_expr(cx, true)?;
1642    let hi = cx.hi();
1643
1644    if decls.is_empty() {
1645        Ok(body)
1646    } else {
1647        let kind = ExprKind::Block(decls, Box::new(body));
1648        Ok(Expr { kind, node_id: cx.next_node_id(), span: cx.mk_span(lo, hi) })
1649    }
1650}
1651
1652/// `⟨let_decl⟩ := let ⟨refine_param⟩ = ⟨expr⟩ ;`
1653fn parse_let_decl(cx: &mut ParseCtxt) -> ParseResult<LetDecl> {
1654    cx.expect(kw::Let)?;
1655    let param = parse_refine_param(cx, RequireSort::Maybe)?;
1656    cx.expect(token::Eq)?;
1657    let init = parse_expr(cx, true)?;
1658    cx.expect(token::Semi)?;
1659    Ok(LetDecl { param, init })
1660}
1661
1662/// ```text
1663/// ⟨lit⟩ := ⟨a Rust literal like an integer or a boolean⟩
1664/// ```
1665fn parse_lit(cx: &mut ParseCtxt) -> ParseResult<Expr> {
1666    if let Token { kind: token::Literal(lit), lo, hi } = cx.at(0) {
1667        cx.advance();
1668        Ok(Expr {
1669            kind: ExprKind::Literal(lit),
1670            node_id: cx.next_node_id(),
1671            span: cx.mk_span(lo, hi),
1672        })
1673    } else {
1674        Err(cx.unexpected_token(vec![AnyLit.expected()]))
1675    }
1676}
1677
1678fn parse_ident(cx: &mut ParseCtxt) -> ParseResult<Ident> {
1679    if let Token { kind: token::Ident(name, is_raw), lo, hi } = cx.at(0)
1680        && (!cx.is_reserved(name) || is_raw == IdentIsRaw::Yes)
1681    {
1682        cx.advance();
1683        return Ok(Ident { name, span: cx.mk_span(lo, hi) });
1684    }
1685    Err(cx.unexpected_token(vec![NonReserved.expected()]))
1686}
1687
1688fn parse_int<T: FromStr>(cx: &mut ParseCtxt) -> ParseResult<T> {
1689    if let token::Literal(lit) = cx.at(0).kind
1690        && let Lit { kind: LitKind::Integer, symbol, suffix: None, .. } = lit
1691        && let Ok(value) = symbol.as_str().parse::<T>()
1692    {
1693        cx.advance();
1694        return Ok(value);
1695    }
1696
1697    Err(cx.unexpected_token(vec![Expected::Str(std::any::type_name::<T>())]))
1698}
1699
1700/// ```text
1701/// ⟨sort⟩ :=  ⟨base_sort⟩
1702///         |  ( ⟨base_sort⟩,* ) -> ⟨base_sort⟩
1703///         |  ⟨base_sort⟩ -> ⟨base_sort⟩
1704/// ```
1705fn parse_sort(cx: &mut ParseCtxt) -> ParseResult<Sort> {
1706    if cx.peek(token::OpenParen) {
1707        // ( ⟨base_sort⟩,* ) -> ⟨base_sort⟩ | ( ⟨base_sort⟩,* )
1708        let inputs = parens(cx, Comma, parse_base_sort)?;
1709        if cx.advance_if(token::RArrow) {
1710            // ( ⟨base_sort⟩,* ) -> ⟨base_sort⟩
1711            let output = parse_base_sort(cx)?;
1712            Ok(Sort::Func { inputs, output })
1713        } else {
1714            // ( ⟨base_sort⟩,* )
1715            Ok(Sort::Base(BaseSort::Tuple(inputs)))
1716        }
1717    } else {
1718        let bsort = parse_base_sort(cx)?;
1719        if cx.advance_if(token::RArrow) {
1720            // ⟨base_sort⟩ -> ⟨base_sort⟩
1721            let output = parse_base_sort(cx)?;
1722            Ok(Sort::Func { inputs: vec![bsort], output })
1723        } else {
1724            // ⟨base_sort⟩
1725            Ok(Sort::Base(bsort))
1726        }
1727    }
1728}
1729
1730/// ```text
1731/// ⟨base_sort⟩ := bitvec < ⟨u32⟩ >
1732///              | ( ⟨base_sort⟩,* )
1733///              | ⟨sort_path⟩ < ⟨base_sort⟩,* >
1734///              | < ⟨ty⟩ as ⟨path⟩ > :: ⟨segment⟩
1735/// ⟨sort_path⟩ := ⟨ident⟩ ⟨ :: ⟨ident⟩ ⟩* < (⟨base_sort⟩,*) >
1736/// ```
1737fn parse_base_sort(cx: &mut ParseCtxt) -> ParseResult<BaseSort> {
1738    if cx.advance_if(kw::Bitvec) {
1739        // bitvec < ⟨u32⟩ >
1740        cx.expect(LAngle)?;
1741        let len = parse_int(cx)?;
1742        cx.expect(RAngle)?;
1743        Ok(BaseSort::BitVec(len))
1744    } else if cx.peek(token::OpenParen) {
1745        // ( ⟨base_sort⟩,* )
1746        let sorts = parens(cx, Comma, parse_base_sort)?;
1747        Ok(BaseSort::Tuple(sorts))
1748    } else if cx.advance_if(LAngle) {
1749        // < ⟨ty⟩ as ⟨path⟩ > :: ⟨segment⟩
1750        let qself = parse_type(cx)?;
1751        cx.expect(kw::As)?;
1752        let mut path = parse_path(cx)?;
1753        cx.expect(RAngle)?;
1754        cx.expect(token::PathSep)?;
1755        path.segments.push(parse_segment(cx)?);
1756        Ok(BaseSort::SortOf(Box::new(qself), path))
1757    } else {
1758        // ⟨sort_path⟩ < ⟨base_sort⟩,* >
1759        let segments = sep1(cx, token::PathSep, parse_ident)?;
1760        let args = opt_angle(cx, Comma, parse_base_sort)?;
1761        let path = SortPath { segments, args, node_id: cx.next_node_id() };
1762        Ok(BaseSort::Path(path))
1763    }
1764}
1765
1766// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
1767#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
1768enum Precedence {
1769    /// <=>
1770    Iff,
1771    /// =>
1772    Implies,
1773    /// ||
1774    Or,
1775    /// &&
1776    And,
1777    /// == != < > <= >=
1778    Compare,
1779    /// |
1780    BitOr,
1781    /// ^
1782    BitXor,
1783    /// &
1784    BitAnd,
1785    /// << >>
1786    Shift,
1787    /// + -
1788    Sum,
1789    /// * / %
1790    Product,
1791    /// unary - and !
1792    Prefix,
1793}
1794
1795enum Associativity {
1796    Right,
1797    Left,
1798    None,
1799}
1800
1801impl Precedence {
1802    const MIN: Self = Precedence::Iff;
1803
1804    fn of_binop(op: &BinOp) -> Precedence {
1805        match op {
1806            BinOp::Iff => Precedence::Iff,
1807            BinOp::Imp => Precedence::Implies,
1808            BinOp::Or => Precedence::Or,
1809            BinOp::And => Precedence::And,
1810            BinOp::Eq | BinOp::Ne | BinOp::Gt | BinOp::Ge | BinOp::Lt | BinOp::Le => {
1811                Precedence::Compare
1812            }
1813            BinOp::BitOr => Precedence::BitOr,
1814            BinOp::BitXor => Precedence::BitXor,
1815            BinOp::BitAnd => Precedence::BitAnd,
1816            BinOp::BitShl | BinOp::BitShr => Precedence::Shift,
1817            BinOp::Add | BinOp::Sub => Precedence::Sum,
1818            BinOp::Mul | BinOp::Div | BinOp::Mod => Precedence::Product,
1819        }
1820    }
1821
1822    fn next(self) -> Precedence {
1823        match self {
1824            Precedence::Iff => Precedence::Implies,
1825            Precedence::Implies => Precedence::Or,
1826            Precedence::Or => Precedence::And,
1827            Precedence::And => Precedence::Compare,
1828            Precedence::Compare => Precedence::BitOr,
1829            Precedence::BitOr => Precedence::BitXor,
1830            Precedence::BitXor => Precedence::BitAnd,
1831            Precedence::BitAnd => Precedence::Shift,
1832            Precedence::Shift => Precedence::Sum,
1833            Precedence::Sum => Precedence::Product,
1834            Precedence::Product => Precedence::Prefix,
1835            Precedence::Prefix => Precedence::Prefix,
1836        }
1837    }
1838
1839    fn associativity(self) -> Associativity {
1840        match self {
1841            Precedence::Or
1842            | Precedence::And
1843            | Precedence::BitOr
1844            | Precedence::BitXor
1845            | Precedence::BitAnd
1846            | Precedence::Shift
1847            | Precedence::Sum
1848            | Precedence::Product => Associativity::Left,
1849            Precedence::Compare | Precedence::Iff => Associativity::None,
1850            Precedence::Implies | Precedence::Prefix => Associativity::Right,
1851        }
1852    }
1853}