flux_driver/collector/
extern_specs.rs

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    /// The block corresponding to the `const _: () = { ... }` annotated with `flux::extern_spec`
22    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 = attrs.fn_sig();
72            self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
73            let node_id = self.inner.next_node_id();
74            self.inner.insert_item(
75                item.owner_id,
76                surface::Item {
77                    attrs: attrs.into_attr_vec(),
78                    kind: surface::ItemKind::Fn(sig),
79                    node_id,
80                },
81            )?;
82        }
83
84        let extern_id = self.extract_extern_id_from_fn(item)?;
85        self.insert_extern_id(item.owner_id.def_id, extern_id)?;
86        self.check_generics(item.owner_id, extern_id)?;
87
88        Ok(())
89    }
90
91    fn collect_extern_struct(
92        &mut self,
93        struct_id: OwnerId,
94        variant: &hir::VariantData,
95        attrs: FluxAttrs,
96    ) -> Result {
97        let dummy_struct = self.item_at(1)?;
98        self.inner.specs.insert_dummy(dummy_struct.owner_id.def_id);
99
100        let extern_id = self.extract_extern_id_from_struct(dummy_struct).unwrap();
101        self.insert_extern_id(struct_id.def_id, extern_id)?;
102        self.check_generics(struct_id, extern_id)?;
103
104        if let Some(ctor_id) = variant.ctor_def_id() {
105            self.inner.specs.insert_dummy(ctor_id);
106        }
107
108        self.inner.collect_struct_def(struct_id, attrs, variant)?;
109
110        Ok(())
111    }
112
113    fn collect_extern_enum(
114        &mut self,
115        enum_id: OwnerId,
116        enum_def: &hir::EnumDef,
117        attrs: FluxAttrs,
118    ) -> Result {
119        let dummy_struct = self.item_at(1)?;
120        self.inner.specs.insert_dummy(dummy_struct.owner_id.def_id);
121
122        let extern_id = self.extract_extern_id_from_struct(dummy_struct).unwrap();
123        self.insert_extern_id(enum_id.def_id, extern_id)?;
124        self.check_generics(enum_id, extern_id)?;
125
126        self.inner.collect_enum_def(enum_id, attrs, enum_def)?;
127
128        // Add stuff about Ctor
129        // Get the AdtDef for the enum
130        let extern_enum_def = self.tcx().adt_def(extern_id);
131
132        // Collect all constructor DefIds from variants
133        let extern_variants = extern_enum_def.variants();
134        let enum_variants = enum_def.variants;
135        let extern_len = extern_variants.len();
136        let enum_len = enum_variants.len();
137        if extern_len != enum_len {
138            let reason = format!("expected {extern_len:?} variants but only have {enum_len:?}");
139            return Err(self.invalid_enum_extern_spec(reason));
140        }
141        for (extern_variant, variant) in extern_enum_def.variants().iter().zip(enum_def.variants) {
142            if let Some(extern_ctor) = extern_variant.ctor_def_id()
143                && let Some(ctor) = variant.data.ctor_def_id()
144                && self.tcx().def_kind(extern_ctor) == self.tcx().def_kind(ctor)
145            {
146                self.insert_extern_id(ctor, extern_ctor)?;
147            } else {
148                let reason = format!(
149                    "extern variant `{}` incompatible with specified `{}`",
150                    extern_variant.ident(self.tcx()),
151                    rustc_hir_pretty::id_to_string(&self.tcx(), variant.hir_id)
152                );
153                return Err(self.invalid_enum_extern_spec(reason));
154            }
155        }
156        Ok(())
157    }
158
159    fn collect_extern_impl(
160        &mut self,
161        impl_id: OwnerId,
162        impl_: &hir::Impl,
163        attrs: FluxAttrs,
164    ) -> Result {
165        self.inner.collect_impl(impl_id, attrs)?;
166
167        let dummy_item = self.item_at(1)?;
168        self.inner.specs.insert_dummy(dummy_item.owner_id.def_id);
169
170        // If this is a trait impl compute the impl_id from the trait_ref
171        let mut impl_of_trait = None;
172        let mut local_trait_self_ty = None;
173        if let hir::ItemKind::Impl(dummy_impl) = &dummy_item.kind {
174            let (extern_id, self_ty) =
175                self.extract_extern_id_from_impl(dummy_item.owner_id, dummy_impl)?;
176            impl_of_trait = Some(extern_id);
177            local_trait_self_ty = Some(self_ty);
178
179            self.inner
180                .specs
181                .insert_dummy(self.item_at(2)?.owner_id.def_id);
182        }
183
184        let mut extern_impl_id = impl_of_trait;
185        for item_id in impl_.items {
186            let item = self.tcx().hir_impl_item(*item_id);
187            let extern_item = if let hir::ImplItemKind::Fn { .. } = item.kind {
188                let attrs = self
189                    .inner
190                    .parse_attrs_and_report_dups(item_id.owner_id.def_id)?;
191                self.collect_extern_impl_fn(impl_of_trait, item, attrs)?
192            } else {
193                continue;
194            };
195
196            if *extern_impl_id.get_or_insert(extern_item.impl_id) != extern_item.impl_id {
197                return Err(self.invalid_impl_block());
198            }
199        }
200
201        if let Some(extern_impl_id) = extern_impl_id {
202            self.check_generics(impl_id, extern_impl_id)?;
203            // For trait impls, check that the self type matches the external definition
204            if let Some(local_self_ty) = local_trait_self_ty {
205                self.check_extern_impl_self_ty(impl_id, local_self_ty, extern_impl_id)?;
206            }
207            self.insert_extern_id(impl_id.def_id, extern_impl_id)?;
208        }
209
210        Ok(())
211    }
212
213    fn collect_extern_impl_fn(
214        &mut self,
215        impl_of_trait: Option<DefId>,
216        item: &hir::ImplItem,
217        mut attrs: FluxAttrs,
218    ) -> Result<ExternImplItem> {
219        if attrs.has_attrs() {
220            let sig = attrs.fn_sig();
221            self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
222            let node_id = self.inner.next_node_id();
223            self.inner.insert_impl_item(
224                item.owner_id,
225                surface::ImplItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
226            )?;
227        }
228
229        let extern_impl_item = self.extract_extern_id_from_impl_fn(impl_of_trait, item)?;
230        self.insert_extern_id(item.owner_id.def_id, extern_impl_item.item_id)?;
231        self.check_generics(item.owner_id, extern_impl_item.item_id)?;
232
233        Ok(extern_impl_item)
234    }
235
236    fn collect_extern_trait(
237        &mut self,
238        trait_id: OwnerId,
239        bounds: &hir::GenericBounds,
240        items: &[hir::TraitItemId],
241        attrs: FluxAttrs,
242    ) -> Result {
243        self.inner.collect_trait(trait_id, attrs)?;
244
245        let extern_trait_id = self.extract_extern_id_from_trait(bounds)?;
246        self.insert_extern_id(trait_id.def_id, extern_trait_id)?;
247        self.check_generics(trait_id, extern_trait_id)?;
248
249        for item_id in items {
250            let item = self.tcx().hir_trait_item(*item_id);
251            if let hir::TraitItemKind::Fn { .. } = item.kind {
252                let attrs = self
253                    .inner
254                    .parse_attrs_and_report_dups(item.owner_id.def_id)?;
255                self.collect_extern_trait_fn(extern_trait_id, item, attrs)?;
256            } else {
257                continue;
258            }
259        }
260
261        Ok(())
262    }
263
264    fn collect_extern_trait_fn(
265        &mut self,
266        extern_trait_id: DefId,
267        item: &hir::TraitItem,
268        mut attrs: FluxAttrs,
269    ) -> Result {
270        let item_id = item.owner_id;
271        if attrs.has_attrs() {
272            let sig = attrs.fn_sig();
273            self.inner.check_fn_sig_name(item.owner_id, sig.as_ref())?;
274            let node_id = self.inner.next_node_id();
275            self.inner.insert_trait_item(
276                item.owner_id,
277                surface::TraitItemFn { attrs: attrs.into_attr_vec(), sig, node_id },
278            )?;
279        }
280
281        let extern_fn_id = self.extract_extern_id_from_trait_fn(extern_trait_id, item)?;
282        self.insert_extern_id(item.owner_id.def_id, extern_fn_id)?;
283        self.check_generics(item_id, extern_fn_id)?;
284
285        Ok(())
286    }
287
288    fn extract_extern_id_from_struct(&self, item: &hir::Item) -> Result<DefId> {
289        if let hir::ItemKind::Struct(_, _, data) = item.kind
290            && let Some(extern_field) = data.fields().last()
291            && let ty = self.tcx().type_of(extern_field.def_id)
292            && let Some(adt_def) = ty.skip_binder().ty_adt_def()
293        {
294            Ok(adt_def.did())
295        } else {
296            Err(self.malformed())
297        }
298    }
299
300    fn extract_extern_id_from_fn(&self, item: &hir::Item) -> Result<DefId> {
301        if let hir::ItemKind::Fn { body, .. } = item.kind {
302            self.extract_callee_from_body(body)
303        } else {
304            Err(self.malformed())
305        }
306    }
307
308    fn extract_extern_id_from_impl_fn(
309        &self,
310        impl_of_trait: Option<DefId>,
311        item: &hir::ImplItem,
312    ) -> Result<ExternImplItem> {
313        if let hir::ImplItemKind::Fn(_, body_id) = item.kind {
314            let callee_id = self.extract_callee_from_body(body_id)?;
315            if let Some(extern_impl_id) = impl_of_trait {
316                let map = self.tcx().impl_item_implementor_ids(extern_impl_id);
317                if let Some(extern_item_id) = map.get(&callee_id) {
318                    Ok(ExternImplItem { impl_id: extern_impl_id, item_id: *extern_item_id })
319                } else {
320                    Err(self.item_not_in_trait_impl(item.owner_id, callee_id, extern_impl_id))
321                }
322            } else {
323                let opt_extern_impl_id = self.tcx().impl_of_assoc(callee_id);
324                if let Some(extern_impl_id) = opt_extern_impl_id {
325                    debug_assert!(!self.tcx().impl_is_of_trait(extern_impl_id));
326                    Ok(ExternImplItem { impl_id: extern_impl_id, item_id: callee_id })
327                } else {
328                    Err(self.invalid_item_in_inherent_impl(item.owner_id, callee_id))
329                }
330            }
331        } else {
332            Err(self.malformed())
333        }
334    }
335
336    fn extract_extern_id_from_trait(&self, bounds: &hir::GenericBounds) -> Result<DefId> {
337        if let Some(bound) = bounds.first()
338            && let Some(trait_ref) = bound.trait_ref()
339            && let Some(trait_id) = trait_ref.trait_def_id()
340        {
341            Ok(trait_id)
342        } else {
343            Err(self.malformed())
344        }
345    }
346
347    fn extract_extern_id_from_trait_fn(
348        &self,
349        trait_id: DefId,
350        item: &hir::TraitItem,
351    ) -> Result<DefId> {
352        if let hir::TraitItemKind::Fn(_, trait_fn) = item.kind
353            && let hir::TraitFn::Provided(body_id) = trait_fn
354        {
355            let callee_id = self.extract_callee_from_body(body_id)?;
356            if let Some(callee_trait_id) = self.tcx().trait_of_assoc(callee_id)
357                && trait_id == callee_trait_id
358            {
359                Ok(callee_id)
360            } else {
361                // I can't figure out how to trigger this via code generated with the extern spec
362                // macro that also type checks but leaving it here as a precaution.
363                Err(self.item_not_in_trait(item.owner_id, callee_id, trait_id))
364            }
365        } else {
366            Err(self.malformed())
367        }
368    }
369
370    fn extract_extern_id_from_impl(
371        &self,
372        impl_id: OwnerId,
373        impl_: &hir::Impl,
374    ) -> Result<(DefId, ty::Ty<'tcx>)> {
375        if let Some(item_id) = impl_.items.first()
376            && let hir::ImplItemKind::Fn { .. } = self.tcx().hir_impl_item(*item_id).kind
377            && let Some((clause, _)) = self
378                .tcx()
379                .predicates_of(item_id.owner_id.def_id)
380                .predicates
381                .first()
382            && let Some(poly_trait_pred) = clause.as_trait_clause()
383            && let Some(trait_pred) = poly_trait_pred.no_bound_vars()
384        {
385            let trait_ref = trait_pred.trait_ref;
386            let local_self_ty = trait_ref.self_ty();
387            lowering::resolve_trait_ref_impl_id(self.tcx(), impl_id.to_def_id(), trait_ref)
388                .map(|(impl_id, _)| (impl_id, local_self_ty))
389                .ok_or_else(|| self.cannot_resolve_trait_impl())
390        } else {
391            Err(self.malformed())
392        }
393    }
394
395    fn extract_callee_from_body(&self, body_id: hir::BodyId) -> Result<DefId> {
396        let owner = self.tcx().hir_body_owner_def_id(body_id);
397        let typeck = self.tcx().typeck(owner);
398        if let hir::ExprKind::Block(b, _) = self.tcx().hir_body(body_id).value.kind
399            && let Some(e) = b.expr
400        {
401            // Peel through an optional `unsafe { ... }` block
402            let call_expr =
403                if let hir::ExprKind::Block(inner_b, _) = e.kind { inner_b.expr } else { Some(e) };
404            if let Some(e) = call_expr
405                && let hir::ExprKind::Call(callee, _) = e.kind
406                && let rustc_middle::ty::FnDef(callee_id, _) =
407                    typeck.node_type(callee.hir_id).kind()
408            {
409                return Ok(*callee_id);
410            }
411        }
412        Err(self.malformed())
413    }
414
415    /// Returns the item inside the const block at position `i` starting from the end.
416    #[track_caller]
417    fn item_at(&self, i: usize) -> Result<&'tcx hir::Item<'tcx>> {
418        let stmts = self.block.stmts;
419        let index = stmts
420            .len()
421            .checked_sub(i + 1)
422            .ok_or_else(|| self.malformed())?;
423        let st = stmts.get(index).ok_or_else(|| self.malformed())?;
424        if let hir::StmtKind::Item(item_id) = st.kind {
425            Ok(self.tcx().hir_item(item_id))
426        } else {
427            Err(self.malformed())
428        }
429    }
430
431    fn insert_extern_id(&mut self, local_id: LocalDefId, extern_id: DefId) -> Result {
432        self.inner
433            .specs
434            .insert_extern_spec_id_mapping(local_id, extern_id)
435            .map_err(|err| {
436                match err {
437                    ExternSpecMappingErr::IsLocal(extern_id_local) => {
438                        self.emit(errors::ExternSpecForLocalDef {
439                            span: ident_or_def_span(self.tcx(), local_id),
440                            local_def_span: ident_or_def_span(self.tcx(), extern_id_local),
441                            name: self.tcx().def_path_str(extern_id),
442                        })
443                    }
444                    ExternSpecMappingErr::Dup(previous_extern_spec) => {
445                        self.emit(errors::DupExternSpec {
446                            span: ident_or_def_span(self.tcx(), local_id),
447                            previous_span: ident_or_def_span(self.tcx(), previous_extern_spec),
448                            name: self.tcx().def_path_str(extern_id),
449                        })
450                    }
451                }
452            })
453    }
454
455    fn check_generics(&mut self, local_id: OwnerId, extern_id: DefId) -> Result {
456        let tcx = self.tcx();
457        let local_params = &tcx.generics_of(local_id).own_params;
458        let extern_params = &tcx.generics_of(extern_id).own_params;
459
460        let mismatch = 'mismatch: {
461            if local_params.len() != extern_params.len() {
462                break 'mismatch true;
463            }
464            for (local_param, extern_param) in iter::zip(local_params, extern_params) {
465                if !cmp_generic_param_def(local_param, extern_param) {
466                    break 'mismatch true;
467                }
468                // We skip the self parameter because its id is the same as the trait's id, which
469                // has already been inserted.
470                if local_param.name != kw::SelfUpper {
471                    #[expect(clippy::disallowed_methods)]
472                    self.insert_extern_id(local_param.def_id.expect_local(), extern_param.def_id)?;
473                }
474            }
475            false
476        };
477        if mismatch {
478            let local_hir_generics = tcx.hir_get_generics(local_id.def_id).unwrap();
479            let span = local_hir_generics.span;
480            Err(self.emit(errors::MismatchedGenerics {
481                span,
482                extern_def: tcx.def_span(extern_id),
483                def_descr: tcx.def_descr(extern_id),
484            }))
485        } else {
486            Ok(())
487        }
488    }
489
490    fn check_extern_impl_self_ty(
491        &mut self,
492        local_impl_id: OwnerId,
493        local_self_ty: ty::Ty<'tcx>,
494        extern_impl_id: DefId,
495    ) -> Result {
496        let tcx = self.tcx();
497
498        // Get the self type from the external impl
499        let extern_self_ty = tcx.type_of(extern_impl_id).instantiate_identity();
500
501        // Compare self types. `local_self_ty` is the user-written self type from the extern
502        // spec's trait_ref (not the `__FluxExternImplStruct` wrapper that the macro retargets
503        // the impl onto). After `check_generics` has verified param names and indices match,
504        // raw Ty equality is sound for the cases we want to catch (concrete type mismatches
505        // like `Range<usize>` vs `Range<A>`).
506        if local_self_ty != extern_self_ty {
507            // Emit on the user's impl block (compiletest matches `//~ ERROR` against the
508            // primary span line). The dummy `__FluxExternImplStruct` wrapper's self_ty has
509            // a macro-generated span that doesn't land on user source.
510            let span = tcx.def_span(local_impl_id);
511            Err(self.emit(errors::MismatchedImplSelfTy {
512                span,
513                local_self_ty: local_self_ty.to_string(),
514                extern_self_ty: extern_self_ty.to_string(),
515                extern_impl_span: tcx.def_span(extern_impl_id),
516            }))
517        } else {
518            Ok(())
519        }
520    }
521
522    #[track_caller]
523    fn malformed(&self) -> ErrorGuaranteed {
524        self.emit(errors::MalformedExternSpec::new(self.block.span))
525    }
526
527    #[track_caller]
528    fn invalid_enum_extern_spec(&self, reason: String) -> ErrorGuaranteed {
529        self.emit(errors::InvalidEnumExternSpec::new(self.block.span, reason))
530    }
531
532    #[track_caller]
533    fn item_not_in_trait_impl(
534        &self,
535        local_id: OwnerId,
536        extern_id: DefId,
537        extern_impl_id: DefId,
538    ) -> ErrorGuaranteed {
539        let tcx = self.tcx();
540        self.emit(errors::ItemNotInTraitImpl {
541            span: ident_or_def_span(tcx, local_id),
542            name: tcx.def_path_str(extern_id),
543            extern_impl_span: tcx.def_span(extern_impl_id),
544        })
545    }
546
547    fn invalid_item_in_inherent_impl(
548        &self,
549        local_id: OwnerId,
550        extern_id: DefId,
551    ) -> ErrorGuaranteed {
552        let tcx = self.tcx();
553        self.emit(errors::InvalidItemInInherentImpl {
554            span: ident_or_def_span(tcx, local_id),
555            name: tcx.def_path_str(extern_id),
556            extern_item_span: tcx.def_span(extern_id),
557        })
558    }
559
560    #[track_caller]
561    fn invalid_impl_block(&self) -> ErrorGuaranteed {
562        self.emit(errors::InvalidImplBlock { span: self.block.span })
563    }
564
565    #[track_caller]
566    fn cannot_resolve_trait_impl(&self) -> ErrorGuaranteed {
567        self.emit(errors::CannotResolveTraitImpl { span: self.block.span })
568    }
569
570    #[track_caller]
571    fn item_not_in_trait(
572        &self,
573        local_id: OwnerId,
574        extern_id: DefId,
575        extern_trait_id: DefId,
576    ) -> ErrorGuaranteed {
577        let tcx = self.tcx();
578        self.emit(errors::ItemNotInTrait {
579            span: ident_or_def_span(tcx, local_id),
580            name: tcx.def_path_str(extern_id),
581            extern_trait_span: tcx.def_span(extern_trait_id),
582        })
583    }
584
585    #[track_caller]
586    fn emit<'b>(&'b self, err: impl Diagnostic<'b>) -> ErrorGuaranteed {
587        self.inner.errors.emit(err)
588    }
589
590    fn tcx(&self) -> TyCtxt<'tcx> {
591        self.inner.tcx
592    }
593}
594
595fn cmp_generic_param_def(a: &ty::GenericParamDef, b: &ty::GenericParamDef) -> bool {
596    if a.name != b.name {
597        return false;
598    }
599    if a.index != b.index {
600        return false;
601    }
602    matches!(
603        (&a.kind, &b.kind),
604        (ty::GenericParamDefKind::Lifetime, ty::GenericParamDefKind::Lifetime)
605            | (ty::GenericParamDefKind::Type { .. }, ty::GenericParamDefKind::Type { .. })
606            | (ty::GenericParamDefKind::Const { .. }, ty::GenericParamDefKind::Const { .. })
607    )
608}
609
610fn ident_or_def_span(tcx: TyCtxt, def_id: impl Into<DefId>) -> Span {
611    let def_id = def_id.into();
612    tcx.def_ident_span(def_id)
613        .unwrap_or_else(|| tcx.def_span(def_id))
614}
615
616mod errors {
617    use flux_errors::E0999;
618    use flux_macros::Diagnostic;
619    use rustc_span::Span;
620
621    #[derive(Diagnostic)]
622    #[diag(driver_malformed_extern_spec, code = E0999)]
623    pub(super) struct MalformedExternSpec {
624        #[primary_span]
625        span: Span,
626    }
627
628    impl MalformedExternSpec {
629        pub(super) fn new(span: Span) -> Self {
630            Self { span }
631        }
632    }
633
634    #[derive(Diagnostic)]
635    #[diag(driver_invalid_enum_extern_spec, code = E0999)]
636    pub(super) struct InvalidEnumExternSpec {
637        #[primary_span]
638        span: Span,
639        reason: String,
640    }
641
642    impl InvalidEnumExternSpec {
643        pub(super) fn new(span: Span, reason: String) -> Self {
644            Self { span, reason }
645        }
646    }
647
648    #[derive(Diagnostic)]
649    #[diag(driver_cannot_resolve_trait_impl, code = E0999)]
650    #[note]
651    pub(super) struct CannotResolveTraitImpl {
652        #[primary_span]
653        pub span: Span,
654    }
655
656    #[derive(Diagnostic)]
657    #[diag(driver_invalid_impl_block, code = E0999)]
658    pub(super) struct InvalidImplBlock {
659        #[primary_span]
660        #[label]
661        pub span: Span,
662    }
663
664    #[derive(Diagnostic)]
665    #[diag(driver_item_not_in_trait_impl, code = E0999)]
666    pub(super) struct ItemNotInTraitImpl {
667        #[primary_span]
668        #[label]
669        pub span: Span,
670        pub name: String,
671        #[note]
672        pub extern_impl_span: Span,
673    }
674
675    #[derive(Diagnostic)]
676    #[diag(driver_invalid_item_in_inherent_impl, code = E0999)]
677    pub(super) struct InvalidItemInInherentImpl {
678        #[primary_span]
679        #[label]
680        pub span: Span,
681        pub name: String,
682        #[note]
683        pub extern_item_span: Span,
684    }
685
686    #[derive(Diagnostic)]
687    #[diag(driver_item_not_in_trait, code = E0999)]
688    pub(super) struct ItemNotInTrait {
689        #[primary_span]
690        #[label]
691        pub span: Span,
692        pub name: String,
693        #[note]
694        pub extern_trait_span: Span,
695    }
696
697    #[derive(Diagnostic)]
698    #[diag(driver_extern_spec_for_local_def, code = E0999)]
699    pub(super) struct ExternSpecForLocalDef {
700        #[primary_span]
701        pub span: Span,
702        #[help]
703        pub local_def_span: Span,
704        pub name: String,
705    }
706
707    #[derive(Diagnostic)]
708    #[diag(driver_dup_extern_spec, code = E0999)]
709    pub(super) struct DupExternSpec {
710        #[primary_span]
711        #[label]
712        pub span: Span,
713        #[note]
714        pub previous_span: Span,
715        pub name: String,
716    }
717
718    #[derive(Diagnostic)]
719    #[diag(driver_mismatched_generics, code = E0999)]
720    #[note]
721    pub(super) struct MismatchedGenerics {
722        #[primary_span]
723        #[label]
724        pub span: Span,
725        #[label(driver_extern_def_label)]
726        pub extern_def: Span,
727        pub def_descr: &'static str,
728    }
729
730    #[derive(Diagnostic)]
731    #[diag(driver_mismatched_impl_self_ty, code = E0999)]
732    #[note]
733    pub(super) struct MismatchedImplSelfTy {
734        #[primary_span]
735        #[label]
736        pub span: Span,
737        pub local_self_ty: String,
738        pub extern_self_ty: String,
739        #[label(driver_extern_impl_label)]
740        pub extern_impl_span: Span,
741    }
742}