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