Skip to main content

clippy_utils/
res.rs

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