Skip to main content

flux_desugar/resolver/
refinement_resolver.rs

1use std::ops::ControlFlow;
2
3use flux_common::index::IndexGen;
4use flux_errors::Errors;
5use flux_middle::{
6    ResolverOutput,
7    fhir::{
8        self,
9        Namespace::{ReftNS, TypeNS, ValueNS},
10        PartialRes, Res,
11    },
12};
13use flux_syntax::{
14    surface::{self, FluxItem, Ident, NodeId, visit::Visitor as _},
15    walk_list,
16};
17use rustc_data_structures::{fx::FxIndexMap, unord::UnordMap};
18use rustc_hash::FxHashMap;
19use rustc_middle::ty::TyCtxt;
20use rustc_span::{ErrorGuaranteed, Span};
21
22use super::{BindingSource, CrateResolver, ResolveError, RibKind, Segment};
23
24type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
25
26pub(crate) trait ScopedVisitor: Sized {
27    fn is_box(&self, segment: &surface::PathSegment) -> bool;
28    fn enter_scope(&mut self, kind: RibKind) -> ControlFlow<()>;
29    fn exit_scope(&mut self) {}
30
31    fn wrap(self) -> ScopedVisitorWrapper<Self> {
32        ScopedVisitorWrapper(self)
33    }
34
35    fn on_implicit_param(&mut self, _ident: Ident, _kind: fhir::ParamKind, _node_id: NodeId) {}
36    fn on_generic_param(&mut self, _param: &surface::GenericParam) {}
37    fn on_refine_param(&mut self, _param: &surface::RefineParam) {}
38    fn on_enum_variant(&mut self, _variant: &surface::VariantDef) {}
39    fn on_fn_trait_input(&mut self, _in_arg: &surface::GenericArg, _node_id: NodeId) {}
40    fn on_fn_sig(&mut self, _fn_sig: &surface::FnSig) {}
41    fn on_fn_output(&mut self, _output: &surface::FnOutput) {}
42    fn on_loc(&mut self, _loc: Ident, _node_id: NodeId) {}
43    fn on_path(&mut self, _path: &surface::ExprPath) {}
44    fn on_base_sort(&mut self, _sort: &surface::BaseSort) {}
45}
46
47pub(crate) struct ScopedVisitorWrapper<V>(V);
48
49impl<V: ScopedVisitor> ScopedVisitorWrapper<V> {
50    fn with_scope(&mut self, kind: RibKind, f: impl FnOnce(&mut Self)) {
51        let scope = self.0.enter_scope(kind);
52        if let ControlFlow::Continue(_) = scope {
53            f(self);
54            self.0.exit_scope();
55        }
56    }
57}
58
59impl<V> std::ops::Deref for ScopedVisitorWrapper<V> {
60    type Target = V;
61
62    fn deref(&self) -> &Self::Target {
63        &self.0
64    }
65}
66impl<V> std::ops::DerefMut for ScopedVisitorWrapper<V> {
67    fn deref_mut(&mut self) -> &mut Self::Target {
68        &mut self.0
69    }
70}
71
72impl<V: ScopedVisitor> surface::visit::Visitor for ScopedVisitorWrapper<V> {
73    fn visit_trait_assoc_reft(&mut self, assoc_reft: &surface::TraitAssocReft) {
74        self.with_scope(RibKind::Misc, |this| {
75            surface::visit::walk_trait_assoc_reft(this, assoc_reft);
76        });
77    }
78
79    fn visit_impl_assoc_reft(&mut self, assoc_reft: &surface::ImplAssocReft) {
80        self.with_scope(RibKind::Misc, |this| {
81            surface::visit::walk_impl_assoc_reft(this, assoc_reft);
82        });
83    }
84
85    fn visit_qualifier(&mut self, qualifier: &surface::Qualifier) {
86        self.with_scope(RibKind::Misc, |this| {
87            surface::visit::walk_qualifier(this, qualifier);
88        });
89    }
90
91    fn visit_defn(&mut self, defn: &surface::SpecFunc) {
92        self.with_scope(RibKind::Misc, |this| {
93            surface::visit::walk_defn(this, defn);
94        });
95    }
96
97    fn visit_primop_prop(&mut self, prop: &surface::PrimOpProp) {
98        self.with_scope(RibKind::Misc, |this| {
99            surface::visit::walk_primop_prop(this, prop);
100        });
101    }
102
103    fn visit_generic_param(&mut self, param: &surface::GenericParam) {
104        self.on_generic_param(param);
105        surface::visit::walk_generic_param(self, param);
106    }
107
108    fn visit_refine_param(&mut self, param: &surface::RefineParam) {
109        self.on_refine_param(param);
110        surface::visit::walk_refine_param(self, param);
111    }
112
113    fn visit_ty_alias(&mut self, ty_alias: &surface::TyAlias) {
114        self.with_scope(RibKind::Misc, |this| {
115            surface::visit::walk_ty_alias(this, ty_alias);
116        });
117    }
118
119    fn visit_struct_def(&mut self, struct_def: &surface::StructDef) {
120        self.with_scope(RibKind::Misc, |this| {
121            surface::visit::walk_struct_def(this, struct_def);
122        });
123    }
124
125    fn visit_enum_def(&mut self, enum_def: &surface::EnumDef) {
126        self.with_scope(RibKind::Misc, |this| {
127            surface::visit::walk_enum_def(this, enum_def);
128        });
129    }
130
131    fn visit_variant(&mut self, variant: &surface::VariantDef) {
132        self.with_scope(RibKind::Variant, |this| {
133            this.on_enum_variant(variant);
134            surface::visit::walk_variant(this, variant);
135        });
136    }
137
138    fn visit_trait_ref(&mut self, trait_ref: &surface::TraitRef) {
139        match trait_ref.as_fn_trait_ref() {
140            Some((in_arg, out_arg)) => {
141                self.with_scope(RibKind::FnTraitInput, |this| {
142                    this.on_fn_trait_input(in_arg, trait_ref.node_id);
143                    surface::visit::walk_generic_arg(this, in_arg);
144                    this.with_scope(RibKind::Misc, |this| {
145                        surface::visit::walk_generic_arg(this, out_arg);
146                    });
147                });
148            }
149            None => {
150                self.with_scope(RibKind::Misc, |this| {
151                    surface::visit::walk_trait_ref(this, trait_ref);
152                });
153            }
154        }
155    }
156
157    fn visit_variant_ret(&mut self, ret: &surface::VariantRet) {
158        self.with_scope(RibKind::Misc, |this| {
159            surface::visit::walk_variant_ret(this, ret);
160        });
161    }
162
163    fn visit_generics(&mut self, generics: &surface::Generics) {
164        self.with_scope(RibKind::Misc, |this| {
165            surface::visit::walk_generics(this, generics);
166        });
167    }
168
169    fn visit_fn_sig(&mut self, fn_sig: &surface::FnSig) {
170        self.with_scope(RibKind::FnInput, |this| {
171            this.on_fn_sig(fn_sig);
172            surface::visit::walk_fn_sig(this, fn_sig);
173        });
174    }
175
176    fn visit_fn_output(&mut self, output: &surface::FnOutput) {
177        self.with_scope(RibKind::FnOutput, |this| {
178            this.on_fn_output(output);
179            surface::visit::walk_fn_output(this, output);
180        });
181    }
182
183    fn visit_fn_input(&mut self, arg: &surface::FnInput) {
184        match arg {
185            surface::FnInput::Constr(bind, _, _, node_id) => {
186                self.on_implicit_param(*bind, fhir::ParamKind::Colon, *node_id);
187            }
188            surface::FnInput::StrgRef(loc, _, node_id) => {
189                self.on_implicit_param(*loc, fhir::ParamKind::Loc, *node_id);
190            }
191            surface::FnInput::Ty(bind, ty, node_id) => {
192                if let &Some(bind) = bind {
193                    let param_kind = if let surface::TyKind::Base(_) = &ty.kind {
194                        fhir::ParamKind::Colon
195                    } else {
196                        fhir::ParamKind::Error
197                    };
198                    self.on_implicit_param(bind, param_kind, *node_id);
199                }
200            }
201        }
202        surface::visit::walk_fn_input(self, arg);
203    }
204
205    fn visit_ensures(&mut self, constraint: &surface::Ensures) {
206        if let surface::Ensures::Type(loc, _, node_id) = constraint {
207            self.on_loc(*loc, *node_id);
208        }
209        surface::visit::walk_ensures(self, constraint);
210    }
211
212    fn visit_refine_arg(&mut self, arg: &surface::RefineArg) {
213        match arg {
214            surface::RefineArg::Bind(ident, kind, _, node_id) => {
215                let kind = match kind {
216                    surface::BindKind::At => fhir::ParamKind::At,
217                    surface::BindKind::Pound => fhir::ParamKind::Pound,
218                };
219                self.on_implicit_param(*ident, kind, *node_id);
220            }
221            surface::RefineArg::Abs(..) => {
222                self.with_scope(RibKind::Misc, |this| {
223                    surface::visit::walk_refine_arg(this, arg);
224                });
225            }
226            surface::RefineArg::Expr(expr) => self.visit_expr(expr),
227        }
228    }
229
230    fn visit_path(&mut self, path: &surface::Path) {
231        for arg in &path.refine {
232            self.with_scope(RibKind::Misc, |this| this.visit_refine_arg(arg));
233        }
234        walk_list!(self, visit_path_segment, &path.segments);
235    }
236
237    fn visit_path_segment(&mut self, segment: &surface::PathSegment) {
238        let is_box = self.is_box(segment);
239        for (i, arg) in segment.args.iter().enumerate() {
240            if is_box && i == 0 {
241                self.visit_generic_arg(arg);
242            } else {
243                self.with_scope(RibKind::Misc, |this| this.visit_generic_arg(arg));
244            }
245        }
246    }
247
248    fn visit_ty(&mut self, ty: &surface::Ty) {
249        let node_id = ty.node_id;
250        match &ty.kind {
251            surface::TyKind::Exists { bind, .. } => {
252                self.with_scope(RibKind::Misc, |this| {
253                    let param = surface::RefineParam {
254                        ident: *bind,
255                        mode: None,
256                        sort: surface::Sort::Infer,
257                        node_id,
258                        span: bind.span,
259                    };
260                    this.on_refine_param(&param);
261                    surface::visit::walk_ty(this, ty);
262                });
263            }
264            surface::TyKind::GeneralExists { .. } => {
265                self.with_scope(RibKind::Misc, |this| {
266                    surface::visit::walk_ty(this, ty);
267                });
268            }
269            surface::TyKind::Array(..) => {
270                self.with_scope(RibKind::Misc, |this| {
271                    surface::visit::walk_ty(this, ty);
272                });
273            }
274            _ => surface::visit::walk_ty(self, ty),
275        }
276    }
277
278    fn visit_bty(&mut self, bty: &surface::BaseTy) {
279        match &bty.kind {
280            surface::BaseTyKind::Slice(_) | surface::BaseTyKind::Ptr(..) => {
281                self.with_scope(RibKind::Misc, |this| {
282                    surface::visit::walk_bty(this, bty);
283                });
284            }
285            surface::BaseTyKind::Path(..) => {
286                surface::visit::walk_bty(self, bty);
287            }
288        }
289    }
290
291    fn visit_path_expr(&mut self, path: &surface::ExprPath) {
292        self.on_path(path);
293    }
294
295    fn visit_base_sort(&mut self, bsort: &surface::BaseSort) {
296        self.on_base_sort(bsort);
297        surface::visit::walk_base_sort(self, bsort);
298    }
299}
300
301struct ImplicitParamCollector<'a, 'tcx> {
302    tcx: TyCtxt<'tcx>,
303    path_res_map: &'a UnordMap<surface::NodeId, fhir::PartialRes<NodeId>>,
304    kind: RibKind,
305    params: Vec<(Ident, fhir::ParamKind, NodeId)>,
306}
307
308impl<'a, 'tcx> ImplicitParamCollector<'a, 'tcx> {
309    fn new(
310        tcx: TyCtxt<'tcx>,
311        path_res_map: &'a UnordMap<surface::NodeId, fhir::PartialRes<NodeId>>,
312        kind: RibKind,
313    ) -> Self {
314        Self { tcx, path_res_map, kind, params: vec![] }
315    }
316
317    fn run(
318        self,
319        f: impl FnOnce(&mut ScopedVisitorWrapper<Self>),
320    ) -> Vec<(Ident, fhir::ParamKind, NodeId)> {
321        let mut wrapped = self.wrap();
322        f(&mut wrapped);
323        wrapped.0.params
324    }
325}
326
327impl ScopedVisitor for ImplicitParamCollector<'_, '_> {
328    fn is_box(&self, segment: &surface::PathSegment) -> bool {
329        self.path_res_map
330            .get(&segment.node_id)
331            .map(|r| r.is_box(self.tcx))
332            .unwrap_or(false)
333    }
334
335    fn enter_scope(&mut self, kind: RibKind) -> ControlFlow<()> {
336        if self.kind == kind { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
337    }
338
339    fn on_implicit_param(&mut self, ident: Ident, param: fhir::ParamKind, node_id: NodeId) {
340        self.params.push((ident, param, node_id));
341    }
342}
343
344#[derive(Clone, Copy)]
345struct ParamDef {
346    ident: Ident,
347    kind: fhir::ParamKind,
348    scope: Option<NodeId>,
349}
350
351pub(crate) struct RefinementResolver<'a, 'genv, 'tcx> {
352    param_defs: FxIndexMap<NodeId, ParamDef>,
353    resolver: &'a mut CrateResolver<'genv, 'tcx>,
354    path_res_map: FxHashMap<NodeId, PartialRes<NodeId>>,
355    errors: Errors<'genv>,
356}
357
358impl<'a, 'genv, 'tcx> RefinementResolver<'a, 'genv, 'tcx> {
359    pub(crate) fn resolve_flux_item(
360        resolver: &'a mut CrateResolver<'genv, 'tcx>,
361        item: &FluxItem,
362    ) -> Result {
363        let sort_vars = match item {
364            FluxItem::FuncDef(defn) => &defn.sort_vars[..],
365            FluxItem::SortDecl(sort_decl) => &sort_decl.sort_vars[..],
366            FluxItem::Qualifier(_) | FluxItem::PrimOpProp(_) => &[],
367            FluxItem::Use(_) => {
368                // Use paths are resolved `CrateResolver::resolve_use_path`
369                return Ok(());
370            }
371        };
372        Self::new(resolver).run(sort_vars, |r| r.visit_flux_item(item))
373    }
374
375    pub(crate) fn resolve_item(
376        resolver: &'a mut CrateResolver<'genv, 'tcx>,
377        item: &surface::Item,
378    ) -> Result {
379        IllegalBinderVisitor::new(resolver).run(|vis| vis.visit_item(item))?;
380        Self::new(resolver).run(&[], |vis| vis.visit_item(item))
381    }
382
383    pub(crate) fn resolve_trait_item(
384        resolver: &'a mut CrateResolver<'genv, 'tcx>,
385        item: &surface::TraitItemFn,
386    ) -> Result {
387        IllegalBinderVisitor::new(resolver).run(|vis| vis.visit_trait_item(item))?;
388        Self::new(resolver).run(&[], |vis| vis.visit_trait_item(item))
389    }
390
391    pub(crate) fn resolve_impl_item(
392        resolver: &'a mut CrateResolver<'genv, 'tcx>,
393        item: &surface::ImplItemFn,
394    ) -> Result {
395        IllegalBinderVisitor::new(resolver).run(|vis| vis.visit_impl_item(item))?;
396        Self::new(resolver).run(&[], |vis| vis.visit_impl_item(item))
397    }
398
399    fn new(resolver: &'a mut CrateResolver<'genv, 'tcx>) -> Self {
400        let errors = Errors::new(resolver.genv.sess());
401        Self { resolver, param_defs: Default::default(), path_res_map: Default::default(), errors }
402    }
403
404    fn run(self, sort_vars: &[Ident], f: impl FnOnce(&mut ScopedVisitorWrapper<Self>)) -> Result {
405        // Sort variables share the type namespace with sorts/types (see [`fhir::Namespace`]).
406        self.resolver.push_rib(TypeNS, RibKind::Misc);
407        for (idx, ident) in sort_vars.iter().enumerate() {
408            self.resolver.define_res_in(
409                Res::SortParam(idx),
410                TypeNS,
411                BindingSource::Explicit(*ident),
412            );
413        }
414        let mut wrapper = self.wrap();
415        f(&mut wrapper);
416        wrapper.resolver.pop_rib(TypeNS);
417
418        wrapper.0.finish()
419    }
420
421    fn define_param(
422        &mut self,
423        ident: Ident,
424        kind: fhir::ParamKind,
425        param_id: NodeId,
426        scope: Option<NodeId>,
427    ) {
428        self.param_defs
429            .insert(param_id, ParamDef { ident, kind, scope });
430
431        self.resolver.define_res_in(
432            Res::Param(kind, param_id),
433            ReftNS,
434            BindingSource::Explicit(ident),
435        );
436    }
437
438    fn emit_ambiguity_err(&mut self, ambiguity: super::Ambiguity) {
439        self.errors
440            .emit(super::errors::AmbiguousName::new(ambiguity));
441    }
442
443    fn resolve_path(&mut self, path: &surface::ExprPath) {
444        match self.try_resolve_expr_with_ribs(&path.segments) {
445            Ok(res) => {
446                self.check_unrefined_param(res, path.segments.last().unwrap().ident);
447                self.path_res_map.insert(path.node_id, res);
448            }
449            Err(ResolveError::Ambiguous(ambiguity)) => self.emit_ambiguity_err(ambiguity),
450            Err(ResolveError::NotFound) => self.emit_unresolved_expr_path(path),
451        }
452    }
453
454    fn resolve_ident(&mut self, ident: Ident, node_id: NodeId) {
455        match self.try_resolve_expr_with_ribs(&[ident]) {
456            Ok(res) => {
457                self.check_unrefined_param(res, ident);
458                self.path_res_map.insert(node_id, res);
459            }
460            Err(ResolveError::Ambiguous(ambiguity)) => self.emit_ambiguity_err(ambiguity),
461            Err(ResolveError::NotFound) => self.emit_unresolved_ident(ident),
462        }
463    }
464
465    /// Emit an error if `res` resolved to a param that cannot be refined.
466    /// e.g., `fn(x: &mut i32) -> i32[x]`
467    fn check_unrefined_param(&mut self, res: PartialRes<NodeId>, ident: Ident) {
468        if let Some(Res::Param(fhir::ParamKind::Error, _)) = res.full_res() {
469            self.errors.emit(errors::InvalidUnrefinedParam::new(ident));
470        }
471    }
472
473    fn try_resolve_expr_with_ribs<S: Segment>(
474        &mut self,
475        segments: &[S],
476    ) -> std::result::Result<PartialRes<NodeId>, ResolveError> {
477        // Try the refinement namespace first so that refinement params (and then flux funcs) take
478        // precedence over Rust value/type bindings — in particular, a param shadows a Rust const of
479        // the same name.
480        //
481        // An ambiguity in one namespace doesn't stop us from trying the next: a later namespace
482        // may still resolve the name unambiguously, exactly as it would shadow it. But if nothing
483        // resolves anywhere, we report the ambiguity rather than "unresolved name", which would
484        // point the user at the wrong problem.
485        let mut ambiguity = None;
486        for ns in [ReftNS, ValueNS, TypeNS] {
487            match self.resolver.resolve_path_with_ribs(segments, ns) {
488                Ok(partial_res) => return Ok(partial_res),
489                Err(ResolveError::Ambiguous(amb)) => ambiguity = ambiguity.or(Some(amb)),
490                Err(ResolveError::NotFound) => {}
491            }
492        }
493        Err(ambiguity.map_or(ResolveError::NotFound, ResolveError::Ambiguous))
494    }
495
496    fn resolve_sort_path(&mut self, path: &surface::SortPath) {
497        // Sorts resolve in the type namespace: primitive/user sorts and sort parameters live there
498        // alongside types, and any type can also denote a sort. We only report a *name* that fails
499        // to resolve here; whether the resolved item is admissible as a sort (and the corresponding
500        // diagnostic) is decided later in `conv_sort_path`.
501        let res = match self.resolver.resolve_path_with_ribs(&path.segments, TypeNS) {
502            Ok(res) => res,
503            Err(ResolveError::NotFound) => {
504                self.emit_unresolved_sort_path(path);
505                PartialRes::new(fhir::Res::Err)
506            }
507            Err(ResolveError::Ambiguous(ambiguity)) => {
508                self.emit_ambiguity_err(ambiguity);
509                PartialRes::new(fhir::Res::Err)
510            }
511        };
512        self.resolver.output.path_res_map.insert(path.node_id, res);
513    }
514
515    pub(crate) fn finish(self) -> Result {
516        let param_id_gen = IndexGen::new();
517        let mut params = FxIndexMap::default();
518
519        // Create an `fhir::ParamId` for all parameters used in a path before iterating over
520        // `param_defs` such that we can skip `fhir::ParamKind::Colon` if the param wasn't used
521        for (node_id, res) in self.path_res_map {
522            self.resolver.output.path_res_map.insert(node_id, res);
523            if let Res::Param(_, param_id) = res.base_res() {
524                params
525                    .entry(param_id)
526                    .or_insert_with(|| param_id_gen.fresh());
527            }
528        }
529
530        // At this point, the `params` map contains all parameters that were used in an expression,
531        // so we can safely skip `ParamKind::Colon` if there's no entry for it.
532        for (node_id, param_def) in self.param_defs {
533            let param_id = match param_def.kind {
534                fhir::ParamKind::Colon => {
535                    let Some(param_id) = params.get(&node_id) else { continue };
536                    *param_id
537                }
538                fhir::ParamKind::Error => continue,
539                _ => {
540                    params
541                        .get(&node_id)
542                        .copied()
543                        .unwrap_or_else(|| param_id_gen.fresh())
544                }
545            };
546            let output = &mut self.resolver.output;
547            output
548                .param_res_map
549                .insert(node_id, (param_id, param_def.kind));
550
551            if let Some(scope) = param_def.scope {
552                output
553                    .implicit_params
554                    .entry(scope)
555                    .or_default()
556                    .push((param_def.ident, node_id));
557            }
558        }
559        self.errors.to_result()
560    }
561
562    fn resolver_output(&self) -> &ResolverOutput {
563        &self.resolver.output
564    }
565
566    fn emit_unresolved_ident(&mut self, ident: Ident) {
567        self.errors.emit(super::errors::UnresolvedName {
568            span: ident.span,
569            name: ident.to_string(),
570            kind: "value",
571        });
572    }
573
574    fn emit_unresolved_expr_path(&mut self, path: &surface::ExprPath) {
575        self.errors.emit(super::errors::UnresolvedName {
576            span: path.span,
577            name: Segment::format_iter(&path.segments),
578            kind: "value",
579        });
580    }
581
582    fn emit_unresolved_sort_path(&mut self, path: &surface::SortPath) {
583        self.errors.emit(super::errors::UnresolvedName {
584            span: path
585                .segments
586                .iter()
587                .map(|ident| ident.span)
588                .reduce(Span::to)
589                .unwrap_or_default(),
590            name: Segment::format_iter(&path.segments),
591            kind: "sort",
592        });
593    }
594}
595
596impl ScopedVisitor for RefinementResolver<'_, '_, '_> {
597    fn is_box(&self, segment: &surface::PathSegment) -> bool {
598        self.resolver_output()
599            .path_res_map
600            .get(&segment.node_id)
601            .map(|r| r.is_box(self.resolver.genv.tcx()))
602            .unwrap_or(false)
603    }
604
605    fn enter_scope(&mut self, kind: RibKind) -> ControlFlow<()> {
606        self.resolver.push_rib(ReftNS, kind);
607        ControlFlow::Continue(())
608    }
609
610    fn exit_scope(&mut self) {
611        self.resolver.pop_rib(ReftNS);
612    }
613
614    fn on_fn_trait_input(&mut self, in_arg: &surface::GenericArg, trait_node_id: NodeId) {
615        let params = ImplicitParamCollector::new(
616            self.resolver.genv.tcx(),
617            &self.resolver.output.path_res_map,
618            RibKind::FnTraitInput,
619        )
620        .run(|vis| vis.visit_generic_arg(in_arg));
621        for (ident, kind, node_id) in params {
622            self.define_param(ident, kind, node_id, Some(trait_node_id));
623        }
624    }
625
626    fn on_enum_variant(&mut self, variant: &surface::VariantDef) {
627        let params = ImplicitParamCollector::new(
628            self.resolver.genv.tcx(),
629            &self.resolver.output.path_res_map,
630            RibKind::Variant,
631        )
632        .run(|vis| vis.visit_variant(variant));
633        for (ident, kind, node_id) in params {
634            self.define_param(ident, kind, node_id, Some(variant.node_id));
635        }
636    }
637
638    fn on_fn_sig(&mut self, fn_sig: &surface::FnSig) {
639        let params = ImplicitParamCollector::new(
640            self.resolver.genv.tcx(),
641            &self.resolver.output.path_res_map,
642            RibKind::FnInput,
643        )
644        .run(|vis| vis.visit_fn_sig(fn_sig));
645        for (ident, kind, param_id) in params {
646            self.define_param(ident, kind, param_id, Some(fn_sig.node_id));
647        }
648    }
649
650    fn on_fn_output(&mut self, output: &surface::FnOutput) {
651        let params = ImplicitParamCollector::new(
652            self.resolver.genv.tcx(),
653            &self.resolver.output.path_res_map,
654            RibKind::FnOutput,
655        )
656        .run(|vis| vis.visit_fn_output(output));
657        for (ident, kind, param_id) in params {
658            self.define_param(ident, kind, param_id, Some(output.node_id));
659        }
660    }
661
662    fn on_refine_param(&mut self, param: &surface::RefineParam) {
663        self.define_param(
664            param.ident,
665            fhir::ParamKind::Explicit(param.mode.map(Into::into)),
666            param.node_id,
667            None,
668        );
669    }
670
671    fn on_loc(&mut self, loc: Ident, node_id: NodeId) {
672        self.resolve_ident(loc, node_id);
673    }
674
675    fn on_path(&mut self, path: &surface::ExprPath) {
676        self.resolve_path(path);
677    }
678
679    fn on_base_sort(&mut self, sort: &surface::BaseSort) {
680        match sort {
681            surface::BaseSort::Path(path) => {
682                self.resolve_sort_path(path);
683            }
684            surface::BaseSort::BitVec(_) => {}
685            surface::BaseSort::SortOf(..) => {}
686            surface::BaseSort::Tuple(sorts) => {
687                for sort in sorts {
688                    self.on_base_sort(sort);
689                }
690            }
691        }
692    }
693}
694
695struct IllegalBinderVisitor<'a, 'genv, 'tcx> {
696    scopes: Vec<RibKind>,
697    resolver: &'a CrateResolver<'genv, 'tcx>,
698    errors: Errors<'genv>,
699}
700
701impl<'a, 'genv, 'tcx> IllegalBinderVisitor<'a, 'genv, 'tcx> {
702    fn new(resolver: &'a mut CrateResolver<'genv, 'tcx>) -> Self {
703        let errors = Errors::new(resolver.genv.sess());
704        Self { scopes: vec![], resolver, errors }
705    }
706
707    fn run(self, f: impl FnOnce(&mut ScopedVisitorWrapper<Self>)) -> Result {
708        let mut vis = self.wrap();
709        f(&mut vis);
710        vis.0.errors.to_result()
711    }
712}
713
714impl ScopedVisitor for IllegalBinderVisitor<'_, '_, '_> {
715    fn is_box(&self, segment: &surface::PathSegment) -> bool {
716        self.resolver
717            .output
718            .path_res_map
719            .get(&segment.node_id)
720            .map(|r| r.is_box(self.resolver.genv.tcx()))
721            .unwrap_or(false)
722    }
723
724    fn enter_scope(&mut self, kind: RibKind) -> ControlFlow<()> {
725        self.scopes.push(kind);
726        ControlFlow::Continue(())
727    }
728
729    fn exit_scope(&mut self) {
730        self.scopes.pop();
731    }
732
733    fn on_implicit_param(&mut self, ident: Ident, param_kind: fhir::ParamKind, _: NodeId) {
734        let Some(scope_kind) = self.scopes.last() else { return };
735        let (allowed, bind_kind) = match param_kind {
736            fhir::ParamKind::At => {
737                (
738                    matches!(
739                        scope_kind,
740                        RibKind::FnInput | RibKind::FnTraitInput | RibKind::Variant
741                    ),
742                    surface::BindKind::At,
743                )
744            }
745            fhir::ParamKind::Pound => {
746                (matches!(scope_kind, RibKind::FnOutput), surface::BindKind::Pound)
747            }
748            fhir::ParamKind::Colon
749            | fhir::ParamKind::Loc
750            | fhir::ParamKind::Error
751            | fhir::ParamKind::Explicit(..) => return,
752        };
753        if !allowed {
754            self.errors
755                .emit(errors::IllegalBinder::new(ident.span, bind_kind));
756        }
757    }
758}
759
760mod errors {
761    use flux_errors::E0999;
762    use flux_macros::Diagnostic;
763    use flux_syntax::surface;
764    use rustc_span::{Span, symbol::Ident};
765
766    #[derive(Diagnostic)]
767    #[diag(desugar_invalid_unrefined_param, code = E0999)]
768    pub(super) struct InvalidUnrefinedParam {
769        #[primary_span]
770        #[label]
771        span: Span,
772        var: Ident,
773    }
774
775    impl InvalidUnrefinedParam {
776        pub(super) fn new(var: Ident) -> Self {
777            Self { var, span: var.span }
778        }
779    }
780
781    #[derive(Diagnostic)]
782    #[diag(desugar_illegal_binder, code = E0999)]
783    pub(super) struct IllegalBinder {
784        #[primary_span]
785        #[label]
786        span: Span,
787        kind: &'static str,
788    }
789
790    impl IllegalBinder {
791        pub(super) fn new(span: Span, kind: surface::BindKind) -> Self {
792            Self { span, kind: kind.token_str() }
793        }
794    }
795}