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