]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/clippy/clippy_utils/src/consts.rs
implement valtrees as the type-system representation for constant values
[rust.git] / src / tools / clippy / clippy_utils / src / consts.rs
index 9f162a117b2d103cc12309f33029f24203ff4a3b..c31c560f427f25ef3ec33c05078ffa7b1158e182 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -423,14 +422,14 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                 let result = self
                     .lcx
                     .tcx
-                    .const_eval_resolve(
+                    .const_eval_resolve_for_typeck(
                         self.param_env,
                         ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
                         None,
                     )
                     .ok()
-                    .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
-                let result = miri_to_const(result);
+                    .and_then(|val| val.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty)))?;
+                let result = miri_to_const(self.lcx.tcx, result);
                 if result.is_some() {
                     self.needed_resolution = true;
                 }
@@ -478,7 +477,7 @@ fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
     fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
         if let Some(Constant::Bool(b)) = self.expr(cond) {
             if b {
-                self.expr(&*then)
+                self.expr(then)
             } else {
                 otherwise.as_ref().and_then(|expr| self.expr(expr))
             }
@@ -580,80 +579,69 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
     }
 }
 
-pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> {
-    use rustc_middle::mir::interpret::ConstValue;
-    match result.val() {
-        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
-            match result.ty().kind() {
-                ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
-                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
-                ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
+pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: ty::Const<'tcx>) -> Option<Constant> {
+    match result.kind() {
+        ty::ConstKind::Value(valtree) => {
+            match (valtree, result.ty().kind()) {
+                (ty::ValTree::Leaf(int), ty::Bool) => Some(Constant::Bool(int == ScalarInt::TRUE)),
+                (ty::ValTree::Leaf(int), ty::Uint(_) | ty::Int(_)) => Some(Constant::Int(int.assert_bits(int.size()))),
+                (ty::ValTree::Leaf(int), ty::Float(FloatTy::F32)) => Some(Constant::F32(f32::from_bits(
                     int.try_into().expect("invalid f32 bit representation"),
                 ))),
-                ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
+                (ty::ValTree::Leaf(int), ty::Float(FloatTy::F64)) => Some(Constant::F64(f64::from_bits(
                     int.try_into().expect("invalid f64 bit representation"),
                 ))),
-                ty::RawPtr(type_and_mut) => {
+                (ty::ValTree::Leaf(int), ty::RawPtr(type_and_mut)) => {
                     if let ty::Uint(_) = type_and_mut.ty.kind() {
                         return Some(Constant::RawPtr(int.assert_bits(int.size())));
                     }
                     None
                 },
-                // FIXME: implement other conversions.
-                _ => None,
-            }
-        },
-        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() {
-            ty::Ref(_, tam, _) => match tam.kind() {
-                ty::Str => String::from_utf8(
-                    data.inner()
-                        .inspect_with_uninit_and_ptr_outside_interpreter(start..end)
-                        .to_owned(),
-                )
-                .ok()
-                .map(Constant::Str),
-                _ => None,
-            },
-            _ => None,
-        },
-        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() {
-            ty::Array(sub_type, len) => match sub_type.kind() {
-                ty::Float(FloatTy::F32) => match miri_to_const(*len) {
-                    Some(Constant::Int(len)) => alloc
-                        .inner()
-                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
-                        .to_owned()
-                        .chunks(4)
-                        .map(|chunk| {
-                            Some(Constant::F32(f32::from_le_bytes(
-                                chunk.try_into().expect("this shouldn't happen"),
-                            )))
-                        })
-                        .collect::<Option<Vec<Constant>>>()
-                        .map(Constant::Vec),
-                    _ => None,
-                },
-                ty::Float(FloatTy::F64) => match miri_to_const(*len) {
-                    Some(Constant::Int(len)) => alloc
-                        .inner()
-                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
-                        .to_owned()
-                        .chunks(8)
-                        .map(|chunk| {
-                            Some(Constant::F64(f64::from_le_bytes(
-                                chunk.try_into().expect("this shouldn't happen"),
-                            )))
-                        })
-                        .collect::<Option<Vec<Constant>>>()
-                        .map(Constant::Vec),
+                (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) if *inner_ty == tcx.types.str_ => valtree
+                    .try_to_raw_bytes(tcx, result.ty())
+                    .and_then(|bytes| String::from_utf8(bytes.to_owned()).ok().map(Constant::Str)),
+                (ty::ValTree::Branch(_), ty::Array(arr_ty, len)) => match arr_ty.kind() {
+                    ty::Float(float_ty) => {
+                        let chunk_size = match float_ty {
+                            FloatTy::F32 => 4,
+                            FloatTy::F64 => 8,
+                        };
+
+                        match miri_to_const(tcx, *len) {
+                            Some(Constant::Int(_)) => valtree.try_to_raw_bytes(tcx, result.ty()).and_then(|bytes| {
+                                bytes
+                                    .to_owned()
+                                    .chunks(chunk_size)
+                                    .map(|chunk| match float_ty {
+                                        FloatTy::F32 => {
+                                            let float = f32::from_le_bytes(
+                                                chunk
+                                                    .try_into()
+                                                    .expect(&format!("expected to construct f32 from {:?}", chunk)),
+                                            );
+                                            Some(Constant::F32(float))
+                                        },
+                                        FloatTy::F64 => {
+                                            let float = f64::from_le_bytes(
+                                                chunk
+                                                    .try_into()
+                                                    .expect(&format!("expected to construct f64 from {:?}", chunk)),
+                                            );
+                                            Some(Constant::F64(float))
+                                        },
+                                    })
+                                    .collect::<Option<Vec<Constant>>>()
+                                    .map(Constant::Vec)
+                            }),
+                            _ => None,
+                        }
+                    },
                     _ => None,
                 },
-                // FIXME: implement other array type conversions.
+                // FIXME: implement other conversions.
                 _ => None,
-            },
-            _ => None,
+            }
         },
-        // FIXME: implement other conversions.
         _ => None,
     }
 }