1
Fork 0

switch to using constvals for constants, instead of having constant

trees in MIR
This commit is contained in:
Niko Matsakis 2015-09-10 15:44:44 -04:00
parent dedde0bb5a
commit 1f4acfa691
11 changed files with 107 additions and 236 deletions

View file

@ -242,7 +242,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
}
}
#[derive(Clone, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum ConstVal {
Float(f64),
Int(i64),

View file

@ -10,8 +10,6 @@
//! See docs in build/expr/mod.rs
use rustc_data_structures::fnv::FnvHashMap;
use build::{Builder};
use hair::*;
use repr::*;
@ -28,93 +26,16 @@ impl<H:Hair> Builder<H> {
fn expr_as_constant(&mut self, expr: Expr<H>) -> Constant<H> {
let this = self;
let Expr { ty: _, temp_lifetime: _, span, kind } = expr;
let kind = match kind {
ExprKind::Scope { extent: _, value } => {
return this.as_constant(value);
}
ExprKind::Literal { literal } => {
ConstantKind::Literal(literal)
}
ExprKind::Vec { fields } => {
let fields = this.as_constants(fields);
ConstantKind::Aggregate(AggregateKind::Vec, fields)
}
ExprKind::Tuple { fields } => {
let fields = this.as_constants(fields);
ConstantKind::Aggregate(AggregateKind::Tuple, fields)
}
ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => {
let field_names = this.hir.fields(adt_def, variant_index);
let fields = this.named_field_constants(field_names, fields);
ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields)
}
ExprKind::Repeat { value, count } => {
let value = Box::new(this.as_constant(value));
let count = Box::new(this.as_constant(count));
ConstantKind::Repeat(value, count)
}
ExprKind::Binary { op, lhs, rhs } => {
let lhs = Box::new(this.as_constant(lhs));
let rhs = Box::new(this.as_constant(rhs));
ConstantKind::BinaryOp(op, lhs, rhs)
}
ExprKind::Unary { op, arg } => {
let arg = Box::new(this.as_constant(arg));
ConstantKind::UnaryOp(op, arg)
}
ExprKind::Field { lhs, name } => {
let lhs = this.as_constant(lhs);
ConstantKind::Projection(
Box::new(ConstantProjection {
base: lhs,
elem: ProjectionElem::Field(name),
}))
}
ExprKind::Deref { arg } => {
let arg = this.as_constant(arg);
ConstantKind::Projection(
Box::new(ConstantProjection {
base: arg,
elem: ProjectionElem::Deref,
}))
}
ExprKind::Call { fun, args } => {
let fun = this.as_constant(fun);
let args = this.as_constants(args);
ConstantKind::Call(Box::new(fun), args)
}
_ => {
let Expr { ty, temp_lifetime: _, span, kind } = expr;
match kind {
ExprKind::Scope { extent: _, value } =>
this.as_constant(value),
ExprKind::Literal { literal } =>
Constant { span: span, ty: ty, literal: literal },
_ =>
this.hir.span_bug(
span,
&format!("expression is not a valid constant {:?}", kind));
}
};
Constant { span: span, kind: kind }
}
fn as_constants(&mut self,
exprs: Vec<ExprRef<H>>)
-> Vec<Constant<H>>
{
exprs.into_iter().map(|expr| self.as_constant(expr)).collect()
}
fn named_field_constants(&mut self,
field_names: Vec<Field<H>>,
field_exprs: Vec<FieldExprRef<H>>)
-> Vec<Constant<H>>
{
let fields_map: FnvHashMap<_, _> =
field_exprs.into_iter()
.map(|f| (f.name, self.as_constant(f.expr)))
.collect();
let fields: Vec<_> =
field_names.into_iter()
.map(|n| fields_map[&n].clone())
.collect();
fields
&format!("expression is not a valid constant {:?}", kind)),
}
}
}

View file

