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 { generics, refined_by, fields, opaque, invariants }))
239    }
240
241    fn parse_constant_spec(&mut self, owner_id: OwnerId, mut attrs: FluxAttrs) -> Result {
242        if let Some(constant) = attrs.constant() {
243            self.specs.constants.insert(owner_id, constant);
244        }
245        Ok(())
246    }
247
248    fn parse_field_spec(
249        &mut self,
250        field: &rustc_hir::FieldDef,
251        opaque: bool,
252    ) -> Result<Option<surface::Ty>> {
253        let mut attrs = self.parse_attrs_and_report_dups(field.def_id)?;
254        let field_attr = attrs.field();
255
256        // We warn if a struct marked as opaque has a refined type annotation. We allow unrefined
257        // annotations, because the `flux!` macro unconditionally adds a `#[flux_tool::field(..)]`
258        // annotation, even if the struct is opaque.
259        if opaque
260            && let Some(ty) = field_attr.as_ref()
261            && ty.is_refined()
262        {
263            return Err(self.errors.emit(errors::AttrOnOpaque::new(ty.span, field)));
264        }
265        Ok(field_attr)
266    }
267
268    fn collect_enum_def(
269        &mut self,
270        owner_id: OwnerId,
271        mut attrs: FluxAttrs,
272        enum_def: &EnumDef,
273    ) -> Result<&mut surface::EnumDef> {
274        let generics = attrs.generics();
275        let refined_by = attrs.refined_by();
276        let reflected = attrs.reflected();
277
278        if refined_by.is_some() && reflected {
279            let span = self.tcx.def_span(owner_id.to_def_id());
280            return Err(self
281                .errors
282                .emit(errors::ReflectedEnumWithRefinedBy::new(span)));
283        }
284
285        let variants = enum_def
286            .variants
287            .iter()
288            .take(enum_def.variants.len())
289            .map(|variant| self.collect_variant(variant, refined_by.is_some()))
290            .try_collect_exhaust()?;
291
292        let invariants = attrs.invariants();
293
294        Ok(self
295            .specs
296            .enums
297            .entry(owner_id)
298            .or_insert(surface::EnumDef { generics, refined_by, variants, invariants, reflected }))
299    }
300
301    fn collect_variant(
302        &mut self,
303        hir_variant: &rustc_hir::Variant,
304        has_refined_by: bool,
305    ) -> Result<Option<surface::VariantDef>> {
306        let mut attrs = self.parse_attrs_and_report_dups(hir_variant.def_id)?;
307
308        let variant = attrs.variant();
309
310        if variant.is_none() && has_refined_by {
311            return Err(self
312                .errors
313                .emit(errors::MissingVariant::new(hir_variant.span)));
314        }
315
316        Ok(variant)
317    }
318
319    fn collect_constant(&mut self, owner_id: OwnerId, attrs: FluxAttrs) -> Result {
320        self.parse_constant_spec(owner_id, attrs)
321    }
322
323    fn collect_fn_spec(
324        &mut self,
325        owner_id: OwnerId,
326        mut attrs: FluxAttrs,
327    ) -> Result<&mut surface::FnSpec> {
328        let fn_sig = attrs.fn_sig();
329
330        if let Some(fn_sig) = &fn_sig
331            && let Some(ident) = fn_sig.ident
332            && let Some(item_ident) = self.tcx.opt_item_ident(owner_id.to_def_id())
333            && ident != item_ident
334        {
335            return Err(self.errors.emit(errors::MismatchedSpecName::new(
336                self.tcx,
337                ident,
338                owner_id.to_def_id(),
339            )));
340        };
341
342        if attrs.should_fail() {
343            self.specs.should_fail.insert(owner_id.def_id);
344        }
345
346        let qual_names: Option<surface::QualNames> = attrs.qual_names();
347
348        let reveal_names: Option<surface::RevealNames> = attrs.reveal_names();
349
350        Ok(self
351            .specs
352            .fn_sigs
353            .entry(owner_id)
354            .or_insert(surface::FnSpec { fn_sig, qual_names, reveal_names }))
355    }
356
357    fn parse_attrs_and_report_dups(&mut self, def_id: LocalDefId) -> Result<FluxAttrs> {
358        let attrs = self.parse_flux_attrs(def_id)?;
359        self.report_dups(&attrs)?;
360        Ok(attrs)
361    }
362
363    fn parse_flux_attrs(&mut self, def_id: LocalDefId) -> Result<FluxAttrs> {
364        let def_kind = self.tcx.def_kind(def_id);
365        let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
366        let attrs = self.tcx.hir_attrs(hir_id);
367        let attrs: Vec<_> = attrs
368            .iter()
369            .filter_map(|attr| {
370                if let Attribute::Unparsed(attr_item) = &attr {
371                    match &attr_item.path.segments[..] {
372                        [first, ..] => {
373                            let ident = first.as_str();
374                            if ident == "flux" || ident == "flux_tool" {
375                                Some(attr_item)
376                            } else {
377                                None
378                            }
379                        }
380                        _ => None,
381                    }
382                } else {
383                    None
384                }
385            })
386            .map(|attr_item| self.parse_flux_attr(attr_item, def_kind))
387            .try_collect_exhaust()?;
388
389        Ok(FluxAttrs::new(attrs))
390    }
391
392    fn parse_flux_attr(
393        &mut self,
394        attr_item: &hir::AttrItem,
395        def_kind: DefKind,
396    ) -> Result<FluxAttr> {
397        let invalid_attr_err = |this: &Self| {
398            this.errors
399                .emit(errors::InvalidAttr { span: attr_item_span(attr_item) })
400        };
401
402        let [_, segment] = &attr_item.path.segments[..] else { return Err(invalid_attr_err(self)) };
403
404        let kind = match (segment.as_str(), &attr_item.args) {
405            ("alias", hir::AttrArgs::Delimited(dargs)) => {
406                self.parse(dargs, ParseSess::parse_type_alias, |t| {
407                    FluxAttrKind::TypeAlias(Box::new(t))
408                })?
409            }
410            ("sig" | "spec", hir::AttrArgs::Delimited(dargs)) => {
411                self.parse(dargs, ParseSess::parse_fn_sig, FluxAttrKind::FnSig)?
412            }
413            ("assoc" | "reft", hir::AttrArgs::Delimited(dargs)) => {
414                match def_kind {
415                    DefKind::Trait => {
416                        self.parse(
417                            dargs,
418                            ParseSess::parse_trait_assoc_reft,
419                            FluxAttrKind::TraitAssocReft,
420                        )?
421                    }
422                    DefKind::Impl { .. } => {
423                        self.parse(
424                            dargs,
425                            ParseSess::parse_impl_assoc_reft,
426                            FluxAttrKind::ImplAssocReft,
427                        )?
428                    }
429                    _ => return Err(invalid_attr_err(self)),
430                }
431            }
432            ("qualifiers", hir::AttrArgs::Delimited(dargs)) => {
433                self.parse(dargs, ParseSess::parse_qual_names, FluxAttrKind::QualNames)?
434            }
435            ("reveal", hir::AttrArgs::Delimited(dargs)) => {
436                self.parse(dargs, ParseSess::parse_reveal_names, FluxAttrKind::RevealNames)?
437            }
438            ("defs", hir::AttrArgs::Delimited(dargs)) => {
439                self.parse(dargs, ParseSess::parse_flux_item, FluxAttrKind::Items)?
440            }
441            ("refined_by", hir::AttrArgs::Delimited(dargs)) => {
442                self.parse(dargs, ParseSess::parse_refined_by, FluxAttrKind::RefinedBy)?
443            }
444            ("field", hir::AttrArgs::Delimited(dargs)) => {
445                self.parse(dargs, ParseSess::parse_type, FluxAttrKind::Field)?
446            }
447            ("variant", hir::AttrArgs::Delimited(dargs)) => {
448                self.parse(dargs, ParseSess::parse_variant, FluxAttrKind::Variant)?
449            }
450            ("invariant", hir::AttrArgs::Delimited(dargs)) => {
451                self.parse(dargs, ParseSess::parse_expr, FluxAttrKind::Invariant)?
452            }
453            ("constant", hir::AttrArgs::Delimited(dargs)) => {
454                self.parse(dargs, ParseSess::parse_constant_info, FluxAttrKind::Constant)?
455            }
456            ("opts", hir::AttrArgs::Delimited(..)) => {
457                let opts = AttrMap::parse(attr_item)
458                    .emit(&self.errors)?
459                    .try_into_infer_opts()
460                    .emit(&self.errors)?;
461                FluxAttrKind::InferOpts(opts)
462            }
463            ("ignore", hir::AttrArgs::Delimited(dargs)) => {
464                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
465                    FluxAttrKind::Ignore(b.into())
466                })?
467            }
468            ("ignore", hir::AttrArgs::Empty) => FluxAttrKind::Ignore(Ignored::Yes),
469            ("trusted", hir::AttrArgs::Delimited(dargs)) => {
470                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
471                    FluxAttrKind::Trusted(b.into())
472                })?
473            }
474            ("trusted", hir::AttrArgs::Empty) => FluxAttrKind::Trusted(Trusted::Yes),
475            ("trusted_impl", hir::AttrArgs::Delimited(dargs)) => {
476                self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
477                    FluxAttrKind::TrustedImpl(b.into())
478                })?
479            }
480            ("trusted_impl", hir::AttrArgs::Empty) => FluxAttrKind::TrustedImpl(Trusted::Yes),
481            ("opaque", hir::AttrArgs::Empty) => FluxAttrKind::Opaque,
482            ("reflect", hir::AttrArgs::Empty) => FluxAttrKind::Reflect,
483            ("extern_spec", hir::AttrArgs::Empty) => FluxAttrKind::ExternSpec,
484            ("should_fail", hir::AttrArgs::Empty) => FluxAttrKind::ShouldFail,
485            _ => return Err(invalid_attr_err(self)),
486        };
487        if config::annots() {
488            self.stats.add(self.tcx, segment.as_str(), &attr_item.args);
489        }
490        Ok(FluxAttr { kind, span: attr_item_span(attr_item) })
491    }
492
493    fn parse<T>(
494        &mut self,
495        dargs: &rustc_ast::DelimArgs,
496        parser: impl FnOnce(&mut ParseSess, &TokenStream, Span) -> ParseResult<T>,
497        ctor: impl FnOnce(T) -> FluxAttrKind,
498    ) -> Result<FluxAttrKind> {
499        let entire = dargs.dspan.entire().with_ctxt(SyntaxContext::root());
500        parser(&mut self.parse_sess, &dargs.tokens, entire)
501            .map(ctor)
502            .map_err(errors::SyntaxErr::from)
503            .emit(&self.errors)
504    }
505
506    fn report_dups(&mut self, attrs: &FluxAttrs) -> Result {
507        let mut err = None;
508        for (name, dups) in attrs.dups() {
509            for attr in dups {
510                if attr.allow_dups() {
511                    continue;
512                }
513                err.collect(
514                    self.errors
515                        .emit(errors::DuplicatedAttr { span: attr.span, name }),
516                );
517            }
518        }
519        err.into_result()
520    }
521
522    fn collect_ignore_and_trusted(&mut self, attrs: &mut FluxAttrs, def_id: LocalDefId) {
523        if let Some(ignored) = attrs.ignore() {
524            self.specs.ignores.insert(def_id, ignored);
525        }
526        if let Some(trusted) = attrs.trusted() {
527            self.specs.trusted.insert(def_id, trusted);
528        }
529        if let Some(trusted_impl) = attrs.trusted_impl() {
530            self.specs.trusted_impl.insert(def_id, trusted_impl);
531        }
532    }
533
534    fn collect_infer_opts(&mut self, attrs: &mut FluxAttrs, def_id: LocalDefId) {
535        if let Some(check_overflow) = attrs.infer_opts() {
536            self.specs.infer_opts.insert(def_id, check_overflow);
537        }
538    }
539}
540
541#[derive(Debug)]
542struct FluxAttrs {
543    map: HashMap<&'static str, Vec<FluxAttr>>,
544}
545
546#[derive(Debug)]
547struct FluxAttr {
548    kind: FluxAttrKind,
549    span: Span,
550}
551
552#[derive(Debug)]
553enum FluxAttrKind {
554    Trusted(Trusted),
555    TrustedImpl(Trusted),
556    Opaque,
557    Reflect,
558    FnSig(surface::FnSig),
559    TraitAssocReft(Vec<surface::TraitAssocReft>),
560    ImplAssocReft(Vec<surface::ImplAssocReft>),
561    RefinedBy(surface::RefineParams),
562    Generics(surface::Generics),
563    QualNames(surface::QualNames),
564    RevealNames(surface::RevealNames),
565    Items(Vec<surface::Item>),
566    TypeAlias(Box<surface::TyAlias>),
567    Field(surface::Ty),
568    Constant(surface::ConstantInfo),
569    Variant(surface::VariantDef),
570    InferOpts(config::PartialInferOpts),
571    Invariant(surface::Expr),
572    Ignore(Ignored),
573    ShouldFail,
574    ExternSpec,
575}
576
577macro_rules! read_flag {
578    ($self:expr, $kind:ident) => {{ $self.map.get(attr_name!($kind)).is_some() }};
579}
580
581macro_rules! read_attrs {
582    ($self:expr, $kind:ident) => {
583        $self
584            .map
585            .remove(attr_name!($kind))
586            .unwrap_or_else(|| vec![])
587            .into_iter()
588            .filter_map(|attr| if let FluxAttrKind::$kind(v) = attr.kind { Some(v) } else { None })
589            .collect::<Vec<_>>()
590    };
591}
592
593macro_rules! read_attr {
594    ($self:expr, $kind:ident) => {
595        read_attrs!($self, $kind).pop()
596    };
597}
598
599impl FluxAttr {
600    pub fn allow_dups(&self) -> bool {
601        matches!(
602            &self.kind,
603            FluxAttrKind::Invariant(..)
604                | FluxAttrKind::TraitAssocReft(..)
605                | FluxAttrKind::ImplAssocReft(..)
606        )
607    }
608}
609
610impl FluxAttrs {
611    fn new(attrs: Vec<FluxAttr>) -> Self {
612        FluxAttrs { map: attrs.into_iter().into_group_map_by(|attr| attr.kind.name()) }
613    }
614
615    fn dups(&self) -> impl Iterator<Item = (&'static str, &[FluxAttr])> {
616        self.map
617            .iter()
618            .filter(|(_, attrs)| attrs.len() > 1)
619            .map(|(name, attrs)| (*name, &attrs[1..]))
620    }
621
622    fn trusted(&mut self) -> Option<Trusted> {
623        read_attr!(self, Trusted)
624    }
625
626    fn trusted_impl(&mut self) -> Option<Trusted> {
627        read_attr!(self, TrustedImpl)
628    }
629
630    fn ignore(&mut self) -> Option<Ignored> {
631        read_attr!(self, Ignore)
632    }
633
634    fn opaque(&self) -> bool {
635        read_flag!(self, Opaque)
636    }
637
638    fn reflected(&self) -> bool {
639        read_flag!(self, Reflect)
640    }
641
642    fn items(&mut self) -> Vec<surface::Item> {
643        read_attrs!(self, Items).into_iter().flatten().collect()
644    }
645
646    fn fn_sig(&mut self) -> Option<surface::FnSig> {
647        read_attr!(self, FnSig)
648    }
649
650    fn qual_names(&mut self) -> Option<surface::QualNames> {
651        read_attr!(self, QualNames)
652    }
653
654    fn reveal_names(&mut self) -> Option<surface::RevealNames> {
655        read_attr!(self, RevealNames)
656    }
657
658    fn ty_alias(&mut self) -> Option<Box<surface::TyAlias>> {
659        read_attr!(self, TypeAlias)
660    }
661
662    fn refined_by(&mut self) -> Option<surface::RefineParams> {
663        read_attr!(self, RefinedBy)
664    }
665
666    fn generics(&mut self) -> Option<surface::Generics> {
667        read_attr!(self, Generics)
668    }
669
670    fn trait_assoc_refts(&mut self) -> Vec<surface::TraitAssocReft> {
671        read_attrs!(self, TraitAssocReft)
672            .into_iter()
673            .flatten()
674            .collect()
675    }
676
677    fn impl_assoc_refts(&mut self) -> Vec<surface::ImplAssocReft> {
678        read_attrs!(self, ImplAssocReft)
679            .into_iter()
680            .flatten()
681            .collect()
682    }
683
684    fn field(&mut self) -> Option<surface::Ty> {
685        read_attr!(self, Field)
686    }
687
688    fn constant(&mut self) -> Option<surface::ConstantInfo> {
689        read_attr!(self, Constant)
690    }
691
692    fn variant(&mut self) -> Option<surface::VariantDef> {
693        read_attr!(self, Variant)
694    }
695
696    fn infer_opts(&mut self) -> Option<config::PartialInferOpts> {
697        read_attr!(self, InferOpts)
698    }
699
700    fn invariants(&mut self) -> Vec<surface::Expr> {
701        read_attrs!(self, Invariant)
702    }
703
704    fn extern_spec(&self) -> bool {
705        read_flag!(self, ExternSpec)
706    }
707
708    fn should_fail(&self) -> bool {
709        read_flag!(self, ShouldFail)
710    }
711}
712
713impl FluxAttrKind {
714    fn name(&self) -> &'static str {
715        match self {
716            FluxAttrKind::Trusted(_) => attr_name!(Trusted),
717            FluxAttrKind::TrustedImpl(_) => attr_name!(TrustedImpl),
718            FluxAttrKind::Opaque => attr_name!(Opaque),
719            FluxAttrKind::Reflect => attr_name!(Reflect),
720            FluxAttrKind::FnSig(_) => attr_name!(FnSig),
721            FluxAttrKind::TraitAssocReft(_) => attr_name!(TraitAssocReft),
722            FluxAttrKind::ImplAssocReft(_) => attr_name!(ImplAssocReft),
723            FluxAttrKind::RefinedBy(_) => attr_name!(RefinedBy),
724            FluxAttrKind::Generics(_) => attr_name!(Generics),
725            FluxAttrKind::Items(_) => attr_name!(Items),
726            FluxAttrKind::QualNames(_) => attr_name!(QualNames),
727            FluxAttrKind::RevealNames(_) => attr_name!(RevealNames),
728            FluxAttrKind::Field(_) => attr_name!(Field),
729            FluxAttrKind::Constant(_) => attr_name!(Constant),
730            FluxAttrKind::Variant(_) => attr_name!(Variant),
731            FluxAttrKind::TypeAlias(_) => attr_name!(TypeAlias),
732            FluxAttrKind::InferOpts(_) => attr_name!(InferOpts),
733            FluxAttrKind::Ignore(_) => attr_name!(Ignore),
734            FluxAttrKind::Invariant(_) => attr_name!(Invariant),
735            FluxAttrKind::ShouldFail => attr_name!(ShouldFail),
736            FluxAttrKind::ExternSpec => attr_name!(ExternSpec),
737        }
738    }
739}
740
741#[derive(Debug)]
742struct AttrMapValue {
743    setting: Symbol,
744    span: Span,
745}
746
747#[derive(Debug)]
748struct AttrMap {
749    map: HashMap<String, AttrMapValue>,
750}
751
752macro_rules! try_read_setting {
753    ($self:expr, $setting:ident, $type:ident, $cfg:expr) => {{
754        let val =
755            if let Some(AttrMapValue { setting, span }) = $self.map.remove(stringify!($setting)) {
756                let parse_result = setting.as_str().parse::<$type>();
757                if let Ok(val) = parse_result {
758                    Some(val)
759                } else {
760                    return Err(errors::AttrMapErr {
761                        span,
762                        message: format!(
763                            "incorrect type in value for setting `{}`, expected {}",
764                            stringify!($setting),
765                            stringify!($type)
766                        ),
767                    });
768                }
769            } else {
770                None
771            };
772        $cfg.$setting = val;
773    }};
774}
775
776type AttrMapErr<T = ()> = std::result::Result<T, errors::AttrMapErr>;
777
778impl AttrMap {
779    fn parse(attr_item: &hir::AttrItem) -> AttrMapErr<Self> {
780        let mut map = Self { map: HashMap::new() };
781        let err = || {
782            Err(errors::AttrMapErr {
783                span: attr_item_span(attr_item),
784                message: "bad syntax".to_string(),
785            })
786        };
787        let hir::AttrArgs::Delimited(d) = &attr_item.args else { return err() };
788        let Some(items) = MetaItemKind::list_from_tokens(d.tokens.clone()) else { return err() };
789        for item in items {
790            map.parse_entry(&item)?;
791        }
792        Ok(map)
793    }
794
795    fn parse_entry(&mut self, nested_item: &MetaItemInner) -> AttrMapErr {
796        match nested_item {
797            MetaItemInner::MetaItem(item) => {
798                let name = item.name().map(|sym| sym.to_ident_string());
799                let span = item.span;
800                if let Some(name) = name {
801                    if self.map.contains_key(&name) {
802                        return Err(errors::AttrMapErr {
803                            span,
804                            message: format!("duplicated key `{name}`"),
805                        });
806                    }
807
808                    // TODO: support types of values other than strings
809                    let value = item.name_value_literal().ok_or_else(|| {
810                        errors::AttrMapErr { span, message: "unsupported value".to_string() }
811                    })?;
812
813                    let setting = AttrMapValue { setting: value.symbol, span: item.span };
814                    self.map.insert(name, setting);
815                    return Ok(());
816                }
817                Err(errors::AttrMapErr { span, message: "bad setting name".to_string() })
818            }
819            MetaItemInner::Lit(_) => {
820                Err(errors::AttrMapErr {
821                    span: nested_item.span(),
822                    message: "unsupported item".to_string(),
823                })
824            }
825        }
826    }
827
828    fn try_into_infer_opts(&mut self) -> AttrMapErr<PartialInferOpts> {
829        let mut infer_opts = PartialInferOpts::default();
830        try_read_setting!(self, check_overflow, bool, infer_opts);
831        try_read_setting!(self, scrape_quals, bool, infer_opts);
832        try_read_setting!(self, solver, SmtSolver, infer_opts);
833
834        if let Some((name, setting)) = self.map.iter().next() {
835            return Err(errors::AttrMapErr {
836                span: setting.span,
837                message: format!("invalid crate cfg keyword `{name}`"),
838            });
839        }
840
841        Ok(infer_opts)
842    }
843}
844
845fn attr_item_span(attr_item: &hir::AttrItem) -> Span {
846    attr_args_span(&attr_item.args)
847        .map_or(attr_item.path.span, |args_span| attr_item.path.span.to(args_span))
848}
849
850fn attr_args_span(attr_args: &hir::AttrArgs) -> Option<Span> {
851    match attr_args {
852        hir::AttrArgs::Empty => None,
853        hir::AttrArgs::Delimited(args) => Some(args.dspan.entire()),
854        hir::AttrArgs::Eq { eq_span, expr } => Some(eq_span.to(expr.span)),
855    }
856}
857
858mod errors {
859    use flux_errors::E0999;
860    use flux_macros::Diagnostic;
861    use itertools::Itertools;
862    use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
863    use rustc_hir::def_id::DefId;
864    use rustc_middle::ty::TyCtxt;
865    use rustc_span::{ErrorGuaranteed, Span, symbol::Ident};
866
867    #[derive(Diagnostic)]
868    #[diag(driver_duplicated_attr, code = E0999)]
869    pub(super) struct DuplicatedAttr {
870        #[primary_span]
871        pub span: Span,
872        pub name: &'static str,
873    }
874
875    #[derive(Diagnostic)]
876    #[diag(driver_invalid_attr, code = E0999)]
877    pub(super) struct InvalidAttr {
878        #[primary_span]
879        pub span: Span,
880    }
881
882    #[derive(Diagnostic)]
883    #[diag(driver_invalid_attr_map, code = E0999)]
884    pub(super) struct AttrMapErr {
885        #[primary_span]
886        pub span: Span,
887        pub message: String,
888    }
889
890    pub(super) struct SyntaxErr(flux_syntax::ParseError);
891
892    impl From<flux_syntax::ParseError> for SyntaxErr {
893        fn from(err: flux_syntax::ParseError) -> Self {
894            SyntaxErr(err)
895        }
896    }
897
898    impl<'sess> Diagnostic<'sess> for SyntaxErr {
899        fn into_diag(
900            self,
901            dcx: DiagCtxtHandle<'sess>,
902            level: Level,
903        ) -> Diag<'sess, ErrorGuaranteed> {
904            use flux_syntax::ParseErrorKind;
905            let mut diag = Diag::new(dcx, level, crate::fluent_generated::driver_syntax_err);
906            diag.code(E0999).span(self.0.span).span_label(
907                self.0.span,
908                match &self.0.kind {
909                    ParseErrorKind::UnexpectedEof => "unexpected end of input".to_string(),
910                    ParseErrorKind::UnexpectedToken { expected } => {
911                        match &expected[..] {
912                            [] => "unexpected token".to_string(),
913                            [a] => format!("unexpected token, expected `{a}`"),
914                            [a, b] => format!("unexpected token, expected `{a}` or `{b}`"),
915                            [prefix @ .., last] => {
916                                format!(
917                                    "unexpected token, expected one of {}, or `{last}`",
918                                    prefix
919                                        .iter()
920                                        .format_with(", ", |it, f| f(&format_args!("`{it}`")))
921                                )
922                            }
923                        }
924                    }
925                    ParseErrorKind::CannotBeChained => "operator cannot be chained".to_string(),
926                    ParseErrorKind::InvalidBinding => {
927                        "identifier must be a mutable reference".to_string()
928                    }
929                    ParseErrorKind::InvalidSort => {
930                        "property parameter sort is inherited from the primitive operator"
931                            .to_string()
932                    }
933                },
934            );
935            diag
936        }
937    }
938
939    #[derive(Diagnostic)]
940    #[diag(driver_attr_on_opaque, code = E0999)]
941    pub(super) struct AttrOnOpaque {
942        #[primary_span]
943        span: Span,
944        #[label]
945        field_span: Span,
946    }
947
948    impl AttrOnOpaque {
949        pub(super) fn new(span: Span, field: &rustc_hir::FieldDef) -> Self {
950            let field_span = field.ident.span;
951            Self { span, field_span }
952        }
953    }
954
955    #[derive(Diagnostic)]
956    #[diag(driver_reflected_enum_with_refined_by, code = E0999)]
957    pub(super) struct ReflectedEnumWithRefinedBy {
958        #[primary_span]
959        #[label]
960        span: Span,
961    }
962    impl ReflectedEnumWithRefinedBy {
963        pub(super) fn new(span: Span) -> Self {
964            Self { span }
965        }
966    }
967
968    #[derive(Diagnostic)]
969    #[diag(driver_missing_variant, code = E0999)]
970    #[note]
971    pub(super) struct MissingVariant {
972        #[primary_span]
973        #[label]
974        span: Span,
975    }
976
977    impl MissingVariant {
978        pub(super) fn new(span: Span) -> Self {
979            Self { span }
980        }
981    }
982
983    #[derive(Diagnostic)]
984    #[diag(driver_mismatched_spec_name, code = E0999)]
985    pub(super) struct MismatchedSpecName {
986        #[primary_span]
987        #[label]
988        span: Span,
989        #[label(driver_item_def_ident)]
990        item_ident_span: Span,
991        item_ident: Ident,
992        def_descr: &'static str,
993    }
994
995    impl MismatchedSpecName {
996        pub(super) fn new(tcx: TyCtxt, ident: Ident, def_id: DefId) -> Self {
997            let def_descr = tcx.def_descr(def_id);
998            let item_ident = tcx.opt_item_ident(def_id).unwrap();
999            Self { span: ident.span, item_ident_span: item_ident.span, item_ident, def_descr }
1000        }
1001    }
1002}