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