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 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 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 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 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}