Skip to main content

clippy_utils/
res.rs

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