rustc_utils/hir/
ty.rs

1//! Utilities for [`Ty`].
2
3use rustc_hir::def_id::DefId;
4use rustc_infer::infer::TyCtxtInferExt;
5use rustc_middle::ty::{GenericArgKind, ParamEnv, Region, Ty, TyCtxt, TypingEnv};
6use rustc_trait_selection::infer::InferCtxtExt;
7use rustc_type_ir::TypingMode;
8
9/// Extension trait for [`Ty`].
10pub trait TyExt<'tcx> {
11  /// Returns an iterator over the regions appearing within a type.
12  fn inner_regions(self) -> impl Iterator<Item = Region<'tcx>>;
13
14  /// Returns true if a type implements a given trait.
15  fn does_implement_trait(
16    self,
17    tcx: TyCtxt<'tcx>,
18    param_env: ParamEnv<'tcx>,
19    trait_def_id: DefId,
20  ) -> bool;
21
22  #[allow(clippy::wrong_self_convention)]
23  /// Returns true if a type implements `Copy`.
24  fn is_copyable(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool;
25}
26
27impl<'tcx> TyExt<'tcx> for Ty<'tcx> {
28  fn inner_regions(self) -> impl Iterator<Item = Region<'tcx>> {
29    self.walk().filter_map(|part| match part.kind() {
30      GenericArgKind::Lifetime(region) => Some(region),
31      _ => None,
32    })
33  }
34
35  fn does_implement_trait(
36    self,
37    tcx: TyCtxt<'tcx>,
38    param_env: ParamEnv<'tcx>,
39    trait_def_id: DefId,
40  ) -> bool {
41    use rustc_infer::traits::EvaluationResult;
42
43    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
44    let ty = tcx.erase_regions(self);
45    let result = infcx.type_implements_trait(trait_def_id, [ty], param_env);
46    matches!(
47      result,
48      EvaluationResult::EvaluatedToOk | EvaluationResult::EvaluatedToOkModuloRegions
49    )
50  }
51
52  fn is_copyable(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool {
53    let ty = tcx.erase_regions(self);
54    tcx.type_is_copy_modulo_regions(typing_env, ty)
55  }
56}
57
58#[cfg(test)]
59mod test {
60  use rustc_middle::ty::TypingEnv;
61
62  use super::TyExt;
63  use crate::{BodyExt, test_utils};
64
65  #[test]
66  fn test_ty_ext() {
67    let input = r"
68fn main() {
69  let x = &mut 0;
70  let y = 0;
71}";
72
73    test_utils::compile_body(input, |tcx, _, body| {
74      let body = &body.body;
75      let locals = body.debug_info_name_map();
76      let x = &body.local_decls[locals["x"]];
77      let y = &body.local_decls[locals["y"]];
78      assert_eq!(x.ty.inner_regions().count(), 1);
79      assert_eq!(y.ty.inner_regions().count(), 0);
80
81      assert!(!x.ty.is_copyable(tcx, TypingEnv::fully_monomorphized()));
82      assert!(y.ty.is_copyable(tcx, TypingEnv::fully_monomorphized()));
83    });
84  }
85}