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