flux_driver/collector/
mod.rs

1mod annot_stats;
2mod detached_specs;
3mod extern_specs;
4
5use std::{collections::HashMap, iter};
6
7use annot_stats::Stats;
8use extern_specs::ExternSpecCollector;
9use flux_common::{
10    iter::IterExt,
11    result::{ErrorCollector, ResultExt},
12    tracked_span_assert_eq,
13};
14use flux_config::{self as config, OverflowMode, PartialInferOpts, SmtSolver};
15use flux_errors::{Errors, FluxSession};
16use flux_middle::Specs;
17use flux_syntax::{
18    ParseResult, ParseSess,
19    surface::{self, NodeId, Trusted},
20};
21use rustc_ast::{MetaItemInner, MetaItemKind, tokenstream::TokenStream};
22use rustc_data_structures::fx::FxIndexMap;
23use rustc_errors::ErrorGuaranteed;
24use rustc_hir::{
25    self as hir, Attribute, CRATE_OWNER_ID, EnumDef, ImplItemKind, Item, ItemKind, OwnerId,
26    VariantData,
27    def::DefKind,
28    def_id::{CRATE_DEF_ID, DefId, LocalDefId},
29};
30use rustc_middle::ty::TyCtxt;
31use rustc_span::{Ident, Span, Symbol, SyntaxContext};
32
33use crate::collector::detached_specs::DetachedSpecsCollector;
34type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
35
36pub(crate) struct SpecCollector<'sess, 'tcx> {
37    tcx: TyCtxt<'tcx>,
38    parse_sess: ParseSess,
39    specs: Specs,
40    errors: Errors<'sess>,
41    stats: Stats,
42}
43
44macro_rules! attr_name {
45    ($kind:ident) => {{
46        let _ = FluxAttrKind::$kind;
47        stringify!($kind)
48    }};
49}
50
51impl<'tcx> hir::intravisit::Visitor<'tcx> for SpecCollector<'_, 'tcx> {
52    type NestedFilter = rustc_middle::hir::nested_filter::All;
53
54    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
55        self.tcx
56    }
57
58    fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
59        let _ = self.collect_item(item);
60    }
61
62    fn visit_trait_item(&mut self, trait_item: &'tcx rustc_hir::TraitItem<'tcx>) {
63        let _ = self.collect_trait_item(trait_item);
64    }
65
66    fn visit_impl_item(&mut self, impl_item: &'tcx rustc_hir::ImplItem<'tcx>) {
67        let _ = self.collect_impl_item(impl_item);
68    }
69}
70
71impl<'a, 'tcx> SpecCollector<'a, 'tcx> {
72    pub(crate) fn collect(tcx: TyCtxt<'tcx>, sess: &'a FluxSession) -> Result<Specs> {
73        let mut collector = Self {
74            tcx,
75            parse_sess: ParseSess::default(),
76            specs: Specs::default(),
77            errors: Errors::new(sess),
78            stats: Default::default(),
79        };
80
81        let _ = collector.collect_crate();
82        tcx.hir_walk_toplevel_module(&mut collector);
83
84        if config::annots() {
85            collector.stats.save(tcx).unwrap();
86        }
87
88        collector.errors.into_result()?;
89
90        Ok(collector.specs)
91    }
92
93    fn collect_crate(&mut self) -> Result {
94        let mut attrs = self.parse_attrs_and_report_dups(CRATE_DEF_ID)?;
95        DetachedSpecsCollector::collect(self, &mut attrs, CRATE_DEF_ID)?;
96        self.collect_mod(CRATE_OWNER_ID, attrs)
97    }
98
99    fn collect_item(&mut self, item: &'tcx Item<'tcx>) -> Result {
100        let owner_id = item.owner_id;
101
102        let mut attrs = self.parse_attrs_and_report_dups(owner_id.def_id)?;
103
104        // Get the parent module's LocalDefId
105        let module_id = self
106            .tcx
107            .parent_module_from_def_id(owner_id.def_id)
108            .to_local_def_id();
109        DetachedSpecsCollector::collect(self, &mut attrs, module_id)?;
110
111        match &item.kind {
112            ItemKind::Fn { .. } => {
113                if attrs.has_attrs() {
114                    let fn_sig = attrs.fn_sig();
115                    self.check_fn_sig_name(owner_id, fn_sig.as_ref())?;
116                    let node_id = self.next_node_id();
117                    self.insert_item(
118                        owner_id,
119                        surface::Item {
120                            attrs: attrs.into_attr_vec(),
121                            kind: surface::ItemKind::Fn(fn_sig),
122                            node_id,
123                        },
124                    )?;
125                }
126            }
127            ItemKind::Struct(_, _, variant) => {
128                self.collect_struct_def(owner_id, attrs, variant)?;
129            }
130            ItemKind::Union(_, _, variant) => {
131                // currently no refinements on unions
132                tracked_span_assert_eq!(attrs.items().is_empty(), true);
133                self.collect_struct_def(owner_id, attrs, variant)?;
134            }
135            ItemKind::Enum(_, _, enum_def) => {
136                self.collect_enum_def(owner_id, attrs, enum_def)?;
137            }
138            ItemKind::Mod(..) => self.collect_mod(owner_id, attrs)?,
139            ItemKind::TyAlias(..) => self.collect_type_alias(owner_id, attrs)?,
140            ItemKind::Impl(..) => self.collect_impl(owner_id, attrs)?,
141            ItemKind::Trait(..) => self.collect_trait(owner_id, attrs)?,
142            ItemKind::Const(.., body_id) => {
143                // The flux-rs macro puts defs as an outer attribute on a `const _: () = { }`. We
144                // consider these defs to be defined in the parent of the const.
145                self.specs
146                    .flux_items_by_parent
147                    .entry(self.tcx.hir_get_parent_item(item.hir_id()))
148                    .or_default()
149                    .extend(attrs.items());
150
151                if attrs.extern_spec() {
152                    return ExternSpecCollector::collect(self, *body_id);
153                }
154
155                self.collect_constant(owner_id, attrs)?;
156            }
157            _ => {}
158        }
159        hir::intravisit::walk_item(self, item);
160        Ok(())
161    }
162
163    fn collect_trait_item(&mut self, trait_item: &'tcx rustc_hir::TraitItem<'tcx>) -> Result {
164        let owner_id = trait_item.owner_id;
165
166        let mut attrs = self.parse_attrs_and_report_dups(owner_id.def_id)?;
167        if let rustc_hir::TraitItemKind::Fn(_, _) = trait_item.kind
168            && attrs.has_attrs()
169        {
170            let sig = attrs.fn_sig();
171            self.check_fn_sig_name(owner_id, sig.as_ref())?;
172            let node_id = self.next_node_id();
173            self.insert_trait_item(
174                owner_id,
175                surface::TraitItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
176            )?;
177        }
178        hir::intravisit::walk_trait_item(self, trait_item);
179        Ok(())
180    }
181
182    fn collect_impl_item(&mut self, impl_item: &'tcx rustc_hir::ImplItem<'tcx>) -> Result {
183        let owner_id = impl_item.owner_id;
184
185        let mut attrs = self.parse_attrs_and_report_dups(owner_id.def_id)?;
186
187        if let ImplItemKind::Fn(..) = &impl_item.kind
188            && attrs.has_attrs()
189        {
190            let sig = attrs.fn_sig();
191            self.check_fn_sig_name(owner_id, sig.as_ref())?;
192            let node_id = self.next_node_id();
193            self.insert_impl_item(
194                owner_id,
195                surface::ImplItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
196            )?;
197        }
198        hir::intravisit::walk_impl_item(self, impl_item);
199        Ok(())
200    }
201
202    fn collect_mod(&mut self, module_id: OwnerId, mut attrs: FluxAttrs) -> Result {
203        self.specs
204            .flux_items_by_parent
205            .entry(module_id)
206            .or_default()
207            .extend(attrs.items());
208
209        if attrs.has_attrs() {
210            let node_id = self.next_node_id();
211            self.insert_item(
212                module_id,
213                surface::Item {
214                    attrs: attrs.into_attr_vec(),
215                    kind: surface::ItemKind::Mod,
216                    node_id,
217                },
218            )?;
219        }
220
221        Ok(())
222    }
223
224    fn collect_trait(&mut self, owner_id: OwnerId, mut attrs: FluxAttrs) -> Result {
225        if !attrs.has_attrs() {
226            return Ok(());
227        }
228
229        let generics = attrs.generics();
230        let assoc_refinements = attrs.trait_assoc_refts();
231
232        let node_id = self.next_node_id();
233        self.insert_item(
234            owner_id,
235            surface::Item {
236                attrs: attrs.into_attr_vec(),
237                kind: surface::ItemKind::Trait(surface::Trait { generics, assoc_refinements }),
238                node_id,
239            },
240        )
241    }
242
243    fn collect_impl(&mut self, owner_id: OwnerId, mut attrs: FluxAttrs) -> Result {
244        if !attrs.has_attrs() {
245            return Ok(());
246        }
247
248        let generics = attrs.generics();
249        let assoc_refinements = attrs.impl_assoc_refts();
250
251        let node_id = self.next_node_id();
252        self.insert_item(
253            owner_id,
254            surface::Item {
255                attrs: attrs.into_attr_vec(),
256                kind: surface::ItemKind::Impl(surface::Impl { generics, assoc_refinements }),
257                node_id,
258            },
259        )
260    }
261
262    fn collect_type_alias(&mut self, owner_id: OwnerId, mut attrs: FluxAttrs) -> Result {
263        if let Some(ty_alias) = attrs.ty_alias() {
264            let node_id = self.next_node_id();
265            self.insert_item(
266                owner_id,
267                surface::Item {
268                    attrs: attrs.into_attr_vec(),
269                    kind: surface::ItemKind::TyAlias(ty_alias),
270                    node_id,
271                },
272            )?;
273        }
274        Ok(())
275    }
276
277    fn collect_struct_def(
278        &mut self,
279        owner_id: OwnerId,
280        mut attrs: FluxAttrs,
281        data: &VariantData,
282    ) -> Result {
283        let fields: Vec<_> = data
284            .fields()
285            .iter()
286            .take(data.fields().len())
287            .map(|field| self.parse_field(field))
288            .try_collect_exhaust()?;
289
290        // We consider the struct unannotatd if the struct itself doesn't have attrs *and* none of
291        // the fields have attributes.
292        let fields_have_attrs = fields.iter().any(|f| f.is_some());
293        if !attrs.has_attrs() && !fields_have_attrs {
294            return Ok(());
295        }
296
297        let opaque = attrs.opaque();
298        let refined_by = attrs.refined_by();
299        let generics = attrs.generics();
300        let invariants = attrs.invariants();
301
302        // Report an error if the struct is marked as opaque and there's a field with an annotation
303        for (field, hir_field) in iter::zip(&fields, data.fields()) {
304            // The `flux!` macro unconditionally adds a `#[flux_tool::field(..)]` annotations, even
305            // if the struct is opaque so we only consider the field annotated if it's is refined.
306            if opaque
307                && let Some(ty) = field
308                && ty.is_refined()
309            {
310                return Err(self
311                    .errors
312                    .emit(errors::AttrOnOpaque::new(ty.span, hir_field)));
313            }
314        }
315
316        let struct_def = surface::StructDef { generics, refined_by, fields, opaque, invariants };
317        let node_id = self.next_node_id();
318        self.insert_item(
319            owner_id,
320            surface::Item {
321                attrs: attrs.into_attr_vec(),
322                kind: surface::ItemKind::Struct(struct_def),
323                node_id,
324            },
325        )
326    }
327
328    fn parse_constant_spec(&mut self, owner_id: OwnerId, mut attrs: FluxAttrs) -> Result {
329        if let Some(constant) = attrs.constant() {
330            let node_id = self.next_node_id();
331            self.insert_item(
332                owner_id,
333                surface::Item {
334                    attrs: attrs.into_attr_vec(),
335                    kind: surface::ItemKind::Const(constant),
336                    node_id,
337                },
338            )?;
339        }
340        Ok(())
341    }
342
343    fn parse_field(&mut self, field: &rustc_hir::FieldDef) -> Result<Option<surface::Ty>> {
344        let mut attrs = self.parse_attrs_and_report_dups(field.def_id)?;
345        Ok(attrs.field())
346    }
347
348    fn collect_enum_def(
349        &mut self,
350        owner_id: OwnerId,
351        mut attrs: FluxAttrs,
352        enum_def: &EnumDef,
353    ) -> Result {
354        let variants: Vec<_> = enum_def
355            .variants
356            .iter()
357            .take(enum_def.variants.len())
358            .map(|variant| self.parse_variant(variant))
359            .try_collect_exhaust()?;
360
361        // We consider the enum unannotatd if the enum itself doesn't have attrs *and* none of
362        // the variants have attributes.
363        let variants_have_attrs = variants.iter().any(|v| v.is_some());
364        if !attrs.has_attrs() && !variants_have_attrs {
365            return Ok(());
366        }
367
368        let generics = attrs.generics();
369        let refined_by = attrs.refined_by();
370        let reflected = attrs.reflected();
371        let invariants = attrs.invariants();
372
373        // Can't use `refined_by` and `reflected` at the same time
374        if refined_by.is_some() && reflected {
375            let span = self.tcx.def_span(owner_id.to_def_id());
376            return Err(self
377                .errors
378                .emit(errors::ReflectedEnumWithRefinedBy::new(span)));
379        }
380
381        // Report an error if the enum has a refined_by and one of the variants is not annotated
382        for (variant, hir_variant) in iter::zip(&variants, enum_def.variants) {
383            if variant.is_none() && refined_by.is_some() {
384                return Err(self
385                    .errors
386                    .emit(errors::MissingVariant::new(hir_variant.span)));
387            }
388        }
389
390        let enum_def = surface::EnumDef { generics, refined_by, variants, invariants, reflected };
391        let node_id = self.next_node_id();
392        self.insert_item(
393            owner_id,
394            surface::Item {
395                attrs: attrs.into_attr_vec(),
396                kind: surface::ItemKind::Enum(enum_def),
397                node_id,
398            },
399        )
400    }
401
402    fn parse_variant(
403        &mut self,
404        hir_variant: &rustc_hir::Variant,
405    ) -> Result<Option<surface::VariantDef>> {
406        let mut attrs = self.parse_attrs_and_report_dups(hir_variant.def_id)?;
407        Ok(attrs.variant())
408    }
409
410    fn collect_constant(&mut self, owner_id: OwnerId, attrs: FluxAttrs) -> Result {
411        self.parse_constant_spec(owner_id, attrs)
412    }
413
414    fn check_fn_sig_name(&mut self, owner_id: OwnerId, fn_sig: Option<&surface::FnSig>) -> Result {
415        if let Some(fn_sig) = fn_sig
416            && let Some(ident) = fn_sig.ident
417            && let Some(item_ident) = self.tcx.opt_item_ident(owner_id.to_def_id())
418            && ident != item_ident
419        {
420            return Err(self.errors.emit(errors::MismatchedSpecName::new(
421                self.tcx,
422                ident,
423                owner_id.to_def_id(),
424            )));
425        };
426        Ok(())
427    }
428
429    fn parse_attrs_and_report_dups(&mut self, def_id: LocalDefId) -> Result<FluxAttrs> {
430        let attrs = self.parse_flux_attrs(def_id)?;
431        self.report_dups(&attrs)?;
432        Ok(attrs)
433    }
434
435    fn parse_flux_attrs(&mut self, def_id: LocalDefId) -> Result<FluxAttrs> {
436        let def_kind = self.tcx.def_kind(def_id);
437        let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
438        let attrs = self.tcx.hir_attrs(hir_id);
439        let attrs: Vec<_> = attrs
440            .iter()
441            .filter_map(|attr| {
442                if let Attribute::Unparsed(attr_item) = &attr {
443                    match &attr_item.path.segments[..] {
444                        [first, ..] => {
445                            let ident = first.as_str();
446                            if ident == "flux" || ident == "flux_tool" {
447                                Some(attr_item)
448                            } else {
449                                None
450                            }
451                        }
452                        _ => None,
453                    }
454                } else {
455                    None
456                }
457            })
458            .map(|attr_item| self.parse_flux_attr(attr_item, def_kind))
459            .try_collect_exhaust()?;
460
461        Ok(FluxAttrs::new(attrs))
462    }
463
464    fn parse_flux_attr(
465        &mut self,
466        attr_item: &hir::AttrItem,
467        def_kind: DefKind,
468    ) -> Result<FluxAttr> {
469        let invalid_attr_err = |this: &Self| {
470            this.errors
471                .emit(errors::InvalidAttr { span: attr_item_inner_span(attr_item) })
472        };
473
474        let [_, segment] = &attr_item.path.segments[..] else { return Err(invalid_attr_err(self)) };
475
476        let kind = match (segment.as_str(), &attr_item.args) {
477            ("alias", hir::AttrArgs::Delimited(dargs)) => {
478                self.parse(dargs, ParseSess::parse_type_alias, |t| {
479                    FluxAttrKind::TypeAlias(Box::new(t))
480                })?
481            }
482            ("sig" | "spec", hir::AttrArgs::Delimited(dargs)) => {
483                self.parse(dargs, ParseSess::parse_fn_sig, FluxAttrKind::FnSig)?
484            }
485            ("assoc" | "reft", hir::AttrArgs::Delimited(dargs)) => {
486                match def_kind {
487                    DefKind::Trait => {
488                        self.parse(
489                            dargs,
490                            ParseSess::parse_trait_assoc_reft,
491                            FluxAttrKind::TraitAssocReft,
492                        )?
493                    }
494                    DefKind::Impl { .. } => {
495                        self.parse(
496                            dargs,
497                            ParseSess::parse_impl_assoc_reft,
498                            FluxAttrKind::ImplAssocReft,
499                        )?
500                    }
501                    _ => return Err(invalid_attr_err(self)),
502                }
503            }
504            ("qualifiers", hir::AttrArgs::Delimited(dargs)) => {
505                self.parse(dargs, ParseSess::parse_ident_list, FluxAttrKind::QualNames)?
506            }
507            ("reveal", hir::AttrArgs::Delimited(dargs)) => {
508                self.parse(dargs, ParseSess::parse_ident_list, FluxAttrKind::RevealNames)?
509            }
510            ("defs", hir::AttrArgs::Delimited(dargs)) => {
511                self.parse(dargs, ParseSess::parse_flux_item, FluxAttrKind::Items)?
512            }
513            ("refined_by", hir::AttrArgs::Delimited(dargs)) => {
514                self.parse(dargs, ParseSess::parse_refined_by, FluxAttrKind::RefinedBy)?
515            }
516            ("field", hir::AttrArgs::Delimited(dargs)) => {
517                self.parse(dargs, ParseSess::parse_type, FluxAttrKind::Field)?
518            }
519            ("variant", hir::AttrArgs::Delimited(dargs)) => {
520                self.parse(dargs, ParseSess::parse_variant, FluxAttrKind::Variant)?
521            }
522            ("invariant", hir::AttrArgs::Delimited(dargs)) => {
523                self.parse(dargs, ParseSess::parse_expr, FluxAttrKind::Invariant)?
524            }
525            ("constant", hir::AttrArgs::Delimited(dargs)) => {
526                self.parse(dargs, ParseSess::parse_constant_info, FluxAttrKind::Constant)?
527            }
528            ("opts", hir::AttrArgs::Delimited(..)) => {
529                let opts = AttrMap::parse(attr_item)
530                    .emit(&self.errors)?
531                    .try_into_infer_opts()
532                    .emit(&self.errors)?;
533                FluxAttrKind::InferOpts(opts)
534            }
535            ("ignore", hir::AttrArgs::Delimited(dargs)) => {
536                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
537                    FluxAttrKind::Ignore(b.into())
538                })?
539            }
540            ("ignore", hir::AttrArgs::Empty) => FluxAttrKind::Ignore(surface::Ignored::Yes),
541            ("trusted", hir::AttrArgs::Delimited(dargs)) => {
542                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
543                    FluxAttrKind::Trusted(b.into())
544                })?
545            }
546            ("trusted", hir::AttrArgs::Empty) => FluxAttrKind::Trusted(Trusted::Yes),
547            ("trusted_impl", hir::AttrArgs::Delimited(dargs)) => {
548                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
549                    FluxAttrKind::TrustedImpl(b.into())
550                })?
551            }
552            ("proven_externally", _) => {
553                let span = attr_item_inner_span(attr_item);
554                FluxAttrKind::ProvenExternally(span)
555            }
556            ("trusted_impl", hir::AttrArgs::Empty) => FluxAttrKind::TrustedImpl(Trusted::Yes),
557            ("opaque", hir::AttrArgs::Empty) => FluxAttrKind::Opaque,
558            ("reflect", hir::AttrArgs::Empty) => FluxAttrKind::Reflect,
559            ("extern_spec", hir::AttrArgs::Empty) => FluxAttrKind::ExternSpec,
560            ("no_panic", hir::AttrArgs::Empty) => FluxAttrKind::NoPanic,
561            ("should_fail", hir::AttrArgs::Empty) => FluxAttrKind::ShouldFail,
562            ("specs", hir::AttrArgs::Delimited(dargs)) => {
563                self.parse(dargs, ParseSess::parse_detached_specs, FluxAttrKind::DetachedSpecs)?
564            }
565            _ => return Err(invalid_attr_err(self)),
566        };
567        if config::annots() {
568            self.stats.add(self.tcx, segment.as_str(), &attr_item.args);
569        }
570        Ok(FluxAttr { kind, span: attr_item_inner_span(attr_item) })
571    }
572
573    fn parse<T>(
574        &mut self,
575        dargs: &rustc_ast::DelimArgs,
576        parser: impl FnOnce(&mut ParseSess, &TokenStream, Span) -> ParseResult<T>,
577        ctor: impl FnOnce(T) -> FluxAttrKind,
578    ) -> Result<FluxAttrKind> {
579        let entire = dargs.dspan.entire().with_ctxt(SyntaxContext::root());
580        parser(&mut self.parse_sess, &dargs.tokens, entire)
581            .map(ctor)
582            .map_err(errors::SyntaxErr::from)
583            .emit(&self.errors)
584    }
585
586    fn report_dups(&mut self, attrs: &FluxAttrs) -> Result {
587        let mut err = None;
588        for (name, dups) in attrs.dups() {
589            for attr in dups {
590                if attr.allow_dups() {
591                    continue;
592                }
593                err.collect(
594                    self.errors
595                        .emit(errors::DuplicatedAttr { span: attr.span, name }),
596                );
597            }
598        }
599        err.into_result()
600    }
601
602    fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Result {
603        match self.specs.insert_item(owner_id, item) {
604            Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
605            None => Ok(()),
606        }
607    }
608
609    fn insert_trait_item(&mut self, owner_id: OwnerId, item: surface::TraitItemFn) -> Result {
610        match self.specs.insert_trait_item(owner_id, item) {
611            Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
612            None => Ok(()),
613        }
614    }
615
616    fn insert_impl_item(&mut self, owner_id: OwnerId, item: surface::ImplItemFn) -> Result {
617        match self.specs.insert_impl_item(owner_id, item) {
618            Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
619            None => Ok(()),
620        }
621    }
622
623    fn err_multiple_specs(&mut self, def_id: DefId) -> ErrorGuaranteed {
624        let name = self.tcx.def_path_str(def_id);
625        let span = self.tcx.def_span(def_id);
626        let name = Symbol::intern(&name);
627        self.errors
628            .emit(errors::MultipleSpecifications { name, span })
629    }
630
631    fn next_node_id(&mut self) -> NodeId {
632        self.parse_sess.next_node_id()
633    }
634}
635
636#[derive(Debug)]
637struct FluxAttrs {
638    map: FxIndexMap<&'static str, Vec<FluxAttr>>,
639}
640
641#[derive(Debug)]
642struct FluxAttr {
643    kind: FluxAttrKind,
644    span: Span,
645}
646
647#[derive(Debug)]
648enum FluxAttrKind {
649    Trusted(Trusted),
650    TrustedImpl(Trusted),
651    ProvenExternally(Span),
652    Opaque,
653    Reflect,
654    FnSig(surface::FnSig),
655    TraitAssocReft(Vec<surface::TraitAssocReft>),
656    ImplAssocReft(Vec<surface::ImplAssocReft>),
657    RefinedBy(surface::RefineParams),
658    Generics(surface::Generics),
659    QualNames(Vec<Ident>),
660    RevealNames(Vec<Ident>),
661    Items(Vec<surface::FluxItem>),
662    TypeAlias(Box<surface::TyAlias>),
663    Field(surface::Ty),
664    Constant(surface::ConstantInfo),
665    Variant(surface::VariantDef),
666    InferOpts(config::PartialInferOpts),
667    Invariant(surface::Expr),
668    Ignore(surface::Ignored),
669    ShouldFail,
670    ExternSpec,
671    NoPanic,
672    /// See `detachXX.rs`
673    DetachedSpecs(surface::DetachedSpecs),
674}
675
676macro_rules! read_flag {
677    ($self:expr, $kind:ident) => {{ $self.map.get(attr_name!($kind)).is_some() }};
678}
679
680macro_rules! read_attrs {
681    ($self:expr, $kind:ident) => {
682        $self
683            .map
684            .swap_remove(attr_name!($kind))
685            .unwrap_or_else(|| vec![])
686            .into_iter()
687            .filter_map(|attr| if let FluxAttrKind::$kind(v) = attr.kind { Some(v) } else { None })
688            .collect::<Vec<_>>()
689    };
690}
691
692macro_rules! read_attr {
693    ($self:expr, $kind:ident) => {
694        read_attrs!($self, $kind).pop()
695    };
696}
697
698impl FluxAttr {
699    pub fn allow_dups(&self) -> bool {
700        matches!(
701            &self.kind,
702            FluxAttrKind::Invariant(..)
703                | FluxAttrKind::TraitAssocReft(..)
704                | FluxAttrKind::ImplAssocReft(..)
705        )
706    }
707}
708
709impl FluxAttrs {
710    fn new(attrs: Vec<FluxAttr>) -> Self {
711        let mut map: FxIndexMap<&'static str, Vec<FluxAttr>> = Default::default();
712        for attr in attrs {
713            map.entry(attr.kind.name()).or_default().push(attr);
714        }
715        FluxAttrs { map }
716    }
717
718    fn has_attrs(&self) -> bool {
719        !self.map.is_empty()
720    }
721
722    fn dups(&self) -> impl Iterator<Item = (&'static str, &[FluxAttr])> {
723        self.map
724            .iter()
725            .filter(|(_, attrs)| attrs.len() > 1)
726            .map(|(name, attrs)| (*name, &attrs[1..]))
727    }
728
729    fn opaque(&self) -> bool {
730        read_flag!(self, Opaque)
731    }
732
733    fn reflected(&self) -> bool {
734        read_flag!(self, Reflect)
735    }
736
737    fn items(&mut self) -> Vec<surface::FluxItem> {
738        read_attrs!(self, Items).into_iter().flatten().collect()
739    }
740
741    fn fn_sig(&mut self) -> Option<surface::FnSig> {
742        read_attr!(self, FnSig)
743    }
744
745    fn ty_alias(&mut self) -> Option<Box<surface::TyAlias>> {
746        read_attr!(self, TypeAlias)
747    }
748
749    fn refined_by(&mut self) -> Option<surface::RefineParams> {
750        read_attr!(self, RefinedBy)
751    }
752
753    fn generics(&mut self) -> Option<surface::Generics> {
754        read_attr!(self, Generics)
755    }
756
757    fn trait_assoc_refts(&mut self) -> Vec<surface::TraitAssocReft> {
758        read_attrs!(self, TraitAssocReft)
759            .into_iter()
760            .flatten()
761            .collect()
762    }
763
764    fn impl_assoc_refts(&mut self) -> Vec<surface::ImplAssocReft> {
765        read_attrs!(self, ImplAssocReft)
766            .into_iter()
767            .flatten()
768            .collect()
769    }
770
771    fn field(&mut self) -> Option<surface::Ty> {
772        read_attr!(self, Field)
773    }
774
775    fn constant(&mut self) -> Option<surface::ConstantInfo> {
776        read_attr!(self, Constant)
777    }
778
779    fn variant(&mut self) -> Option<surface::VariantDef> {
780        read_attr!(self, Variant)
781    }
782
783    fn invariants(&mut self) -> Vec<surface::Expr> {
784        read_attrs!(self, Invariant)
785    }
786
787    fn extern_spec(&self) -> bool {
788        read_flag!(self, ExternSpec)
789    }
790
791    fn detached_specs(&mut self) -> Option<surface::DetachedSpecs> {
792        read_attr!(self, DetachedSpecs)
793    }
794
795    fn into_attr_vec(self) -> Vec<surface::Attr> {
796        let mut attrs = vec![];
797        for attr in self.map.into_values().flatten() {
798            let attr = match attr.kind {
799                FluxAttrKind::Trusted(trusted) => surface::Attr::Trusted(trusted),
800                FluxAttrKind::TrustedImpl(trusted) => surface::Attr::TrustedImpl(trusted),
801                FluxAttrKind::ProvenExternally(span) => surface::Attr::ProvenExternally(span),
802                FluxAttrKind::QualNames(names) => surface::Attr::Qualifiers(names),
803                FluxAttrKind::RevealNames(names) => surface::Attr::Reveal(names),
804                FluxAttrKind::InferOpts(opts) => surface::Attr::InferOpts(opts),
805                FluxAttrKind::Ignore(ignored) => surface::Attr::Ignore(ignored),
806                FluxAttrKind::ShouldFail => surface::Attr::ShouldFail,
807                FluxAttrKind::NoPanic => surface::Attr::NoPanic,
808                FluxAttrKind::Opaque
809                | FluxAttrKind::Reflect
810                | FluxAttrKind::FnSig(_)
811                | FluxAttrKind::TraitAssocReft(_)
812                | FluxAttrKind::ImplAssocReft(_)
813                | FluxAttrKind::RefinedBy(_)
814                | FluxAttrKind::Generics(_)
815                | FluxAttrKind::Items(_)
816                | FluxAttrKind::TypeAlias(_)
817                | FluxAttrKind::Field(_)
818                | FluxAttrKind::Constant(_)
819                | FluxAttrKind::Variant(_)
820                | FluxAttrKind::Invariant(_)
821                | FluxAttrKind::ExternSpec
822                | FluxAttrKind::DetachedSpecs(_) => continue,
823            };
824            attrs.push(attr);
825        }
826        attrs
827    }
828}
829
830impl FluxAttrKind {
831    fn name(&self) -> &'static str {
832        match self {
833            FluxAttrKind::Trusted(_) => attr_name!(Trusted),
834            FluxAttrKind::TrustedImpl(_) => attr_name!(TrustedImpl),
835            FluxAttrKind::ProvenExternally(_) => attr_name!(ProvenExternally),
836            FluxAttrKind::Opaque => attr_name!(Opaque),
837            FluxAttrKind::Reflect => attr_name!(Reflect),
838            FluxAttrKind::FnSig(_) => attr_name!(FnSig),
839            FluxAttrKind::TraitAssocReft(_) => attr_name!(TraitAssocReft),
840            FluxAttrKind::ImplAssocReft(_) => attr_name!(ImplAssocReft),
841            FluxAttrKind::RefinedBy(_) => attr_name!(RefinedBy),
842            FluxAttrKind::Generics(_) => attr_name!(Generics),
843            FluxAttrKind::Items(_) => attr_name!(Items),
844            FluxAttrKind::QualNames(_) => attr_name!(QualNames),
845            FluxAttrKind::RevealNames(_) => attr_name!(RevealNames),
846            FluxAttrKind::Field(_) => attr_name!(Field),
847            FluxAttrKind::Constant(_) => attr_name!(Constant),
848            FluxAttrKind::Variant(_) => attr_name!(Variant),
849            FluxAttrKind::TypeAlias(_) => attr_name!(TypeAlias),
850            FluxAttrKind::InferOpts(_) => attr_name!(InferOpts),
851            FluxAttrKind::Ignore(_) => attr_name!(Ignore),
852            FluxAttrKind::Invariant(_) => attr_name!(Invariant),
853            FluxAttrKind::ShouldFail => attr_name!(ShouldFail),
854            FluxAttrKind::ExternSpec => attr_name!(ExternSpec),
855            FluxAttrKind::DetachedSpecs(_) => attr_name!(DetachedSpecs),
856            FluxAttrKind::NoPanic => attr_name!(NoPanic),
857        }
858    }
859}
860
861#[derive(Debug)]
862struct AttrMapValue {
863    setting: Symbol,
864    span: Span,
865}
866
867#[derive(Debug)]
868struct AttrMap {
869    map: HashMap<String, AttrMapValue>,
870}
871
872macro_rules! try_read_setting {
873    ($self:expr, $setting:ident, $type:ident, $cfg:expr) => {{
874        let val =
875            if let Some(AttrMapValue { setting, span }) = $self.map.remove(stringify!($setting)) {
876                let parse_result = setting.as_str().parse::<$type>();
877                if let Ok(val) = parse_result {
878                    Some(val)
879                } else {
880                    return Err(errors::AttrMapErr {
881                        span,
882                        message: format!(
883                            "incorrect type in value for setting `{}`, expected {}",
884                            stringify!($setting),
885                            stringify!($type)
886                        ),
887                    });
888                }
889            } else {
890                None
891            };
892        $cfg.$setting = val;
893    }};
894}
895
896type AttrMapErr<T = ()> = std::result::Result<T, errors::AttrMapErr>;
897
898impl AttrMap {
899    fn parse(attr_item: &hir::AttrItem) -> AttrMapErr<Self> {
900        let mut map = Self { map: HashMap::new() };
901        let err = || {
902            Err(errors::AttrMapErr {
903                span: attr_item_inner_span(attr_item),
904                message: "bad syntax".to_string(),
905            })
906        };
907        let hir::AttrArgs::Delimited(d) = &attr_item.args else { return err() };
908        let Some(items) = MetaItemKind::list_from_tokens(d.tokens.clone()) else { return err() };
909        for item in items {
910            map.parse_entry(&item)?;
911        }
912        Ok(map)
913    }
914
915    fn parse_entry(&mut self, nested_item: &MetaItemInner) -> AttrMapErr {
916        match nested_item {
917            MetaItemInner::MetaItem(item) => {
918                let name = item.name().map(|sym| sym.to_ident_string());
919                let span = item.span;
920                if let Some(name) = name {
921                    if self.map.contains_key(&name) {
922                        return Err(errors::AttrMapErr {
923                            span,
924                            message: format!("duplicated key `{name}`"),
925                        });
926                    }
927
928                    // TODO: support types of values other than strings
929                    let value = item.name_value_literal().ok_or_else(|| {
930                        errors::AttrMapErr { span, message: "unsupported value".to_string() }
931                    })?;
932
933                    let setting = AttrMapValue { setting: value.symbol, span: item.span };
934                    self.map.insert(name, setting);
935                    return Ok(());
936                }
937                Err(errors::AttrMapErr { span, message: "bad setting name".to_string() })
938            }
939            MetaItemInner::Lit(_) => {
940                Err(errors::AttrMapErr {
941                    span: nested_item.span(),
942                    message: "unsupported item".to_string(),
943                })
944            }
945        }
946    }
947
948    fn try_into_infer_opts(&mut self) -> AttrMapErr<PartialInferOpts> {
949        let mut infer_opts = PartialInferOpts::default();
950        try_read_setting!(self, allow_uninterpreted_cast, bool, infer_opts);
951        try_read_setting!(self, check_overflow, OverflowMode, infer_opts);
952        try_read_setting!(self, scrape_quals, bool, infer_opts);
953        try_read_setting!(self, solver, SmtSolver, infer_opts);
954
955        if let Some((name, setting)) = self.map.iter().next() {
956            return Err(errors::AttrMapErr {
957                span: setting.span,
958                message: format!("invalid crate cfg keyword `{name}`"),
959            });
960        }
961
962        Ok(infer_opts)
963    }
964}
965
966/// Returns the span of an attribute without `#[` and `]`
967fn attr_item_inner_span(attr_item: &hir::AttrItem) -> Span {
968    attr_args_span(&attr_item.args)
969        .map_or(attr_item.path.span, |args_span| attr_item.path.span.to(args_span))
970}
971
972fn attr_args_span(attr_args: &hir::AttrArgs) -> Option<Span> {
973    match attr_args {
974        hir::AttrArgs::Empty => None,
975        hir::AttrArgs::Delimited(args) => Some(args.dspan.entire()),
976        hir::AttrArgs::Eq { eq_span, expr } => Some(eq_span.to(expr.span)),
977    }
978}
979
980mod errors {
981    use flux_errors::E0999;
982    use flux_macros::Diagnostic;
983    use flux_syntax::surface::ExprPath;
984    use itertools::Itertools;
985    use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
986    use rustc_hir::def_id::DefId;
987    use rustc_middle::ty::TyCtxt;
988    use rustc_span::{ErrorGuaranteed, Span, Symbol, symbol::Ident};
989
990    #[derive(Diagnostic)]
991    #[diag(driver_duplicated_attr, code = E0999)]
992    pub(super) struct DuplicatedAttr {
993        #[primary_span]
994        pub span: Span,
995        pub name: &'static str,
996    }
997
998    #[derive(Diagnostic)]
999    #[diag(driver_invalid_attr, code = E0999)]
1000    pub(super) struct InvalidAttr {
1001        #[primary_span]
1002        pub span: Span,
1003    }
1004
1005    #[derive(Diagnostic)]
1006    #[diag(driver_invalid_attr_map, code = E0999)]
1007    pub(super) struct AttrMapErr {
1008        #[primary_span]
1009        pub span: Span,
1010        pub message: String,
1011    }
1012
1013    #[derive(Diagnostic)]
1014    #[diag(driver_unresolved_specification, code = E0999)]
1015    pub(super) struct UnresolvedSpecification {
1016        #[primary_span]
1017        pub span: Span,
1018        pub ident: Ident,
1019        pub thing: String,
1020    }
1021
1022    impl UnresolvedSpecification {
1023        pub(super) fn new(path: &ExprPath, thing: &str) -> Self {
1024            let span = path.span;
1025            let ident = path
1026                .segments
1027                .last()
1028                .map_or_else(|| Ident::with_dummy_span(Symbol::intern("")), |seg| seg.ident);
1029            Self { span, ident, thing: thing.to_string() }
1030        }
1031    }
1032
1033    #[derive(Diagnostic)]
1034    #[diag(driver_multiple_specifications, code = E0999)]
1035    pub(super) struct MultipleSpecifications {
1036        #[primary_span]
1037        pub span: Span,
1038        pub name: Symbol,
1039    }
1040
1041    pub(super) struct SyntaxErr(flux_syntax::ParseError);
1042
1043    impl From<flux_syntax::ParseError> for SyntaxErr {
1044        fn from(err: flux_syntax::ParseError) -> Self {
1045            SyntaxErr(err)
1046        }
1047    }
1048
1049    impl<'sess> Diagnostic<'sess> for SyntaxErr {
1050        fn into_diag(
1051            self,
1052            dcx: DiagCtxtHandle<'sess>,
1053            level: Level,
1054        ) -> Diag<'sess, ErrorGuaranteed> {
1055            use flux_syntax::ParseErrorKind;
1056            let mut diag = Diag::new(dcx, level, crate::fluent_generated::driver_syntax_err);
1057            diag.code(E0999).span(self.0.span).span_label(
1058                self.0.span,
1059                match &self.0.kind {
1060                    ParseErrorKind::UnexpectedEof => "unexpected end of input".to_string(),
1061                    ParseErrorKind::UnexpectedToken { expected } => {
1062                        match &expected[..] {
1063                            [] => "unexpected token".to_string(),
1064                            [a] => format!("unexpected token, expected `{a}`"),
1065                            [a, b] => format!("unexpected token, expected `{a}` or `{b}`"),
1066                            [prefix @ .., last] => {
1067                                format!(
1068                                    "unexpected token, expected one of {}, or `{last}`",
1069                                    prefix
1070                                        .iter()
1071                                        .format_with(", ", |it, f| f(&format_args!("`{it}`")))
1072                                )
1073                            }
1074                        }
1075                    }
1076                    ParseErrorKind::CannotBeChained => "operator cannot be chained".to_string(),
1077                    ParseErrorKind::InvalidBinding => {
1078                        "identifier must be a mutable reference".to_string()
1079                    }
1080                    ParseErrorKind::InvalidSort => {
1081                        "property parameter sort is inherited from the primitive operator"
1082                            .to_string()
1083                    }
1084                    ParseErrorKind::InvalidDetachedSpec => {
1085                        "detached spec requires an identifier name".to_string()
1086                    }
1087                },
1088            );
1089            diag
1090        }
1091    }
1092
1093    #[derive(Diagnostic)]
1094    #[diag(driver_attr_on_opaque, code = E0999)]
1095    pub(super) struct AttrOnOpaque {
1096        #[primary_span]
1097        span: Span,
1098        #[label]
1099        field_span: Span,
1100    }
1101
1102    impl AttrOnOpaque {
1103        pub(super) fn new(span: Span, field: &rustc_hir::FieldDef) -> Self {
1104            let field_span = field.ident.span;
1105            Self { span, field_span }
1106        }
1107    }
1108
1109    #[derive(Diagnostic)]
1110    #[diag(driver_reflected_enum_with_refined_by, code = E0999)]
1111    pub(super) struct ReflectedEnumWithRefinedBy {
1112        #[primary_span]
1113        #[label]
1114        span: Span,
1115    }
1116    impl ReflectedEnumWithRefinedBy {
1117        pub(super) fn new(span: Span) -> Self {
1118            Self { span }
1119        }
1120    }
1121
1122    #[derive(Diagnostic)]
1123    #[diag(driver_missing_variant, code = E0999)]
1124    #[note]
1125    pub(super) struct MissingVariant {
1126        #[primary_span]
1127        #[label]
1128        span: Span,
1129    }
1130
1131    impl MissingVariant {
1132        pub(super) fn new(span: Span) -> Self {
1133            Self { span }
1134        }
1135    }
1136
1137    #[derive(Diagnostic)]
1138    #[diag(driver_mismatched_spec_name, code = E0999)]
1139    pub(super) struct MismatchedSpecName {
1140        #[primary_span]
1141        #[label]
1142        span: Span,
1143        #[label(driver_item_def_ident)]
1144        item_ident_span: Span,
1145        item_ident: Ident,
1146        def_descr: &'static str,
1147    }
1148
1149    impl MismatchedSpecName {
1150        pub(super) fn new(tcx: TyCtxt, ident: Ident, def_id: DefId) -> Self {
1151            let def_descr = tcx.def_descr(def_id);
1152            let item_ident = tcx.opt_item_ident(def_id).unwrap();
1153            Self { span: ident.span, item_ident_span: item_ident.span, item_ident, def_descr }
1154        }
1155    }
1156}