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