flux_driver/collector/
mod.rs

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