1pub mod visit;
2use std::{borrow::Cow, fmt, ops::Range};
3
4use flux_config::PartialInferOpts;
5pub use rustc_ast::{
6 Mutability,
7 token::{Lit, LitKind},
8};
9use rustc_hash::FxHashSet;
10pub use rustc_span::{Span, symbol::Ident};
11use rustc_span::{Symbol, symbol::sym};
12
13use crate::surface::visit::Visitor;
14
15#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
18pub struct NodeId(pub(super) usize);
19
20impl NodeId {
21 pub fn as_usize(&self) -> usize {
22 self.0
23 }
24}
25
26#[derive(Debug)]
27pub struct SortDecl {
28 pub name: Ident,
29 pub sort_vars: Vec<Ident>,
30}
31
32#[derive(Debug)]
33pub enum FluxItem {
34 Qualifier(Qualifier),
35 FuncDef(SpecFunc),
36 SortDecl(SortDecl),
37 PrimOpProp(PrimOpProp),
38}
39
40impl FluxItem {
41 pub fn name(&self) -> Ident {
42 match self {
43 FluxItem::Qualifier(qualifier) => qualifier.name,
44 FluxItem::FuncDef(spec_func) => spec_func.name,
45 FluxItem::SortDecl(sort_decl) => sort_decl.name,
46 FluxItem::PrimOpProp(primop_prop) => primop_prop.name,
47 }
48 }
49}
50
51#[derive(Debug)]
52pub struct Qualifier {
53 pub name: Ident,
54 pub params: RefineParams,
55 pub expr: Expr,
56 pub span: Span,
57 pub kind: QualifierKind,
58}
59
60#[derive(Debug)]
61pub enum QualifierKind {
62 Global,
63 Local,
64 Hint,
65}
66
67#[derive(Debug)]
70pub struct SpecFunc {
71 pub name: Ident,
72 pub sort_vars: Vec<Ident>,
73 pub params: RefineParams,
74 pub output: Sort,
75 pub body: Option<Expr>,
77 pub hide: bool,
81}
82
83#[derive(Debug)]
85pub struct PrimOpProp {
86 pub name: Ident,
88 pub op: BinOp,
90 pub params: RefineParams,
93 pub body: Expr,
95 pub span: Span,
96}
97
98#[derive(Debug)]
99pub struct Generics {
100 pub params: Vec<GenericParam>,
101 pub predicates: Option<Vec<WhereBoundPredicate>>,
102 pub span: Span,
103}
104
105#[derive(Debug)]
106pub struct GenericParam {
107 pub name: Ident,
108 pub node_id: NodeId,
109}
110
111#[derive(Debug)]
112pub struct TyAlias {
113 pub ident: Ident,
114 pub generics: Generics,
115 pub params: RefineParams,
116 pub index: Option<RefineParam>,
117 pub ty: Ty,
118 pub node_id: NodeId,
119 pub span: Span,
120}
121
122pub struct Item {
123 pub attrs: Vec<Attr>,
124 pub kind: ItemKind,
125 pub node_id: NodeId,
126}
127
128pub enum ItemKind {
129 Fn(Option<FnSig>),
130 Struct(StructDef),
131 Enum(EnumDef),
132 Trait(Trait),
133 Impl(Impl),
134 Const(ConstantInfo),
135 TyAlias(Box<TyAlias>),
136 Static(StaticInfo),
137 Mod,
140}
141
142pub struct TraitItemFn {
143 pub attrs: Vec<Attr>,
144 pub sig: Option<FnSig>,
145 pub node_id: NodeId,
146}
147
148pub struct ImplItemFn {
149 pub attrs: Vec<Attr>,
150 pub sig: Option<FnSig>,
151 pub node_id: NodeId,
152}
153
154#[derive(Debug)]
155pub struct DetachedSpecs {
156 pub items: Vec<DetachedItem>,
157}
158
159#[derive(Debug)]
160pub struct DetachedTraitImpl {
161 pub trait_: ExprPath,
162 pub items: Vec<DetachedItem<FnSig>>,
163 pub refts: Vec<ImplAssocReft>,
164 pub span: Span,
165}
166
167#[derive(Debug, Default)]
168pub struct DetachedTrait {
169 pub items: Vec<DetachedItem<FnSig>>,
170 pub refts: Vec<TraitAssocReft>,
171}
172
173#[derive(Debug)]
174pub struct DetachedInherentImpl {
175 pub items: Vec<DetachedItem<FnSig>>,
176 pub span: Span,
177}
178
179impl DetachedInherentImpl {
180 pub fn extend(&mut self, other: DetachedInherentImpl) {
181 self.items.extend(other.items);
182 }
183}
184
185#[derive(Debug)]
186pub struct DetachedItem<K = DetachedItemKind> {
187 pub attrs: Vec<Attr>,
188 pub path: ExprPath,
189 pub kind: K,
190 pub node_id: NodeId,
191}
192
193impl<K> DetachedItem<K> {
194 pub fn map_kind<R>(self, f: impl FnOnce(K) -> R) -> DetachedItem<R> {
195 DetachedItem {
196 attrs: self.attrs,
197 path: self.path,
198 kind: f(self.kind),
199 node_id: self.node_id,
200 }
201 }
202}
203
204impl DetachedItem<DetachedItemKind> {
205 pub fn span(&self) -> Span {
206 match &self.kind {
207 DetachedItemKind::InherentImpl(impl_) => impl_.span,
208 DetachedItemKind::TraitImpl(trait_impl) => trait_impl.span,
209 _ => self.path.span,
210 }
211 }
212}
213
214#[derive(Debug)]
215pub enum DetachedItemKind {
216 FnSig(FnSig),
217 Mod(DetachedSpecs),
218 Struct(StructDef),
219 Enum(EnumDef),
220 InherentImpl(DetachedInherentImpl),
221 TraitImpl(DetachedTraitImpl),
222 Trait(DetachedTrait),
223 Static(StaticInfo),
224}
225
226#[derive(Debug)]
227pub struct ConstantInfo {
228 pub expr: Option<Expr>,
229}
230
231#[derive(Debug)]
232pub struct StaticInfo {
233 pub ty: Ty,
234}
235
236#[derive(Debug)]
237pub struct StructDef {
238 pub generics: Option<Generics>,
239 pub refined_by: Option<RefineParams>,
240 pub fields: Vec<Option<Ty>>,
241 pub opaque: bool,
242 pub invariants: Vec<Expr>,
243}
244
245#[derive(Debug)]
246pub struct EnumDef {
247 pub generics: Option<Generics>,
248 pub refined_by: Option<RefineParams>,
249 pub variants: Vec<Option<VariantDef>>,
250 pub invariants: Vec<Expr>,
251 pub reflected: bool,
252}
253
254#[derive(Debug)]
255pub struct VariantDef {
256 pub ident: Option<Ident>,
257 pub fields: Vec<Ty>,
258 pub ret: Option<VariantRet>,
259 pub node_id: NodeId,
260 pub span: Span,
261}
262
263#[derive(Debug)]
264pub struct VariantRet {
265 pub path: Path,
266 pub indices: Indices,
269}
270
271pub type RefineParams = Vec<RefineParam>;
272
273#[derive(Debug)]
274pub struct RefineParam {
275 pub ident: Ident,
276 pub sort: Sort,
277 pub mode: Option<ParamMode>,
278 pub span: Span,
279 pub node_id: NodeId,
280}
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283pub enum ParamMode {
284 Horn,
285 Hindley,
286}
287
288#[derive(Debug)]
289pub enum Sort {
290 Base(BaseSort),
292 Func { inputs: Vec<BaseSort>, output: BaseSort },
295 Infer,
297}
298
299#[derive(Debug)]
300pub enum BaseSort {
301 BitVec(u32),
303 SortOf(Box<Ty>, Path),
304 Path(SortPath),
305 Tuple(Vec<BaseSort>),
307}
308
309#[derive(Debug)]
311pub struct SortPath {
312 pub segments: Vec<Ident>,
314 pub args: Vec<BaseSort>,
316 pub node_id: NodeId,
317}
318
319#[derive(Debug)]
320pub struct Impl {
321 pub generics: Option<Generics>,
322 pub assoc_refinements: Vec<ImplAssocReft>,
323}
324
325#[derive(Debug)]
326pub struct ImplAssocReft {
327 pub name: Ident,
328 pub params: RefineParams,
329 pub output: BaseSort,
330 pub body: Expr,
331 pub span: Span,
332}
333
334#[derive(Debug)]
335pub struct Trait {
336 pub generics: Option<Generics>,
337 pub assoc_refinements: Vec<TraitAssocReft>,
338}
339
340#[derive(Debug)]
341pub struct TraitAssocReft {
342 pub name: Ident,
343 pub params: RefineParams,
344 pub output: BaseSort,
345 pub body: Option<Expr>,
346 pub span: Span,
347 pub final_: bool,
348}
349
350#[derive(Debug)]
351pub struct FnSig {
352 pub asyncness: Async,
353 pub ident: Option<Ident>,
354 pub generics: Generics,
355 pub params: RefineParams,
356 pub requires: Vec<Requires>,
358 pub inputs: Vec<FnInput>,
360 pub output: FnOutput,
361 pub span: Span,
363 pub node_id: NodeId,
364 pub no_panic: Option<Expr>,
365}
366
367#[derive(Debug)]
368pub struct Requires {
369 pub params: RefineParams,
371 pub pred: Expr,
372}
373
374#[derive(Debug)]
375pub struct FnOutput {
376 pub returns: FnRetTy,
378 pub ensures: Vec<Ensures>,
380 pub node_id: NodeId,
381}
382
383#[derive(Debug)]
384pub enum Ensures {
385 Type(Ident, Ty, NodeId),
387 Pred(Expr),
389}
390
391#[derive(Debug)]
392pub enum FnRetTy {
393 Default(Span),
394 Ty(Box<Ty>),
395}
396
397#[derive(Debug, Copy, Clone)]
398pub enum Async {
399 Yes { node_id: NodeId, span: Span },
400 No,
401}
402
403#[derive(Debug)]
404pub struct WhereBoundPredicate {
405 pub span: Span,
406 pub bounded_ty: Ty,
407 pub bounds: GenericBounds,
408}
409
410pub type GenericBounds = Vec<TraitRef>;
411
412#[derive(Debug)]
413pub struct TraitRef {
414 pub path: Path,
415 pub node_id: NodeId,
416}
417
418impl TraitRef {
419 fn is_fn_trait_name(name: Symbol) -> bool {
420 name == sym::FnOnce || name == sym::FnMut || name == sym::Fn
421 }
422
423 pub fn as_fn_trait_ref(&self) -> Option<(&GenericArg, &GenericArg)> {
424 if let [segment] = self.path.segments.as_slice()
425 && Self::is_fn_trait_name(segment.ident.name)
426 && let [in_arg, out_arg] = segment.args.as_slice()
427 {
428 return Some((in_arg, out_arg));
429 }
430 None
431 }
432}
433
434#[derive(Debug)]
435pub enum FnInput {
436 Constr(Ident, Path, Expr, NodeId),
438 StrgRef(Ident, Ty, NodeId),
440 Ty(Option<Ident>, Ty, NodeId),
443}
444
445#[derive(Debug)]
446pub struct Ty {
447 pub kind: TyKind,
448 pub node_id: NodeId,
449 pub span: Span,
450}
451
452#[derive(Debug)]
453pub enum TyKind {
454 Base(BaseTy),
456 Indexed {
458 bty: BaseTy,
459 indices: Indices,
460 },
461 Exists {
463 bind: Ident,
464 bty: BaseTy,
465 pred: Expr,
466 },
467 GeneralExists {
468 params: RefineParams,
469 ty: Box<Ty>,
470 pred: Option<Expr>,
471 },
472 Ref(Mutability, Box<Ty>),
474 Constr(Expr, Box<Ty>),
476 Tuple(Vec<Ty>),
477 Array(Box<Ty>, ConstArg),
478 ImplTrait(NodeId, GenericBounds),
480 Hole,
481}
482
483impl Ty {
484 pub fn is_refined(&self) -> bool {
485 struct IsRefinedVisitor {
486 is_refined: bool,
487 }
488 let mut vis = IsRefinedVisitor { is_refined: false };
489 impl visit::Visitor for IsRefinedVisitor {
490 fn visit_ty(&mut self, ty: &Ty) {
491 match &ty.kind {
492 TyKind::Tuple(_)
493 | TyKind::Ref(..)
494 | TyKind::Array(..)
495 | TyKind::ImplTrait(..)
496 | TyKind::Hole
497 | TyKind::Base(_) => {
498 visit::walk_ty(self, ty);
499 }
500 TyKind::Indexed { .. }
501 | TyKind::Exists { .. }
502 | TyKind::GeneralExists { .. }
503 | TyKind::Constr(..) => {
504 self.is_refined = true;
505 }
506 }
507 }
508 }
509 vis.visit_ty(self);
510 vis.is_refined
511 }
512
513 pub fn is_potential_const_arg(&self) -> Option<&Path> {
514 if let TyKind::Base(bty) = &self.kind
515 && let BaseTyKind::Path(None, path) = &bty.kind
516 && let [segment] = &path.segments[..]
517 && segment.args.is_empty()
518 {
519 Some(path)
520 } else {
521 None
522 }
523 }
524}
525#[derive(Debug)]
526pub struct BaseTy {
527 pub kind: BaseTyKind,
528 pub span: Span,
529}
530
531#[derive(Debug)]
532pub enum BaseTyKind {
533 Path(Option<Box<Ty>>, Path),
534 Slice(Box<Ty>),
535 Ptr(Mutability, Box<Ty>),
537}
538
539#[derive(PartialEq, Eq, Clone, Debug, Copy)]
540pub struct ConstArg {
541 pub kind: ConstArgKind,
542 pub span: Span,
543}
544
545#[derive(PartialEq, Eq, Clone, Debug, Copy)]
546pub enum ConstArgKind {
547 Lit(usize),
548 Infer,
549}
550
551#[derive(Debug)]
552pub struct Indices {
553 pub indices: Vec<RefineArg>,
554 pub span: Span,
555}
556
557#[derive(Debug)]
558pub enum RefineArg {
559 Bind(Ident, BindKind, Span, NodeId),
561 Expr(Expr),
562 Abs(RefineParams, Expr, Span, NodeId),
563}
564
565#[derive(Debug, Clone, Copy)]
566pub enum BindKind {
567 At,
568 Pound,
569}
570
571#[derive(Debug, Eq, PartialEq, Copy, Clone)]
573pub enum Trusted {
574 Yes,
575 No,
576}
577
578impl Trusted {
579 pub fn to_bool(self) -> bool {
580 match self {
581 Trusted::Yes => true,
582 Trusted::No => false,
583 }
584 }
585}
586
587impl From<bool> for Trusted {
588 fn from(value: bool) -> Self {
589 if value { Trusted::Yes } else { Trusted::No }
590 }
591}
592
593#[derive(Debug, Eq, PartialEq, Copy, Clone)]
595pub enum Ignored {
596 Yes,
597 No,
598}
599
600impl Ignored {
601 pub fn to_bool(self) -> bool {
602 match self {
603 Ignored::Yes => true,
604 Ignored::No => false,
605 }
606 }
607}
608
609impl From<bool> for Ignored {
610 fn from(value: bool) -> Self {
611 if value { Ignored::Yes } else { Ignored::No }
612 }
613}
614
615#[derive(Debug)]
624pub enum Attr {
625 Trusted(Trusted),
627 TrustedImpl(Trusted),
629 Ignore(Ignored),
631 ProvenExternally(Span),
633 ShouldFail,
635 Qualifiers(Vec<Ident>),
637 Reveal(Vec<Ident>),
639 InferOpts(PartialInferOpts),
641 NoPanic,
643}
644
645#[derive(Debug)]
646pub struct Path {
647 pub segments: Vec<PathSegment>,
648 pub refine: Vec<RefineArg>,
649 pub node_id: NodeId,
650 pub span: Span,
651}
652
653impl Path {
654 pub fn last(&self) -> &PathSegment {
655 self.segments
656 .last()
657 .expect("path must have at least one segment")
658 }
659}
660
661#[derive(Debug)]
662pub struct PathSegment {
663 pub ident: Ident,
664 pub args: Vec<GenericArg>,
665 pub node_id: NodeId,
666}
667
668#[derive(Debug)]
669pub struct GenericArg {
670 pub kind: GenericArgKind,
671 pub node_id: NodeId,
672}
673
674#[derive(Debug)]
675pub enum GenericArgKind {
676 Type(Ty),
677 Constraint(Ident, Ty),
678}
679
680#[derive(Debug)]
681pub struct FieldExpr {
682 pub ident: Ident,
683 pub expr: Expr,
684 pub span: Span,
685 pub node_id: NodeId,
686}
687
688#[derive(Debug)]
689pub struct Spread {
690 pub expr: Expr,
691 pub span: Span,
692 pub node_id: NodeId,
693}
694
695#[derive(Debug)]
696pub enum ConstructorArg {
697 FieldExpr(FieldExpr),
698 Spread(Spread),
699}
700
701#[derive(Debug)]
702pub struct Expr {
703 pub kind: ExprKind,
704 pub node_id: NodeId,
705 pub span: Span,
706}
707
708#[derive(Debug)]
709pub enum QuantKind {
710 Forall,
711 Exists,
712}
713
714#[derive(Debug)]
715pub enum ExprKind {
716 Path(ExprPath),
717 Dot(Box<Expr>, Ident),
718 Literal(Lit),
719 BinaryOp(BinOp, Box<[Expr; 2]>),
720 UnaryOp(UnOp, Box<Expr>),
721 Call(Box<Expr>, Vec<Expr>),
722 PrimUIF(BinOp),
724 AssocReft(Box<Ty>, Path, Ident),
726 IfThenElse(Box<[Expr; 3]>),
727 Constructor(Option<ExprPath>, Vec<ConstructorArg>),
728 BoundedQuant(QuantKind, RefineParam, Range<usize>, Box<Expr>),
729 Block(Vec<LetDecl>, Box<Expr>),
730 SetLiteral(Vec<Expr>),
732 Tuple(Vec<Expr>),
734}
735
736#[derive(Debug)]
737pub struct LetDecl {
738 pub param: RefineParam,
739 pub init: Expr,
740}
741
742#[derive(Debug, Clone)]
744pub struct ExprPath {
745 pub segments: Vec<ExprPathSegment>,
746 pub node_id: NodeId,
747 pub span: Span,
748}
749
750#[derive(Debug, Clone)]
751pub struct ExprPathSegment {
752 pub ident: Ident,
753 pub node_id: NodeId,
754}
755#[derive(Copy, Clone, Hash, Eq, PartialEq)]
756pub enum BinOp {
757 Iff,
758 Imp,
759 Or,
760 And,
761 Eq,
762 Ne,
763 Gt,
764 Ge,
765 Lt,
766 Le,
767 Add,
768 Sub,
769 Mul,
770 Div,
771 Mod,
772 BitOr,
773 BitXor,
774 BitAnd,
775 BitShl,
776 BitShr,
777}
778
779impl fmt::Debug for BinOp {
780 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
781 match self {
782 BinOp::Iff => write!(f, "<=>"),
783 BinOp::Imp => write!(f, "=>"),
784 BinOp::Or => write!(f, "||"),
785 BinOp::And => write!(f, "&&"),
786 BinOp::Eq => write!(f, "=="),
787 BinOp::Ne => write!(f, "!="),
788 BinOp::Lt => write!(f, "<"),
789 BinOp::Le => write!(f, "<="),
790 BinOp::Gt => write!(f, ">"),
791 BinOp::Ge => write!(f, ">="),
792 BinOp::Add => write!(f, "+"),
793 BinOp::Sub => write!(f, "-"),
794 BinOp::Mod => write!(f, "mod"),
795 BinOp::Mul => write!(f, "*"),
796 BinOp::Div => write!(f, "/"),
797 BinOp::BitOr => write!(f, "|"),
798 BinOp::BitXor => write!(f, "^"),
799 BinOp::BitAnd => write!(f, "&"),
800 BinOp::BitShl => write!(f, "<<"),
801 BinOp::BitShr => write!(f, ">>"),
802 }
803 }
804}
805
806impl rustc_errors::IntoDiagArg for BinOp {
807 fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
808 rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
809 }
810}
811
812#[derive(Copy, Clone)]
813pub enum UnOp {
814 Not,
815 Neg,
816}
817
818impl fmt::Debug for UnOp {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 match self {
821 Self::Not => write!(f, "!"),
822 Self::Neg => write!(f, "-"),
823 }
824 }
825}
826
827impl BindKind {
828 pub fn token_str(&self) -> &'static str {
829 match self {
830 BindKind::At => "@",
831 BindKind::Pound => "#",
832 }
833 }
834}
835
836pub struct Punctuated<T, P> {
838 inner: Vec<(T, P)>,
839 last: Option<Box<T>>,
840}
841
842impl<T, P> From<Vec<(T, P)>> for Punctuated<T, P> {
843 fn from(inner: Vec<(T, P)>) -> Self {
844 Self { inner, last: None }
845 }
846}
847
848impl<T, P> Punctuated<T, P> {
849 pub fn len(&self) -> usize {
850 self.inner.len() + self.last.is_some() as usize
851 }
852
853 pub fn is_empty(&self) -> bool {
856 self.inner.len() == 0 && self.last.is_none()
857 }
858
859 pub fn push_value(&mut self, value: T) {
867 assert!(
868 self.empty_or_trailing(),
869 "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
870 );
871
872 self.last = Some(Box::new(value));
873 }
874
875 pub fn empty_or_trailing(&self) -> bool {
880 self.last.is_none()
881 }
882
883 pub fn trailing_punct(&self) -> bool {
886 self.last.is_none() && !self.is_empty()
887 }
888
889 pub fn into_values(self) -> Vec<T> {
890 let mut v: Vec<T> = self.inner.into_iter().map(|(v, _)| v).collect();
891 if let Some(last) = self.last {
892 v.push(*last);
893 }
894 v
895 }
896}
897
898impl Expr {
899 pub fn free_vars(&self) -> FxHashSet<Ident> {
902 struct FreeVarsVisitor {
903 vars: FxHashSet<Ident>,
904 }
905
906 impl visit::Visitor for FreeVarsVisitor {
907 fn visit_expr(&mut self, expr: &Expr) {
908 if let ExprKind::Path(path) = &expr.kind {
909 if let [segment] = path.segments.as_slice() {
911 self.vars.insert(segment.ident);
912 }
913 }
914 visit::walk_expr(self, expr);
916 }
917 }
918
919 let mut visitor = FreeVarsVisitor { vars: FxHashSet::default() };
920 visitor.visit_expr(self);
921 visitor.vars
922 }
923}