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#[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 Simple,
64 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#[derive(Debug)]
87pub struct SpecFunc {
88 pub name: Ident,
89 pub sort_vars: Vec<Ident>,
90 pub params: RefineParams,
91 pub output: Sort,
92 pub body: Option<Expr>,
94 pub hide: bool,
98}
99
100#[derive(Debug)]
102pub struct PrimOpProp {
103 pub name: Ident,
105 pub op: BinOp,
107 pub params: RefineParams,
110 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 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 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 Base(BaseSort),
309 Func { inputs: Vec<BaseSort>, output: BaseSort },
312 Infer,
314}
315
316#[derive(Debug)]
317pub enum BaseSort {
318 BitVec(u32),
320 SortOf(Box<Ty>, Path),
321 Path(SortPath),
322 Tuple(Vec<BaseSort>),
324}
325
326#[derive(Debug)]
328pub struct SortPath {
329 pub segments: Vec<Ident>,
331 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 pub requires: Vec<Requires>,
375 pub inputs: Vec<FnInput>,
377 pub output: FnOutput,
378 pub span: Span,
380 pub node_id: NodeId,
381 pub no_panic: Option<Expr>,
382}
383
384#[derive(Debug)]
385pub struct Requires {
386 pub params: RefineParams,
388 pub pred: Expr,
389}
390
391#[derive(Debug)]
392pub struct FnOutput {
393 pub returns: FnRetTy,
395 pub ensures: Vec<Ensures>,
397 pub node_id: NodeId,
398}
399
400#[derive(Debug)]
401pub enum Ensures {
402 Type(Ident, Ty, NodeId),
404 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 Constr(Ident, Path, Expr, NodeId),
455 StrgRef(Ident, Ty, NodeId),
457 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 Base(BaseTy),
473 Indexed {
475 bty: BaseTy,
476 indices: Indices,
477 },
478 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 Ref(Mutability, Box<Ty>),
491 Constr(Expr, Box<Ty>),
493 Tuple(Vec<Ty>),
494 Array(Box<Ty>, ConstArg),
495 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 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 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#[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#[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#[derive(Debug)]
642pub enum Attr {
643 Trusted(Trusted),
645 TrustedImpl(Trusted),
647 Ignore(Ignored),
649 ProvenExternally(Span),
651 ShouldFail,
653 Qualifiers(Vec<Ident>),
655 Reveal(Vec<Ident>),
657 InferOpts(PartialInferOpts),
659 NoPanic,
661 AssumeParametric(Vec<Ident>),
663 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 PrimUIF(BinOp),
746 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 SetLiteral(Vec<Expr>),
754 Tuple(Vec<Expr>),
756}
757
758#[derive(Debug)]
759pub struct LetDecl {
760 pub param: RefineParam,
761 pub init: Expr,
762}
763
764#[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
858pub 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 pub fn is_empty(&self) -> bool {
878 self.inner.len() == 0 && self.last.is_none()
879 }
880
881 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 pub fn empty_or_trailing(&self) -> bool {
902 self.last.is_none()
903 }
904
905 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 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 if let [segment] = path.segments.as_slice() {
934 self.vars.insert(segment.ident);
935 }
936 }
937 ExprKind::Call(callee, args) => {
938 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 _ => 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}