Reuse the pretty printing architecture for printing of constants

This commit is contained in:
Oliver Scherer 2019-03-29 10:52:09 +01:00
parent d85e866c0d
commit 8d4f4cdada
5 changed files with 100 additions and 80 deletions

View file

@ -9,8 +9,6 @@ use crate::hir::def_id::DefId;
use crate::hir::{self, InlineAsm as HirInlineAsm};
use crate::mir::interpret::{ConstValue, InterpError, Scalar};
use crate::mir::visit::MirVisitable;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
@ -21,13 +19,13 @@ use rustc_macros::HashStable;
use crate::rustc_serialize::{self as serialize};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter, Write};
use std::fmt::{self, Debug, Formatter, Write, Display};
use std::iter::FusedIterator;
use std::ops::{Index, IndexMut};
use std::slice;
use std::vec::IntoIter;
use std::{iter, mem, option, u32};
use syntax::ast::{self, Name};
use syntax::ast::Name;
use syntax::symbol::{InternedString, Symbol};
use syntax_pos::{Span, DUMMY_SP};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@ -1670,8 +1668,7 @@ impl<'tcx> TerminatorKind<'tcx> {
values
.iter()
.map(|&u| {
let mut s = String::new();
let c = ty::Const {
(&ty::Const {
val: ConstValue::Scalar(
Scalar::Bits {
bits: u,
@ -1679,9 +1676,7 @@ impl<'tcx> TerminatorKind<'tcx> {
}.into(),
),
ty: switch_ty,
};
fmt_const_val(&mut s, c).unwrap();
s.into()
}).to_string().into()
}).chain(iter::once("otherwise".into()))
.collect()
}
@ -2827,67 +2822,15 @@ newtype_index! {
impl<'tcx> Debug for Constant<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
write!(fmt, "const ")?;
fmt_const_val(fmt, *self.literal)
write!(fmt, "{}", self)
}
}
/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result {
use crate::ty::TyKind::*;
let value = const_val.val;
let ty = const_val.ty;
// print some primitives
if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = value {
match ty.sty {
Bool if bits == 0 => return write!(f, "false"),
Bool if bits == 1 => return write!(f, "true"),
Float(ast::FloatTy::F32) => return write!(f, "{}f32", Single::from_bits(bits)),
Float(ast::FloatTy::F64) => return write!(f, "{}f64", Double::from_bits(bits)),
Uint(ui) => return write!(f, "{:?}{}", bits, ui),
Int(i) => {
let bit_width = ty::tls::with(|tcx| {
let ty = tcx.lift_to_global(&ty).unwrap();
tcx.layout_of(ty::ParamEnv::empty().and(ty))
.unwrap()
.size
.bits()
});
let shift = 128 - bit_width;
return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i);
}
Char => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
_ => {}
}
}
// print function definitions
if let FnDef(did, _) = ty.sty {
return write!(f, "{}", def_path_str(did));
}
// print string literals
if let ConstValue::Slice(ptr, len) = value {
if let Scalar::Ptr(ptr) = ptr {
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
assert_eq!(len as usize as u64, len);
let slice =
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
write!(f, "{:?}", s)
} else {
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
});
}
}
}
// just raw dump everything else
write!(f, "{:?} : {}", value, ty)
}
fn def_path_str(def_id: DefId) -> String {
ty::tls::with(|tcx| tcx.def_path_str(def_id))
impl<'tcx> Display for Constant<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
write!(fmt, "const ")?;
write!(fmt, "{}", self.literal)
}
}
impl<'tcx> graph::DirectedGraph for Mir<'tcx> {

View file

@ -6,7 +6,10 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource};
use crate::middle::region;
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
use crate::ty::subst::{Kind, Subst, UnpackedKind};
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{ConstValue, sign_extend, Scalar};
use syntax::ast;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_target::spec::abi::Abi;
use syntax::symbol::{kw, InternedString};
@ -1533,12 +1536,54 @@ define_print_and_forward_display! {
p!(print_def_path(self.def_id, self.substs));
}
&'tcx ty::Const<'tcx> {
match self.val {
ConstValue::Unevaluated(..) |
ConstValue::Infer(..) => p!(write("_")),
ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)),
_ => p!(write("{:?}", self)),
ty::Const<'tcx> {
match (self.val, &self.ty.sty) {
| (ConstValue::Unevaluated(..), _)
| (ConstValue::Infer(..), _)
=> p!(write("_: "), print(self.ty)),
(ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
(ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")),
(ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")),
(ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F32)) =>
p!(write(
"{}f32",
Single::from_bits(bits)
)),
(ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F64)) =>
p!(write(
"{}f64",
Double::from_bits(bits)
)),
(ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) =>
p!(write("{}{}", bits, ui)),
(ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => {
let size = ty::tls::with(|tcx| {
let ty = tcx.lift_to_global(&self.ty).unwrap();
tcx.layout_of(ty::ParamEnv::empty().and(ty))
.unwrap()
.size
});
p!(write("{}{}", sign_extend(bits, size) as i128, i))
},
(ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
=> p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())),
(_, ty::FnDef(did, _)) => p!(write("{}", ty::tls::with(|tcx| tcx.def_path_str(*did)))),
(ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) =>
p!(write("\"\"")),
(
ConstValue::Slice(Scalar::Ptr(ptr), len),
ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
) => {
ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
assert_eq!(len as usize as u64, len);
let slice =
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
Ok(p!(write("{:?}", s)))
})?;
},
_ => p!(write("{:?} : ", self.val), print(self.ty)),
}
}

