Skip to main content

clippy_utils/
res.rs

1use rustc_hir::def::{DefKind, Res};
2use rustc_hir::def_id::DefId;
3use rustc_hir::{
4    self as hir, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, TyKind,
5};
6use rustc_lint::LateContext;
7use rustc_middle::ty::layout::HasTyCtxt;
8use rustc_middle::ty::{AdtDef, AdtKind, Binder, EarlyBinder, Ty, TypeckResults};
9use rustc_span::{Ident, Symbol};
10
11/// Either a `HirId` or a type which can be identified by one.
12pub trait HasHirId: Copy {
13    fn hir_id(self) -> HirId;
14}
15impl HasHirId for HirId {
16    #[inline]
17    fn hir_id(self) -> HirId {
18        self
19    }
20}
21impl HasHirId for &Expr<'_> {
22    #[inline]
23    fn hir_id(self) -> HirId {
24        self.hir_id
25    }
26}
27
28type DefRes = (DefKind, DefId);
29
30pub trait MaybeTypeckRes<'tcx> {
31    /// Gets the contained `TypeckResults`.
32    ///
33    /// With debug assertions enabled this will always return `Some`. `None` is
34    /// only returned so logic errors can be handled by not emitting a lint on
35    /// release builds.
36    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>>;
37
38    /// Gets the type-dependent resolution of the specified node.
39    ///
40    /// With debug assertions enabled this will always return `Some`. `None` is
41    /// only returned so logic errors can be handled by not emitting a lint on
42    /// release builds.
43    #[inline]
44    #[cfg_attr(debug_assertions, track_caller)]
45    fn ty_based_def(&self, node: impl HasHirId) -> Option<DefRes> {
46        #[inline]
47        #[cfg_attr(debug_assertions, track_caller)]
48        fn f(typeck: &TypeckResults<'_>, id: HirId) -> Option<DefRes> {
49            if typeck.hir_owner == id.owner {
50                let def = typeck.type_dependent_def(id);
51                debug_assert!(
52                    def.is_some(),
53                    "attempted type-dependent lookup for a node with no definition\
54                        \n  node `{id:?}`",
55                );
56                def
57            } else {
58                debug_assert!(
59                    false,
60                    "attempted type-dependent lookup for a node in the wrong body\
61                        \n  in body `{:?}`\
62                        \n  expected body `{:?}`",
63                    typeck.hir_owner, id.owner,
64                );
65                None
66            }
67        }
68        self.typeck_res().and_then(|typeck| f(typeck, node.hir_id()))
69    }
70}
71impl<'tcx> MaybeTypeckRes<'tcx> for LateContext<'tcx> {
72    #[inline]
73    #[cfg_attr(debug_assertions, track_caller)]
74    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
75        if let Some(typeck) = self.typeck_results {
76            Some(typeck)
77        } else {
78            // It's possible to get the `TypeckResults` for any other body, but
79            // attempting to lookup the type of something across bodies like this
80            // is a good indication of a bug.
81            debug_assert!(false, "attempted type-dependent lookup in a non-body context");
82            None
83        }
84    }
85}
86impl<'tcx> MaybeTypeckRes<'tcx> for TypeckResults<'tcx> {
87    #[inline]
88    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
89        Some(self)
90    }
91}
92
93/// A `QPath` with the `HirId` of the node containing it.
94type QPathId<'tcx> = (&'tcx QPath<'tcx>, HirId);
95
96/// A HIR node which might be a `QPath`.
97pub trait MaybeQPath<'a>: Copy {
98    /// If this node is a path gets both the contained path and the `HirId` to
99    /// use for type dependant lookup.
100    fn opt_qpath(self) -> Option<QPathId<'a>>;
101
102    /// If this is a path gets its resolution. Returns `Res::Err` otherwise.
103    #[inline]
104    #[cfg_attr(debug_assertions, track_caller)]
105    fn res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
106        #[cfg_attr(debug_assertions, track_caller)]
107        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
108            match *qpath {
109                QPath::Resolved(_, p) => p.res,
110                QPath::TypeRelative(..) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
111                QPath::TypeRelative(..) => Res::Err,
112            }
113        }
114        match self.opt_qpath() {
115            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
116            _ => Res::Err,
117        }
118    }
119
120    /// If this is a path with the specified name as its final segment gets its
121    /// resolution. Returns `Res::Err` otherwise.
122    #[inline]
123    #[cfg_attr(debug_assertions, track_caller)]
124    fn res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
125        #[cfg_attr(debug_assertions, track_caller)]
126        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
127            match *qpath {
128                QPath::Resolved(_, p)
129                    if let [.., seg] = p.segments
130                        && seg.ident.name == name =>
131                {
132                    p.res
133                },
134                QPath::TypeRelative(_, seg)
135                    if seg.ident.name == name
136                        && let Some((kind, id)) = typeck.ty_based_def(id) =>
137                {
138                    Res::Def(kind, id)
139                },
140                QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
141            }
142        }
143        match self.opt_qpath() {
144            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
145            _ => Res::Err,
146        }
147    }
148
149    /// If this is a path gets both its resolution and final segment.
150    #[inline]
151    #[cfg_attr(debug_assertions, track_caller)]
152    fn res_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> (Res, Option<&'a PathSegment<'a>>) {
153        #[cfg_attr(debug_assertions, track_caller)]
154        fn f<'a>(qpath: &QPath<'a>, id: HirId, typeck: &TypeckResults<'_>) -> (Res, Option<&'a PathSegment<'a>>) {
155            match *qpath {
156                QPath::Resolved(_, p) if let [.., seg] = p.segments => (p.res, Some(seg)),
157                QPath::TypeRelative(_, seg) if let Some((kind, id)) = typeck.ty_based_def(id) => {
158                    (Res::Def(kind, id), Some(seg))
159                },
160                QPath::Resolved(..) | QPath::TypeRelative(..) => (Res::Err, None),
161            }
162        }
163        match self.opt_qpath() {
164            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
165            _ => (Res::Err, None),
166        }
167    }
168
169    /// If this is a path without an explicit `Self` type gets its resolution.
170    /// Returns `Res::Err` otherwise.
171    ///
172    /// Only paths to trait items can optionally contain a `Self` type.
173    #[inline]
174    #[cfg_attr(debug_assertions, track_caller)]
175    fn typeless_res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
176        #[cfg_attr(debug_assertions, track_caller)]
177        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
178            match *qpath {
179                QPath::Resolved(
180                    None
181                    | Some(&hir::Ty {
182                        kind: TyKind::Infer(()),
183                        ..
184                    }),
185                    p,
186                ) => p.res,
187                QPath::TypeRelative(
188                    &hir::Ty {
189                        kind: TyKind::Infer(()),
190                        ..
191                    },
192                    _,
193                ) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
194                QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
195            }
196        }
197        match self.opt_qpath() {
198            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
199            _ => Res::Err,
200        }
201    }
202
203    /// If this is a path without an explicit `Self` type to an item with the
204    /// specified name gets its resolution. Returns `Res::Err` otherwise.
205    ///
206    /// Only paths to trait items can optionally contain a `Self` type.
207    #[inline]
208    #[cfg_attr(debug_assertions, track_caller)]
209    fn typeless_res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
210        #[cfg_attr(debug_assertions, track_caller)]
211        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
212            match *qpath {
213                QPath::Resolved(
214                    None
215                    | Some(&hir::Ty {
216                        kind: TyKind::Infer(()),
217                        ..
218                    }),
219                    p,
220                ) if let [.., seg] = p.segments
221                    && seg.ident.name == name =>
222                {
223                    p.res
224                },
225                QPath::TypeRelative(
226                    &hir::Ty {
227                        kind: TyKind::Infer(()),
228                        ..
229                    },
230                    seg,
231                ) if seg.ident.name == name
232                    && let Some((kind, id)) = typeck.ty_based_def(id) =>
233                {
234                    Res::Def(kind, id)
235                },
236                QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
237            }
238        }
239        match self.opt_qpath() {
240            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
241            _ => Res::Err,
242        }
243    }
244
245    /// If this is a type-relative path gets the definition it resolves to.
246    ///
247    /// Only inherent associated items require a type-relative path.
248    #[inline]
249    #[cfg_attr(debug_assertions, track_caller)]
250    fn ty_rel_def<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<DefRes> {
251        match self.opt_qpath() {
252            Some((QPath::TypeRelative(..), id)) => typeck.ty_based_def(id),
253            _ => None,
254        }
255    }
256
257    /// If this is a type-relative path to an item with the specified name gets
258    /// the definition it resolves to.
259    ///
260    /// Only inherent associated items require a type-relative path.
261    #[inline]
262    #[cfg_attr(debug_assertions, track_caller)]
263    fn ty_rel_def_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Option<DefRes> {
264        match self.opt_qpath() {
265            Some((&QPath::TypeRelative(_, seg), id)) if seg.ident.name == name => typeck.ty_based_def(id),
266            _ => None,
267        }
268    }
269
270    /// If this is a type-relative path gets the definition it resolves to and
271    /// its final segment.
272    ///
273    /// Only inherent associated items require a type-relative path.
274    #[inline]
275    #[cfg_attr(debug_assertions, track_caller)]
276    fn ty_rel_def_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<(DefRes, &'a PathSegment<'a>)> {
277        match self.opt_qpath() {
278            Some((QPath::TypeRelative(_, seg), id)) if let Some(def) = typeck.ty_based_def(id) => Some((def, seg)),
279            _ => None,
280        }
281    }
282}
283
284impl<'tcx> MaybeQPath<'tcx> for QPathId<'tcx> {
285    #[inline]
286    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
287        Some((self.0, self.1))
288    }
289}
290impl<'tcx> MaybeQPath<'tcx> for &'tcx Expr<'_> {
291    #[inline]
292    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
293        match &self.kind {
294            ExprKind::Path(qpath) => Some((qpath, self.hir_id)),
295            _ => None,
296        }
297    }
298}
299impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> {
300    #[inline]
301    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
302        match &self.kind {
303            PatExprKind::Path(qpath) => Some((qpath, self.hir_id)),
304            PatExprKind::Lit { .. } => None,
305        }
306    }
307}
308impl<'tcx, AmbigArg> MaybeQPath<'tcx> for &'tcx hir::Ty<'_, AmbigArg> {
309    #[inline]
310    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
311        match &self.kind {
312            TyKind::Path(qpath) => Some((qpath, self.hir_id)),
313            _ => None,
314        }
315    }
316}
317impl<'tcx> MaybeQPath<'tcx> for &'_ Pat<'tcx> {
318    #[inline]
319    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
320        match self.kind {
321            PatKind::Expr(e) => e.opt_qpath(),
322            _ => None,
323        }
324    }
325}
326impl<'tcx, T: MaybeQPath<'tcx>> MaybeQPath<'tcx> for Option<T> {
327    #[inline]
328    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
329        self.and_then(T::opt_qpath)
330    }
331}
332impl<'tcx, T: Copy + MaybeQPath<'tcx>> MaybeQPath<'tcx> for &Option<T> {
333    #[inline]
334    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
335        self.and_then(T::opt_qpath)
336    }
337}
338
339/// A resolved path and the explicit `Self` type if there is one.
340type OptResPath<'tcx> = (Option<&'tcx hir::Ty<'tcx>>, Option<&'tcx Path<'tcx>>);
341
342type OptTyRelPath<'tcx> = Option<(&'tcx hir::Ty<'tcx>, &'tcx PathSegment<'tcx>)>;
343
344/// A HIR node which might be a `QPath::Resolved`.
345///
346/// The following are resolved paths:
347/// * A path to a module or crate item.
348/// * A path to a trait item via the trait's name.
349/// * A path to a struct or variant constructor via the original type's path.
350/// * A local.
351///
352/// All other paths are `TypeRelative` and require using `PathRes` to lookup the
353/// resolution.
354pub trait MaybeResPath<'a>: Copy {
355    /// If this node is a resolved path gets both the contained path and the
356    /// type associated with it.
357    fn opt_res_path(self) -> OptResPath<'a>;
358
359    /// If this node is a type relative path gets both the type and the final
360    /// segments of the path.
361    fn opt_ty_rel_path(self) -> OptTyRelPath<'a>;
362
363    /// If this node is a resolved path gets it's resolution. Returns `Res::Err`
364    /// otherwise.
365    #[inline]
366    fn basic_res(self) -> &'a Res {
367        self.opt_res_path().1.map_or(&Res::Err, |p| &p.res)
368    }
369
370    /// If this node is a path to a local gets the local's `HirId`.
371    #[inline]
372    fn res_local_id(self) -> Option<HirId> {
373        if let (_, Some(p)) = self.opt_res_path()
374            && let Res::Local(id) = p.res
375        {
376            Some(id)
377        } else {
378            None
379        }
380    }
381
382    /// If this node is a path to a local gets the local's `HirId` and identifier.
383    fn res_local_id_and_ident(self) -> Option<(HirId, &'a Ident)> {
384        if let (_, Some(p)) = self.opt_res_path()
385            && let Res::Local(id) = p.res
386            && let [seg] = p.segments
387        {
388            Some((id, &seg.ident))
389        } else {
390            None
391        }
392    }
393}
394impl<'a> MaybeResPath<'a> for &'a Path<'a> {
395    #[inline]
396    fn opt_res_path(self) -> OptResPath<'a> {
397        (None, Some(self))
398    }
399
400    #[inline]
401    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
402        None
403    }
404
405    #[inline]
406    fn basic_res(self) -> &'a Res {
407        &self.res
408    }
409}
410impl<'a> MaybeResPath<'a> for &QPath<'a> {
411    #[inline]
412    fn opt_res_path(self) -> OptResPath<'a> {
413        match *self {
414            QPath::Resolved(ty, path) => (ty, Some(path)),
415            QPath::TypeRelative(..) => (None, None),
416        }
417    }
418
419    #[inline]
420    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
421        match *self {
422            QPath::TypeRelative(ty, seg) => Some((ty, seg)),
423            QPath::Resolved(..) => None,
424        }
425    }
426}
427impl<'a> MaybeResPath<'a> for &Expr<'a> {
428    #[inline]
429    fn opt_res_path(self) -> OptResPath<'a> {
430        match &self.kind {
431            ExprKind::Path(qpath) => qpath.opt_res_path(),
432            _ => (None, None),
433        }
434    }
435
436    #[inline]
437    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
438        match &self.kind {
439            ExprKind::Path(qpath) => qpath.opt_ty_rel_path(),
440            _ => None,
441        }
442    }
443}
444impl<'a> MaybeResPath<'a> for &PatExpr<'a> {
445    #[inline]
446    fn opt_res_path(self) -> OptResPath<'a> {
447        match &self.kind {
448            PatExprKind::Path(qpath) => qpath.opt_res_path(),
449            PatExprKind::Lit { .. } => (None, None),
450        }
451    }
452
453    #[inline]
454    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
455        match &self.kind {
456            PatExprKind::Path(qpath) => qpath.opt_ty_rel_path(),
457            PatExprKind::Lit { .. } => None,
458        }
459    }
460}
461impl<'a, AmbigArg> MaybeResPath<'a> for &hir::Ty<'a, AmbigArg> {
462    #[inline]
463    fn opt_res_path(self) -> OptResPath<'a> {
464        match &self.kind {
465            TyKind::Path(qpath) => qpath.opt_res_path(),
466            _ => (None, None),
467        }
468    }
469
470    #[inline]
471    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
472        match &self.kind {
473            TyKind::Path(qpath) => qpath.opt_ty_rel_path(),
474            _ => None,
475        }
476    }
477}
478impl<'a> MaybeResPath<'a> for &Pat<'a> {
479    #[inline]
480    fn opt_res_path(self) -> OptResPath<'a> {
481        match self.kind {
482            PatKind::Expr(e) => e.opt_res_path(),
483            _ => (None, None),
484        }
485    }
486
487    #[inline]
488    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
489        match self.kind {
490            PatKind::Expr(e) => e.opt_ty_rel_path(),
491            _ => None,
492        }
493    }
494}
495impl<'a, T: MaybeResPath<'a>> MaybeResPath<'a> for Option<T> {
496    #[inline]
497    fn opt_res_path(self) -> OptResPath<'a> {
498        match self {
499            Some(x) => T::opt_res_path(x),
500            None => (None, None),
501        }
502    }
503
504    #[inline]
505    fn opt_ty_rel_path(self) -> OptTyRelPath<'a> {
506        self.and_then(T::opt_ty_rel_path)
507    }
508
509    #[inline]
510    fn basic_res(self) -> &'a Res {
511        self.map_or(&Res::Err, T::basic_res)
512    }
513}
514
515/// A type which may either contain a `DefId` or be referred to by a `DefId`.
516pub trait MaybeDef: Copy {
517    fn opt_def_id(self) -> Option<DefId>;
518
519    /// Gets this definition's id and kind. This will lookup the kind in the def
520    /// tree if needed.
521    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)>;
522
523    /// Gets the diagnostic name of this definition if it has one.
524    #[inline]
525    fn opt_diag_name<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<Symbol> {
526        self.opt_def_id().and_then(|id| tcx.tcx().get_diagnostic_name(id))
527    }
528
529    /// Checks if this definition has the specified diagnostic name.
530    #[inline]
531    fn is_diag_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, name: Symbol) -> bool {
532        self.opt_def_id()
533            .is_some_and(|id| tcx.tcx().is_diagnostic_item(name, id))
534    }
535
536    /// Checks if this definition is the specified `LangItem`.
537    #[inline]
538    fn is_lang_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, item: LangItem) -> bool {
539        self.opt_def_id()
540            .is_some_and(|id| tcx.tcx().lang_items().get(item) == Some(id))
541    }
542
543    /// If this definition is an impl block gets its type.
544    #[inline]
545    fn opt_impl_ty<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<EarlyBinder<'tcx, Ty<'tcx>>> {
546        match self.opt_def(tcx) {
547            Some((DefKind::Impl { .. }, id)) => Some(tcx.tcx().type_of(id)),
548            _ => None,
549        }
550    }
551
552    /// Gets the parent of this definition if it has one.
553    #[inline]
554    fn opt_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
555        self.opt_def_id().and_then(|id| tcx.tcx().opt_parent(id))
556    }
557
558    /// Checks if this definition is an impl block.
559    #[inline]
560    fn is_impl<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> bool {
561        matches!(self.opt_def(tcx), Some((DefKind::Impl { .. }, _)))
562    }
563
564    /// If this definition is a constructor gets the `DefId` of it's type or variant.
565    #[inline]
566    fn ctor_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
567        match self.opt_def(tcx) {
568            Some((DefKind::Ctor(..), id)) => tcx.tcx().opt_parent(id),
569            _ => None,
570        }
571    }
572
573    /// If this definition is an associated item of an impl or trait gets the
574    /// `DefId` of its parent.
575    #[inline]
576    fn assoc_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
577        match self.opt_def(tcx) {
578            Some((DefKind::AssocConst { .. } | DefKind::AssocFn | DefKind::AssocTy, id)) => tcx.tcx().opt_parent(id),
579            _ => None,
580        }
581    }
582
583    /// If this definition is an associated function of an impl or trait gets the
584    /// `DefId` of its parent.
585    #[inline]
586    fn assoc_fn_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
587        match self.opt_def(tcx) {
588            Some((DefKind::AssocFn, id)) => tcx.tcx().opt_parent(id),
589            _ => None,
590        }
591    }
592}
593impl MaybeDef for DefId {
594    #[inline]
595    fn opt_def_id(self) -> Option<DefId> {
596        Some(self)
597    }
598
599    #[inline]
600    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
601        self.opt_def_id().map(|id| (tcx.tcx().def_kind(id), id))
602    }
603}
604impl MaybeDef for (DefKind, DefId) {
605    #[inline]
606    fn opt_def_id(self) -> Option<DefId> {
607        Some(self.1)
608    }
609
610    #[inline]
611    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
612        Some(self)
613    }
614}
615impl MaybeDef for AdtDef<'_> {
616    #[inline]
617    fn opt_def_id(self) -> Option<DefId> {
618        Some(self.did())
619    }
620
621    #[inline]
622    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
623        let did = self.did();
624        match self.adt_kind() {
625            AdtKind::Enum => Some((DefKind::Enum, did)),
626            AdtKind::Struct => Some((DefKind::Struct, did)),
627            AdtKind::Union => Some((DefKind::Union, did)),
628        }
629    }
630}
631impl MaybeDef for Ty<'_> {
632    #[inline]
633    fn opt_def_id(self) -> Option<DefId> {
634        self.ty_adt_def().opt_def_id()
635    }
636
637    #[inline]
638    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
639        self.ty_adt_def().opt_def(tcx)
640    }
641}
642impl MaybeDef for Res {
643    #[inline]
644    fn opt_def_id(self) -> Option<DefId> {
645        Res::opt_def_id(&self)
646    }
647
648    #[inline]
649    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
650        match self {
651            Res::Def(kind, id) => Some((kind, id)),
652            _ => None,
653        }
654    }
655}
656impl<T: MaybeDef> MaybeDef for Option<T> {
657    #[inline]
658    fn opt_def_id(self) -> Option<DefId> {
659        self.and_then(T::opt_def_id)
660    }
661
662    #[inline]
663    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
664        self.and_then(|x| T::opt_def(x, tcx))
665    }
666}
667impl<T: MaybeDef> MaybeDef for EarlyBinder<'_, T> {
668    #[inline]
669    fn opt_def_id(self) -> Option<DefId> {
670        self.skip_binder().opt_def_id()
671    }
672
673    #[inline]
674    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
675        self.skip_binder().opt_def(tcx)
676    }
677}
678impl<T: MaybeDef> MaybeDef for Binder<'_, T> {
679    #[inline]
680    fn opt_def_id(self) -> Option<DefId> {
681        self.skip_binder().opt_def_id()
682    }
683
684    #[inline]
685    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
686        self.skip_binder().opt_def(tcx)
687    }
688}