@ -99,14 +99,16 @@ impl<H:Hair> Builder<H> {
true_block, expr_span, destination,
Constant {
span: expr_span,
kind: ConstantKind::Literal(Literal::Bool { value: true }),
ty: this.hir.bool_ty(),
literal: this.hir.true_literal(),
});
this.cfg.push_assign_constant(
false_block, expr_span, destination,
Constant {
span: expr_span,
kind: ConstantKind::Literal(Literal::Bool { value: false }),
ty: this.hir.bool_ty(),
literal: this.hir.false_literal(),
});
this.cfg.terminate(true_block, Terminator::Goto { target: join_block });

View file

@ -221,10 +221,10 @@ enum TestKind<H:Hair> {
Switch { adt_def: H::AdtDef },
// test for equality
Eq { value: Constant<H>, ty: H::Ty },
Eq { value: Literal<H>, ty: H::Ty },
// test whether the value falls within an inclusive range
Range { lo: Constant<H>, hi: Constant<H>, ty: H::Ty },
Range { lo: Literal<H>, hi: Literal<H>, ty: H::Ty },
// test length of the slice is equal to len
Len { len: usize, op: BinOp },
@ -267,9 +267,12 @@ impl<H:Hair> Builder<H> {
// If so, apply any bindings, test the guard (if any), and
// branch to the arm.
let candidate = candidates.pop().unwrap();
match self.bind_and_guard_matched_candidate(block, var_extent, candidate) {
None => { return; }
Some(b) => { block = b; }
if let Some(b) = self.bind_and_guard_matched_candidate(block, var_extent, candidate) {
block = b;
} else {
// if None is returned, then any remaining candidates
// are unreachable (at least not through this path).
return;
}
}

View file

@ -33,20 +33,20 @@ impl<H:Hair> Builder<H> {
}
}
PatternKind::Constant { ref expr } => {
let expr = self.as_constant(expr.clone());
PatternKind::Constant { ref value } => {
Test {
span: match_pair.pattern.span,
kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() },
kind: TestKind::Eq { value: value.clone(),
ty: match_pair.pattern.ty.clone() },
}
}
PatternKind::Range { ref lo, ref hi } => {
let lo = self.as_constant(lo.clone());
let hi = self.as_constant(hi.clone());
Test {
span: match_pair.pattern.span,
kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() },
kind: TestKind::Range { lo: lo.clone(),
hi: hi.clone(),
ty: match_pair.pattern.ty.clone() },
}
}
@ -90,15 +90,15 @@ impl<H:Hair> Builder<H> {
TestKind::Eq { value, ty } => {
// call PartialEq::eq(discrim, constant)
let constant = self.push_constant(block, test.span, ty.clone(), value);
let constant = self.push_literal(block, test.span, ty.clone(), value);
let item_ref = self.hir.partial_eq(ty);
self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant)
}
TestKind::Range { lo, hi, ty } => {
// Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`.
let lo = self.push_constant(block, test.span, ty.clone(), lo);
let hi = self.push_constant(block, test.span, ty.clone(), hi);
let lo = self.push_literal(block, test.span, ty.clone(), lo);
let hi = self.push_literal(block, test.span, ty.clone(), hi);
let item_ref = self.hir.partial_le(ty);
let lo_blocks =

View file

@ -33,13 +33,14 @@ impl<H:Hair> Builder<H> {
lvalue
}
pub fn push_constant(&mut self,
block: BasicBlock,
span: H::Span,
ty: H::Ty,
constant: Constant<H>)
-> Lvalue<H> {
let temp = self.temp(ty);
pub fn push_literal(&mut self,
block: BasicBlock,
span: H::Span,
ty: H::Ty,
literal: Literal<H>)
-> Lvalue<H> {
let temp = self.temp(ty.clone());
let constant = Constant { span: span, ty: ty, literal: literal };
self.cfg.push_assign_constant(block, span, &temp, constant);
temp
}
@ -55,8 +56,8 @@ impl<H:Hair> Builder<H> {
block, span, &temp,
Constant {
span: span,
kind: ConstantKind::Literal(Literal::Uint { bits: IntegralBits::BSize,
value: value as u64 }),
ty: self.hir.usize_ty(),
literal: self.hir.usize_literal(value),
});
temp
}
@ -66,13 +67,7 @@ impl<H:Hair> Builder<H> {
span: H::Span,
item_ref: ItemRef<H>)
-> Lvalue<H> {
let constant = Constant {
span: span,
kind: ConstantKind::Literal(Literal::Item {
def_id: item_ref.def_id,
substs: item_ref.substs
})
};
self.push_constant(block, span, item_ref.ty, constant)
let literal = Literal::Item { def_id: item_ref.def_id, substs: item_ref.substs };
self.push_literal(block, span, item_ref.ty, literal)
}
}

