use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{GenericArgKind, ParamEnv, Region, Ty, TyCtxt, TypingEnv};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_type_ir::TypingMode;
pub trait TyExt<'tcx> {
fn inner_regions(self) -> impl Iterator<Item = Region<'tcx>>;
fn does_implement_trait(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
trait_def_id: DefId,
) -> bool;
#[allow(clippy::wrong_self_convention)]
fn is_copyable(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool;
}
impl<'tcx> TyExt<'tcx> for Ty<'tcx> {
fn inner_regions(self) -> impl Iterator<Item = Region<'tcx>> {
self.walk().filter_map(|part| match part.unpack() {
GenericArgKind::Lifetime(region) => Some(region),
_ => None,
})
}
fn does_implement_trait(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
trait_def_id: DefId,
) -> bool {
use rustc_infer::traits::EvaluationResult;
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ty = tcx.erase_regions(self);
let result = infcx.type_implements_trait(trait_def_id, [ty], param_env);
matches!(
result,
EvaluationResult::EvaluatedToOk | EvaluationResult::EvaluatedToOkModuloRegions
)
}
fn is_copyable(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool {
let ty = tcx.erase_regions(self);
tcx.type_is_copy_modulo_regions(typing_env, ty)
}
}
#[cfg(test)]
mod test {
use rustc_middle::ty::TypingEnv;
use super::TyExt;
use crate::{mir::body, test_utils, BodyExt};
#[test]
fn test_ty_ext() {
let input = r"
fn main() {
let x = &mut 0;
let y = 0;
}";
test_utils::CompileBuilder::new(input).expect_compile(|result| {
let tcx = result.tcx;
let body = result.as_body().1;
let body = &body.body;
let locals = body.debug_info_name_map();
let x = &body.local_decls[locals["x"]];
let y = &body.local_decls[locals["y"]];
assert_eq!(x.ty.inner_regions().count(), 1);
assert_eq!(y.ty.inner_regions().count(), 0);
assert!(!x.ty.is_copyable(tcx, TypingEnv::fully_monomorphized()));
assert!(y.ty.is_copyable(tcx, TypingEnv::fully_monomorphized()));
});
}
}