View file

@ -295,6 +295,9 @@ CloneTypeFoldableAndLiftImpls! {
(),
bool,
usize,
u32,
crate::ty::BoundVar,
crate::ty::DebruijnIndex,
crate::ty::layout::VariantIdx,
u64,
String,
@ -311,6 +314,8 @@ CloneTypeFoldableAndLiftImpls! {
::rustc_target::spec::abi::Abi,
crate::mir::Local,
crate::mir::Promoted,
crate::mir::interpret::Scalar,
crate::mir::interpret::Pointer,
crate::traits::Reveal,
crate::ty::adjustment::AutoBorrowMutability,
crate::ty::AdtKind,
@ -788,6 +793,34 @@ BraceStructLiftImpl! {
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
type Lifted = ty::Const<'tcx>;
val, ty
}
}
EnumLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for interpret::ConstValue<'a> {
type Lifted = interpret::ConstValue<'tcx>;
(interpret::ConstValue::Unevaluated)(a, b),
(interpret::ConstValue::Param)(a),
(interpret::ConstValue::Infer)(a),
(interpret::ConstValue::Scalar)(a),
(interpret::ConstValue::Slice)(a, b),
(interpret::ConstValue::ByRef)(a, b),
}
}
EnumLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for ty::InferConst<'a> {
type Lifted = ty::InferConst<'tcx>;
(ty::InferConst::Var)(a),
(ty::InferConst::Fresh)(a),
(ty::InferConst::Canonical)(a, b),
}
}
impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> {
type Lifted = ConstVid<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {

View file

@ -10,7 +10,7 @@ use crate::const_eval::{const_field, const_variant_index};
use crate::hair::util::UserAnnotatedTyHelpers;
use crate::hair::constant::*;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::{UserTypeProjection};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
@ -291,15 +291,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
write!(f, "{}", subpattern)
}
PatternKind::Constant { value } => {
fmt_const_val(f, value)
write!(f, "{}", &value)
}
PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => {
fmt_const_val(f, lo)?;
write!(f, "{}", &lo)?;
match end {
RangeEnd::Included => write!(f, "..=")?,
RangeEnd::Excluded => write!(f, "..")?,
}
fmt_const_val(f, hi)
write!(f, "{}", &hi)
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => {

View file

@ -4136,8 +4136,7 @@ fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
}
},
_ => {
let mut s = String::new();
::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
let mut s = n.to_string();
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();