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