Extract some util functions

This commit is contained in:
Jason Newcomb 2022-02-18 09:10:48 -05:00
parent 90bb7a3476
commit 88ecdd0804
3 changed files with 68 additions and 63 deletions

View file

@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, TyKind, Unsafety};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{
self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr,
};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{Size, VariantIdx};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
use std::iter;
@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
}
}
}
#[derive(Clone, Copy)]
pub enum EnumValue {
Unsigned(u128),
Signed(i128),
}
impl core::ops::Add<u32> for EnumValue {
type Output = Self;
fn add(self, n: u32) -> Self::Output {
match self {
Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
Self::Signed(x) => Self::Signed(x + i128::from(n)),
}
}
}
/// Attempts to read the given constant as though it were an an enum value.
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
match tcx.type_of(id).kind() {
ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
16 => value.assert_bits(Size::from_bytes(16)) as i128,
_ => return None,
})),
ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
1 => value.assert_bits(Size::from_bytes(1)),
2 => value.assert_bits(Size::from_bytes(2)),
4 => value.assert_bits(Size::from_bytes(4)),
8 => value.assert_bits(Size::from_bytes(8)),
16 => value.assert_bits(Size::from_bytes(16)),
_ => return None,
})),
_ => None,
}
} else {
None
}
}
/// Gets the value of the given variant.
pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue {
let variant = &adt.variants[i];
match variant.discr {
VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(),
VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr {
VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x,
VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()),
},
}
}