1use std::iter;
2
3use flux_middle::ExternSpecMappingErr;
4use flux_rustc_bridge::lowering;
5use flux_syntax::surface;
6use rustc_errors::Diagnostic;
7use rustc_hir as hir;
8use rustc_hir::{
9 BodyId, OwnerId,
10 def_id::{DefId, LocalDefId},
11};
12use rustc_middle::ty::{self, TyCtxt};
13use rustc_span::{ErrorGuaranteed, Span, symbol::kw};
14
15use super::{FluxAttrs, SpecCollector};
16
17type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
18
19pub(super) struct ExternSpecCollector<'a, 'sess, 'tcx> {
20 inner: &'a mut SpecCollector<'sess, 'tcx>,
21 block: &'tcx hir::Block<'tcx>,
23}
24
25struct ExternImplItem {
26 impl_id: DefId,
27 item_id: DefId,
28}
29
30impl<'a, 'sess, 'tcx> ExternSpecCollector<'a, 'sess, 'tcx> {
31 pub(super) fn collect(inner: &'a mut SpecCollector<'sess, 'tcx>, body_id: BodyId) -> Result {
32 Self::new(inner, body_id)?.run()
33 }
34
35 fn new(inner: &'a mut SpecCollector<'sess, 'tcx>, body_id: BodyId) -> Result<Self> {
36 let body = inner.tcx.hir_body(body_id);
37 if let hir::ExprKind::Block(block, _) = body.value.kind {
38 Ok(Self { inner, block })
39 } else {
40 Err(inner
41 .errors
42 .emit(errors::MalformedExternSpec::new(body.value.span)))
43 }
44 }
45
46 fn run(mut self) -> Result {
47 let item = self.item_at(0)?;
48
49 let attrs = self
50 .inner
51 .parse_attrs_and_report_dups(item.owner_id.def_id)?;
52
53 match &item.kind {
54 hir::ItemKind::Fn { .. } => self.collect_extern_fn(item, attrs),
55 hir::ItemKind::Enum(_, _, enum_def) => {
56 self.collect_extern_enum(item.owner_id, enum_def, attrs)
57 }
58 hir::ItemKind::Struct(_, _, variant) => {
59 self.collect_extern_struct(item.owner_id, variant, attrs)
60 }
61 hir::ItemKind::Trait { bounds, items, .. } => {
62 self.collect_extern_trait(item.owner_id, bounds, items, attrs)
63 }
64 hir::ItemKind::Impl(impl_) => self.collect_extern_impl(item.owner_id, impl_, attrs),
65 _ => Err(self.malformed()),
66 }
67 }
68
69 fn collect_extern_fn(&mut self, item: &hir::Item, mut attrs: FluxAttrs) -> Result {
70 if attrs.has_attrs() {
71 let (sig, attr_span) = if let Some((sig, span)) = attrs.fn_sig_with_attr_span() {
72 (Some(sig), Some(span))
73 } else {
74 (None, None)
75 };
76 self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
77 let node_id = self.inner.next_node_id();
78 self.inner.insert_item(
79 item.owner_id,
80 surface::Item {
81 attrs: attrs.into_attr_vec(),
82 kind: surface::ItemKind::Fn(sig),
83 node_id,
84 },
85 )?;
86 if let Some(span) = attr_span {
87 self.inner
88 .specs
89 .set_spec_attr_span(item.owner_id.def_id.to_def_id(), span);
90 }
91 }
92
93 let extern_id = self.extract_extern_id_from_fn(item)?;
94 self.insert_extern_id(item.owner_id.def_id, extern_id)?;
95 self.check_generics(item.owner_id, extern_id)?;
96
97 Ok(())
98 }
99
100 fn collect_extern_struct(
101 &mut self,
102 struct_id: OwnerId,
103 variant: &hir::VariantData,
104 attrs: FluxAttrs,
105 ) -> Result {
106 let dummy_struct = self.item_at(1)?;
107 self.inner.specs.insert_dummy(dummy_struct.owner_id.def_id);
108
109 let extern_id = self.extract_extern_id_from_struct(dummy_struct).unwrap();
110 self.insert_extern_id(struct_id.def_id, extern_id)?;
111 self.check_generics(struct_id, extern_id)?;
112
113 if let Some(ctor_id) = variant.ctor_def_id() {
114 self.inner.specs.insert_dummy(ctor_id);
115 }
116
117 self.inner.collect_struct_def(struct_id, attrs, variant)?;
118
119 Ok(())
120 }
121
122 fn collect_extern_enum(
123 &mut self,
124 enum_id: OwnerId,
125 enum_def: &hir::EnumDef,
126 attrs: FluxAttrs,
127 ) -> Result {
128 let dummy_struct = self.item_at(1)?;
129 self.inner.specs.insert_dummy(dummy_struct.owner_id.def_id);
130
131 let extern_id = self.extract_extern_id_from_struct(dummy_struct).unwrap();
132 self.insert_extern_id(enum_id.def_id, extern_id)?;
133 self.check_generics(enum_id, extern_id)?;
134
135 self.inner.collect_enum_def(enum_id, attrs, enum_def)?;
136
137 let extern_enum_def = self.tcx().adt_def(extern_id);
140
141 let extern_variants = extern_enum_def.variants();
143 let enum_variants = enum_def.variants;
144 let extern_len = extern_variants.len();
145 let enum_len = enum_variants.len();
146 if extern_len != enum_len {
147 let reason = format!("expected {extern_len:?} variants but only have {enum_len:?}");
148 return Err(self.invalid_enum_extern_spec(reason));
149 }
150 for (extern_variant, variant) in extern_enum_def.variants().iter().zip(enum_def.variants) {
151 if let Some(extern_ctor) = extern_variant.ctor_def_id()
152 && let Some(ctor) = variant.data.ctor_def_id()
153 && self.tcx().def_kind(extern_ctor) == self.tcx().def_kind(ctor)
154 {
155 self.insert_extern_id(ctor, extern_ctor)?;
156 } else {
157 let reason = format!(
158 "extern variant `{}` incompatible with specified `{}`",
159 extern_variant.ident(self.tcx()),
160 rustc_hir_pretty::id_to_string(&self.tcx(), variant.hir_id)
161 );
162 return Err(self.invalid_enum_extern_spec(reason));
163 }
164 }
165 Ok(())
166 }
167
168 fn collect_extern_impl(
169 &mut self,
170 impl_id: OwnerId,
171 impl_: &hir::Impl,
172 attrs: FluxAttrs,
173 ) -> Result {
174 self.inner.collect_impl(impl_id, attrs)?;
175
176 let dummy_item = self.item_at(1)?;
177 self.inner.specs.insert_dummy(dummy_item.owner_id.def_id);
178
179 let mut impl_of_trait = None;
181 let mut local_trait_self_ty = None;
182 if let hir::ItemKind::Impl(dummy_impl) = &dummy_item.kind {
183 let (extern_id, self_ty) =
184 self.extract_extern_id_from_impl(dummy_item.owner_id, dummy_impl)?;
185 impl_of_trait = Some(extern_id);
186 local_trait_self_ty = Some(self_ty);
187
188 self.inner
189 .specs
190 .insert_dummy(self.item_at(2)?.owner_id.def_id);
191 }
192
193 let mut extern_impl_id = impl_of_trait;
194 for item_id in impl_.items {
195 let item = self.tcx().hir_impl_item(*item_id);
196 let extern_item = if let hir::ImplItemKind::Fn { .. } = item.kind {
197 let attrs = self
198 .inner
199 .parse_attrs_and_report_dups(item_id.owner_id.def_id)?;
200 self.collect_extern_impl_fn(impl_of_trait, item, attrs)?
201 } else {
202 continue;
203 };
204
205 if *extern_impl_id.get_or_insert(extern_item.impl_id) != extern_item.impl_id {
206 return Err(self.invalid_impl_block());
207 }
208 }
209
210 if let Some(extern_impl_id) = extern_impl_id {
211 self.check_generics(impl_id, extern_impl_id)?;
212 if let Some(local_self_ty) = local_trait_self_ty {
214 self.check_extern_impl_self_ty(impl_id, local_self_ty, extern_impl_id)?;
215 }
216 self.insert_extern_id(impl_id.def_id, extern_impl_id)?;
217 }
218
219 Ok(())
220 }
221
222 fn collect_extern_impl_fn(
223 &mut self,
224 impl_of_trait: Option<DefId>,
225 item: &hir::ImplItem,
226 mut attrs: FluxAttrs,
227 ) -> Result<ExternImplItem> {
228 if attrs.has_attrs() {
229 let (sig, attr_span) = if let Some((sig, span)) = attrs.fn_sig_with_attr_span() {
230 (Some(sig), Some(span))
231 } else {
232 (None, None)
233 };
234 self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
235 let node_id = self.inner.next_node_id();
236 self.inner.insert_impl_item(
237 item.owner_id,
238 surface::ImplItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
239 )?;
240 if let Some(span) = attr_span {
241 self.inner
242 .specs
243 .set_spec_attr_span(item.owner_id.def_id.to_def_id(), span);
244 }
245 }
246
247 let extern_impl_item = self.extract_extern_id_from_impl_fn(impl_of_trait, item)?;
248 self.insert_extern_id(item.owner_id.def_id, extern_impl_item.item_id)?;
249 self.check_generics(item.owner_id, extern_impl_item.item_id)?;
250
251 Ok(extern_impl_item)
252 }
253
254 fn collect_extern_trait(
255 &mut self,
256 trait_id: OwnerId,
257 bounds: &hir::GenericBounds,
258 items: &[hir::TraitItemId],
259 attrs: FluxAttrs,
260 ) -> Result {
261 self.inner.collect_trait(trait_id, attrs)?;
262
263 let extern_trait_id = self.extract_extern_id_from_trait(bounds)?;
264 self.insert_extern_id(trait_id.def_id, extern_trait_id)?;
265 self.check_generics(trait_id, extern_trait_id)?;
266
267 for item_id in items {
268 let item = self.tcx().hir_trait_item(*item_id);
269 if let hir::TraitItemKind::Fn { .. } = item.kind {
270 let attrs = self
271 .inner
272 .parse_attrs_and_report_dups(item.owner_id.def_id)?;
273 self.collect_extern_trait_fn(extern_trait_id, item, attrs)?;
274 } else {
275 continue;
276 }
277 }
278
279 Ok(())
280 }
281
282 fn collect_extern_trait_fn(
283 &mut self,
284 extern_trait_id: DefId,
285 item: &hir::TraitItem,
286 mut attrs: FluxAttrs,
287 ) -> Result {
288 let item_id = item.owner_id;
289 if attrs.has_attrs() {
290 let (sig, attr_span) = if let Some((sig, span)) = attrs.fn_sig_with_attr_span() {
291 (Some(sig), Some(span))
292 } else {
293 (None, None)
294 };
295 self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
296 let node_id = self.inner.next_node_id();
297 self.inner.insert_trait_item(
298 item.owner_id,
299 surface::TraitItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
300 )?;
301 if let Some(span) = attr_span {
302 self.inner
303 .specs
304 .set_spec_attr_span(item.owner_id.def_id.to_def_id(), span);
305 }
306 }
307
308 let extern_fn_id = self.extract_extern_id_from_trait_fn(extern_trait_id, item)?;
309 self.insert_extern_id(item.owner_id.def_id, extern_fn_id)?;
310 self.check_generics(item_id, extern_fn_id)?;
311
312 Ok(())
313 }
314
315 fn extract_extern_id_from_struct(&self, item: &hir::Item) -> Result<DefId> {
316 if let hir::ItemKind::Struct(_, _, data) = item.kind
317 && let Some(extern_field) = data.fields().last()
318 && let ty = self.tcx().type_of(extern_field.def_id)
319 && let Some(adt_def) = ty.skip_binder().ty_adt_def()
320 {
321 Ok(adt_def.did())
322 } else {
323 Err(self.malformed())
324 }
325 }
326
327 fn extract_extern_id_from_fn(&self, item: &hir::Item) -> Result<DefId> {
328 if let hir::ItemKind::Fn { body, .. } = item.kind {
329 self.extract_callee_from_body(body)
330 } else {
331 Err(self.malformed())
332 }
333 }
334
335 fn extract_extern_id_from_impl_fn(
336 &self,
337 impl_of_trait: Option<DefId>,
338 item: &hir::ImplItem,
339 ) -> Result<ExternImplItem> {
340 if let hir::ImplItemKind::Fn(_, body_id) = item.kind {
341 let callee_id = self.extract_callee_from_body(body_id)?;
342 if let Some(extern_impl_id) = impl_of_trait {
343 let map = self.tcx().impl_item_implementor_ids(extern_impl_id);
344 if let Some(extern_item_id) = map.get(&callee_id) {
345 Ok(ExternImplItem { impl_id: extern_impl_id, item_id: *extern_item_id })
346 } else {
347 Err(self.item_not_in_trait_impl(item.owner_id, callee_id, extern_impl_id))
348 }
349 } else {
350 let opt_extern_impl_id = self.tcx().impl_of_assoc(callee_id);
351 if let Some(extern_impl_id) = opt_extern_impl_id {
352 debug_assert!(!self.tcx().impl_is_of_trait(extern_impl_id));
353 Ok(ExternImplItem { impl_id: extern_impl_id, item_id: callee_id })
354 } else {
355 Err(self.invalid_item_in_inherent_impl(item.owner_id, callee_id))
356 }
357 }
358 } else {
359 Err(self.malformed())
360 }
361 }
362
363 fn extract_extern_id_from_trait(&self, bounds: &hir::GenericBounds) -> Result<DefId> {
364 if let Some(bound) = bounds.first()
365 && let Some(trait_ref) = bound.trait_ref()
366 && let Some(trait_id) = trait_ref.trait_def_id()
367 {
368 Ok(trait_id)
369 } else {
370 Err(self.malformed())
371 }
372 }
373
374 fn extract_extern_id_from_trait_fn(
375 &self,
376 trait_id: DefId,
377 item: &hir::TraitItem,
378 ) -> Result<DefId> {
379 if let hir::TraitItemKind::Fn(_, trait_fn) = item.kind
380 && let hir::TraitFn::Provided(body_id) = trait_fn
381 {
382 let callee_id = self.extract_callee_from_body(body_id)?;
383 if let Some(callee_trait_id) = self.tcx().trait_of_assoc(callee_id)
384 && trait_id == callee_trait_id
385 {
386 Ok(callee_id)
387 } else {
388 Err(self.item_not_in_trait(item.owner_id, callee_id, trait_id))
391 }
392 } else {
393 Err(self.malformed())
394 }
395 }
396
397 fn extract_extern_id_from_impl(
398 &self,
399 impl_id: OwnerId,
400 impl_: &hir::Impl,
401 ) -> Result<(DefId, ty::Ty<'tcx>)> {
402 if let Some(item_id) = impl_.items.first()
403 && let hir::ImplItemKind::Fn { .. } = self.tcx().hir_impl_item(*item_id).kind
404 && let Some((clause, _)) = self
405 .tcx()
406 .clauses_of(item_id.owner_id.def_id)
407 .clauses
408 .first()
409 && let Some(poly_trait_pred) = clause.as_trait_clause()
410 && let Some(trait_pred) = poly_trait_pred.no_bound_vars()
411 {
412 let trait_ref = trait_pred.trait_ref;
413 let local_self_ty = trait_ref.self_ty();
414 lowering::resolve_trait_ref_impl_id(self.tcx(), impl_id.to_def_id(), trait_ref)
415 .map(|(impl_id, _)| (impl_id, local_self_ty))
416 .ok_or_else(|| self.cannot_resolve_trait_impl())
417 } else {
418 Err(self.malformed())
419 }
420 }
421
422 fn extract_callee_from_body(&self, body_id: hir::BodyId) -> Result<DefId> {
423 let owner = self.tcx().hir_body_owner_def_id(body_id);
424 let typeck = self.tcx().typeck(owner);
425 if let hir::ExprKind::Block(b, _) = self.tcx().hir_body(body_id).value.kind
426 && let Some(e) = b.expr
427 {
428 let call_expr =
430 if let hir::ExprKind::Block(inner_b, _) = e.kind { inner_b.expr } else { Some(e) };
431 if let Some(e) = call_expr
432 && let hir::ExprKind::Call(callee, _) = e.kind
433 && let rustc_middle::ty::FnDef(callee_id, _) =
434 typeck.node_type(callee.hir_id).kind()
435 {
436 return Ok(*callee_id);
437 }
438 }
439 Err(self.malformed())
440 }
441
442 #[track_caller]
444 fn item_at(&self, i: usize) -> Result<&'tcx hir::Item<'tcx>> {
445 let stmts = self.block.stmts;
446 let index = stmts
447 .len()
448 .checked_sub(i + 1)
449 .ok_or_else(|| self.malformed())?;
450 let st = stmts.get(index).ok_or_else(|| self.malformed())?;
451 if let hir::StmtKind::Item(item_id) = st.kind {
452 Ok(self.tcx().hir_item(item_id))
453 } else {
454 Err(self.malformed())
455 }
456 }
457
458 fn insert_extern_id(&mut self, local_id: LocalDefId, extern_id: DefId) -> Result {
459 self.inner
460 .specs
461 .insert_extern_spec_id_mapping(local_id, extern_id)
462 .map_err(|err| {
463 match err {
464 ExternSpecMappingErr::IsLocal(extern_id_local) => {
465 self.emit(errors::ExternSpecForLocalDef {
466 span: ident_or_def_span(self.tcx(), local_id),
467 local_def_span: ident_or_def_span(self.tcx(), extern_id_local),
468 name: self.tcx().def_path_str(extern_id),
469 })
470 }
471 ExternSpecMappingErr::Dup(previous_extern_spec) => {
472 self.emit(errors::DupExternSpec {
473 span: ident_or_def_span(self.tcx(), local_id),
474 previous_span: ident_or_def_span(self.tcx(), previous_extern_spec),
475 name: self.tcx().def_path_str(extern_id),
476 })
477 }
478 }
479 })
480 }
481
482 fn check_generics(&mut self, local_id: OwnerId, extern_id: DefId) -> Result {
483 let tcx = self.tcx();
484 let local_params = &tcx.generics_of(local_id).own_params;
485 let extern_params = &tcx.generics_of(extern_id).own_params;
486
487 let mismatch = 'mismatch: {
488 if local_params.len() != extern_params.len() {
489 break 'mismatch true;
490 }
491 for (local_param, extern_param) in iter::zip(local_params, extern_params) {
492 if !cmp_generic_param_def(local_param, extern_param) {
493 break 'mismatch true;
494 }
495 if local_param.name != kw::SelfUpper {
498 #[expect(clippy::disallowed_methods)]
499 self.insert_extern_id(local_param.def_id.expect_local(), extern_param.def_id)?;
500 }
501 }
502 false
503 };
504 if mismatch {
505 let local_hir_generics = tcx.hir_get_generics(local_id.def_id).unwrap();
506 let span = local_hir_generics.span;
507 Err(self.emit(errors::MismatchedGenerics {
508 span,
509 extern_def: tcx.def_span(extern_id),
510 def_descr: tcx.def_descr(extern_id),
511 }))
512 } else {
513 Ok(())
514 }
515 }
516
517 fn check_extern_impl_self_ty(
518 &mut self,
519 local_impl_id: OwnerId,
520 local_self_ty: ty::Ty<'tcx>,
521 extern_impl_id: DefId,
522 ) -> Result {
523 let tcx = self.tcx();
524
525 let local_args = ty::GenericArgs::identity_for_item(tcx, local_impl_id);
527 let extern_self_ty = tcx
528 .type_of(extern_impl_id)
529 .instantiate(tcx, local_args)
530 .skip_norm_wip();
531
532 if local_self_ty != extern_self_ty {
538 let span = tcx.def_span(local_impl_id);
542 Err(self.emit(errors::MismatchedImplSelfTy {
543 span,
544 local_self_ty: local_self_ty.to_string(),
545 extern_self_ty: extern_self_ty.to_string(),
546 extern_impl_span: tcx.def_span(extern_impl_id),
547 }))
548 } else {
549 Ok(())
550 }
551 }
552
553 #[track_caller]
554 fn malformed(&self) -> ErrorGuaranteed {
555 self.emit(errors::MalformedExternSpec::new(self.block.span))
556 }
557
558 #[track_caller]
559 fn invalid_enum_extern_spec(&self, reason: String) -> ErrorGuaranteed {
560 self.emit(errors::InvalidEnumExternSpec::new(self.block.span, reason))
561 }
562
563 #[track_caller]
564 fn item_not_in_trait_impl(
565 &self,
566 local_id: OwnerId,
567 extern_id: DefId,
568 extern_impl_id: DefId,
569 ) -> ErrorGuaranteed {
570 let tcx = self.tcx();
571 self.emit(errors::ItemNotInTraitImpl {
572 span: ident_or_def_span(tcx, local_id),
573 name: tcx.def_path_str(extern_id),
574 extern_impl_span: tcx.def_span(extern_impl_id),
575 })
576 }
577
578 fn invalid_item_in_inherent_impl(
579 &self,
580 local_id: OwnerId,
581 extern_id: DefId,
582 ) -> ErrorGuaranteed {
583 let tcx = self.tcx();
584 self.emit(errors::InvalidItemInInherentImpl {
585 span: ident_or_def_span(tcx, local_id),
586 name: tcx.def_path_str(extern_id),
587 extern_item_span: tcx.def_span(extern_id),
588 })
589 }
590
591 #[track_caller]
592 fn invalid_impl_block(&self) -> ErrorGuaranteed {
593 self.emit(errors::InvalidImplBlock { span: self.block.span })
594 }
595
596 #[track_caller]
597 fn cannot_resolve_trait_impl(&self) -> ErrorGuaranteed {
598 self.emit(errors::CannotResolveTraitImpl { span: self.block.span })
599 }
600
601 #[track_caller]
602 fn item_not_in_trait(
603 &self,
604 local_id: OwnerId,
605 extern_id: DefId,
606 extern_trait_id: DefId,
607 ) -> ErrorGuaranteed {
608 let tcx = self.tcx();
609 self.emit(errors::ItemNotInTrait {
610 span: ident_or_def_span(tcx, local_id),
611 name: tcx.def_path_str(extern_id),
612 extern_trait_span: tcx.def_span(extern_trait_id),
613 })
614 }
615
616 #[track_caller]
617 fn emit<'b>(&'b self, err: impl Diagnostic<'b>) -> ErrorGuaranteed {
618 self.inner.errors.emit(err)
619 }
620
621 fn tcx(&self) -> TyCtxt<'tcx> {
622 self.inner.tcx
623 }
624}
625
626fn cmp_generic_param_def(a: &ty::GenericParamDef, b: &ty::GenericParamDef) -> bool {
627 if a.name != b.name && !b.is_anonymous_lifetime() {
628 return false;
629 }
630 if a.index != b.index {
631 return false;
632 }
633 matches!(
634 (&a.kind, &b.kind),
635 (ty::GenericParamDefKind::Lifetime, ty::GenericParamDefKind::Lifetime)
636 | (ty::GenericParamDefKind::Type { .. }, ty::GenericParamDefKind::Type { .. })
637 | (ty::GenericParamDefKind::Const { .. }, ty::GenericParamDefKind::Const { .. })
638 )
639}
640
641fn ident_or_def_span(tcx: TyCtxt, def_id: impl Into<DefId>) -> Span {
642 let def_id = def_id.into();
643 tcx.def_ident_span(def_id)
644 .unwrap_or_else(|| tcx.def_span(def_id))
645}
646
647mod errors {
648 use flux_errors::E0999;
649 use flux_macros::Diagnostic;
650 use rustc_span::Span;
651
652 #[derive(Diagnostic)]
653 #[diag("malformed extern_spec, this should never happen if you are using the extern_spec macro. Did you accidentally use the internal flux::extern_spec attribute?", code = E0999)]
654 pub(super) struct MalformedExternSpec {
655 #[primary_span]
656 span: Span,
657 }
658
659 impl MalformedExternSpec {
660 pub(super) fn new(span: Span) -> Self {
661 Self { span }
662 }
663 }
664
665 #[derive(Diagnostic)]
666 #[diag("invalid extern_spec for enum: {$reason}", code = E0999)]
667 pub(super) struct InvalidEnumExternSpec {
668 #[primary_span]
669 span: Span,
670 reason: String,
671 }
672
673 impl InvalidEnumExternSpec {
674 pub(super) fn new(span: Span, reason: String) -> Self {
675 Self { span, reason }
676 }
677 }
678
679 #[derive(Diagnostic)]
680 #[diag("cannot resolve trait implementation", code = E0999)]
681 #[note("this is probably a bug in Flux")]
682 pub(super) struct CannotResolveTraitImpl {
683 #[primary_span]
684 pub span: Span,
685 }
686
687 #[derive(Diagnostic)]
688 #[diag("invalid impl extern spec", code = E0999)]
689 pub(super) struct InvalidImplBlock {
690 #[primary_span]
691 #[label("items in this extern spec are not defined in the same extern impl block")]
692 pub span: Span,
693 }
694
695 #[derive(Diagnostic)]
696 #[diag("invalid extern spec for trait impl", code = E0999)]
697 pub(super) struct ItemNotInTraitImpl {
698 #[primary_span]
699 #[label("`{$name}` is not defined in extern trait impl")]
700 pub span: Span,
701 pub name: String,
702 #[note("extern trait impl defined here")]
703 pub extern_impl_span: Span,
704 }
705
706 #[derive(Diagnostic)]
707 #[diag("invalid extern spec for inherent impl", code = E0999)]
708 pub(super) struct InvalidItemInInherentImpl {
709 #[primary_span]
710 #[label("`{$name}` is not a member of an inherent impl")]
711 pub span: Span,
712 pub name: String,
713 #[note("`{$name}` defined here")]
714 pub extern_item_span: Span,
715 }
716
717 #[derive(Diagnostic)]
718 #[diag("invalid extern spec for trait", code = E0999)]
719 pub(super) struct ItemNotInTrait {
720 #[primary_span]
721 #[label("`{$name}` is not defined in extern trait")]
722 pub span: Span,
723 pub name: String,
724 #[note("extern trait defined here")]
725 pub extern_trait_span: Span,
726 }
727
728 #[derive(Diagnostic)]
729 #[diag("cannot add extern specs to local definition", code = E0999)]
730 pub(super) struct ExternSpecForLocalDef {
731 #[primary_span]
732 pub span: Span,
733 #[help(
734 "`{$name}` defined here in the same crate, use a detached spec https://flux-rs.github.io/flux/guide/specifications.html?highlight=detached#detached-specifications"
735 )]
736 pub local_def_span: Span,
737 pub name: String,
738 }
739
740 #[derive(Diagnostic)]
741 #[diag("multiple extern specs for `{$name}`", code = E0999)]
742 pub(super) struct DupExternSpec {
743 #[primary_span]
744 #[label("extern spec for `{$name}` redefined here")]
745 pub span: Span,
746 #[note("previous extern spec for `{$name}` defined here")]
747 pub previous_span: Span,
748 pub name: String,
749 }
750
751 #[derive(Diagnostic)]
752 #[diag("invalid extern spec for {$def_descr}", code = E0999)]
753 #[note(
754 "extern specs must exactly match the external definition, including the list of generic parameters and their names"
755 )]
756 pub(super) struct MismatchedGenerics {
757 #[primary_span]
758 #[label("generic parameters don't match the external {$def_descr}")]
759 pub span: Span,
760 #[label("external {$def_descr} found here")]
761 pub extern_def: Span,
762 pub def_descr: &'static str,
763 }
764
765 #[derive(Diagnostic)]
766 #[diag("invalid extern spec for trait impl", code = E0999)]
767 #[note(
768 "the self type in an extern spec for a trait impl must exactly match the external implementation"
769 )]
770 pub(super) struct MismatchedImplSelfTy {
771 #[primary_span]
772 #[label("self type `{$local_self_ty}` doesn't match the external trait impl")]
773 pub span: Span,
774 pub local_self_ty: String,
775 pub extern_self_ty: String,
776 #[label("external trait impl has self type `{$extern_self_ty}`")]
777 pub extern_impl_span: Span,
778 }
779}