diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index e275ac7bc7dc..78acff0ada38 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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), diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 5d20fe4bab4f..6cc99a56933d 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -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 Builder { fn expr_as_constant(&mut self, expr: Expr) -> Constant { 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>) - -> Vec> - { - exprs.into_iter().map(|expr| self.as_constant(expr)).collect() - } - - fn named_field_constants(&mut self, - field_names: Vec>, - field_exprs: Vec>) - -> Vec> - { - 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)), + } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 72e505f2b6ed..61eeac30c0f1 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -99,14 +99,16 @@ impl Builder { 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 }); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2ff57a187123..519c6117717c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -221,10 +221,10 @@ enum TestKind { Switch { adt_def: H::AdtDef }, // test for equality - Eq { value: Constant, ty: H::Ty }, + Eq { value: Literal, ty: H::Ty }, // test whether the value falls within an inclusive range - Range { lo: Constant, hi: Constant, ty: H::Ty }, + Range { lo: Literal, hi: Literal, ty: H::Ty }, // test length of the slice is equal to len Len { len: usize, op: BinOp }, @@ -267,9 +267,12 @@ impl Builder { // 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; } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 2d0a6e61beb2..2d034baef167 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -33,20 +33,20 @@ impl Builder { } } - 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 Builder { 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 = diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 1c44988e4b40..9fa1d55e82f9 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -33,13 +33,14 @@ impl Builder { lvalue } - pub fn push_constant(&mut self, - block: BasicBlock, - span: H::Span, - ty: H::Ty, - constant: Constant) - -> Lvalue { - let temp = self.temp(ty); + pub fn push_literal(&mut self, + block: BasicBlock, + span: H::Span, + ty: H::Ty, + literal: Literal) + -> Lvalue { + 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 Builder { 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 Builder { span: H::Span, item_ref: ItemRef) -> Lvalue { - 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) } } diff --git a/src/librustc_mir/hair.rs b/src/librustc_mir/hair.rs index cb094ad49055..f4eb03c5d07c 100644 --- a/src/librustc_mir/hair.rs +++ b/src/librustc_mir/hair.rs @@ -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>; // e.g., &P type Expr: Clone+Debug+Mirror>; // e.g., &P type Stmt: Clone+Debug+Mirror>; // e.g., &P @@ -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; + /// Returns the type `bool`. fn bool_ty(&mut self) -> Self::Ty; + /// Returns the literal for `true` + fn true_literal(&mut self) -> Literal; + + /// Returns the literal for `true` + fn false_literal(&mut self) -> Literal; + /// Returns a reference to `PartialEq::::eq` fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef; @@ -261,9 +271,9 @@ pub enum PatternKind { Deref { subpattern: PatternRef }, // box P, &P, &mut P, etc - Constant { expr: ExprRef }, + Constant { value: Literal }, - Range { lo: ExprRef, hi: ExprRef }, + Range { lo: Literal, hi: Literal }, // matches against a slice, checking the length and extracting elements Slice { prefix: Vec>, diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index a1b891ab0908..e5a03cbb5864 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -646,44 +646,12 @@ impl Debug for Rvalue { #[derive(Clone, Debug, PartialEq)] pub struct Constant { pub span: H::Span, - pub kind: ConstantKind + pub ty: H::Ty, + pub literal: Literal } -#[derive(Clone, Debug, PartialEq)] -pub enum ConstantKind { - Literal(Literal), - Aggregate(AggregateKind, Vec>), - Call(Box>, Vec>), - Cast(Box>, H::Ty), - Repeat(Box>, Box>), - Ref(BorrowKind, Box>), - BinaryOp(BinOp, Box>, Box>), - UnaryOp(UnOp, Box>), - Projection(Box>) -} - -pub type ConstantProjection = - Projection,Constant>; - #[derive(Clone, Debug, PartialEq)] pub enum Literal { 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 }, } diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs index 97becd474b1f..098a85514eb2 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/tcx/expr.rs @@ -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> 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> -{ - 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::().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::().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> { let map = if arm.pats.len() == 1 { None diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs index 9c0ef55b3d83..04f52a52464b 100644 --- a/src/librustc_mir/tcx/mod.rs +++ b/src/librustc_mir/tcx/mod.rs @@ -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 { + 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 { + Literal::Value { value: ConstVal::Bool(true) } + } + + fn false_literal(&mut self) -> Literal { + Literal::Value { value: ConstVal::Bool(false) } + } + fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef { let eq_def_id = self.tcx.lang_items.eq_trait().unwrap(); self.cmp_method_ref(eq_def_id, "eq", ty) diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/tcx/pattern.rs index d80fbfa7fe89..fe0c2c6c76ad 100644 --- a/src/librustc_mir/tcx/pattern.rs +++ b/src/librustc_mir/tcx/pattern.rs @@ -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> 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> 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(