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(Debug)]
540pub struct ConstArg {
541 pub kind: ConstArgKind,
542 pub span: Span,
543}
544
545#[derive(Debug)]
546pub enum ConstArgKind {
547 Lit(usize),
548 Path(Path),
549 Infer,
550}
551
552#[derive(Debug)]
553pub struct Indices {
554 pub indices: Vec<RefineArg>,
555 pub span: Span,
556}
557
558#[derive(Debug)]
559pub enum RefineArg {
560 Bind(Ident, BindKind, Span, NodeId),
562 Expr(Expr),
563 Abs(RefineParams, Expr, Span, NodeId),
564}
565
566#[derive(Debug, Clone, Copy)]
567pub enum BindKind {
568 At,
569 Pound,
570}
571
572#[derive(Debug, Eq, PartialEq, Copy, Clone)]
574pub enum Trusted {
575 Yes,
576 No,
577}
578
579impl Trusted {
580 pub fn to_bool(self) -> bool {
581 match self {
582 Trusted::Yes => true,
583 Trusted::No => false,
584 }
585 }
586}
587
588impl From<bool> for Trusted {
589 fn from(value: bool) -> Self {
590 if value { Trusted::Yes } else { Trusted::No }
591 }
592}
593
594#[derive(Debug, Eq, PartialEq, Copy, Clone)]
596pub enum Ignored {
597 Yes,
598 No,
599}
600
601impl Ignored {
602 pub fn to_bool(self) -> bool {
603 match self {
604 Ignored::Yes => true,
605 Ignored::No => false,
606 }
607 }
608}
609
610impl From<bool> for Ignored {
611 fn from(value: bool) -> Self {
612 if value { Ignored::Yes } else { Ignored::No }
613 }
614}
615
616#[derive(Debug)]
625pub enum Attr {
626 Trusted(Trusted),
628 TrustedImpl(Trusted),
630 Ignore(Ignored),
632 ProvenExternally(Span),
634 ShouldFail,
636 Qualifiers(Vec<Ident>),
638 Reveal(Vec<Ident>),
640 InferOpts(PartialInferOpts),
642 NoPanic,
644 AssumeParametric(Vec<Ident>),
646}
647
648#[derive(Debug)]
649pub struct Path {
650 pub segments: Vec<PathSegment>,
651 pub refine: Vec<RefineArg>,
652 pub node_id: NodeId,
653 pub span: Span,
654}
655
656impl Path {
657 pub fn last(&self) -> &PathSegment {
658 self.segments
659 .last()
660 .expect("path must have at least one segment")
661 }
662}
663
664#[derive(Debug)]
665pub struct PathSegment {
666 pub ident: Ident,
667 pub args: Vec<GenericArg>,
668 pub node_id: NodeId,
669}
670
671#[derive(Debug)]
672pub struct GenericArg {
673 pub kind: GenericArgKind,
674 pub node_id: NodeId,
675}
676
677#[derive(Debug)]
678pub enum GenericArgKind {
679 Type(Ty),
680 Constraint(Ident, Ty),
681}
682
683#[derive(Debug)]
684pub struct FieldExpr {
685 pub ident: Ident,
686 pub expr: RefineArg,
687 pub span: Span,
688 pub node_id: NodeId,
689}
690
691#[derive(Debug)]
692pub struct Spread {
693 pub expr: Expr,
694 pub span: Span,
695 pub node_id: NodeId,
696}
697
698#[derive(Debug)]
699pub enum ConstructorArg {
700 FieldExpr(FieldExpr),
701 Spread(Spread),
702}
703
704#[derive(Debug)]
705pub struct Expr {
706 pub kind: ExprKind,
707 pub node_id: NodeId,
708 pub span: Span,
709}
710
711#[derive(Debug)]
712pub enum QuantKind {
713 Forall,
714 Exists,
715}
716
717#[derive(Debug)]
718pub enum ExprKind {
719 Path(ExprPath),
720 Dot(Box<Expr>, Ident),
721 Literal(Lit),
722 BinaryOp(BinOp, Box<[Expr; 2]>),
723 UnaryOp(UnOp, Box<Expr>),
724 Call(Box<Expr>, Vec<Expr>),
725 PrimUIF(BinOp),
727 AssocReft(Box<Ty>, Path, Ident),
729 IfThenElse(Box<[Expr; 3]>),
730 Constructor(Option<ExprPath>, Vec<ConstructorArg>),
731 BoundedQuant(QuantKind, RefineParam, Range<usize>, Box<Expr>),
732 Block(Vec<LetDecl>, Box<Expr>),
733 SetLiteral(Vec<Expr>),
735 Tuple(Vec<Expr>),
737}
738
739#[derive(Debug)]
740pub struct LetDecl {
741 pub param: RefineParam,
742 pub init: Expr,
743}
744
745#[derive(Debug, Clone)]
747pub struct ExprPath {
748 pub segments: Vec<ExprPathSegment>,
749 pub node_id: NodeId,
750 pub span: Span,
751}
752
753#[derive(Debug, Clone)]
754pub struct ExprPathSegment {
755 pub ident: Ident,
756 pub node_id: NodeId,
757}
758#[derive(Copy, Clone, Hash, Eq, PartialEq)]
759pub enum BinOp {
760 Iff,
761 Imp,
762 Or,
763 And,
764 Eq,
765 Ne,
766 Gt,
767 Ge,
768 Lt,
769 Le,
770 Add,
771 Sub,
772 Mul,
773 Div,
774 Mod,
775 BitOr,
776 BitXor,
777 BitAnd,
778 BitShl,
779 BitShr,
780}
781
782impl fmt::Debug for BinOp {
783 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784 match self {
785 BinOp::Iff => write!(f, "<=>"),
786 BinOp::Imp => write!(f, "=>"),
787 BinOp::Or => write!(f, "||"),
788 BinOp::And => write!(f, "&&"),
789 BinOp::Eq => write!(f, "=="),
790 BinOp::Ne => write!(f, "!="),
791 BinOp::Lt => write!(f, "<"),
792 BinOp::Le => write!(f, "<="),
793 BinOp::Gt => write!(f, ">"),
794 BinOp::Ge => write!(f, ">="),
795 BinOp::Add => write!(f, "+"),
796 BinOp::Sub => write!(f, "-"),
797 BinOp::Mod => write!(f, "mod"),
798 BinOp::Mul => write!(f, "*"),
799 BinOp::Div => write!(f, "/"),
800 BinOp::BitOr => write!(f, "|"),
801 BinOp::BitXor => write!(f, "^"),
802 BinOp::BitAnd => write!(f, "&"),
803 BinOp::BitShl => write!(f, "<<"),
804 BinOp::BitShr => write!(f, ">>"),
805 }
806 }
807}
808
809impl rustc_errors::IntoDiagArg for BinOp {
810 fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
811 rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
812 }
813}
814
815#[derive(Copy, Clone)]
816pub enum UnOp {
817 Not,
818 Neg,
819}
820
821impl fmt::Debug for UnOp {
822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
823 match self {
824 Self::Not => write!(f, "!"),
825 Self::Neg => write!(f, "-"),
826 }
827 }
828}
829
830impl BindKind {
831 pub fn token_str(&self) -> &'static str {
832 match self {
833 BindKind::At => "@",
834 BindKind::Pound => "#",
835 }
836 }
837}
838
839pub struct Punctuated<T, P> {
841 inner: Vec<(T, P)>,
842 last: Option<Box<T>>,
843}
844
845impl<T, P> From<Vec<(T, P)>> for Punctuated<T, P> {
846 fn from(inner: Vec<(T, P)>) -> Self {
847 Self { inner, last: None }
848 }
849}
850
851impl<T, P> Punctuated<T, P> {
852 pub fn len(&self) -> usize {
853 self.inner.len() + self.last.is_some() as usize
854 }
855
856 pub fn is_empty(&self) -> bool {
859 self.inner.len() == 0 && self.last.is_none()
860 }
861
862 pub fn push_value(&mut self, value: T) {
870 assert!(
871 self.empty_or_trailing(),
872 "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
873 );
874
875 self.last = Some(Box::new(value));
876 }
877
878 pub fn empty_or_trailing(&self) -> bool {
883 self.last.is_none()
884 }
885
886 pub fn trailing_punct(&self) -> bool {
889 self.last.is_none() && !self.is_empty()
890 }
891
892 pub fn into_values(self) -> Vec<T> {
893 let mut v: Vec<T> = self.inner.into_iter().map(|(v, _)| v).collect();
894 if let Some(last) = self.last {
895 v.push(*last);
896 }
897 v
898 }
899}
900
901impl Expr {
902 pub fn free_vars(&self) -> FxHashSet<Ident> {
905 struct FreeVarsVisitor {
906 vars: FxHashSet<Ident>,
907 }
908
909 impl visit::Visitor for FreeVarsVisitor {
910 fn visit_expr(&mut self, expr: &Expr) {
911 if let ExprKind::Path(path) = &expr.kind {
912 if let [segment] = path.segments.as_slice() {
914 self.vars.insert(segment.ident);
915 }
916 }
917 visit::walk_expr(self, expr);
919 }
920 }
921
922 let mut visitor = FreeVarsVisitor { vars: FxHashSet::default() };
923 visitor.visit_expr(self);
924 visitor.vars
925 }
926}