Skip to main content

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