Skip to main content

flux_syntax/
surface.rs

1pub mod visit;
2
3use std::{borrow::Cow, fmt, ops::Range};
4
5use flux_config::PartialInferOpts;
6pub use rustc_ast::{
7    Mutability,
8    token::{Lit, LitKind},
9};
10use rustc_hash::FxHashSet;
11pub use rustc_span::{Span, symbol::Ident};
12use rustc_span::{Symbol, symbol::sym};
13
14use crate::surface::visit::Visitor;
15
16/// A [`NodeId`] is a unique identifier we assign to some AST nodes to be able to attach information
17/// to them. For example, to assign a resolution to a [`Path`]. The [`NodeId`] is unique within a crate.
18#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
19pub struct NodeId(pub(super) usize);
20
21impl NodeId {
22    pub fn as_usize(&self) -> usize {
23        self.0
24    }
25}
26
27#[derive(Debug)]
28pub struct SortDecl {
29    pub name: Ident,
30    pub sort_vars: Vec<Ident>,
31}
32
33#[derive(Debug)]
34pub enum FluxItem {
35    Qualifier(Qualifier),
36    FuncDef(SpecFunc),
37    SortDecl(SortDecl),
38    PrimOpProp(PrimOpProp),
39    Use(UseTree),
40}
41
42impl FluxItem {
43    pub fn name(&self) -> Option<Ident> {
44        match self {
45            FluxItem::Qualifier(qualifier) => Some(qualifier.name),
46            FluxItem::FuncDef(spec_func) => Some(spec_func.name),
47            FluxItem::SortDecl(sort_decl) => Some(sort_decl.name),
48            FluxItem::PrimOpProp(primop_prop) => Some(primop_prop.name),
49            FluxItem::Use(_) => None,
50        }
51    }
52}
53
54#[derive(Debug)]
55pub struct UseTree {
56    pub prefix: ExprPath,
57    pub kind: UseTreeKind,
58}
59
60#[derive(Debug)]
61pub enum UseTreeKind {
62    /// `use a::b::c`
63    Simple,
64    /// `use a::b::{...}`
65    Nested(Vec<UseTree>),
66}
67
68#[derive(Debug)]
69pub struct Qualifier {
70    pub name: Ident,
71    pub params: RefineParams,
72    pub expr: Expr,
73    pub span: Span,
74    pub kind: QualifierKind,
75}
76
77#[derive(Debug)]
78pub enum QualifierKind {
79    Global,
80    Local,
81    Hint,
82}
83
84/// A global function definition. It can be either an uninterpreted function or a *syntactic abstraction*,
85/// i.e., a function with a body.
86#[derive(Debug)]
87pub struct SpecFunc {
88    pub name: Ident,
89    pub sort_vars: Vec<Ident>,
90    pub params: RefineParams,
91    pub output: Sort,
92    /// Body of the function. If not present this definition corresponds to an uninterpreted function.
93    pub body: Option<Expr>,
94    /// Is this function "hidden" i.e. to be considered
95    /// as uninterpreted by default (only makes sense if `body` is_some ...)
96    /// as otherwise it is *always* uninterpreted.
97    pub hide: bool,
98}
99
100/// A (currently global) *primop property*; see tests/tests/pos/surface/
101#[derive(Debug)]
102pub struct PrimOpProp {
103    /// The name of the property
104    pub name: Ident,
105    /// The binop it is attached to
106    pub op: BinOp,
107    /// The sort _at_ which the primop is defined,
108    /// The binders for the inputs of the primop; the output sort is always `Bool`
109    pub params: RefineParams,
110    /// The actual definition of the property
111    pub body: Expr,
112    pub span: Span,
113}
114
115#[derive(Debug)]
116pub struct Generics {
117    pub params: Vec<GenericParam>,
118    pub predicates: Option<Vec<WhereBoundPredicate>>,
119    pub span: Span,
120}
121
122#[derive(Debug)]
123pub struct GenericParam {
124    pub name: Ident,
125    pub node_id: NodeId,
126}
127
128#[derive(Debug)]
129pub struct TyAlias {
130    pub ident: Ident,
131    pub generics: Generics,
132    pub params: RefineParams,
133    pub index: Option<RefineParam>,
134    pub ty: Ty,
135    pub node_id: NodeId,
136    pub span: Span,
137}
138
139pub struct Item {
140    pub attrs: Vec<Attr>,
141    pub kind: ItemKind,
142    pub node_id: NodeId,
143}
144
145pub enum ItemKind {
146    Fn(Option<FnSig>),
147    Struct(StructDef),
148    Enum(EnumDef),
149    Trait(Trait),
150    Impl(Impl),
151    Const(ConstantInfo),
152    TyAlias(Box<TyAlias>),
153    Static(StaticInfo),
154    /// Modules can't be refined but we collect attributes for them, e.g., `#[trusted]`
155    /// This kind is also used for the crate root, for which we also collect attributes.
156    Mod,
157}
158
159pub struct TraitItemFn {
160    pub attrs: Vec<Attr>,
161    pub sig: Option<FnSig>,
162    pub node_id: NodeId,
163}
164
165pub struct ImplItemFn {
166    pub attrs: Vec<Attr>,
167    pub sig: Option<FnSig>,
168    pub node_id: NodeId,
169}
170
171#[derive(Debug)]
172pub struct DetachedSpecs {
173    pub items: Vec<DetachedItem>,
174}
175
176#[derive(Debug)]
177pub struct DetachedTraitImpl {
178    pub trait_: ExprPath,
179    pub items: Vec<DetachedItem<FnSig>>,
180    pub refts: Vec<ImplAssocReft>,
181    pub span: Span,
182}
183
184#[derive(Debug, Default)]
185pub struct DetachedTrait {
186    pub items: Vec<DetachedItem<FnSig>>,
187    pub refts: Vec<TraitAssocReft>,
188}
189
190#[derive(Debug)]
191pub struct DetachedInherentImpl {
192    pub items: Vec<DetachedItem<FnSig>>,
193    pub span: Span,
194}
195
196impl DetachedInherentImpl {
197    pub fn extend(&mut self, other: DetachedInherentImpl) {
198        self.items.extend(other.items);
199    }
200}
201
202#[derive(Debug)]
203pub struct DetachedItem<K = DetachedItemKind> {
204    pub attrs: Vec<Attr>,
205    pub path: ExprPath,
206    pub kind: K,
207    pub node_id: NodeId,
208}
209
210impl<K> DetachedItem<K> {
211    pub fn map_kind<R>(self, f: impl FnOnce(K) -> R) -> DetachedItem<R> {
212        DetachedItem {
213            attrs: self.attrs,
214            path: self.path,
215            kind: f(self.kind),
216            node_id: self.node_id,
217        }
218    }
219}
220
221impl DetachedItem<DetachedItemKind> {
222    pub fn span(&self) -> Span {
223        match &self.kind {
224            DetachedItemKind::InherentImpl(impl_) => impl_.span,
225            DetachedItemKind::TraitImpl(trait_impl) => trait_impl.span,
226            _ => self.path.span,
227        }
228    }
229}
230
231#[derive(Debug)]
232pub enum DetachedItemKind {
233    FnSig(FnSig),
234    Mod(DetachedSpecs),
235    Struct(StructDef),
236    Enum(EnumDef),
237    InherentImpl(DetachedInherentImpl),
238    TraitImpl(DetachedTraitImpl),
239    Trait(DetachedTrait),
240    Static(StaticInfo),
241}
242
243#[derive(Debug)]
244pub struct ConstantInfo {
245    pub expr: Option<Expr>,
246}
247
248#[derive(Debug)]
249pub struct StaticInfo {
250    pub ty: Ty,
251}
252
253#[derive(Debug)]
254pub struct StructDef {
255    pub generics: Option<Generics>,
256    pub refined_by: Option<RefineParams>,
257    pub fields: Vec<Option<Ty>>,
258    pub opaque: bool,
259    pub invariants: Vec<Expr>,
260}
261
262#[derive(Debug)]
263pub struct EnumDef {
264    pub generics: Option<Generics>,
265    pub refined_by: Option<RefineParams>,
266    pub variants: Vec<Option<VariantDef>>,
267    pub invariants: Vec<Expr>,
268    pub reflected: bool,
269}
270
271#[derive(Debug)]
272pub struct VariantDef {
273    pub ident: Option<Ident>,
274    pub fields: Vec<Ty>,
275    pub ret: Option<VariantRet>,
276    pub node_id: NodeId,
277    pub span: Span,
278}
279
280#[derive(Debug)]
281pub struct VariantRet {
282    pub path: Path,
283    /// Binders are not allowed at this position, but we parse this as a list of indices
284    /// for better error reporting.
285    pub indices: Indices,
286}
287
288pub type RefineParams = Vec<RefineParam>;
289
290#[derive(Debug)]
291pub struct RefineParam {
292    pub ident: Ident,
293    pub sort: Sort,
294    pub mode: Option<ParamMode>,
295    pub span: Span,
296    pub node_id: NodeId,
297}
298
299#[derive(Clone, Copy, Debug, PartialEq, Eq)]
300pub enum ParamMode {
301    Horn,
302    Hindley,
303}
304
305#[derive(Debug)]
306pub enum Sort {
307    /// A _base_ sort, e.g., `int` or `bool`.
308    Base(BaseSort),
309    /// A _function_ sort of the form `(bi,...) -> bo` where `bi..` and `bo`
310    /// are all base sorts.
311    Func { inputs: Vec<BaseSort>, output: BaseSort },
312    /// A sort that needs to be inferred.
313    Infer,
314}
315
316#[derive(Debug)]
317pub enum BaseSort {
318    /// a bitvector sort, e.g., bitvec<32>
319    BitVec(u32),
320    SortOf(Box<Ty>, Path),
321    Path(SortPath),
322    /// a tuple sort, e.g., (int, bool)
323    Tuple(Vec<BaseSort>),
324}
325
326/// A [`Path`] but for sorts.
327#[derive(Debug)]
328pub struct SortPath {
329    /// The segments in the path
330    pub segments: Vec<Ident>,
331    /// The sort arguments, i.e., the list `[int, bool]` in `Map<int, bool>`.
332    pub args: Vec<BaseSort>,
333    pub node_id: NodeId,
334}
335
336#[derive(Debug)]
337pub struct Impl {
338    pub generics: Option<Generics>,
339    pub assoc_refinements: Vec<ImplAssocReft>,
340}
341
342#[derive(Debug)]
343pub struct ImplAssocReft {
344    pub name: Ident,
345    pub params: RefineParams,
346    pub output: BaseSort,
347    pub body: Expr,
348    pub span: Span,
349}
350
351#[derive(Debug)]
352pub struct Trait {
353    pub generics: Option<Generics>,
354    pub assoc_refinements: Vec<TraitAssocReft>,
355}
356
357#[derive(Debug)]
358pub struct TraitAssocReft {
359    pub name: Ident,
360    pub params: RefineParams,
361    pub output: BaseSort,
362    pub body: Option<Expr>,
363    pub span: Span,
364    pub final_: bool,
365}
366
367#[derive(Debug)]
368pub struct FnSig {
369    pub asyncness: Async,
370    pub ident: Option<Ident>,
371    pub generics: Generics,
372    pub params: RefineParams,
373    /// example: `requires n > 0`
374    pub requires: Vec<Requires>,
375    /// example: `i32<@n>`
376    pub inputs: Vec<FnInput>,
377    pub output: FnOutput,
378    /// source span
379    pub span: Span,
380    pub node_id: NodeId,
381    pub no_panic: Option<Expr>,
382}
383
384#[derive(Debug)]
385pub struct Requires {
386    /// Optional list of universally quantified parameters
387    pub params: RefineParams,
388    pub pred: Expr,
389}
390
391#[derive(Debug)]
392pub struct FnOutput {
393    /// example `i32{v:v >= 0}`
394    pub returns: FnRetTy,
395    /// example: `*x: i32{v. v = n+1}` or just `x > 10`
396    pub ensures: Vec<Ensures>,
397    pub node_id: NodeId,
398}
399
400#[derive(Debug)]
401pub enum Ensures {
402    /// A type constraint on a location
403    Type(Ident, Ty, NodeId),
404    /// A predicate that needs to hold
405    Pred(Expr),
406}
407
408#[derive(Debug)]
409pub enum FnRetTy {
410    Default(Span),
411    Ty(Box<Ty>),
412}
413
414#[derive(Debug, Copy, Clone)]
415pub enum Async {
416    Yes { node_id: NodeId, span: Span },
417    No,
418}
419
420#[derive(Debug)]
421pub struct WhereBoundPredicate {
422    pub span: Span,
423    pub bounded_ty: Ty,
424    pub bounds: GenericBounds,
425}
426
427pub type GenericBounds = Vec<TraitRef>;
428
429#[derive(Debug)]
430pub struct TraitRef {
431    pub path: Path,
432    pub node_id: NodeId,
433}
434
435impl TraitRef {
436    fn is_fn_trait_name(name: Symbol) -> bool {
437        name == sym::FnOnce || name == sym::FnMut || name == sym::Fn
438    }
439
440    pub fn as_fn_trait_ref(&self) -> Option<(&GenericArg, &GenericArg)> {
441        if let [segment] = self.path.segments.as_slice()
442            && Self::is_fn_trait_name(segment.ident.name)
443            && let [in_arg, out_arg] = segment.args.as_slice()
444        {
445            return Some((in_arg, out_arg));
446        }
447        None
448    }
449}
450
451#[derive(Debug)]
452pub enum FnInput {
453    /// example `a: i32{a > 0}`
454    Constr(Ident, Path, Expr, NodeId),
455    /// example `v: &strg i32`
456    StrgRef(Ident, Ty, NodeId),
457    /// A type with an optional binder, e.g, `i32`, `x: i32` or `x: i32{v: v > 0}`.
458    /// The binder has a different meaning depending on the type.
459    Ty(Option<Ident>, Ty, NodeId),
460}
461
462#[derive(Debug)]
463pub struct Ty {
464    pub kind: TyKind,
465    pub node_id: NodeId,
466    pub span: Span,
467}
468
469#[derive(Debug)]
470pub enum TyKind {
471    /// ty
472    Base(BaseTy),
473    /// `B[r]`
474    Indexed {
475        bty: BaseTy,
476        indices: Indices,
477    },
478    /// B{v: r}
479    Exists {
480        bind: Ident,
481        bty: BaseTy,
482        pred: Expr,
483    },
484    GeneralExists {
485        params: RefineParams,
486        ty: Box<Ty>,
487        pred: Option<Expr>,
488    },
489    /// Mutable or shared reference
490    Ref(Mutability, Box<Ty>),
491    /// Constrained type: an exists without binder
492    Constr(Expr, Box<Ty>),
493    Tuple(Vec<Ty>),
494    Array(Box<Ty>, ConstArg),
495    /// The `NodeId` is used to resolve the type to a corresponding `OpaqueTy`
496    ImplTrait(NodeId, GenericBounds),
497    Hole,
498}
499
500impl Ty {
501    pub fn is_refined(&self) -> bool {
502        struct IsRefinedVisitor {
503            is_refined: bool,
504        }
505        let mut vis = IsRefinedVisitor { is_refined: false };
506        impl visit::Visitor for IsRefinedVisitor {
507            fn visit_ty(&mut self, ty: &Ty) {
508                match &ty.kind {
509                    TyKind::Tuple(_)
510                    | TyKind::Ref(..)
511                    | TyKind::Array(..)
512                    | TyKind::ImplTrait(..)
513                    | TyKind::Hole
514                    | TyKind::Base(_) => {
515                        visit::walk_ty(self, ty);
516                    }
517                    TyKind::Indexed { .. }
518                    | TyKind::Exists { .. }
519                    | TyKind::GeneralExists { .. }
520                    | TyKind::Constr(..) => {
521                        self.is_refined = true;
522                    }
523                }
524            }
525        }
526        vis.visit_ty(self);
527        vis.is_refined
528    }
529
530    pub fn is_potential_const_arg(&self) -> Option<&Path> {
531        if let TyKind::Base(bty) = &self.kind
532            && let BaseTyKind::Path(None, path) = &bty.kind
533            && let [segment] = &path.segments[..]
534            && segment.args.is_empty()
535        {
536            Some(path)
537        } else {
538            None
539        }
540    }
541}
542#[derive(Debug)]
543pub struct BaseTy {
544    pub kind: BaseTyKind,
545    pub span: Span,
546}
547
548#[derive(Debug)]
549pub enum BaseTyKind {
550    Path(Option<Box<Ty>>, Path),
551    Slice(Box<Ty>),
552    /// Raw pointer (*const T or *mut T), optionally with refinement on pointer value
553    Ptr(Mutability, Box<Ty>),
554}
555
556#[derive(Debug)]
557pub struct ConstArg {
558    pub kind: ConstArgKind,
559    pub span: Span,
560}
561
562#[derive(Debug)]
563pub enum ConstArgKind {
564    Lit(usize),
565    Path(Path),
566    Infer,
567}
568
569#[derive(Debug)]
570pub struct Indices {
571    pub indices: Vec<RefineArg>,
572    pub span: Span,
573}
574
575#[derive(Debug)]
576pub enum RefineArg {
577    /// `@n` or `#n`, the span corresponds to the span of the identifier plus the binder token (`@` or `#`)
578    Bind(Ident, BindKind, Span, NodeId),
579    Expr(Expr),
580    Abs(RefineParams, Expr, Span, NodeId),
581}
582
583#[derive(Debug, Clone, Copy)]
584pub enum BindKind {
585    At,
586    Pound,
587}
588
589/// A boolean-like enum used to mark whether some code should be trusted.
590#[derive(Debug, Eq, PartialEq, Copy, Clone)]
591pub enum Trusted {
592    Yes,
593    No,
594}
595
596impl Trusted {
597    pub fn to_bool(self) -> bool {
598        match self {
599            Trusted::Yes => true,
600            Trusted::No => false,
601        }
602    }
603}
604
605impl From<bool> for Trusted {
606    fn from(value: bool) -> Self {
607        if value { Trusted::Yes } else { Trusted::No }
608    }
609}
610
611/// A boolean-like enum used to mark whether a piece of code is ignored.
612#[derive(Debug, Eq, PartialEq, Copy, Clone)]
613pub enum Ignored {
614    Yes,
615    No,
616}
617
618impl Ignored {
619    pub fn to_bool(self) -> bool {
620        match self {
621            Ignored::Yes => true,
622            Ignored::No => false,
623        }
624    }
625}
626
627impl From<bool> for Ignored {
628    fn from(value: bool) -> Self {
629        if value { Ignored::Yes } else { Ignored::No }
630    }
631}
632
633/// An attribute attaches metadata to an item.
634///
635/// Note that some of these attributes correspond to a Rust attribute, but some don't. For example,
636/// when annotating a function, a `#[flux::trusted]` is mapped to [`Attr::Trusted`] because it
637/// corresponds to metadata associated to the function, however, a `#[flux::spec(...)]` doesn't
638/// map to any [`Attr`] because that's considered to be part of the *refined syntax* of the item.
639///
640/// Note that these attributes can also originate from detached specs.
641#[derive(Debug)]
642pub enum Attr {
643    /// A `#[trusted(...)]` attribute
644    Trusted(Trusted),
645    /// A `#[trusted_impl(...)]` attribute
646    TrustedImpl(Trusted),
647    /// A `#[ignore(...)]` attribute
648    Ignore(Ignored),
649    /// A `#[proven_externally]` attribute
650    ProvenExternally(Span),
651    /// A `#[should_fail]` attribute
652    ShouldFail,
653    /// A `#[qualifiers(...)]` attribute
654    Qualifiers(Vec<Ident>),
655    /// A `#[reveal(...)]` attribute
656    Reveal(Vec<Ident>),
657    /// A `#[opts(...)]` attribute
658    InferOpts(PartialInferOpts),
659    /// A `#[no_panic]` attribute
660    NoPanic,
661    /// A `#[assume_parametric(...)]` attribute
662    AssumeParametric(Vec<Ident>),
663    /// A `#[no_suggestions]` attribute
664    NoSuggestions,
665}
666
667#[derive(Debug)]
668pub struct Path {
669    pub segments: Vec<PathSegment>,
670    pub refine: Vec<RefineArg>,
671    pub node_id: NodeId,
672    pub span: Span,
673}
674
675impl Path {
676    pub fn last(&self) -> &PathSegment {
677        self.segments
678            .last()
679            .expect("path must have at least one segment")
680    }
681}
682
683#[derive(Debug)]
684pub struct PathSegment {
685    pub ident: Ident,
686    pub args: Vec<GenericArg>,
687    pub node_id: NodeId,
688}
689
690#[derive(Debug)]
691pub struct GenericArg {
692    pub kind: GenericArgKind,
693    pub node_id: NodeId,
694}
695
696#[derive(Debug)]
697pub enum GenericArgKind {
698    Type(Ty),
699    Constraint(Ident, Ty),
700}
701
702#[derive(Debug)]
703pub struct FieldExpr {
704    pub ident: Ident,
705    pub expr: RefineArg,
706    pub span: Span,
707    pub node_id: NodeId,
708}
709
710#[derive(Debug)]
711pub struct Spread {
712    pub expr: Expr,
713    pub span: Span,
714    pub node_id: NodeId,
715}
716
717#[derive(Debug)]
718pub enum ConstructorArg {
719    FieldExpr(FieldExpr),
720    Spread(Spread),
721}
722
723#[derive(Debug)]
724pub struct Expr {
725    pub kind: ExprKind,
726    pub node_id: NodeId,
727    pub span: Span,
728}
729
730#[derive(Debug)]
731pub enum QuantKind {
732    Forall,
733    Exists,
734}
735
736#[derive(Debug)]
737pub enum ExprKind {
738    Path(ExprPath),
739    Dot(Box<Expr>, Ident),
740    Literal(Lit),
741    BinaryOp(BinOp, Box<[Expr; 2]>),
742    UnaryOp(UnOp, Box<Expr>),
743    Call(Box<Expr>, Vec<Expr>),
744    /// A UIF representing a PrimOp expression, e.g. `[<<](x, y)`
745    PrimUIF(BinOp),
746    /// `<qself as path>::name`
747    AssocReft(Box<Ty>, Path, Ident),
748    IfThenElse(Box<[Expr; 3]>),
749    Constructor(Option<ExprPath>, Vec<ConstructorArg>),
750    Quant(QuantKind, RefineParam, Option<Range<usize>>, Box<Expr>),
751    Block(Vec<LetDecl>, Box<Expr>),
752    /// Set expression `#{ e1, e2, ..., en }`
753    SetLiteral(Vec<Expr>),
754    /// Tuple expression `(e1, e2, ..., en)`
755    Tuple(Vec<Expr>),
756}
757
758#[derive(Debug)]
759pub struct LetDecl {
760    pub param: RefineParam,
761    pub init: Expr,
762}
763
764/// A [`Path`] but for refinement expressions
765#[derive(Debug, Clone)]
766pub struct ExprPath {
767    pub segments: Vec<ExprPathSegment>,
768    pub node_id: NodeId,
769    pub span: Span,
770}
771
772#[derive(Debug, Clone)]
773pub struct ExprPathSegment {
774    pub ident: Ident,
775    pub node_id: NodeId,
776}
777#[derive(Copy, Clone, Hash, Eq, PartialEq)]
778pub enum BinOp {
779    Iff,
780    Imp,
781    Or,
782    And,
783    Eq,
784    Ne,
785    Gt,
786    Ge,
787    Lt,
788    Le,
789    Add,
790    Sub,
791    Mul,
792    Div,
793    Mod,
794    BitOr,
795    BitXor,
796    BitAnd,
797    BitShl,
798    BitShr,
799}
800
801impl fmt::Debug for BinOp {
802    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
803        match self {
804            BinOp::Iff => write!(f, "<=>"),
805            BinOp::Imp => write!(f, "=>"),
806            BinOp::Or => write!(f, "||"),
807            BinOp::And => write!(f, "&&"),
808            BinOp::Eq => write!(f, "=="),
809            BinOp::Ne => write!(f, "!="),
810            BinOp::Lt => write!(f, "<"),
811            BinOp::Le => write!(f, "<="),
812            BinOp::Gt => write!(f, ">"),
813            BinOp::Ge => write!(f, ">="),
814            BinOp::Add => write!(f, "+"),
815            BinOp::Sub => write!(f, "-"),
816            BinOp::Mod => write!(f, "mod"),
817            BinOp::Mul => write!(f, "*"),
818            BinOp::Div => write!(f, "/"),
819            BinOp::BitOr => write!(f, "|"),
820            BinOp::BitXor => write!(f, "^"),
821            BinOp::BitAnd => write!(f, "&"),
822            BinOp::BitShl => write!(f, "<<"),
823            BinOp::BitShr => write!(f, ">>"),
824        }
825    }
826}
827
828impl rustc_errors::IntoDiagArg for BinOp {
829    fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
830        rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
831    }
832}
833
834#[derive(Copy, Clone)]
835pub enum UnOp {
836    Not,
837    Neg,
838}
839
840impl fmt::Debug for UnOp {
841    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
842        match self {
843            Self::Not => write!(f, "!"),
844            Self::Neg => write!(f, "-"),
845        }
846    }
847}
848
849impl BindKind {
850    pub fn token_str(&self) -> &'static str {
851        match self {
852            BindKind::At => "@",
853            BindKind::Pound => "#",
854        }
855    }
856}
857
858/// A punctuated sequence of values of type `T` separated by punctuation of type `P`
859pub struct Punctuated<T, P> {
860    inner: Vec<(T, P)>,
861    last: Option<Box<T>>,
862}
863
864impl<T, P> From<Vec<(T, P)>> for Punctuated<T, P> {
865    fn from(inner: Vec<(T, P)>) -> Self {
866        Self { inner, last: None }
867    }
868}
869
870impl<T, P> Punctuated<T, P> {
871    pub fn len(&self) -> usize {
872        self.inner.len() + self.last.is_some() as usize
873    }
874
875    /// Determines whether this punctuated sequence is empty, meaning it
876    /// contains no syntax tree nodes or punctuation.
877    pub fn is_empty(&self) -> bool {
878        self.inner.len() == 0 && self.last.is_none()
879    }
880
881    /// Appends a syntax tree node onto the end of this punctuated sequence. The
882    /// sequence must already have a trailing punctuation, or be empty.
883    ///
884    /// # Panics
885    ///
886    /// Panics if the sequence is nonempty and does not already have a trailing
887    /// punctuation.
888    pub fn push_value(&mut self, value: T) {
889        assert!(
890            self.empty_or_trailing(),
891            "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
892        );
893
894        self.last = Some(Box::new(value));
895    }
896
897    /// Returns true if either this `Punctuated` is empty, or it has a trailing
898    /// punctuation.
899    ///
900    /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`.
901    pub fn empty_or_trailing(&self) -> bool {
902        self.last.is_none()
903    }
904
905    /// Determines whether this punctuated sequence ends with a trailing
906    /// punctuation.
907    pub fn trailing_punct(&self) -> bool {
908        self.last.is_none() && !self.is_empty()
909    }
910
911    pub fn into_values(self) -> Vec<T> {
912        let mut v: Vec<T> = self.inner.into_iter().map(|(v, _)| v).collect();
913        if let Some(last) = self.last {
914            v.push(*last);
915        }
916        v
917    }
918}
919
920impl Expr {
921    /// Collects all free variables in an expression.
922    /// A free variable is an `ExprKind::Path` with a single identifier segment.
923    pub fn free_vars(&self) -> FxHashSet<Ident> {
924        struct FreeVarsVisitor {
925            vars: FxHashSet<Ident>,
926        }
927
928        impl visit::Visitor for FreeVarsVisitor {
929            fn visit_expr(&mut self, expr: &Expr) {
930                match &expr.kind {
931                    ExprKind::Path(path) => {
932                        // Only collect paths with a single segment
933                        if let [segment] = path.segments.as_slice() {
934                            self.vars.insert(segment.ident);
935                        }
936                    }
937                    ExprKind::Call(callee, args) => {
938                        // The callee of a call is a refinement function, not a variable, so
939                        // don't collect it. Anything that's not a path may contain free
940                        // variables, so visit it normally.
941                        if !matches!(&callee.kind, ExprKind::Path(_)) {
942                            self.visit_expr(callee);
943                        }
944                        for arg in args {
945                            self.visit_expr(arg);
946                        }
947                    }
948                    // Continue visiting child expressions
949                    _ => visit::walk_expr(self, expr),
950                }
951            }
952        }
953
954        let mut visitor = FreeVarsVisitor { vars: FxHashSet::default() };
955        visitor.visit_expr(self);
956        visitor.vars
957    }
958}