1use 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
9pub trait TyExt<'tcx> {
11 fn inner_regions(self) -> impl Iterator<Item = Region<'tcx>>;
13
14 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 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}