Skip to main content

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