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(¶m);
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 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 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 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 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 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 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}