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_data_structures::fx::FxIndexSet;
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 Axiom(Axiom),
40 Use(UseTree),
41}
42
43impl FluxItem {
44 pub fn name(&self) -> Option<Ident> {
45 match self {
46 FluxItem::Qualifier(qualifier) => Some(qualifier.name),
47 FluxItem::FuncDef(spec_func) => Some(spec_func.name),
48 FluxItem::SortDecl(sort_decl) => Some(sort_decl.name),
49 FluxItem::PrimOpProp(primop_prop) => Some(primop_prop.name),
50 FluxItem::Axiom(axiom) => Some(axiom.name),
51 FluxItem::Use(_) => None,
52 }
53 }
54
55 pub fn sort_vars(&self) -> &[Ident] {
56 match self {
57 FluxItem::FuncDef(defn) => &defn.sort_vars[..],
58 FluxItem::SortDecl(sort_decl) => &sort_decl.sort_vars[..],
59 FluxItem::Qualifier(_)
60 | FluxItem::PrimOpProp(_)
61 | FluxItem::Axiom(_)
62 | FluxItem::Use(_) => &[],
63 }
64 }
65}
66
67#[derive(Debug)]
68pub struct UseTree {
69 pub prefix: ExprPath,
70 pub kind: UseTreeKind,
71}
72
73#[derive(Debug)]
74pub enum UseTreeKind {
75 Simple,
77 Nested(Vec<UseTree>),
79}
80
81#[derive(Debug)]
82pub struct Qualifier {
83 pub name: Ident,
84 pub params: RefineParams,
85 pub wildcards: Vec<bool>,
86 pub expr: Expr,
87 pub span: Span,
88 pub kind: QualifierKind,
89}
90
91#[derive(Debug)]
92pub enum QualifierKind {
93 Global,
94 Local,
95 Hint,
96}
97
98#[derive(Debug)]
101pub struct SpecFunc {
102 pub name: Ident,
103 pub sort_vars: Vec<Ident>,
104 pub params: RefineParams,
105 pub output: Sort,
106 pub body: Option<Expr>,
108 pub hide: bool,
112}
113
114#[derive(Debug)]
116pub struct PrimOpProp {
117 pub name: Ident,
119 pub op: BinOp,
121 pub params: RefineParams,
124 pub body: Expr,
126 pub span: Span,
127}
128
129#[derive(Debug)]
132pub struct Axiom {
133 pub name: Ident,
135 pub params: RefineParams,
137 pub body: Expr,
139 pub span: Span,
140}
141
142#[derive(Debug)]
143pub struct Generics {
144 pub params: Vec<GenericParam>,
145 pub predicates: Option<Vec<WhereBoundPredicate>>,
146 pub span: Span,
147}
148
149#[derive(Debug)]
150pub struct GenericParam {
151 pub name: Ident,
152 pub node_id: NodeId,
153}
154
155#[derive(Debug)]
156pub struct TyAlias {
157 pub ident: Ident,
158 pub generics: Generics,
159 pub params: RefineParams,
160 pub index: Option<RefineParam>,
161 pub ty: Ty,
162 pub node_id: NodeId,
163 pub span: Span,
164}
165
166pub struct Item {
167 pub attrs: Vec<Attr>,
168 pub kind: ItemKind,
169 pub node_id: NodeId,
170}
171
172pub enum ItemKind {
173 Fn(Option<FnSig>),
174 Struct(StructDef),
175 Enum(EnumDef),
176 Trait(Trait),
177 Impl(Impl),
178 Const(ConstantInfo),
179 TyAlias(Box<TyAlias>),
180 Static(StaticInfo),
181 Mod,
184}
185
186pub struct TraitItemFn {
187 pub attrs: Vec<Attr>,
188 pub sig: Option<FnSig>,
189 pub node_id: NodeId,
190}
191
192pub struct ImplItemFn {
193 pub attrs: Vec<Attr>,
194 pub sig: Option<FnSig>,
195 pub node_id: NodeId,
196}
197
198#[derive(Debug)]
199pub struct DetachedSpecs {
200 pub items: Vec<DetachedItem>,
201}
202
203#[derive(Debug)]
204pub struct DetachedTraitImpl {
205 pub trait_: ExprPath,
206 pub items: Vec<DetachedItem<FnSig>>,
207 pub refts: Vec<ImplAssocReft>,
208 pub span: Span,
209}
210
211#[derive(Debug, Default)]
212pub struct DetachedTrait {
213 pub items: Vec<DetachedItem<FnSig>>,
214 pub refts: Vec<TraitAssocReft>,
215}
216
217#[derive(Debug)]
218pub struct DetachedInherentImpl {
219 pub items: Vec<DetachedItem<FnSig>>,
220 pub span: Span,
221}
222
223impl DetachedInherentImpl {
224 pub fn extend(&mut self, other: DetachedInherentImpl) {
225 self.items.extend(other.items);
226 }
227}
228
229#[derive(Debug)]
230pub struct DetachedItem<K = DetachedItemKind> {
231 pub attrs: Vec<Attr>,
232 pub path: ExprPath,
233 pub kind: K,
234 pub node_id: NodeId,
235}
236
237impl<K> DetachedItem<K> {
238 pub fn map_kind<R>(self, f: impl FnOnce(K) -> R) -> DetachedItem<R> {
239 DetachedItem {
240 attrs: self.attrs,
241 path: self.path,
242 kind: f(self.kind),
243 node_id: self.node_id,
244 }
245 }
246}
247
248impl DetachedItem<DetachedItemKind> {
249 pub fn span(&self) -> Span {
250 match &self.kind {
251 DetachedItemKind::InherentImpl(impl_) => impl_.span,
252 DetachedItemKind::TraitImpl(trait_impl) => trait_impl.span,
253 _ => self.path.span,
254 }
255 }
256}
257
258#[derive(Debug)]
259pub enum DetachedItemKind {
260 FnSig(FnSig),
261 Mod(DetachedSpecs),
262 Struct(StructDef),
263 Enum(EnumDef),
264 InherentImpl(DetachedInherentImpl),
265 TraitImpl(DetachedTraitImpl),
266 Trait(DetachedTrait),
267 Static(StaticInfo),
268}
269
270#[derive(Debug)]
271pub struct ConstantInfo {
272 pub expr: Option<Expr>,
273}
274
275#[derive(Debug)]
276pub struct StaticInfo {
277 pub ty: Ty,
278}
279
280#[derive(Debug)]
281pub struct StructDef {
282 pub generics: Option<Generics>,
283 pub refined_by: Option<RefineParams>,
284 pub fields: Vec<Option<Ty>>,
285 pub opaque: bool,
286 pub invariants: Vec<Expr>,
287}
288
289#[derive(Debug)]
290pub struct EnumDef {
291 pub generics: Option<Generics>,
292 pub refined_by: Option<RefineParams>,
293 pub variants: Vec<Option<VariantDef>>,
294 pub invariants: Vec<Expr>,
295 pub reflected: bool,
296}
297
298#[derive(Debug)]
299pub struct VariantDef {
300 pub ident: Option<Ident>,
301 pub fields: Vec<Ty>,
302 pub ret: Option<VariantRet>,
303 pub node_id: NodeId,
304 pub span: Span,
305}
306
307#[derive(Debug)]
308pub struct VariantRet {
309 pub path: Path,
310 pub indices: Indices,
313}
314
315pub type RefineParams = Vec<RefineParam>;
316
317#[derive(Debug)]
318pub struct RefineParam {
319 pub ident: Ident,
320 pub sort: Sort,
321 pub mode: Option<ParamMode>,
322 pub span: Span,
323 pub node_id: NodeId,
324}
325
326#[derive(Clone, Copy, Debug, PartialEq, Eq)]
327pub enum ParamMode {
328 Horn,
329 Hindley,
330}
331
332#[derive(Debug)]
333pub enum Sort {
334 Base(BaseSort),
336 Func { inputs: Vec<BaseSort>, output: BaseSort },
339 Infer,
341}
342
343#[derive(Debug)]
344pub enum BaseSort {
345 BitVec(u32),
347 SortOf(Box<Ty>, Path),
348 Path(SortPath),
349 Tuple(Vec<BaseSort>),
351}
352
353#[derive(Debug)]
355pub struct SortPath {
356 pub segments: Vec<Ident>,
358 pub args: Vec<BaseSort>,
360 pub node_id: NodeId,
361}
362
363impl SortPath {
364 pub fn span(&self) -> Span {
365 self.segments
366 .iter()
367 .map(|ident| ident.span)
368 .reduce(Span::to)
369 .unwrap_or_default()
370 }
371}
372
373#[derive(Debug)]
374pub struct Impl {
375 pub generics: Option<Generics>,
376 pub assoc_refinements: Vec<ImplAssocReft>,
377}
378
379#[derive(Debug)]
380pub struct ImplAssocReft {
381 pub name: Ident,
382 pub params: RefineParams,
383 pub output: BaseSort,
384 pub body: Expr,
385 pub span: Span,
386}
387
388#[derive(Debug)]
389pub struct Trait {
390 pub generics: Option<Generics>,
391 pub assoc_refinements: Vec<TraitAssocReft>,
392}
393
394#[derive(Debug)]
395pub struct TraitAssocReft {
396 pub name: Ident,
397 pub params: RefineParams,
398 pub output: BaseSort,
399 pub body: Option<Expr>,
400 pub span: Span,
401 pub final_: bool,
402}
403
404#[derive(Debug)]
405pub struct FnSig {
406 pub asyncness: Async,
407 pub ident: Option<Ident>,
408 pub generics: Generics,
409 pub params: RefineParams,
410 pub requires: Vec<Requires>,
412 pub inputs: Vec<FnInput>,
414 pub output: FnOutput,
415 pub span: Span,
417 pub node_id: NodeId,
418 pub no_panic: Option<Expr>,
419}
420
421#[derive(Debug)]
422pub struct Requires {
423 pub params: RefineParams,
425 pub pred: Expr,
426}
427
428#[derive(Debug)]
429pub struct FnOutput {
430 pub returns: FnRetTy,
432 pub ensures: Vec<Ensures>,
434 pub node_id: NodeId,
435}
436
437#[derive(Debug)]
438pub enum Ensures {
439 Type(Ident, Ty, NodeId),
441 Pred(Expr),
443}
444
445#[derive(Debug)]
446pub enum FnRetTy {
447 Default(Span),
448 Ty(Box<Ty>),
449}
450
451#[derive(Debug, Copy, Clone)]
452pub enum Async {
453 Yes { node_id: NodeId, span: Span },
454 No,
455}
456
457#[derive(Debug)]
458pub struct WhereBoundPredicate {
459 pub span: Span,
460 pub bounded_ty: Ty,
461 pub bounds: GenericBounds,
462}
463
464pub type GenericBounds = Vec<TraitRef>;
465
466#[derive(Debug)]
467pub struct TraitRef {
468 pub path: Path,
469 pub node_id: NodeId,
470}
471
472impl TraitRef {
473 fn is_fn_trait_name(name: Symbol) -> bool {
474 name == sym::FnOnce || name == sym::FnMut || name == sym::Fn
475 }
476
477 pub fn as_fn_trait_ref(&self) -> Option<(&GenericArg, &GenericArg)> {
478 if let [segment] = self.path.segments.as_slice()
479 && Self::is_fn_trait_name(segment.ident.name)
480 && let [in_arg, out_arg] = segment.args.as_slice()
481 {
482 return Some((in_arg, out_arg));
483 }
484 None
485 }
486}
487
488#[derive(Debug)]
489pub enum FnInput {
490 Constr(Ident, Path, Expr, NodeId),
492 StrgRef(Ident, Ty, NodeId),
494 Ty(Option<Ident>, Ty, NodeId),
497}
498
499#[derive(Debug)]
500pub struct Ty {
501 pub kind: TyKind,
502 pub node_id: NodeId,
503 pub span: Span,
504}
505
506#[derive(Debug)]
507pub enum TyKind {
508 Base(BaseTy),
510 Indexed {
512 bty: BaseTy,
513 indices: Indices,
514 },
515 Exists {
517 bind: Ident,
518 bty: BaseTy,
519 pred: Expr,
520 },
521 GeneralExists {
522 params: RefineParams,
523 ty: Box<Ty>,
524 pred: Option<Expr>,
525 },
526 Ref(Mutability, Box<Ty>),
528 Constr(Expr, Box<Ty>),
530 Tuple(Vec<Ty>),
531 Array(Box<Ty>, ConstArg),
532 BareFn(Box<BareFnTy>),
534 ImplTrait(NodeId, GenericBounds),
536 Hole,
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq)]
540pub enum Safety {
541 Safe,
542 Unsafe,
543}
544
545#[derive(Debug)]
546pub struct BareFnTy {
547 pub safety: Safety,
549 pub abi: Option<Ident>,
552 pub inputs: Vec<Ty>,
554 pub output: FnRetTy,
555 pub node_id: NodeId,
556 pub span: Span,
557}
558
559impl Ty {
560 pub fn is_refined(&self) -> bool {
561 struct IsRefinedVisitor {
562 is_refined: bool,
563 }
564 let mut vis = IsRefinedVisitor { is_refined: false };
565 impl visit::Visitor<'_> for IsRefinedVisitor {
566 fn visit_ty(&mut self, ty: &Ty) {
567 match &ty.kind {
568 TyKind::Tuple(_)
569 | TyKind::Ref(..)
570 | TyKind::Array(..)
571 | TyKind::BareFn(..)
572 | TyKind::ImplTrait(..)
573 | TyKind::Hole
574 | TyKind::Base(_) => {
575 visit::walk_ty(self, ty);
576 }
577 TyKind::Indexed { .. }
578 | TyKind::Exists { .. }
579 | TyKind::GeneralExists { .. }
580 | TyKind::Constr(..) => {
581 self.is_refined = true;
582 }
583 }
584 }
585 }
586 vis.visit_ty(self);
587 vis.is_refined
588 }
589
590 pub fn is_potential_const_arg(&self) -> Option<&Path> {
591 if let TyKind::Base(bty) = &self.kind
592 && let BaseTyKind::Path(None, path) = &bty.kind
593 && let [segment] = &path.segments[..]
594 && segment.args.is_empty()
595 {
596 Some(path)
597 } else {
598 None
599 }
600 }
601}
602#[derive(Debug)]
603pub struct BaseTy {
604 pub kind: BaseTyKind,
605 pub span: Span,
606}
607
608#[derive(Debug)]
609pub enum BaseTyKind {
610 Path(Option<Box<Ty>>, Path),
611 Slice(Box<Ty>),
612 Ptr(Mutability, Box<Ty>),
614}
615
616#[derive(Debug)]
617pub struct ConstArg {
618 pub kind: ConstArgKind,
619 pub span: Span,
620}
621
622#[derive(Debug)]
623pub enum ConstArgKind {
624 Lit(usize),
625 Path(Path),
626 Infer,
627}
628
629#[derive(Debug)]
630pub struct Indices {
631 pub indices: Vec<RefineArg>,
632 pub span: Span,
633}
634
635#[derive(Debug)]
636pub enum RefineArg {
637 Bind(Ident, BindKind, Span, NodeId),
639 Expr(Expr),
640 Abs(RefineParams, Expr, Span, NodeId),
641}
642
643#[derive(Debug, Clone, Copy)]
644pub enum BindKind {
645 At,
646 Pound,
647}
648
649#[derive(Debug, Eq, PartialEq, Copy, Clone)]
651pub enum Trusted {
652 Yes,
653 No,
654}
655
656impl Trusted {
657 pub fn to_bool(self) -> bool {
658 match self {
659 Trusted::Yes => true,
660 Trusted::No => false,
661 }
662 }
663}
664
665impl From<bool> for Trusted {
666 fn from(value: bool) -> Self {
667 if value { Trusted::Yes } else { Trusted::No }
668 }
669}
670
671#[derive(Debug, Eq, PartialEq, Copy, Clone)]
673pub enum Ignored {
674 Yes,
675 No,
676}
677
678impl Ignored {
679 pub fn to_bool(self) -> bool {
680 match self {
681 Ignored::Yes => true,
682 Ignored::No => false,
683 }
684 }
685}
686
687impl From<bool> for Ignored {
688 fn from(value: bool) -> Self {
689 if value { Ignored::Yes } else { Ignored::No }
690 }
691}
692
693#[derive(Debug)]
702pub enum Attr {
703 Trusted(Trusted),
705 TrustedImpl(Trusted),
707 TrustedDerive(Trusted),
709 Ignore(Ignored),
711 ProvenExternally(Span),
713 ShouldFail,
715 Qualifiers(Vec<Ident>),
717 Reveal(Vec<Ident>),
719 Hide(Vec<Ident>),
721 InferOpts(PartialInferOpts),
723 NoPanic,
725 AssumeParametric(Vec<Ident>),
727 NoSuggestions,
729}
730
731#[derive(Debug)]
732pub struct Path {
733 pub segments: Vec<PathSegment>,
734 pub refine: Vec<RefineArg>,
735 pub node_id: NodeId,
736 pub span: Span,
737}
738
739impl Path {
740 pub fn last(&self) -> &PathSegment {
741 self.segments
742 .last()
743 .expect("path must have at least one segment")
744 }
745}
746
747#[derive(Debug)]
748pub struct PathSegment {
749 pub ident: Ident,
750 pub args: Vec<GenericArg>,
751 pub node_id: NodeId,
752}
753
754#[derive(Debug)]
755pub struct GenericArg {
756 pub kind: GenericArgKind,
757 pub node_id: NodeId,
758}
759
760#[derive(Debug)]
761pub enum GenericArgKind {
762 Type(Ty),
763 Constraint(Ident, Ty),
764}
765
766#[derive(Debug)]
767pub struct FieldExpr {
768 pub ident: Ident,
769 pub expr: RefineArg,
770 pub span: Span,
771 pub node_id: NodeId,
772}
773
774#[derive(Debug)]
775pub struct Spread {
776 pub expr: Expr,
777 pub span: Span,
778 pub node_id: NodeId,
779}
780
781#[derive(Debug)]
782pub enum ConstructorArg {
783 FieldExpr(FieldExpr),
784 Spread(Spread),
785}
786
787#[derive(Debug)]
788pub struct Expr {
789 pub kind: ExprKind,
790 pub node_id: NodeId,
791 pub span: Span,
792}
793
794#[derive(Debug)]
795pub enum QuantKind {
796 Forall,
797 Exists,
798}
799
800#[derive(Debug)]
801pub enum ExprKind {
802 Path(ExprPath),
803 Dot(Box<Expr>, Ident),
804 Literal(Lit),
805 BinaryOp(BinOp, Box<[Expr; 2]>),
806 UnaryOp(UnOp, Box<Expr>),
807 Call(Box<Expr>, Vec<Expr>),
808 PrimUIF(BinOp),
810 AssocReft(Box<Ty>, Path, Ident),
812 IfThenElse(Box<[Expr; 3]>),
813 Constructor(Option<ExprPath>, Vec<ConstructorArg>),
814 Quant(QuantKind, RefineParam, Option<Range<usize>>, Box<Expr>),
815 Block(Vec<LetDecl>, Box<Expr>),
816 SetLiteral(Vec<Expr>),
818 Tuple(Vec<Expr>),
820}
821
822#[derive(Debug)]
823pub struct LetDecl {
824 pub param: RefineParam,
825 pub init: Expr,
826}
827
828#[derive(Debug, Clone)]
830pub struct ExprPath {
831 pub segments: Vec<ExprPathSegment>,
832 pub node_id: NodeId,
833 pub span: Span,
834}
835
836#[derive(Debug, Clone)]
837pub struct ExprPathSegment {
838 pub ident: Ident,
839 pub node_id: NodeId,
840}
841#[derive(Copy, Clone, Hash, Eq, PartialEq)]
842pub enum BinOp {
843 Iff,
844 Imp,
845 Or,
846 And,
847 Eq,
848 Ne,
849 Gt,
850 Ge,
851 Lt,
852 Le,
853 Add,
854 Sub,
855 Mul,
856 Div,
857 Mod,
858 BitOr,
859 BitXor,
860 BitAnd,
861 BitShl,
862 BitShr,
863}
864
865impl fmt::Debug for BinOp {
866 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
867 match self {
868 BinOp::Iff => write!(f, "<=>"),
869 BinOp::Imp => write!(f, "=>"),
870 BinOp::Or => write!(f, "||"),
871 BinOp::And => write!(f, "&&"),
872 BinOp::Eq => write!(f, "=="),
873 BinOp::Ne => write!(f, "!="),
874 BinOp::Lt => write!(f, "<"),
875 BinOp::Le => write!(f, "<="),
876 BinOp::Gt => write!(f, ">"),
877 BinOp::Ge => write!(f, ">="),
878 BinOp::Add => write!(f, "+"),
879 BinOp::Sub => write!(f, "-"),
880 BinOp::Mod => write!(f, "mod"),
881 BinOp::Mul => write!(f, "*"),
882 BinOp::Div => write!(f, "/"),
883 BinOp::BitOr => write!(f, "|"),
884 BinOp::BitXor => write!(f, "^"),
885 BinOp::BitAnd => write!(f, "&"),
886 BinOp::BitShl => write!(f, "<<"),
887 BinOp::BitShr => write!(f, ">>"),
888 }
889 }
890}
891
892impl rustc_errors::IntoDiagArg for BinOp {
893 fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
894 rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
895 }
896}
897
898#[derive(Copy, Clone)]
899pub enum UnOp {
900 Not,
901 Neg,
902}
903
904impl fmt::Debug for UnOp {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 match self {
907 Self::Not => write!(f, "!"),
908 Self::Neg => write!(f, "-"),
909 }
910 }
911}
912
913impl BindKind {
914 pub fn token_str(&self) -> &'static str {
915 match self {
916 BindKind::At => "@",
917 BindKind::Pound => "#",
918 }
919 }
920}
921
922pub struct Punctuated<T, P> {
924 inner: Vec<(T, P)>,
925 last: Option<Box<T>>,
926}
927
928impl<T, P> From<Vec<(T, P)>> for Punctuated<T, P> {
929 fn from(inner: Vec<(T, P)>) -> Self {
930 Self { inner, last: None }
931 }
932}
933
934impl<T, P> Punctuated<T, P> {
935 pub fn len(&self) -> usize {
936 self.inner.len() + self.last.is_some() as usize
937 }
938
939 pub fn is_empty(&self) -> bool {
942 self.inner.len() == 0 && self.last.is_none()
943 }
944
945 pub fn push_value(&mut self, value: T) {
953 assert!(
954 self.empty_or_trailing(),
955 "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
956 );
957
958 self.last = Some(Box::new(value));
959 }
960
961 pub fn empty_or_trailing(&self) -> bool {
966 self.last.is_none()
967 }
968
969 pub fn trailing_punct(&self) -> bool {
972 self.last.is_none() && !self.is_empty()
973 }
974
975 pub fn into_values(self) -> Vec<T> {
976 let mut v: Vec<T> = self.inner.into_iter().map(|(v, _)| v).collect();
977 if let Some(last) = self.last {
978 v.push(*last);
979 }
980 v
981 }
982}
983
984impl Expr {
985 pub fn free_vars(&self) -> FxIndexSet<Ident> {
990 struct FreeVarsVisitor {
991 vars: FxIndexSet<Ident>,
992 }
993
994 impl visit::Visitor<'_> for FreeVarsVisitor {
995 fn visit_expr(&mut self, expr: &Expr) {
996 match &expr.kind {
997 ExprKind::Path(path) => {
998 if let [segment] = path.segments.as_slice() {
1000 self.vars.insert(segment.ident);
1001 }
1002 }
1003 ExprKind::Call(callee, args) => {
1004 if !matches!(&callee.kind, ExprKind::Path(_)) {
1008 self.visit_expr(callee);
1009 }
1010 for arg in args {
1011 self.visit_expr(arg);
1012 }
1013 }
1014 _ => visit::walk_expr(self, expr),
1016 }
1017 }
1018 }
1019
1020 let mut visitor = FreeVarsVisitor { vars: FxIndexSet::default() };
1021 visitor.visit_expr(self);
1022 visitor.vars
1023 }
1024}