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