View file

@ -38,6 +38,7 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*)
type Ty: Clone+Debug+Eq; // e.g., ty::Ty<'tcx>
type Region: Copy+Debug; // e.g., ty::Region
type CodeExtent: Copy+Debug+Hash+Eq; // e.g., region::CodeExtent
type ConstVal: Clone+Debug+PartialEq; // e.g., ConstVal
type Pattern: Clone+Debug+Mirror<Self,Output=Pattern<Self>>; // e.g., &P<ast::Pat>
type Expr: Clone+Debug+Mirror<Self,Output=Expr<Self>>; // e.g., &P<ast::Expr>
type Stmt: Clone+Debug+Mirror<Self,Output=Stmt<Self>>; // e.g., &P<ast::Stmt>
@ -55,9 +56,18 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*)
/// Returns the type `usize`.
fn usize_ty(&mut self) -> Self::Ty;
/// Returns the literal for `true`
fn usize_literal(&mut self, value: usize) -> Literal<Self>;
/// Returns the type `bool`.
fn bool_ty(&mut self) -> Self::Ty;
/// Returns the literal for `true`
fn true_literal(&mut self) -> Literal<Self>;
/// Returns the literal for `true`
fn false_literal(&mut self) -> Literal<Self>;
/// Returns a reference to `PartialEq::<T,T>::eq`
fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef<Self>;
@ -261,9 +271,9 @@ pub enum PatternKind<H:Hair> {
Deref { subpattern: PatternRef<H> }, // box P, &P, &mut P, etc
Constant { expr: ExprRef<H> },
Constant { value: Literal<H> },
Range { lo: ExprRef<H>, hi: ExprRef<H> },
Range { lo: Literal<H>, hi: Literal<H> },
// matches against a slice, checking the length and extracting elements
Slice { prefix: Vec<PatternRef<H>>,

View file

@ -646,44 +646,12 @@ impl<H:Hair> Debug for Rvalue<H> {
#[derive(Clone, Debug, PartialEq)]
pub struct Constant<H:Hair> {
pub span: H::Span,
pub kind: ConstantKind<H>
pub ty: H::Ty,
pub literal: Literal<H>
}
#[derive(Clone, Debug, PartialEq)]
pub enum ConstantKind<H:Hair> {
Literal(Literal<H>),
Aggregate(AggregateKind<H>, Vec<Constant<H>>),
Call(Box<Constant<H>>, Vec<Constant<H>>),
Cast(Box<Constant<H>>, H::Ty),
Repeat(Box<Constant<H>>, Box<Constant<H>>),
Ref(BorrowKind, Box<Constant<H>>),
BinaryOp(BinOp, Box<Constant<H>>, Box<Constant<H>>),
UnaryOp(UnOp, Box<Constant<H>>),
Projection(Box<ConstantProjection<H>>)
}
pub type ConstantProjection<H> =
Projection<H,Constant<H>,Constant<H>>;
#[derive(Clone, Debug, PartialEq)]
pub enum Literal<H:Hair> {
Item { def_id: H::DefId, substs: H::Substs },
Projection { projection: H::Projection },
Int { bits: IntegralBits, value: i64 },
Uint { bits: IntegralBits, value: u64 },
Float { bits: FloatBits, value: f64 },
Char { c: char },
Bool { value: bool },
Bytes { value: H::Bytes },
String { value: H::InternedString },
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum IntegralBits {
B8, B16, B32, B64, BSize
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum FloatBits {
F32, F64
Value { value: H::ConstVal },
}

View file

@ -16,14 +16,13 @@ use tcx::Cx;
use tcx::block;
use tcx::pattern::PatNode;
use tcx::rustc::front::map;
use tcx::rustc::middle::const_eval;
use tcx::rustc::middle::def;
use tcx::rustc::middle::region::CodeExtent;
use tcx::rustc::middle::pat_util;
use tcx::rustc::middle::ty::{self, Ty};
use tcx::rustc_front::hir;
use tcx::rustc_front::util as hir_util;
use tcx::syntax::ast;
use tcx::syntax::codemap::Span;
use tcx::syntax::parse::token;
use tcx::syntax::ptr::P;
use tcx::to_ref::ToRef;
@ -83,9 +82,9 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
}
}
hir::ExprLit(ref lit) => {
let literal = convert_literal(cx, self.span, expr_ty, lit);
ExprKind::Literal { literal: literal }
hir::ExprLit(..) => {
let value = const_eval::eval_const_expr(cx.tcx, self);
ExprKind::Literal { literal: Literal::Value { value: value } }
}
hir::ExprBinary(op, ref lhs, ref rhs) => {
@ -452,67 +451,6 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
}
}
fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
expr_span: Span,
expr_ty: Ty<'tcx>,
literal: &ast::Lit)
-> Literal<Cx<'a,'tcx>>
{
use repr::IntegralBits::*;
match (&literal.node, &expr_ty.sty) {
(&ast::LitStr(ref text, _), _) =>
Literal::String { value: text.clone() },
(&ast::LitByteStr(ref bytes), _) =>
Literal::Bytes { value: bytes.clone() },
(&ast::LitByte(c), _) =>
Literal::Uint { bits: B8, value: c as u64 },
(&ast::LitChar(c), _) =>
Literal::Char { c: c },
(&ast::LitInt(v, _), &ty::TyUint(ast::TyU8)) =>
Literal::Uint { bits: B8, value: v },
(&ast::LitInt(v, _), &ty::TyUint(ast::TyU16)) =>
Literal::Uint { bits: B16, value: v },
(&ast::LitInt(v, _), &ty::TyUint(ast::TyU32)) =>
Literal::Uint { bits: B32, value: v },
(&ast::LitInt(v, _), &ty::TyUint(ast::TyU64)) =>
Literal::Uint { bits: B64, value: v },
(&ast::LitInt(v, _), &ty::TyUint(ast::TyUs)) =>
Literal::Uint { bits: BSize, value: v },
(&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI8)) =>
Literal::Int { bits: B8, value: -(v as i64) },
(&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI16)) =>
Literal::Int { bits: B16, value: -(v as i64) },
(&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI32)) =>
Literal::Int { bits: B32, value: -(v as i64) },
(&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI64)) =>
Literal::Int { bits: B64, value: -(v as i64) },
(&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyIs)) =>
Literal::Int { bits: BSize, value: -(v as i64) },
(&ast::LitInt(v, _), &ty::TyInt(ast::TyI8)) =>
Literal::Int { bits: B8, value: v as i64 },
(&ast::LitInt(v, _), &ty::TyInt(ast::TyI16)) =>
Literal::Int { bits: B16, value: v as i64 },
(&ast::LitInt(v, _), &ty::TyInt(ast::TyI32)) =>
Literal::Int { bits: B32, value: v as i64 },
(&ast::LitInt(v, _), &ty::TyInt(ast::TyI64)) =>
Literal::Int { bits: B64, value: v as i64 },
(&ast::LitInt(v, _), &ty::TyInt(ast::TyIs)) =>
Literal::Int { bits: BSize, value: v as i64 },
(&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF32)) |
(&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF32)) =>
Literal::Float { bits: FloatBits::F32, value: v.parse::<f64>().unwrap() },
(&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF64)) |
(&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF64)) =>
Literal::Float { bits: FloatBits::F64, value: v.parse::<f64>().unwrap() },
(&ast::LitBool(v), _) =>
Literal::Bool { value: v },
(ref l, ref t) =>
cx.tcx.sess.span_bug(
expr_span,
&format!("Invalid literal/type combination: {:?},{:?}", l, t))
}
}
fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'tcx>> {
let map = if arm.pats.len() == 1 {
None

View file

@ -14,6 +14,7 @@ use std::fmt::{Debug, Formatter, Error};
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use self::rustc::middle::const_eval::ConstVal;
use self::rustc::middle::def_id::DefId;
use self::rustc::middle::infer::InferCtxt;
use self::rustc::middle::region::CodeExtent;
@ -56,6 +57,7 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
type Ty = Ty<'tcx>;
type Region = ty::Region;
type CodeExtent = CodeExtent;
type ConstVal = ConstVal;
type Pattern = PatNode<'tcx>;
type Expr = &'tcx hir::Expr;
type Stmt = &'tcx hir::Stmt;
@ -70,10 +72,22 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
self.tcx.types.usize
}
fn usize_literal(&mut self, value: usize) -> Literal<Self> {
Literal::Value { value: ConstVal::Uint(value as u64) }
}
fn bool_ty(&mut self) -> Ty<'tcx> {
self.tcx.types.bool
}
fn true_literal(&mut self) -> Literal<Self> {
Literal::Value { value: ConstVal::Bool(true) }
}
fn false_literal(&mut self) -> Literal<Self> {
Literal::Value { value: ConstVal::Bool(false) }
}
fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
self.cmp_method_ref(eq_def_id, "eq", ty)

