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 if attrs
502 .iter()
503 .any(|attr| matches!(attr.kind, FluxAttrKind::NoPanicIf(_)))
504 && !attrs
505 .iter()
506 .any(|attr| matches!(attr.kind, FluxAttrKind::FnSig(_)))
507 {
508 let span = attrs
509 .iter()
510 .find_map(|attr| {
511 if let FluxAttrKind::NoPanicIf(_) = attr.kind { Some(attr.span) } else { None }
512 })
513 .unwrap();
514 return Err(self.errors.emit(errors::NoPanicIfWithoutSig { span }));
515 }
516
517 Ok(FluxAttrs::new(attrs))
518 }
519
520 fn parse_flux_attr(
521 &mut self,
522 attr_item: &hir::AttrItem,
523 def_kind: DefKind,
524 ) -> Result<FluxAttr> {
525 let invalid_attr_err = |this: &Self| {
526 this.errors
527 .emit(errors::InvalidAttr { span: attr_item_inner_span(attr_item) })
528 };
529
530 let [_, segment] = &attr_item.path.segments[..] else { return Err(invalid_attr_err(self)) };
531
532 let kind = match (segment.as_str(), &attr_item.args) {
533 ("alias", hir::AttrArgs::Delimited(dargs)) => {
534 self.parse(dargs, ParseSess::parse_type_alias, |t| {
535 FluxAttrKind::TypeAlias(Box::new(t))
536 })?
537 }
538 ("sig" | "spec", hir::AttrArgs::Delimited(dargs)) => {
539 if matches!(def_kind, DefKind::Static { .. }) {
540 self.parse(dargs, ParseSess::parse_static_info, FluxAttrKind::StaticSpec)?
541 } else {
542 self.parse(dargs, ParseSess::parse_fn_sig, FluxAttrKind::FnSig)?
543 }
544 }
545 ("assoc" | "reft", hir::AttrArgs::Delimited(dargs)) => {
546 match def_kind {
547 DefKind::Trait => {
548 self.parse(
549 dargs,
550 ParseSess::parse_trait_assoc_reft,
551 FluxAttrKind::TraitAssocReft,
552 )?
553 }
554 DefKind::Impl { .. } => {
555 self.parse(
556 dargs,
557 ParseSess::parse_impl_assoc_reft,
558 FluxAttrKind::ImplAssocReft,
559 )?
560 }
561 _ => return Err(invalid_attr_err(self)),
562 }
563 }
564 ("qualifiers", hir::AttrArgs::Delimited(dargs)) => {
565 self.parse(dargs, ParseSess::parse_ident_list, FluxAttrKind::QualNames)?
566 }
567 ("reveal", hir::AttrArgs::Delimited(dargs)) => {
568 self.parse(dargs, ParseSess::parse_ident_list, FluxAttrKind::RevealNames)?
569 }
570 ("defs", hir::AttrArgs::Delimited(dargs)) => {
571 self.parse(dargs, ParseSess::parse_flux_item, FluxAttrKind::Items)?
572 }
573 ("refined_by", hir::AttrArgs::Delimited(dargs)) => {
574 self.parse(dargs, ParseSess::parse_refined_by, FluxAttrKind::RefinedBy)?
575 }
576 ("field", hir::AttrArgs::Delimited(dargs)) => {
577 self.parse(dargs, ParseSess::parse_type, FluxAttrKind::Field)?
578 }
579 ("variant", hir::AttrArgs::Delimited(dargs)) => {
580 self.parse(dargs, ParseSess::parse_variant, FluxAttrKind::Variant)?
581 }
582 ("invariant", hir::AttrArgs::Delimited(dargs)) => {
583 self.parse(dargs, ParseSess::parse_expr, FluxAttrKind::Invariant)?
584 }
585 ("no_panic_if", hir::AttrArgs::Delimited(dargs)) => {
586 self.parse(dargs, ParseSess::parse_expr, FluxAttrKind::NoPanicIf)?
587 }
588 ("constant", hir::AttrArgs::Delimited(dargs)) => {
589 self.parse(dargs, ParseSess::parse_constant_info, FluxAttrKind::Constant)?
590 }
591 ("opts", hir::AttrArgs::Delimited(..)) => {
592 let opts = AttrMap::parse(attr_item)
593 .emit(&self.errors)?
594 .try_into_infer_opts()
595 .emit(&self.errors)?;
596 FluxAttrKind::InferOpts(opts)
597 }
598 ("ignore", hir::AttrArgs::Delimited(dargs)) => {
599 self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
600 FluxAttrKind::Ignore(b.into())
601 })?
602 }
603 ("ignore", hir::AttrArgs::Empty) => FluxAttrKind::Ignore(surface::Ignored::Yes),
604 ("trusted", hir::AttrArgs::Delimited(dargs)) => {
605 self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
606 FluxAttrKind::Trusted(b.into())
607 })?
608 }
609 ("trusted", hir::AttrArgs::Empty) => FluxAttrKind::Trusted(Trusted::Yes),
610 ("trusted_impl", hir::AttrArgs::Delimited(dargs)) => {
611 self.parse(dargs, ParseSess::parse_yes_or_no_with_reason, |b| {
612 FluxAttrKind::TrustedImpl(b.into())
613 })?
614 }
615 ("proven_externally", _) => {
616 let span = attr_item_inner_span(attr_item);
617 FluxAttrKind::ProvenExternally(span)
618 }
619 ("trusted_impl", hir::AttrArgs::Empty) => FluxAttrKind::TrustedImpl(Trusted::Yes),
620 ("opaque", hir::AttrArgs::Empty) => FluxAttrKind::Opaque,
621 ("reflect", hir::AttrArgs::Empty) => FluxAttrKind::Reflect,
622 ("extern_spec", hir::AttrArgs::Empty) => FluxAttrKind::ExternSpec,
623 ("no_panic", hir::AttrArgs::Empty) => FluxAttrKind::NoPanic,
624 ("should_fail", hir::AttrArgs::Empty) => FluxAttrKind::ShouldFail,
625 ("specs", hir::AttrArgs::Delimited(dargs)) => {
626 self.parse(dargs, ParseSess::parse_detached_specs, FluxAttrKind::DetachedSpecs)?
627 }
628
629 _ => return Err(invalid_attr_err(self)),
630 };
631 if config::annots() {
632 self.stats.add(self.tcx, segment.as_str(), &attr_item.args);
633 }
634 Ok(FluxAttr { kind, span: attr_item_inner_span(attr_item) })
635 }
636
637 fn parse<T>(
638 &mut self,
639 dargs: &rustc_ast::DelimArgs,
640 parser: impl FnOnce(&mut ParseSess, &TokenStream, Span) -> ParseResult<T>,
641 ctor: impl FnOnce(T) -> FluxAttrKind,
642 ) -> Result<FluxAttrKind> {
643 let entire = dargs.dspan.entire().with_ctxt(SyntaxContext::root());
644 parser(&mut self.parse_sess, &dargs.tokens, entire)
645 .map(ctor)
646 .map_err(errors::SyntaxErr::from)
647 .emit(&self.errors)
648 }
649
650 fn report_dups(&mut self, attrs: &FluxAttrs) -> Result {
651 let mut err = None;
652
653 let has_no_panic_if = attrs.has_no_panic_if();
655 if has_no_panic_if && let Some(no_panic_attr_span) = attrs.has_no_panic() {
656 err.collect(self.errors.emit(errors::DuplicatedAttr {
657 span: no_panic_attr_span,
658 name: "NoPanic and NoPanicIf",
659 }));
660 }
661
662 for (name, dups) in attrs.dups() {
663 for attr in dups {
664 if attr.allow_dups() {
665 continue;
666 }
667 err.collect(
668 self.errors
669 .emit(errors::DuplicatedAttr { span: attr.span, name }),
670 );
671 }
672 }
673 err.into_result()
674 }
675
676 fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Result {
677 match self.specs.insert_item(owner_id, item) {
678 Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
679 None => Ok(()),
680 }
681 }
682
683 fn insert_trait_item(&mut self, owner_id: OwnerId, item: surface::TraitItemFn) -> Result {
684 match self.specs.insert_trait_item(owner_id, item) {
685 Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
686 None => Ok(()),
687 }
688 }
689
690 fn insert_impl_item(&mut self, owner_id: OwnerId, item: surface::ImplItemFn) -> Result {
691 match self.specs.insert_impl_item(owner_id, item) {
692 Some(_) => Err(self.err_multiple_specs(owner_id.to_def_id())),
693 None => Ok(()),
694 }
695 }
696
697 fn err_multiple_specs(&mut self, def_id: DefId) -> ErrorGuaranteed {
698 let name = self.tcx.def_path_str(def_id);
699 let span = self.tcx.def_span(def_id);
700 let name = Symbol::intern(&name);
701 self.errors
702 .emit(errors::MultipleSpecifications { name, span })
703 }
704
705 fn next_node_id(&mut self) -> NodeId {
706 self.parse_sess.next_node_id()
707 }
708}
709
710#[derive(Debug)]
711struct FluxAttrs {
712 map: FxIndexMap<&'static str, Vec<FluxAttr>>,
713}
714
715#[derive(Debug)]
716struct FluxAttr {
717 kind: FluxAttrKind,
718 span: Span,
719}
720
721#[derive(Debug)]
722enum FluxAttrKind {
723 Trusted(Trusted),
724 TrustedImpl(Trusted),
725 ProvenExternally(Span),
726 Opaque,
727 Reflect,
728 FnSig(surface::FnSig),
729 TraitAssocReft(Vec<surface::TraitAssocReft>),
730 ImplAssocReft(Vec<surface::ImplAssocReft>),
731 RefinedBy(surface::RefineParams),
732 Generics(surface::Generics),
733 QualNames(Vec<Ident>),
734 RevealNames(Vec<Ident>),
735 Items(Vec<surface::FluxItem>),
736 TypeAlias(Box<surface::TyAlias>),
737 Field(surface::Ty),
738 Constant(surface::ConstantInfo),
739 StaticSpec(surface::StaticInfo),
740 Variant(surface::VariantDef),
741 InferOpts(config::PartialInferOpts),
742 Invariant(surface::Expr),
743 Ignore(surface::Ignored),
744 ShouldFail,
745 ExternSpec,
746 NoPanic,
747 NoPanicIf(surface::Expr),
748 DetachedSpecs(surface::DetachedSpecs),
750}
751
752macro_rules! read_flag {
753 ($self:expr, $kind:ident) => {{ $self.map.get(attr_name!($kind)).is_some() }};
754}
755
756macro_rules! read_attrs {
757 ($self:expr, $kind:ident) => {
758 $self
759 .map
760 .swap_remove(attr_name!($kind))
761 .unwrap_or_else(|| vec![])
762 .into_iter()
763 .filter_map(|attr| if let FluxAttrKind::$kind(v) = attr.kind { Some(v) } else { None })
764 .collect::<Vec<_>>()
765 };
766}
767
768macro_rules! read_attr {
769 ($self:expr, $kind:ident) => {
770 read_attrs!($self, $kind).pop()
771 };
772}
773
774impl FluxAttr {
775 pub fn allow_dups(&self) -> bool {
776 matches!(
777 &self.kind,
778 FluxAttrKind::Invariant(..)
779 | FluxAttrKind::TraitAssocReft(..)
780 | FluxAttrKind::ImplAssocReft(..)
781 )
782 }
783}
784
785impl FluxAttrs {
786 fn new(attrs: Vec<FluxAttr>) -> Self {
787 let mut map: FxIndexMap<&'static str, Vec<FluxAttr>> = Default::default();
788 for attr in attrs {
789 map.entry(attr.kind.name()).or_default().push(attr);
790 }
791 FluxAttrs { map }
792 }
793
794 fn has_attrs(&self) -> bool {
795 !self.map.is_empty()
796 }
797
798 fn dups(&self) -> impl Iterator<Item = (&'static str, &[FluxAttr])> {
799 self.map
800 .iter()
801 .filter(|(_, attrs)| attrs.len() > 1)
802 .map(|(name, attrs)| (*name, &attrs[1..]))
803 }
804
805 fn opaque(&self) -> bool {
806 read_flag!(self, Opaque)
807 }
808
809 fn reflected(&self) -> bool {
810 read_flag!(self, Reflect)
811 }
812
813 fn items(&mut self) -> Vec<surface::FluxItem> {
814 read_attrs!(self, Items).into_iter().flatten().collect()
815 }
816
817 fn fn_sig(&mut self) -> Option<surface::FnSig> {
818 let mut fn_sig = read_attr!(self, FnSig);
819 if let Some(fn_sig) = &mut fn_sig {
822 fn_sig.no_panic = read_attr!(self, NoPanicIf);
823 }
824 fn_sig
825 }
826
827 fn ty_alias(&mut self) -> Option<Box<surface::TyAlias>> {
828 read_attr!(self, TypeAlias)
829 }
830
831 fn refined_by(&mut self) -> Option<surface::RefineParams> {
832 read_attr!(self, RefinedBy)
833 }
834
835 fn generics(&mut self) -> Option<surface::Generics> {
836 read_attr!(self, Generics)
837 }
838
839 fn has_no_panic(&self) -> Option<Span> {
840 self.map
841 .get(attr_name!(NoPanic))
842 .and_then(|attrs| attrs.first())
843 .map(|attr| attr.span)
844 }
845
846 fn has_no_panic_if(&self) -> bool {
847 read_flag!(self, NoPanicIf)
848 }
849
850 fn trait_assoc_refts(&mut self) -> Vec<surface::TraitAssocReft> {
851 read_attrs!(self, TraitAssocReft)
852 .into_iter()
853 .flatten()
854 .collect()
855 }
856
857 fn impl_assoc_refts(&mut self) -> Vec<surface::ImplAssocReft> {
858 read_attrs!(self, ImplAssocReft)
859 .into_iter()
860 .flatten()
861 .collect()
862 }
863
864 fn field(&mut self) -> Option<surface::Ty> {
865 read_attr!(self, Field)
866 }
867
868 fn static_spec(&mut self) -> Option<surface::StaticInfo> {
869 read_attr!(self, StaticSpec)
870 }
871
872 fn constant(&mut self) -> Option<surface::ConstantInfo> {
873 read_attr!(self, Constant)
874 }
875
876 fn variant(&mut self) -> Option<surface::VariantDef> {
877 read_attr!(self, Variant)
878 }
879
880 fn invariants(&mut self) -> Vec<surface::Expr> {
881 read_attrs!(self, Invariant)
882 }
883
884 fn extern_spec(&self) -> bool {
885 read_flag!(self, ExternSpec)
886 }
887
888 fn detached_specs(&mut self) -> Option<surface::DetachedSpecs> {
889 read_attr!(self, DetachedSpecs)
890 }
891
892 fn into_attr_vec(self) -> Vec<surface::Attr> {
893 let mut attrs = vec![];
894 for attr in self.map.into_values().flatten() {
895 let attr = match attr.kind {
896 FluxAttrKind::Trusted(trusted) => surface::Attr::Trusted(trusted),
897 FluxAttrKind::TrustedImpl(trusted) => surface::Attr::TrustedImpl(trusted),
898 FluxAttrKind::ProvenExternally(span) => surface::Attr::ProvenExternally(span),
899 FluxAttrKind::QualNames(names) => surface::Attr::Qualifiers(names),
900 FluxAttrKind::RevealNames(names) => surface::Attr::Reveal(names),
901 FluxAttrKind::InferOpts(opts) => surface::Attr::InferOpts(opts),
902 FluxAttrKind::Ignore(ignored) => surface::Attr::Ignore(ignored),
903 FluxAttrKind::ShouldFail => surface::Attr::ShouldFail,
904 FluxAttrKind::NoPanic => surface::Attr::NoPanic,
905 FluxAttrKind::Opaque
906 | FluxAttrKind::Reflect
907 | FluxAttrKind::FnSig(_)
908 | FluxAttrKind::TraitAssocReft(_)
909 | FluxAttrKind::ImplAssocReft(_)
910 | FluxAttrKind::RefinedBy(_)
911 | FluxAttrKind::Generics(_)
912 | FluxAttrKind::Items(_)
913 | FluxAttrKind::TypeAlias(_)
914 | FluxAttrKind::Field(_)
915 | FluxAttrKind::Constant(_)
916 | FluxAttrKind::StaticSpec(_)
917 | FluxAttrKind::Variant(_)
918 | FluxAttrKind::Invariant(_)
919 | FluxAttrKind::ExternSpec
920 | FluxAttrKind::DetachedSpecs(_)
921 | FluxAttrKind::NoPanicIf(_) => continue,
922 };
923 attrs.push(attr);
924 }
925 attrs
926 }
927}
928
929impl FluxAttrKind {
930 fn name(&self) -> &'static str {
931 match self {
932 FluxAttrKind::Trusted(_) => attr_name!(Trusted),
933 FluxAttrKind::TrustedImpl(_) => attr_name!(TrustedImpl),
934 FluxAttrKind::ProvenExternally(_) => attr_name!(ProvenExternally),
935 FluxAttrKind::Opaque => attr_name!(Opaque),
936 FluxAttrKind::Reflect => attr_name!(Reflect),
937 FluxAttrKind::FnSig(_) => attr_name!(FnSig),
938 FluxAttrKind::TraitAssocReft(_) => attr_name!(TraitAssocReft),
939 FluxAttrKind::ImplAssocReft(_) => attr_name!(ImplAssocReft),
940 FluxAttrKind::RefinedBy(_) => attr_name!(RefinedBy),
941 FluxAttrKind::Generics(_) => attr_name!(Generics),
942 FluxAttrKind::Items(_) => attr_name!(Items),
943 FluxAttrKind::QualNames(_) => attr_name!(QualNames),
944 FluxAttrKind::RevealNames(_) => attr_name!(RevealNames),
945 FluxAttrKind::Field(_) => attr_name!(Field),
946 FluxAttrKind::Constant(_) => attr_name!(Constant),
947 FluxAttrKind::StaticSpec(_) => attr_name!(StaticSpec),
948 FluxAttrKind::Variant(_) => attr_name!(Variant),
949 FluxAttrKind::TypeAlias(_) => attr_name!(TypeAlias),
950 FluxAttrKind::InferOpts(_) => attr_name!(InferOpts),
951 FluxAttrKind::Ignore(_) => attr_name!(Ignore),
952 FluxAttrKind::Invariant(_) => attr_name!(Invariant),
953 FluxAttrKind::ShouldFail => attr_name!(ShouldFail),
954 FluxAttrKind::ExternSpec => attr_name!(ExternSpec),
955 FluxAttrKind::DetachedSpecs(_) => attr_name!(DetachedSpecs),
956 FluxAttrKind::NoPanic => attr_name!(NoPanic),
957 FluxAttrKind::NoPanicIf(_) => attr_name!(NoPanicIf),
958 }
959 }
960}
961
962#[derive(Debug)]
963struct AttrMapValue {
964 setting: Symbol,
965 span: Span,
966}
967
968#[derive(Debug)]
969struct AttrMap {
970 map: HashMap<String, AttrMapValue>,
971}
972
973macro_rules! try_read_setting {
974 ($self:expr, $setting:ident, $type:ident, $cfg:expr) => {{
975 let val =
976 if let Some(AttrMapValue { setting, span }) = $self.map.remove(stringify!($setting)) {
977 let parse_result = setting.as_str().parse::<$type>();
978 if let Ok(val) = parse_result {
979 Some(val)
980 } else {
981 return Err(errors::AttrMapErr {
982 span,
983 message: format!(
984 "incorrect type in value for setting `{}`, expected {}",
985 stringify!($setting),
986 stringify!($type)
987 ),
988 });
989 }
990 } else {
991 None
992 };
993 $cfg.$setting = val;
994 }};
995}
996
997type AttrMapErr<T = ()> = std::result::Result<T, errors::AttrMapErr>;
998
999impl AttrMap {
1000 fn parse(attr_item: &hir::AttrItem) -> AttrMapErr<Self> {
1001 let mut map = Self { map: HashMap::new() };
1002 let err = || {
1003 Err(errors::AttrMapErr {
1004 span: attr_item_inner_span(attr_item),
1005 message: "bad syntax".to_string(),
1006 })
1007 };
1008 let hir::AttrArgs::Delimited(d) = &attr_item.args else { return err() };
1009 let Some(items) = MetaItemKind::list_from_tokens(d.tokens.clone()) else { return err() };
1010 for item in items {
1011 map.parse_entry(&item)?;
1012 }
1013 Ok(map)
1014 }
1015
1016 fn parse_entry(&mut self, nested_item: &MetaItemInner) -> AttrMapErr {
1017 match nested_item {
1018 MetaItemInner::MetaItem(item) => {
1019 let name = item.name().map(|sym| sym.to_ident_string());
1020 let span = item.span;
1021 if let Some(name) = name {
1022 if self.map.contains_key(&name) {
1023 return Err(errors::AttrMapErr {
1024 span,
1025 message: format!("duplicated key `{name}`"),
1026 });
1027 }
1028
1029 let value = item.name_value_literal().ok_or_else(|| {
1031 errors::AttrMapErr { span, message: "unsupported value".to_string() }
1032 })?;
1033
1034 let setting = AttrMapValue { setting: value.symbol, span: item.span };
1035 self.map.insert(name, setting);
1036 return Ok(());
1037 }
1038 Err(errors::AttrMapErr { span, message: "bad setting name".to_string() })
1039 }
1040 MetaItemInner::Lit(_) => {
1041 Err(errors::AttrMapErr {
1042 span: nested_item.span(),
1043 message: "unsupported item".to_string(),
1044 })
1045 }
1046 }
1047 }
1048
1049 fn try_into_infer_opts(&mut self) -> AttrMapErr<PartialInferOpts> {
1050 let mut infer_opts = PartialInferOpts::default();
1051 try_read_setting!(self, allow_uninterpreted_cast, bool, infer_opts);
1052 try_read_setting!(self, check_overflow, OverflowMode, infer_opts);
1053 try_read_setting!(self, allow_raw_deref, RawDerefMode, infer_opts);
1054 try_read_setting!(self, scrape_quals, bool, infer_opts);
1055 try_read_setting!(self, solver, SmtSolver, infer_opts);
1056
1057 if let Some((name, setting)) = self.map.iter().next() {
1058 return Err(errors::AttrMapErr {
1059 span: setting.span,
1060 message: format!("invalid crate cfg keyword `{name}`"),
1061 });
1062 }
1063
1064 Ok(infer_opts)
1065 }
1066}
1067
1068fn attr_item_inner_span(attr_item: &hir::AttrItem) -> Span {
1070 attr_args_span(&attr_item.args)
1071 .map_or(attr_item.path.span, |args_span| attr_item.path.span.to(args_span))
1072}
1073
1074fn attr_args_span(attr_args: &hir::AttrArgs) -> Option<Span> {
1075 match attr_args {
1076 hir::AttrArgs::Empty => None,
1077 hir::AttrArgs::Delimited(args) => Some(args.dspan.entire()),
1078 hir::AttrArgs::Eq { eq_span, expr } => Some(eq_span.to(expr.span)),
1079 }
1080}
1081
1082mod errors {
1083 use flux_errors::E0999;
1084 use flux_macros::Diagnostic;
1085 use flux_syntax::surface::ExprPath;
1086 use itertools::Itertools;
1087 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
1088 use rustc_hir::def_id::DefId;
1089 use rustc_middle::ty::TyCtxt;
1090 use rustc_span::{ErrorGuaranteed, Span, Symbol, symbol::Ident};
1091
1092 #[derive(Diagnostic)]
1093 #[diag(driver_no_panic_if_without_sig, code = E0999)]
1094 pub(super) struct NoPanicIfWithoutSig {
1095 #[primary_span]
1096 pub span: Span,
1097 }
1098
1099 #[derive(Diagnostic)]
1100 #[diag(driver_duplicated_attr, code = E0999)]
1101 pub(super) struct DuplicatedAttr {
1102 #[primary_span]
1103 pub span: Span,
1104 pub name: &'static str,
1105 }
1106
1107 #[derive(Diagnostic)]
1108 #[diag(driver_invalid_attr, code = E0999)]
1109 pub(super) struct InvalidAttr {
1110 #[primary_span]
1111 pub span: Span,
1112 }
1113
1114 #[derive(Diagnostic)]
1115 #[diag(driver_invalid_attr_map, code = E0999)]
1116 pub(super) struct AttrMapErr {
1117 #[primary_span]
1118 pub span: Span,
1119 pub message: String,
1120 }
1121
1122 #[derive(Diagnostic)]
1123 #[diag(driver_unresolved_specification, code = E0999)]
1124 pub(super) struct UnresolvedSpecification {
1125 #[primary_span]
1126 pub span: Span,
1127 pub ident: Ident,
1128 pub thing: String,
1129 }
1130
1131 impl UnresolvedSpecification {
1132 pub(super) fn new(path: &ExprPath, thing: &str) -> Self {
1133 let span = path.span;
1134 let ident = path
1135 .segments
1136 .last()
1137 .map_or_else(|| Ident::with_dummy_span(Symbol::intern("")), |seg| seg.ident);
1138 Self { span, ident, thing: thing.to_string() }
1139 }
1140 }
1141
1142 #[derive(Diagnostic)]
1143 #[diag(driver_multiple_specifications, code = E0999)]
1144 pub(super) struct MultipleSpecifications {
1145 #[primary_span]
1146 pub span: Span,
1147 pub name: Symbol,
1148 }
1149
1150 pub(super) struct SyntaxErr(flux_syntax::ParseError);
1151
1152 impl From<flux_syntax::ParseError> for SyntaxErr {
1153 fn from(err: flux_syntax::ParseError) -> Self {
1154 SyntaxErr(err)
1155 }
1156 }
1157
1158 impl<'sess> Diagnostic<'sess> for SyntaxErr {
1159 fn into_diag(
1160 self,
1161 dcx: DiagCtxtHandle<'sess>,
1162 level: Level,
1163 ) -> Diag<'sess, ErrorGuaranteed> {
1164 use flux_syntax::ParseErrorKind;
1165 let mut diag = Diag::new(dcx, level, crate::fluent_generated::driver_syntax_err);
1166 diag.code(E0999).span(self.0.span).span_label(
1167 self.0.span,
1168 match &self.0.kind {
1169 ParseErrorKind::UnexpectedEof => "unexpected end of input".to_string(),
1170 ParseErrorKind::UnexpectedToken { expected } => {
1171 match &expected[..] {
1172 [] => "unexpected token".to_string(),
1173 [a] => format!("unexpected token, expected `{a}`"),
1174 [a, b] => format!("unexpected token, expected `{a}` or `{b}`"),
1175 [prefix @ .., last] => {
1176 format!(
1177 "unexpected token, expected one of {}, or `{last}`",
1178 prefix
1179 .iter()
1180 .format_with(", ", |it, f| f(&format_args!("`{it}`")))
1181 )
1182 }
1183 }
1184 }
1185 ParseErrorKind::CannotBeChained => "operator cannot be chained".to_string(),
1186 ParseErrorKind::InvalidBinding => {
1187 "identifier must be a mutable reference".to_string()
1188 }
1189 ParseErrorKind::InvalidSort => {
1190 "property parameter sort is inherited from the primitive operator"
1191 .to_string()
1192 }
1193 ParseErrorKind::InvalidDetachedSpec => {
1194 "detached spec requires an identifier name".to_string()
1195 }
1196 },
1197 );
1198 diag
1199 }
1200 }
1201
1202 #[derive(Diagnostic)]
1203 #[diag(driver_mutable_static_spec, code = E0999)]
1204 pub(super) struct MutableStaticSpec {
1205 #[primary_span]
1206 span: Span,
1207 }
1208
1209 impl MutableStaticSpec {
1210 pub(super) fn new(span: Span) -> Self {
1211 Self { span }
1212 }
1213 }
1214
1215 #[derive(Diagnostic)]
1216 #[diag(driver_attr_on_opaque, code = E0999)]
1217 pub(super) struct AttrOnOpaque {
1218 #[primary_span]
1219 span: Span,
1220 #[label]
1221 field_span: Span,
1222 }
1223
1224 impl AttrOnOpaque {
1225 pub(super) fn new(span: Span, field: &rustc_hir::FieldDef) -> Self {
1226 let field_span = field.ident.span;
1227 Self { span, field_span }
1228 }
1229 }
1230
1231 #[derive(Diagnostic)]
1232 #[diag(driver_reflected_enum_with_refined_by, code = E0999)]
1233 pub(super) struct ReflectedEnumWithRefinedBy {
1234 #[primary_span]
1235 #[label]
1236 span: Span,
1237 }
1238 impl ReflectedEnumWithRefinedBy {
1239 pub(super) fn new(span: Span) -> Self {
1240 Self { span }
1241 }
1242 }
1243
1244 #[derive(Diagnostic)]
1245 #[diag(driver_missing_variant, code = E0999)]
1246 #[note]
1247 pub(super) struct MissingVariant {
1248 #[primary_span]
1249 #[label]
1250 span: Span,
1251 }
1252
1253 impl MissingVariant {
1254 pub(super) fn new(span: Span) -> Self {
1255 Self { span }
1256 }
1257 }
1258
1259 #[derive(Diagnostic)]
1260 #[diag(driver_mismatched_spec_name, code = E0999)]
1261 pub(super) struct MismatchedSpecName {
1262 #[primary_span]
1263 #[label]
1264 span: Span,
1265 #[label(driver_item_def_ident)]
1266 item_ident_span: Span,
1267 item_ident: Ident,
1268 def_descr: &'static str,
1269 }
1270
1271 impl MismatchedSpecName {
1272 pub(super) fn new(tcx: TyCtxt, ident: Ident, def_id: DefId) -> Self {
1273 let def_descr = tcx.def_descr(def_id);
1274 let item_ident = tcx.opt_item_ident(def_id).unwrap();
1275 Self { span: ident.span, item_ident_span: item_ident.span, item_ident, def_descr }
1276 }
1277 }
1278}