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 Mod,
139}
140
141pub struct TraitItemFn {
142 pub attrs: Vec<Attr>,
143 pub sig: Option<FnSig>,
144 pub node_id: NodeId,
145}
146
147pub struct ImplItemFn {
148 pub attrs: Vec<Attr>,
149 pub sig: Option<FnSig>,
150 pub node_id: NodeId,
151}
152
153#[derive(Debug)]
154pub struct DetachedSpecs {
155 pub items: Vec<DetachedItem>,
156}
157
158#[derive(Debug)]
159pub struct DetachedTraitImpl {
160 pub trait_: ExprPath,
161 pub items: Vec<DetachedItem<FnSig>>,
162 pub refts: Vec<ImplAssocReft>,
163 pub span: Span,
164}
165
166#[derive(Debug, Default)]
167pub struct DetachedTrait {
168 pub items: Vec<DetachedItem<FnSig>>,
169 pub refts: Vec<TraitAssocReft>,
170}
171
172#[derive(Debug)]
173pub struct DetachedInherentImpl {
174 pub items: Vec<DetachedItem<FnSig>>,
175 pub span: Span,
176}
177
178impl DetachedInherentImpl {
179 pub fn extend(&mut self, other: DetachedInherentImpl) {
180 self.items.extend(other.items);
181 }
182}
183
184#[derive(Debug)]
185pub struct DetachedItem<K = DetachedItemKind> {
186 pub attrs: Vec<Attr>,
187 pub path: ExprPath,
188 pub kind: K,
189 pub node_id: NodeId,
190}
191
192impl<K> DetachedItem<K> {
193 pub fn map_kind<R>(self, f: impl FnOnce(K) -> R) -> DetachedItem<R> {
194 DetachedItem {
195 attrs: self.attrs,
196 path: self.path,
197 kind: f(self.kind),
198 node_id: self.node_id,
199 }
200 }
201}
202
203impl DetachedItem<DetachedItemKind> {
204 pub fn span(&self) -> Span {
205 match &self.kind {
206 DetachedItemKind::InherentImpl(impl_) => impl_.span,
207 DetachedItemKind::TraitImpl(trait_impl) => trait_impl.span,
208 _ => self.path.span,
209 }
210 }
211}
212
213#[derive(Debug)]
214pub enum DetachedItemKind {
215 FnSig(FnSig),
216 Mod(DetachedSpecs),
217 Struct(StructDef),
218 Enum(EnumDef),
219 InherentImpl(DetachedInherentImpl),
220 TraitImpl(DetachedTraitImpl),
221 Trait(DetachedTrait),
222}
223
224#[derive(Debug)]
225pub struct ConstantInfo {
226 pub expr: Option<Expr>,
227}
228
229#[derive(Debug)]
230pub struct StructDef {
231 pub generics: Option<Generics>,
232 pub refined_by: Option<RefineParams>,
233 pub fields: Vec<Option<Ty>>,
234 pub opaque: bool,
235 pub invariants: Vec<Expr>,
236}
237
238#[derive(Debug)]
239pub struct EnumDef {
240 pub generics: Option<Generics>,
241 pub refined_by: Option<RefineParams>,
242 pub variants: Vec<Option<VariantDef>>,
243 pub invariants: Vec<Expr>,
244 pub reflected: bool,
245}
246
247#[derive(Debug)]
248pub struct VariantDef {
249 pub ident: Option<Ident>,
250 pub fields: Vec<Ty>,
251 pub ret: Option<VariantRet>,
252 pub node_id: NodeId,
253 pub span: Span,
254}
255
256#[derive(Debug)]
257pub struct VariantRet {
258 pub path: Path,
259 pub indices: Indices,
262}
263
264pub type RefineParams = Vec<RefineParam>;
265
266#[derive(Debug)]
267pub struct RefineParam {
268 pub ident: Ident,
269 pub sort: Sort,
270 pub mode: Option<ParamMode>,
271 pub span: Span,
272 pub node_id: NodeId,
273}
274
275#[derive(Clone, Copy, Debug, PartialEq, Eq)]
276pub enum ParamMode {
277 Horn,
278 Hindley,
279}
280
281#[derive(Debug)]
282pub enum Sort {
283 Base(BaseSort),
285 Func { inputs: Vec<BaseSort>, output: BaseSort },
288 Infer,
290}
291
292#[derive(Debug)]
293pub enum BaseSort {
294 BitVec(u32),
296 SortOf(Box<Ty>, Path),
297 Path(SortPath),
298}
299
300#[derive(Debug)]
302pub struct SortPath {
303 pub segments: Vec<Ident>,
305 pub args: Vec<BaseSort>,
307 pub node_id: NodeId,
308}
309
310#[derive(Debug)]
311pub struct Impl {
312 pub generics: Option<Generics>,
313 pub assoc_refinements: Vec<ImplAssocReft>,
314}
315
316#[derive(Debug)]
317pub struct ImplAssocReft {
318 pub name: Ident,
319 pub params: RefineParams,
320 pub output: BaseSort,
321 pub body: Expr,
322 pub span: Span,
323}
324
325#[derive(Debug)]
326pub struct Trait {
327 pub generics: Option<Generics>,
328 pub assoc_refinements: Vec<TraitAssocReft>,
329}
330
331#[derive(Debug)]
332pub struct TraitAssocReft {
333 pub name: Ident,
334 pub params: RefineParams,
335 pub output: BaseSort,
336 pub body: Option<Expr>,
337 pub span: Span,
338 pub final_: bool,
339}
340
341#[derive(Debug)]
342pub struct FnSig {
343 pub asyncness: Async,
344 pub ident: Option<Ident>,
345 pub generics: Generics,
346 pub params: RefineParams,
347 pub requires: Vec<Requires>,
349 pub inputs: Vec<FnInput>,
351 pub output: FnOutput,
352 pub span: Span,
354 pub node_id: NodeId,
355}
356
357#[derive(Debug)]
358pub struct Requires {
359 pub params: RefineParams,
361 pub pred: Expr,
362}
363
364#[derive(Debug)]
365pub struct FnOutput {
366 pub returns: FnRetTy,
368 pub ensures: Vec<Ensures>,
370 pub node_id: NodeId,
371}
372
373#[derive(Debug)]
374pub enum Ensures {
375 Type(Ident, Ty, NodeId),
377 Pred(Expr),
379}
380
381#[derive(Debug)]
382pub enum FnRetTy {
383 Default(Span),
384 Ty(Box<Ty>),
385}
386
387#[derive(Debug, Copy, Clone)]
388pub enum Async {
389 Yes { node_id: NodeId, span: Span },
390 No,
391}
392
393#[derive(Debug)]
394pub struct WhereBoundPredicate {
395 pub span: Span,
396 pub bounded_ty: Ty,
397 pub bounds: GenericBounds,
398}
399
400pub type GenericBounds = Vec<TraitRef>;
401
402#[derive(Debug)]
403pub struct TraitRef {
404 pub path: Path,
405 pub node_id: NodeId,
406}
407
408impl TraitRef {
409 fn is_fn_trait_name(name: Symbol) -> bool {
410 name == sym::FnOnce || name == sym::FnMut || name == sym::Fn
411 }
412
413 pub fn as_fn_trait_ref(&self) -> Option<(&GenericArg, &GenericArg)> {
414 if let [segment] = self.path.segments.as_slice()
415 && Self::is_fn_trait_name(segment.ident.name)
416 && let [in_arg, out_arg] = segment.args.as_slice()
417 {
418 return Some((in_arg, out_arg));
419 }
420 None
421 }
422}
423
424#[derive(Debug)]
425pub enum FnInput {
426 Constr(Ident, Path, Expr, NodeId),
428 StrgRef(Ident, Ty, NodeId),
430 Ty(Option<Ident>, Ty, NodeId),
433}
434
435#[derive(Debug)]
436pub struct Ty {
437 pub kind: TyKind,
438 pub node_id: NodeId,
439 pub span: Span,
440}
441
442#[derive(Debug)]
443pub enum TyKind {
444 Base(BaseTy),
446 Indexed {
448 bty: BaseTy,
449 indices: Indices,
450 },
451 Exists {
453 bind: Ident,
454 bty: BaseTy,
455 pred: Expr,
456 },
457 GeneralExists {
458 params: RefineParams,
459 ty: Box<Ty>,
460 pred: Option<Expr>,
461 },
462 Ref(Mutability, Box<Ty>),
464 Constr(Expr, Box<Ty>),
466 Tuple(Vec<Ty>),
467 Array(Box<Ty>, ConstArg),
468 ImplTrait(NodeId, GenericBounds),
470 Hole,
471}
472
473impl Ty {
474 pub fn is_refined(&self) -> bool {
475 struct IsRefinedVisitor {
476 is_refined: bool,
477 }
478 let mut vis = IsRefinedVisitor { is_refined: false };
479 impl visit::Visitor for IsRefinedVisitor {
480 fn visit_ty(&mut self, ty: &Ty) {
481 match &ty.kind {
482 TyKind::Tuple(_)
483 | TyKind::Ref(..)
484 | TyKind::Array(..)
485 | TyKind::ImplTrait(..)
486 | TyKind::Hole
487 | TyKind::Base(_) => {
488 visit::walk_ty(self, ty);
489 }
490 TyKind::Indexed { .. }
491 | TyKind::Exists { .. }
492 | TyKind::GeneralExists { .. }
493 | TyKind::Constr(..) => {
494 self.is_refined = true;
495 }
496 }
497 }
498 }
499 vis.visit_ty(self);
500 vis.is_refined
501 }
502
503 pub fn is_potential_const_arg(&self) -> Option<&Path> {
504 if let TyKind::Base(bty) = &self.kind
505 && let BaseTyKind::Path(None, path) = &bty.kind
506 && let [segment] = &path.segments[..]
507 && segment.args.is_empty()
508 {
509 Some(path)
510 } else {
511 None
512 }
513 }
514}
515#[derive(Debug)]
516pub struct BaseTy {
517 pub kind: BaseTyKind,
518 pub span: Span,
519}
520
521#[derive(Debug)]
522pub enum BaseTyKind {
523 Path(Option<Box<Ty>>, Path),
524 Slice(Box<Ty>),
525}
526
527#[derive(PartialEq, Eq, Clone, Debug, Copy)]
528pub struct ConstArg {
529 pub kind: ConstArgKind,
530 pub span: Span,
531}
532
533#[derive(PartialEq, Eq, Clone, Debug, Copy)]
534pub enum ConstArgKind {
535 Lit(usize),
536 Infer,
537}
538
539#[derive(Debug)]
540pub struct Indices {
541 pub indices: Vec<RefineArg>,
542 pub span: Span,
543}
544
545#[derive(Debug)]
546pub enum RefineArg {
547 Bind(Ident, BindKind, Span, NodeId),
549 Expr(Expr),
550 Abs(RefineParams, Expr, Span, NodeId),
551}
552
553#[derive(Debug, Clone, Copy)]
554pub enum BindKind {
555 At,
556 Pound,
557}
558
559#[derive(Debug, Eq, PartialEq, Copy, Clone)]
561pub enum Trusted {
562 Yes,
563 No,
564}
565
566impl Trusted {
567 pub fn to_bool(self) -> bool {
568 match self {
569 Trusted::Yes => true,
570 Trusted::No => false,
571 }
572 }
573}
574
575impl From<bool> for Trusted {
576 fn from(value: bool) -> Self {
577 if value { Trusted::Yes } else { Trusted::No }
578 }
579}
580
581#[derive(Debug, Eq, PartialEq, Copy, Clone)]
583pub enum Ignored {
584 Yes,
585 No,
586}
587
588impl Ignored {
589 pub fn to_bool(self) -> bool {
590 match self {
591 Ignored::Yes => true,
592 Ignored::No => false,
593 }
594 }
595}
596
597impl From<bool> for Ignored {
598 fn from(value: bool) -> Self {
599 if value { Ignored::Yes } else { Ignored::No }
600 }
601}
602
603#[derive(Debug)]
612pub enum Attr {
613 Trusted(Trusted),
615 TrustedImpl(Trusted),
617 Ignore(Ignored),
619 ProvenExternally,
621 ShouldFail,
623 Qualifiers(Vec<Ident>),
625 Reveal(Vec<Ident>),
627 InferOpts(PartialInferOpts),
629 NoPanic,
631}
632
633#[derive(Debug)]
634pub struct Path {
635 pub segments: Vec<PathSegment>,
636 pub refine: Vec<RefineArg>,
637 pub node_id: NodeId,
638 pub span: Span,
639}
640
641impl Path {
642 pub fn last(&self) -> &PathSegment {
643 self.segments
644 .last()
645 .expect("path must have at least one segment")
646 }
647}
648
649#[derive(Debug)]
650pub struct PathSegment {
651 pub ident: Ident,
652 pub args: Vec<GenericArg>,
653 pub node_id: NodeId,
654}
655
656#[derive(Debug)]
657pub struct GenericArg {
658 pub kind: GenericArgKind,
659 pub node_id: NodeId,
660}
661
662#[derive(Debug)]
663pub enum GenericArgKind {
664 Type(Ty),
665 Constraint(Ident, Ty),
666}
667
668#[derive(Debug)]
669pub struct FieldExpr {
670 pub ident: Ident,
671 pub expr: Expr,
672 pub span: Span,
673 pub node_id: NodeId,
674}
675
676#[derive(Debug)]
677pub struct Spread {
678 pub expr: Expr,
679 pub span: Span,
680 pub node_id: NodeId,
681}
682
683#[derive(Debug)]
684pub enum ConstructorArg {
685 FieldExpr(FieldExpr),
686 Spread(Spread),
687}
688
689#[derive(Debug)]
690pub struct Expr {
691 pub kind: ExprKind,
692 pub node_id: NodeId,
693 pub span: Span,
694}
695
696#[derive(Debug)]
697pub enum QuantKind {
698 Forall,
699 Exists,
700}
701
702#[derive(Debug)]
703pub enum ExprKind {
704 Path(ExprPath),
705 Dot(Box<Expr>, Ident),
706 Literal(Lit),
707 BinaryOp(BinOp, Box<[Expr; 2]>),
708 UnaryOp(UnOp, Box<Expr>),
709 Call(Box<Expr>, Vec<Expr>),
710 PrimUIF(BinOp),
712 AssocReft(Box<Ty>, Path, Ident),
714 IfThenElse(Box<[Expr; 3]>),
715 Constructor(Option<ExprPath>, Vec<ConstructorArg>),
716 BoundedQuant(QuantKind, RefineParam, Range<usize>, Box<Expr>),
717 Block(Vec<LetDecl>, Box<Expr>),
718 SetLiteral(Vec<Expr>),
720}
721
722#[derive(Debug)]
723pub struct LetDecl {
724 pub param: RefineParam,
725 pub init: Expr,
726}
727
728#[derive(Debug, Clone)]
730pub struct ExprPath {
731 pub segments: Vec<ExprPathSegment>,
732 pub node_id: NodeId,
733 pub span: Span,
734}
735
736#[derive(Debug, Clone)]
737pub struct ExprPathSegment {
738 pub ident: Ident,
739 pub node_id: NodeId,
740}
741#[derive(Copy, Clone, Hash, Eq, PartialEq)]
742pub enum BinOp {
743 Iff,
744 Imp,
745 Or,
746 And,
747 Eq,
748 Ne,
749 Gt,
750 Ge,
751 Lt,
752 Le,
753 Add,
754 Sub,
755 Mul,
756 Div,
757 Mod,
758 BitOr,
759 BitXor,
760 BitAnd,
761 BitShl,
762 BitShr,
763}
764
765impl fmt::Debug for BinOp {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 match self {
768 BinOp::Iff => write!(f, "<=>"),
769 BinOp::Imp => write!(f, "=>"),
770 BinOp::Or => write!(f, "||"),
771 BinOp::And => write!(f, "&&"),
772 BinOp::Eq => write!(f, "=="),
773 BinOp::Ne => write!(f, "!="),
774 BinOp::Lt => write!(f, "<"),
775 BinOp::Le => write!(f, "<="),
776 BinOp::Gt => write!(f, ">"),
777 BinOp::Ge => write!(f, ">="),
778 BinOp::Add => write!(f, "+"),
779 BinOp::Sub => write!(f, "-"),
780 BinOp::Mod => write!(f, "mod"),
781 BinOp::Mul => write!(f, "*"),
782 BinOp::Div => write!(f, "/"),
783 BinOp::BitOr => write!(f, "|"),
784 BinOp::BitXor => write!(f, "^"),
785 BinOp::BitAnd => write!(f, "&"),
786 BinOp::BitShl => write!(f, "<<"),
787 BinOp::BitShr => write!(f, ">>"),
788 }
789 }
790}
791
792impl rustc_errors::IntoDiagArg for BinOp {
793 fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
794 rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
795 }
796}
797
798#[derive(Copy, Clone)]
799pub enum UnOp {
800 Not,
801 Neg,
802}
803
804impl fmt::Debug for UnOp {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 match self {
807 Self::Not => write!(f, "!"),
808 Self::Neg => write!(f, "-"),
809 }
810 }
811}
812
813impl BindKind {
814 pub fn token_str(&self) -> &'static str {
815 match self {
816 BindKind::At => "@",
817 BindKind::Pound => "#",
818 }
819 }
820}
821
822pub struct Punctuated<T, P> {
824 inner: Vec<(T, P)>,
825 last: Option<Box<T>>,
826}
827
828impl<T, P> From<Vec<(T, P)>> for Punctuated<T, P> {
829 fn from(inner: Vec<(T, P)>) -> Self {
830 Self { inner, last: None }
831 }
832}
833
834impl<T, P> Punctuated<T, P> {
835 pub fn len(&self) -> usize {
836 self.inner.len() + self.last.is_some() as usize
837 }
838
839 pub fn is_empty(&self) -> bool {
842 self.inner.len() == 0 && self.last.is_none()
843 }
844
845 pub fn push_value(&mut self, value: T) {
853 assert!(
854 self.empty_or_trailing(),
855 "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
856 );
857
858 self.last = Some(Box::new(value));
859 }
860
861 pub fn empty_or_trailing(&self) -> bool {
866 self.last.is_none()
867 }
868
869 pub fn trailing_punct(&self) -> bool {
872 self.last.is_none() && !self.is_empty()
873 }
874
875 pub fn into_values(self) -> Vec<T> {
876 let mut v: Vec<T> = self.inner.into_iter().map(|(v, _)| v).collect();
877 if let Some(last) = self.last {
878 v.push(*last);
879 }
880 v
881 }
882}
883
884impl Expr {
885 pub fn free_vars(&self) -> FxHashSet<Ident> {
888 struct FreeVarsVisitor {
889 vars: FxHashSet<Ident>,
890 }
891
892 impl visit::Visitor for FreeVarsVisitor {
893 fn visit_expr(&mut self, expr: &Expr) {
894 if let ExprKind::Path(path) = &expr.kind {
895 if let [segment] = path.segments.as_slice() {
897 self.vars.insert(segment.ident);
898 }
899 }
900 visit::walk_expr(self, expr);
902 }
903 }
904
905 let mut visitor = FreeVarsVisitor { vars: FxHashSet::default() };
906 visitor.visit_expr(self);
907 visitor.vars
908 }
909}