View file

@ -14,9 +14,10 @@ use repr::*;
use rustc_data_structures::fnv::FnvHashMap;
use std::rc::Rc;
use tcx::Cx;
use tcx::rustc::middle::const_eval::lookup_const_by_id;
use tcx::rustc::middle::const_eval;
use tcx::rustc::middle::def;
use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
use tcx::rustc::middle::subst::Substs;
use tcx::rustc::middle::ty::{self, Ty};
use tcx::rustc_front::hir;
use tcx::syntax::ast;
@ -145,12 +146,19 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
hir::PatWild(..) =>
PatternKind::Wild,
hir::PatLit(ref lt) =>
PatternKind::Constant { expr: lt.to_ref() },
hir::PatLit(ref value) => {
let value = const_eval::eval_const_expr(cx.tcx, value);
let value = Literal::Value { value: value };
PatternKind::Constant { value: value }
},
hir::PatRange(ref begin, ref end) =>
PatternKind::Range { lo: begin.to_ref(),
hi: end.to_ref() },
hir::PatRange(ref lo, ref hi) => {
let lo = const_eval::eval_const_expr(cx.tcx, lo);
let lo = Literal::Value { value: lo };
let hi = const_eval::eval_const_expr(cx.tcx, hi);
let hi = Literal::Value { value: hi };
PatternKind::Range { lo: lo, hi: hi }
},
hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
if pat_is_resolved_const(&cx.tcx.def_map, self.pat) =>
@ -158,13 +166,25 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
match def {
def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
Some(const_expr) =>
PatternKind::Constant { expr: const_expr.to_ref() },
None =>
match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
Some(const_expr) => {
let opt_value =
const_eval::eval_const_expr_partial(
cx.tcx, const_expr,
const_eval::EvalHint::ExprTypeChecked);
let literal = if let Ok(value) = opt_value {
Literal::Value { value: value }
} else {
let substs = cx.tcx.mk_substs(Substs::empty());
Literal::Item { def_id: def_id, substs: substs }
};
PatternKind::Constant { value: literal }
}
None => {
cx.tcx.sess.span_bug(
self.pat.span,
&format!("cannot eval constant: {:?}", def_id)),
&format!("cannot eval constant: {:?}", def_id))
}
},
_ =>
cx.tcx.sess.span_bug(