diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-02-15 15:00:20 +0200 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-02-25 18:35:26 +0200 |
| commit | e7a48821c0d30ccd6b7ea88be24eed1bcba5f48a (patch) | |
| tree | 82387e47712464862cadd6749f6c8556d59df63b | |
| parent | c832e6f3272fd01e22a6370e7745e305fe13a4c9 (diff) | |
| download | rust-e7a48821c0d30ccd6b7ea88be24eed1bcba5f48a.tar.gz rust-e7a48821c0d30ccd6b7ea88be24eed1bcba5f48a.zip | |
rustc_const_eval: always demand typeck_tables for evaluating constants.
60 files changed, 705 insertions, 1221 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 458a774c956..b1b1b849437 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -390,44 +390,6 @@ RFC. It is, however, [currently unimplemented][iss15872]. [iss15872]: https://github.com/rust-lang/rust/issues/15872 "##, -E0109: r##" -You tried to give a type parameter to a type which doesn't need it. Erroneous -code example: - -```compile_fail,E0109 -type X = u32<i32>; // error: type parameters are not allowed on this type -``` - -Please check that you used the correct type and recheck its definition. Perhaps -it doesn't need the type parameter. - -Example: - -``` -type X = u32; // this compiles -``` - -Note that type parameters for enum-variant constructors go after the variant, -not after the enum (Option::None::<u32>, not Option::<u32>::None). -"##, - -E0110: r##" -You tried to give a lifetime parameter to a type which doesn't need it. -Erroneous code example: - -```compile_fail,E0110 -type X = u32<'static>; // error: lifetime parameters are not allowed on - // this type -``` - -Please check that the correct type was used and recheck its definition; perhaps -it doesn't need the lifetime parameter. Example: - -``` -type X = u32; // ok! -``` -"##, - E0133: r##" Unsafe code was used outside of an unsafe function or block. @@ -627,41 +589,6 @@ attributes: See also https://doc.rust-lang.org/book/no-stdlib.html "##, -E0229: r##" -An associated type binding was done outside of the type parameter declaration -and `where` clause. Erroneous code example: - -```compile_fail,E0229 -pub trait Foo { - type A; - fn boo(&self) -> <Self as Foo>::A; -} - -struct Bar; - -impl Foo for isize { - type A = usize; - fn boo(&self) -> usize { 42 } -} - -fn baz<I>(x: &<I as Foo<A=Bar>>::A) {} -// error: associated type bindings are not allowed here -``` - -To solve this error, please move the type bindings in the type parameter -declaration: - -```ignore -fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok! -``` - -Or in the `where` clause: - -```ignore -fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {} -``` -"##, - E0261: r##" When using a lifetime like `'a` in a type, it must be declared before being used. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 60d03ccfe24..c4fccdcb9eb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -76,7 +76,6 @@ pub mod infer; pub mod lint; pub mod middle { - pub mod astconv_util; pub mod expr_use_visitor; pub mod const_val; pub mod cstore; diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs deleted file mode 100644 index 3418034b069..00000000000 --- a/src/librustc/middle/astconv_util.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * This module contains a simple utility routine - * used by both `typeck` and `const_eval`. - * Almost certainly this could (and should) be refactored out of existence. - */ - -use hir; -use hir::def::Def; -use ty::{Ty, TyCtxt}; - -use syntax_pos::Span; - -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) { - for segment in segments { - for typ in segment.parameters.types() { - struct_span_err!(self.sess, typ.span, E0109, - "type parameters are not allowed on this type") - .span_label(typ.span, &format!("type parameter not allowed")) - .emit(); - break; - } - for lifetime in segment.parameters.lifetimes() { - struct_span_err!(self.sess, lifetime.span, E0110, - "lifetime parameters are not allowed on this type") - .span_label(lifetime.span, - &format!("lifetime parameter not allowed on this type")) - .emit(); - break; - } - for binding in segment.parameters.bindings() { - self.prohibit_projection(binding.span); - break; - } - } - } - - pub fn prohibit_projection(self, span: Span) - { - let mut err = struct_span_err!(self.sess, span, E0229, - "associated type bindings are not allowed here"); - err.span_label(span, &format!("associate type not allowed here")).emit(); - } - - pub fn prim_ty_to_ty(self, - segments: &[hir::PathSegment], - nty: hir::PrimTy) - -> Ty<'tcx> { - self.prohibit_type_params(segments); - match nty { - hir::TyBool => self.types.bool, - hir::TyChar => self.types.char, - hir::TyInt(it) => self.mk_mach_int(it), - hir::TyUint(uit) => self.mk_mach_uint(uit), - hir::TyFloat(ft) => self.mk_mach_float(ft), - hir::TyStr => self.mk_str() - } - } - - /// If a type in the AST is a primitive type, return the ty::Ty corresponding - /// to it. - pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> { - if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node { - if let Def::PrimTy(nty) = path.def { - Some(self.prim_ty_to_ty(&path.segments, nty)) - } else { - None - } - } else { - None - } - } -} diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 11919db479c..d81f89827d9 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -12,28 +12,30 @@ use syntax::symbol::InternedString; use syntax::ast; use std::rc::Rc; use hir::def_id::DefId; +use ty::subst::Substs; use rustc_const_math::*; + use self::ConstVal::*; pub use rustc_const_math::ConstInt; use std::collections::BTreeMap; #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] -pub enum ConstVal { +pub enum ConstVal<'tcx> { Float(ConstFloat), Integral(ConstInt), Str(InternedString), ByteStr(Rc<Vec<u8>>), Bool(bool), - Function(DefId), - Struct(BTreeMap<ast::Name, ConstVal>), - Tuple(Vec<ConstVal>), - Array(Vec<ConstVal>), - Repeat(Box<ConstVal>, u64), + Function(DefId, &'tcx Substs<'tcx>), + Struct(BTreeMap<ast::Name, ConstVal<'tcx>>), + Tuple(Vec<ConstVal<'tcx>>), + Array(Vec<ConstVal<'tcx>>), + Repeat(Box<ConstVal<'tcx>>, u64), Char(char), } -impl ConstVal { +impl<'tcx> ConstVal<'tcx> { pub fn description(&self) -> &'static str { match *self { Float(f) => f.description(), @@ -43,7 +45,7 @@ impl ConstVal { Bool(_) => "boolean", Struct(_) => "struct", Tuple(_) => "tuple", - Function(_) => "function definition", + Function(..) => "function definition", Array(..) => "array", Repeat(..) => "repeat", Char(..) => "char", @@ -53,8 +55,7 @@ impl ConstVal { pub fn to_const_int(&self) -> Option<ConstInt> { match *self { ConstVal::Integral(i) => Some(i), - ConstVal::Bool(true) => Some(ConstInt::Infer(1)), - ConstVal::Bool(false) => Some(ConstInt::Infer(0)), + ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), _ => None } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d2a657e35b5..40ebc97a78a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -542,7 +542,7 @@ impl<'tcx> Terminator<'tcx> { impl<'tcx> TerminatorKind<'tcx> { pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)]; + static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, @@ -1224,7 +1224,7 @@ pub enum Literal<'tcx> { substs: &'tcx Substs<'tcx>, }, Value { - value: ConstVal, + value: ConstVal<'tcx>, }, Promoted { // Index into the `promoted` vector of `Mir`. @@ -1271,7 +1271,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { write!(fmt, "b\"{}\"", escaped) } Bool(b) => write!(fmt, "{:?}", b), - Function(def_id) => write!(fmt, "{}", item_path_str(def_id)), + Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Struct(_) | Tuple(_) | Array(_) | Repeat(..) => bug!("ConstVal `{:?}` should not be in MIR", const_val), Char(c) => write!(fmt, "{:?}", c), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 318c866a59f..6961e0da362 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -244,6 +244,10 @@ pub struct TypeckTables<'tcx> { /// Set of trait imports actually used in the method resolution. /// This is used for warning unused imports. pub used_trait_imports: DefIdSet, + + /// If any errors occurred while type-checking this body, + /// this field will be set to `true`. + pub tainted_by_errors: bool, } impl<'tcx> TypeckTables<'tcx> { @@ -262,6 +266,7 @@ impl<'tcx> TypeckTables<'tcx> { cast_kinds: NodeMap(), lints: lint::LintTable::new(), used_trait_imports: DefIdSet(), + tainted_by_errors: false, } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3773796e47d..e7895ca7990 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; -use rustc_const_math::ConstInt; use std::cmp; use std::fmt; @@ -1183,11 +1182,7 @@ impl<'a, 'gcx, 'tcx> Layout { i64::min_value(), true); for discr in def.discriminants(tcx) { - let x = match discr.erase_type() { - ConstInt::InferSigned(i) => i as i64, - ConstInt::Infer(i) => i as u64 as i64, - _ => bug!() - }; + let x = discr.to_u128_unchecked() as i64; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 358d69ff8db..b79ab2a26fd 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -381,7 +381,7 @@ define_maps! { <'tcx> /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()> + pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()> } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 64480e51022..49c25d25c60 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -47,6 +47,35 @@ type Disr = ConstInt; } +macro_rules! typed_literal { + ($tcx:expr, $ty:expr, $lit:expr) => { + match $ty { + SignedInt(ast::IntTy::I8) => ConstInt::I8($lit), + SignedInt(ast::IntTy::I16) => ConstInt::I16($lit), + SignedInt(ast::IntTy::I32) => ConstInt::I32($lit), + SignedInt(ast::IntTy::I64) => ConstInt::I64($lit), + SignedInt(ast::IntTy::I128) => ConstInt::I128($lit), + SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type { + ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)), + ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)), + ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)), + _ => bug!(), + }, + UnsignedInt(ast::UintTy::U8) => ConstInt::U8($lit), + UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit), + UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit), + UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit), + UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit), + UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type { + ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)), + ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)), + ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)), + _ => bug!(), + }, + } + } +} + impl IntTypeExt for attr::IntType { fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match *self { @@ -66,30 +95,7 @@ impl IntTypeExt for attr::IntType { } fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { - match *self { - SignedInt(ast::IntTy::I8) => ConstInt::I8(0), - SignedInt(ast::IntTy::I16) => ConstInt::I16(0), - SignedInt(ast::IntTy::I32) => ConstInt::I32(0), - SignedInt(ast::IntTy::I64) => ConstInt::I64(0), - SignedInt(ast::IntTy::I128) => ConstInt::I128(0), - SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type { - ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)), - ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)), - ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)), - _ => bug!(), - }, - UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0), - UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0), - UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0), - UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0), - UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0), - UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type { - ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)), - ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)), - ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)), - _ => bug!(), - }, - } + typed_literal!(tcx, *self, 0) } fn assert_ty_matches(&self, val: Disr) { @@ -114,7 +120,7 @@ impl IntTypeExt for attr::IntType { -> Option<Disr> { if let Some(val) = val { self.assert_ty_matches(val); - (val + ConstInt::Infer(1)).ok() + (val + typed_literal!(tcx, *self, 1)).ok() } else { Some(self.initial_discriminant(tcx)) } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 5a9f885719c..53a7e872928 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -221,21 +221,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } #[derive(Clone, Debug, PartialEq)] -pub enum Constructor { +pub enum Constructor<'tcx> { /// The constructor of all patterns that don't vary by constructor, /// e.g. struct patterns and fixed-length arrays. Single, /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(ConstVal), + ConstantValue(ConstVal<'tcx>), /// Ranges of literal values (`2...5` and `2..5`). - ConstantRange(ConstVal, ConstVal, RangeEnd), + ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd), /// Array patterns of length n. Slice(usize), } -impl<'tcx> Constructor { +impl<'tcx> Constructor<'tcx> { fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize { match self { &Variant(vid) => adt.variant_index_with_id(vid), @@ -289,7 +289,7 @@ impl<'tcx> Witness<'tcx> { fn push_wild_constructor<'a>( mut self, cx: &MatchCheckCtxt<'a, 'tcx>, - ctor: &Constructor, + ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> Self { @@ -321,7 +321,7 @@ impl<'tcx> Witness<'tcx> { fn apply_constructor<'a>( mut self, cx: &MatchCheckCtxt<'a,'tcx>, - ctor: &Constructor, + ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> Self { @@ -399,7 +399,8 @@ impl<'tcx> Witness<'tcx> { /// We make sure to omit constructors that are statically impossible. eg for /// Option<!> we do not include Some(_) in the returned list of constructors. fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, - pcx: PatternContext<'tcx>) -> Vec<Constructor> + pcx: PatternContext<'tcx>) + -> Vec<Constructor<'tcx>> { debug!("all_constructors({:?})", pcx.ty); match pcx.ty.sty { @@ -664,7 +665,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( cx: &mut MatchCheckCtxt<'a, 'tcx>, &Matrix(ref m): &Matrix<'p, 'tcx>, v: &[&'p Pattern<'tcx>], - ctor: Constructor, + ctor: Constructor<'tcx>, lty: Ty<'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { @@ -702,10 +703,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. /// /// Returns None in case of a catch-all, which can't be specialized. -fn pat_constructors(_cx: &mut MatchCheckCtxt, - pat: &Pattern, - pcx: PatternContext) - -> Option<Vec<Constructor>> +fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, + pat: &Pattern<'tcx>, + pcx: PatternContext) + -> Option<Vec<Constructor<'tcx>>> { match *pat.kind { PatternKind::Binding { .. } | PatternKind::Wild => diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index db5df72267d..e2b9f174ff0 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { "statics cannot be referenced in patterns"); } PatternError::ConstEval(err) => { - report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit(); + report_const_eval_err(self.tcx, &err, pat_span, "pattern"); } } } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 8c8b2b5da36..9937cbbf8e1 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -576,22 +576,6 @@ integer type: https://doc.rust-lang.org/reference.html#ffi-attributes "##, - -E0306: r##" -In an array type `[T; N]`, `N` is the number of elements in the array. This -must be an unsigned integer. Erroneous code example: - -```compile_fail,E0306 -const X: [i32; true] = [0]; // error: expected `usize` for array length, - // found boolean -``` - -Working example: - -``` -const X: [i32; 1] = [0]; -``` -"##, } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 0ab2255aab0..284991a11b1 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -11,7 +11,6 @@ use rustc::middle::const_val::ConstVal::*; use rustc::middle::const_val::ConstVal; use self::ErrKind::*; -use self::EvalHint::*; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; @@ -20,7 +19,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; -use rustc::ty::subst::Substs; +use rustc::ty::subst::{Substs, Subst}; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::DefIdMap; @@ -28,7 +27,6 @@ use rustc::util::nodemap::DefIdMap; use graphviz::IntoCow; use syntax::ast; use rustc::hir::{self, Expr}; -use syntax::attr::IntType; use syntax_pos::Span; use std::borrow::Cow; @@ -37,18 +35,24 @@ use std::cmp::Ordering; use rustc_const_math::*; use rustc_errors::DiagnosticBuilder; +macro_rules! signal { + ($e:expr, $exn:expr) => { + return Err(ConstEvalErr { span: $e.span, kind: $exn }) + } +} + macro_rules! math { ($e:expr, $op:expr) => { match $op { Ok(val) => val, - Err(e) => signal!($e, Math(e)), + Err(e) => signal!($e, ErrKind::from(e)), } } } fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, variant_def: DefId) - -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>)> { + -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) { let enum_node_id = tcx.hir.get_parent(variant_node_id); if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) { @@ -58,7 +62,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return variant.node.disr_expr.map(|e| { let def_id = tcx.hir.body_owner_def_id(e); (&tcx.hir.body(e).value, - tcx.maps.typeck_tables.borrow().get(&def_id).cloned()) + tcx.item_tables(def_id)) }); } } @@ -75,55 +79,41 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// This generally happens in late/trans const evaluation. pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, - substs: Option<&'tcx Substs<'tcx>>) + substs: &'tcx Substs<'tcx>) -> Option<(&'tcx Expr, - Option<&'a ty::TypeckTables<'tcx>>, - Option<ty::Ty<'tcx>>)> { + &'a ty::TypeckTables<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { None => None, Some(hir_map::NodeItem(&hir::Item { - node: hir::ItemConst(ref ty, body), .. + node: hir::ItemConst(_, body), .. })) | Some(hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Const(ref ty, body), .. + node: hir::ImplItemKind::Const(_, body), .. })) => { Some((&tcx.hir.body(body).value, - tcx.maps.typeck_tables.borrow().get(&def_id).cloned(), - tcx.ast_ty_to_prim_ty(ty))) + tcx.item_tables(def_id))) } Some(hir_map::NodeTraitItem(ti)) => match ti.node { - hir::TraitItemKind::Const(ref ty, default) => { - if let Some(substs) = substs { - // If we have a trait item and the substitutions for it, - // `resolve_trait_associated_const` will select an impl - // or the default. - let trait_id = tcx.hir.get_parent(node_id); - let trait_id = tcx.hir.local_def_id(trait_id); - let default_value = default.map(|body| { - (&tcx.hir.body(body).value, - tcx.maps.typeck_tables.borrow().get(&def_id).cloned(), - tcx.ast_ty_to_prim_ty(ty)) - }); - resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) - } else { - // Technically, without knowing anything about the - // expression that generates the obligation, we could - // still return the default if there is one. However, - // it's safer to return `None` than to return some value - // that may differ from what you would get from - // correctly selecting an impl. - None - } + hir::TraitItemKind::Const(_, default) => { + // If we have a trait item and the substitutions for it, + // `resolve_trait_associated_const` will select an impl + // or the default. + let trait_id = tcx.hir.get_parent(node_id); + let trait_id = tcx.hir.local_def_id(trait_id); + let default_value = default.map(|body| { + (&tcx.hir.body(body).value, + tcx.item_tables(def_id)) + }); + resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) } _ => None }, Some(_) => None } } else { - let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (&body.value, Some(tcx.item_tables(def_id)), - Some(tcx.item_type(def_id))) + let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { + (&body.value, tcx.item_tables(def_id)) }); match tcx.sess.cstore.describe_def(def_id) { Some(Def::AssociatedConst(_)) => { @@ -133,30 +123,26 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // trait-associated const if the caller gives us the // substitutions for the reference to it. if let Some(trait_id) = trait_id { - if let Some(substs) = substs { - resolve_trait_associated_const(tcx, def_id, expr_tables_ty, - trait_id, substs) - } else { - None - } + resolve_trait_associated_const(tcx, def_id, expr_and_tables, + trait_id, substs) } else { - expr_tables_ty + expr_and_tables } }, - Some(Def::Const(..)) => expr_tables_ty, + Some(Def::Const(..)) => expr_and_tables, _ => None } } } fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option<(&'tcx hir::Body, Option<&'a ty::TypeckTables<'tcx>>)> + -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| { if fn_like.constness() == hir::Constness::Const { Some((tcx.hir.body(fn_like.body()), - tcx.maps.typeck_tables.borrow().get(&def_id).cloned())) + tcx.item_tables(def_id))) } else { None } @@ -164,7 +150,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } else { if tcx.sess.cstore.is_const_fn(def_id) { tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (body, Some(tcx.item_tables(def_id))) + (body, tcx.item_tables(def_id)) }) } else { None @@ -172,7 +158,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } } -pub fn report_const_eval_err<'a, 'tcx>( +fn build_const_eval_err<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, err: &ConstEvalErr, primary_span: Span, @@ -189,6 +175,18 @@ pub fn report_const_eval_err<'a, 'tcx>( diag } +pub fn report_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) +{ + if let TypeckError = err.kind { + return; + } + build_const_eval_err(tcx, err, primary_span, primary_kind).emit(); +} + pub fn fatal_const_eval_err<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, err: &ConstEvalErr, @@ -196,7 +194,7 @@ pub fn fatal_const_eval_err<'a, 'tcx>( primary_kind: &str) -> ! { - report_const_eval_err(tcx, err, primary_span, primary_kind).emit(); + report_const_eval_err(tcx, err, primary_span, primary_kind); tcx.sess.abort_if_errors(); unreachable!() } @@ -222,69 +220,57 @@ pub fn note_const_eval_err<'a, 'tcx>( pub struct ConstContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - tables: Option<&'a ty::TypeckTables<'tcx>>, - fn_args: Option<DefIdMap<ConstVal>> + tables: &'a ty::TypeckTables<'tcx>, + substs: &'tcx Substs<'tcx>, + fn_args: Option<DefIdMap<ConstVal<'tcx>>> } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self { let def_id = tcx.hir.body_owner_def_id(body); - ConstContext { - tcx: tcx, - tables: tcx.maps.typeck_tables.borrow().get(&def_id).cloned(), - fn_args: None - } + ConstContext::with_tables(tcx, tcx.item_tables(def_id)) } pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self { ConstContext { tcx: tcx, - tables: Some(tables), + tables: tables, + substs: tcx.intern_substs(&[]), fn_args: None } } /// Evaluate a constant expression in a context where the expression isn't - /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked, - /// but a few places need to evaluate constants during type-checking, like - /// computing the length of an array. (See also the FIXME above EvalHint.) - pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult { - eval_const_expr_partial(self, e, ty_hint) + /// guaranteed to be evaluatable. + pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> { + if self.tables.tainted_by_errors { + signal!(e, TypeckError); + } + eval_const_expr_partial(self, e) } } #[derive(Clone, Debug)] -pub struct ConstEvalErr { +pub struct ConstEvalErr<'tcx> { pub span: Span, - pub kind: ErrKind, + pub kind: ErrKind<'tcx>, } #[derive(Clone, Debug)] -pub enum ErrKind { +pub enum ErrKind<'tcx> { CannotCast, - CannotCastTo(&'static str), - InvalidOpForInts(hir::BinOp_), - InvalidOpForBools(hir::BinOp_), - InvalidOpForFloats(hir::BinOp_), - InvalidOpForIntUint(hir::BinOp_), - InvalidOpForUintInt(hir::BinOp_), - NegateOn(ConstVal), - NotOn(ConstVal), - CallOn(ConstVal), - MissingStructField, + NegateOn(ConstVal<'tcx>), + NotOn(ConstVal<'tcx>), + CallOn(ConstVal<'tcx>), + NonConstPath, UnimplementedConstVal(&'static str), - UnresolvedPath, ExpectedConstTuple, ExpectedConstStruct, - TupleIndexOutOfBounds, IndexedNonVec, - IndexNegative, - IndexNotInt, + IndexNotUsize, IndexOutOfBounds { len: u64, index: u64 }, - RepeatCountNotNatural, - RepeatCountNotInt, MiscBinaryOp, MiscCatchAll, @@ -292,18 +278,17 @@ pub enum ErrKind { IndexOpFeatureGated, Math(ConstMathErr), - IntermediateUnsignedNegative, - /// Expected, Got - TypeMismatch(String, ConstInt), + ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>), - BadType(ConstVal), - ErroneousReferencedConstant(Box<ConstEvalErr>), - CharCast(ConstInt), + TypeckError } -impl From<ConstMathErr> for ErrKind { - fn from(err: ConstMathErr) -> ErrKind { - Math(err) +impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> { + fn from(err: ConstMathErr) -> ErrKind<'tcx> { + match err { + ConstMathErr::UnsignedNegation => TypeckError, + _ => Math(err) + } } } @@ -321,7 +306,7 @@ impl<'a> ConstEvalErrDescription<'a> { } } -impl ConstEvalErr { +impl<'tcx> ConstEvalErr<'tcx> { pub fn description(&self) -> ConstEvalErrDescription { use self::ErrKind::*; use self::ConstEvalErrDescription::*; @@ -335,12 +320,6 @@ impl ConstEvalErr { match self.kind { CannotCast => simple!("can't cast this type"), - CannotCastTo(s) => simple!("can't cast this type to {}", s), - InvalidOpForInts(_) => simple!("can't do this op on integrals"), - InvalidOpForBools(_) => simple!("can't do this op on bools"), - InvalidOpForFloats(_) => simple!("can't do this op on floats"), - InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"), - InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"), NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), NotOn(ref const_val) => simple!("not on {}", const_val.description()), CallOn(ref const_val) => simple!("call on {}", const_val.description()), @@ -349,111 +328,42 @@ impl ConstEvalErr { NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => simple!("unimplemented constant expression: {}", what), - UnresolvedPath => simple!("unresolved path in constant expression"), ExpectedConstTuple => simple!("expected constant tuple"), ExpectedConstStruct => simple!("expected constant struct"), - TupleIndexOutOfBounds => simple!("tuple index out of bounds"), IndexedNonVec => simple!("indexing is only supported for arrays"), - IndexNegative => simple!("indices must be non-negative integers"), - IndexNotInt => simple!("indices must be integers"), + IndexNotUsize => simple!("indices must be of type `usize`"), IndexOutOfBounds { len, index } => { simple!("index out of bounds: the len is {} but the index is {}", len, index) } - RepeatCountNotNatural => simple!("repeat count must be a natural number"), - RepeatCountNotInt => simple!("repeat count must be integers"), MiscBinaryOp => simple!("bad operands for binary"), MiscCatchAll => simple!("unsupported constant expr"), IndexOpFeatureGated => simple!("the index operation on const values is unstable"), Math(ref err) => Simple(err.description().into_cow()), - IntermediateUnsignedNegative => simple!( - "during the computation of an unsigned a negative \ - number was encountered. This is most likely a bug in\ - the constant evaluator"), - - TypeMismatch(ref expected, ref got) => { - simple!("expected {}, found {}", expected, got.description()) - }, - BadType(ref i) => simple!("value of wrong type: {:?}", i), ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), - CharCast(ref got) => { - simple!("only `u8` can be cast as `char`, not `{}`", got.description()) - }, - } - } -} - -pub type EvalResult = Result<ConstVal, ConstEvalErr>; -pub type CastResult = Result<ConstVal, ErrKind>; - -// FIXME: Long-term, this enum should go away: trying to evaluate -// an expression which hasn't been type-checked is a recipe for -// disaster. That said, it's not clear how to fix ast_ty_to_ty -// to avoid the ordering issue. - -/// Hint to determine how to evaluate constant expressions which -/// might not be type-checked. -#[derive(Copy, Clone, Debug)] -pub enum EvalHint<'tcx> { - /// We have a type-checked expression. - ExprTypeChecked, - /// We have an expression which hasn't been type-checked, but we have - /// an idea of what the type will be because of the context. For example, - /// the length of an array is always `usize`. (This is referred to as - /// a hint because it isn't guaranteed to be consistent with what - /// type-checking would compute.) - UncheckedExprHint(Ty<'tcx>), - /// We have an expression which has not yet been type-checked, and - /// and we have no clue what the type will be. - UncheckedExprNoHint, -} -impl<'tcx> EvalHint<'tcx> { - fn erase_hint(&self) -> EvalHint<'tcx> { - match *self { - ExprTypeChecked => ExprTypeChecked, - UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint, - } - } - fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> { - match *self { - ExprTypeChecked => ExprTypeChecked, - _ => UncheckedExprHint(ty), + TypeckError => simple!("type-checking failed"), } } } -macro_rules! signal { - ($e:expr, $exn:expr) => { - return Err(ConstEvalErr { span: $e.span, kind: $exn }) - } -} +pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>; +pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>; fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, - e: &Expr, - ty_hint: EvalHint<'tcx>) -> EvalResult { + e: &Expr) -> EvalResult<'tcx> { let tcx = cx.tcx; - // Try to compute the type of the expression based on the EvalHint. - // (See also the definition of EvalHint, and the FIXME above EvalHint.) - let ety = match ty_hint { - ExprTypeChecked => { - // After type-checking, expr_ty is guaranteed to succeed. - cx.tables.map(|tables| tables.expr_ty(e)) - } - UncheckedExprHint(ty) => { - // Use the type hint; it's not guaranteed to be right, but it's - // usually good enough. - Some(ty) - } - UncheckedExprNoHint => { - // This expression might not be type-checked, and we have no hint. - // Try to query the context for a type anyway; we might get lucky - // (for example, if the expression was imported from another crate). - cx.tables.and_then(|tables| tables.expr_ty_opt(e)) - } + let ety = cx.tables.expr_ty(e); + + // Avoid applying substitutions if they're empty, that'd ICE. + let ety = if cx.substs.is_empty() { + ety + } else { + ety.subst(tcx, cx.substs) }; + let result = match e.node { hir::ExprUnary(hir::UnNeg, ref inner) => { // unary neg literals already got their sign during creation @@ -465,28 +375,28 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; const I128_OVERFLOW: u128 = i128::min_value() as u128; - match (&lit.node, ety.map(|t| &t.sty)) { - (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) | + match (&lit.node, &ety.sty) { + (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { return Ok(Integral(I8(i8::min_value()))) }, - (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) | + (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { return Ok(Integral(I16(i16::min_value()))) }, - (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) | + (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { return Ok(Integral(I32(i32::min_value()))) }, - (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) | + (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { return Ok(Integral(I64(i64::min_value()))) }, - (&LitKind::Int(I128_OVERFLOW, _), Some(&ty::TyInt(IntTy::I128))) | + (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { return Ok(Integral(I128(i128::min_value()))) }, - (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) | + (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) | (&LitKind::Int(n, Signed(IntTy::Is)), _) => { match tcx.sess.target.int_type { IntTy::I16 => if n == I16_OVERFLOW { @@ -498,20 +408,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, IntTy::I64 => if n == I64_OVERFLOW { return Ok(Integral(Isize(Is64(i64::min_value())))); }, - _ => bug!(), + _ => span_bug!(e.span, "typeck error") } }, _ => {}, } } - match cx.eval(inner, ty_hint)? { + match cx.eval(inner)? { Float(f) => Float(-f), Integral(i) => Integral(math!(e, -i)), const_val => signal!(e, NegateOn(const_val)), } } hir::ExprUnary(hir::UnNot, ref inner) => { - match cx.eval(inner, ty_hint)? { + match cx.eval(inner)? { Integral(i) => Integral(math!(e, !i)), Bool(b) => Bool(!b), const_val => signal!(e, NotOn(const_val)), @@ -519,16 +429,11 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")), hir::ExprBinary(op, ref a, ref b) => { - let b_ty = match op.node { - hir::BiShl | hir::BiShr => ty_hint.erase_hint(), - _ => ty_hint - }; // technically, if we don't have type hints, but integral eval // gives us a type through a type-suffix, cast or const def type // we need to re-eval the other value of the BinOp if it was // not inferred - match (cx.eval(a, ty_hint)?, - cx.eval(b, b_ty)?) { + match (cx.eval(a)?, cx.eval(b)?) { (Float(a), Float(b)) => { use std::cmp::Ordering::*; match op.node { @@ -543,7 +448,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), - _ => signal!(e, InvalidOpForFloats(op.node)), + _ => span_bug!(e.span, "typeck error"), } } (Integral(a), Integral(b)) => { @@ -565,7 +470,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), - _ => signal!(e, InvalidOpForInts(op.node)), + _ => span_bug!(e.span, "typeck error"), } } (Bool(a), Bool(b)) => { @@ -581,90 +486,57 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::BiLe => a <= b, hir::BiGe => a >= b, hir::BiGt => a > b, - _ => signal!(e, InvalidOpForBools(op.node)), + _ => span_bug!(e.span, "typeck error"), }) } _ => signal!(e, MiscBinaryOp), } } - hir::ExprCast(ref base, ref target_ty) => { - let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety) - .unwrap_or_else(|| { - tcx.sess.span_fatal(target_ty.span, - "target type not found for const cast") - }); - - let base_hint = if let ExprTypeChecked = ty_hint { - ExprTypeChecked - } else { - match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) { - Some(t) => UncheckedExprHint(t), - None => ty_hint - } - }; - - let val = match cx.eval(base, base_hint) { - Ok(val) => val, - Err(ConstEvalErr { kind: ErroneousReferencedConstant( - box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) | - Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => { - // Something like `5i8 as usize` doesn't need a type hint for the base - // instead take the type hint from the inner value - let hint = match val.int_type() { - Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)), - Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)), - // we had a type hint, so we can't have an unknown type - None => bug!(), - }; - cx.eval(base, hint)? - }, - Err(e) => return Err(e), - }; - match cast_const(tcx, val, ety) { + hir::ExprCast(ref base, _) => { + match cast_const(tcx, cx.eval(base)?, ety) { Ok(val) => val, Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), } } hir::ExprPath(ref qpath) => { - let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| { - // There are no tables so we can only handle already-resolved HIR. - match *qpath { - hir::QPath::Resolved(_, ref path) => path.def, - hir::QPath::TypeRelative(..) => Def::Err - } - }); - match def { + let substs = cx.tables.node_id_item_substs(e.id) + .unwrap_or_else(|| tcx.intern_substs(&[])); + + // Avoid applying substitutions if they're empty, that'd ICE. + let substs = if cx.substs.is_empty() { + substs + } else { + substs.subst(tcx, cx.substs) + }; + + match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let substs = if let ExprTypeChecked = ty_hint { - Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id)) - .unwrap_or_else(|| tcx.intern_substs(&[]))) - } else { - None - }; - if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) { - let item_hint = match ty { - Some(ty) => ty_hint.checked_or(ty), - None => ty_hint, - }; - let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None }; - match cx.eval(expr, item_hint) { + if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) { + let cx = ConstContext::with_tables(tcx, tables); + match cx.eval(expr) { Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } Err(err) => { debug!("bad reference: {:?}, {:?}", err.description(), err.span); signal!(e, ErroneousReferencedConstant(box err)) }, } } else { - signal!(e, NonConstPath); + signal!(e, TypeckError); } }, Def::VariantCtor(variant_def, ..) => { if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { - let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None }; - match cx.eval(expr, ty_hint) { + let cx = ConstContext::with_tables(tcx, tables); + match cx.eval(expr) { Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } Err(err) => { debug!("bad reference: {:?}, {:?}", err.description(), err.span); signal!(e, ErroneousReferencedConstant(box err)) @@ -685,16 +557,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, signal!(e, NonConstPath); } }, - Def::Method(id) | Def::Fn(id) => Function(id), - Def::Err => signal!(e, UnresolvedPath), + Def::Method(id) | Def::Fn(id) => Function(id, substs), + Def::Err => span_bug!(e.span, "typeck error"), _ => signal!(e, NonConstPath), } } hir::ExprCall(ref callee, ref args) => { - let sub_ty_hint = ty_hint.erase_hint(); - let callee_val = cx.eval(callee, sub_ty_hint)?; - let did = match callee_val { - Function(did) => did, + let (did, substs) = match cx.eval(callee)? { + Function(did, substs) => (did, substs), Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), callee => signal!(e, CallOn(callee)), }; @@ -711,8 +581,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, let mut call_args = DefIdMap(); for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) { - let arg_hint = ty_hint.erase_hint(); - let arg_val = cx.eval(arg_expr, arg_hint)?; + let arg_val = cx.eval(arg_expr)?; debug!("const call arg: {:?}", arg); if let Some(def_id) = arg { assert!(call_args.insert(def_id, arg_val).is_none()); @@ -722,9 +591,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, let callee_cx = ConstContext { tcx: tcx, tables: tables, + substs: substs, fn_args: Some(call_args) }; - callee_cx.eval(&body.value, ty_hint)? + callee_cx.eval(&body.value)? }, hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) { Ok(val) => val, @@ -732,32 +602,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }, hir::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => cx.eval(expr, ty_hint)?, - None => signal!(e, UnimplementedConstVal("empty block")), + Some(ref expr) => cx.eval(expr)?, + None => Tuple(vec![]), } } - hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?, + hir::ExprType(ref e, _) => cx.eval(e)?, hir::ExprTup(ref fields) => { - let field_hint = ty_hint.erase_hint(); - Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?) + Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?) } hir::ExprStruct(_, ref fields, _) => { - let field_hint = ty_hint.erase_hint(); Struct(fields.iter().map(|f| { - cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v)) + cx.eval(&f.expr).map(|v| (f.name.node, v)) }).collect::<Result<_, _>>()?) } hir::ExprIndex(ref arr, ref idx) => { if !tcx.sess.features.borrow().const_indexing { signal!(e, IndexOpFeatureGated); } - let arr_hint = ty_hint.erase_hint(); - let arr = cx.eval(arr, arr_hint)?; - let idx_hint = ty_hint.checked_or(tcx.types.usize); - let idx = match cx.eval(idx, idx_hint)? { + let arr = cx.eval(arr)?; + let idx = match cx.eval(idx)? { Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type), - Integral(_) => bug!(), - _ => signal!(idx, IndexNotInt), + _ => signal!(idx, IndexNotUsize), }; assert_eq!(idx as usize as u64, idx); match arr { @@ -787,45 +652,25 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprArray(ref v) => { - let elem_hint = ty_hint.erase_hint(); - Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?) + Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?) } - hir::ExprRepeat(ref elem, count) => { - let elem_hint = ty_hint.erase_hint(); - let len_hint = ty_hint.checked_or(tcx.types.usize); - let n = if let Some(ty) = ety { - // For cross-crate constants, we have the type already, - // but not the body for `count`, so use the type. - match ty.sty { - ty::TyArray(_, n) => n as u64, - _ => bug!() - } - } else { - let n = &tcx.hir.body(count).value; - match ConstContext::new(tcx, count).eval(n, len_hint)? { - Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type), - Integral(_) => signal!(e, RepeatCountNotNatural), - _ => signal!(e, RepeatCountNotInt), - } + hir::ExprRepeat(ref elem, _) => { + let n = match ety.sty { + ty::TyArray(_, n) => n as u64, + _ => span_bug!(e.span, "typeck error") }; - Repeat(Box::new(cx.eval(elem, elem_hint)?), n) + Repeat(Box::new(cx.eval(elem)?), n) }, hir::ExprTupField(ref base, index) => { - let base_hint = ty_hint.erase_hint(); - let c = cx.eval(base, base_hint)?; + let c = cx.eval(base)?; if let Tuple(ref fields) = c { - if let Some(elem) = fields.get(index.node) { - elem.clone() - } else { - signal!(e, TupleIndexOutOfBounds); - } + fields[index.node].clone() } else { signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { - let base_hint = ty_hint.erase_hint(); - let c = cx.eval(base, base_hint)?; + let c = cx.eval(base)?; if let Struct(ref fields) = c { if let Some(f) = fields.get(&field_name.node) { f.clone() @@ -840,82 +685,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, _ => signal!(e, MiscCatchAll) }; - match (ety.map(|t| &t.sty), result) { - (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) { - Ok(inferred) => Ok(Integral(inferred)), - Err(err) => signal!(e, err), - }, - (_, result) => Ok(result), - } -} - -fn infer<'a, 'tcx>(i: ConstInt, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty_hint: &ty::TypeVariants<'tcx>) - -> Result<ConstInt, ErrKind> { - use syntax::ast::*; - - match (ty_hint, i) { - (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result), - (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), - (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result), - (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result), - (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result), - (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result), - - (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result), - (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result), - (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result), - (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result), - (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result), - (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result), - - (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)), - (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)), - (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)), - (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)), - (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)), - (&ty::TyInt(IntTy::Is), Infer(i)) => { - Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type))) - }, - - (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)), - (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)), - (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)), - (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)), - (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)), - (&ty::TyInt(IntTy::Is), InferSigned(i)) => { - Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type))) - }, - - (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)), - (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)), - (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)), - (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)), - (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)), - (&ty::TyUint(UintTy::Us), Infer(i)) => { - Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type))) - }, - (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative), - - (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), - (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), - - (&ty::TyAdt(adt, _), i) if adt.is_enum() => { - let int_ty = adt.repr.discr_type(); - infer(i, tcx, &int_ty.to_ty(tcx).sty) - }, - (_, i) => Err(BadType(ConstVal::Integral(i))), - } + Ok(result) } fn resolve_trait_associated_const<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: DefId, - default_value: Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>, + default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>, trait_id: DefId, rcvr_substs: &'tcx Substs<'tcx> -) -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)> +) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", @@ -950,7 +729,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( let ac = tcx.associated_items(impl_data.impl_def_id) .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), + Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()), None => default_value, } } @@ -961,7 +740,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( }) } -fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult { +fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + val: ConstInt, + ty: Ty<'tcx>) + -> CastResult<'tcx> { let v = val.to_u128_unchecked(); match ty.sty { ty::TyBool if v == 0 => Ok(Bool(false)), @@ -982,42 +764,31 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty:: ty::TyUint(ast::UintTy::Us) => { Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type)))) }, - ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { - Infer(u) => Ok(Float(F64(u as f64))), - InferSigned(i) => Ok(Float(F64(i as f64))), - _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), - }, - ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { - Infer(u) => Ok(Float(F32(u as f32))), - InferSigned(i) => Ok(Float(F32(i as f32))), - _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), - }, + ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))), + ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))), ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), - ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) { - Ok(U8(u)) => Ok(Char(u as char)), - // can only occur before typeck, typeck blocks `T as char` for `T` != `u8` - _ => Err(CharCast(val)), + ty::TyChar => match val { + U8(u) => Ok(Char(u as char)), + _ => bug!(), }, - _ => Err(CannotCast), + _ => bug!(), } } fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstFloat, - ty: ty::Ty) -> CastResult { + ty: Ty<'tcx>) -> CastResult<'tcx> { match ty.sty { ty::TyInt(_) | ty::TyUint(_) => { let i = match val { - F32(f) if f >= 0.0 => Infer(f as u128), - FInfer { f64: f, .. } | - F64(f) if f >= 0.0 => Infer(f as u128), + F32(f) if f >= 0.0 => U128(f as u128), + F64(f) if f >= 0.0 => U128(f as u128), - F32(f) => InferSigned(f as i128), - FInfer { f64: f, .. } | - F64(f) => InferSigned(f as i128) + F32(f) => I128(f as i128), + F64(f) => I128(f as i128) }; - if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) { + if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) { return Err(CannotCast); } @@ -1025,23 +796,26 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val { F32(f) => f as f64, - FInfer { f64: f, .. } | F64(f) => f + F64(f) => f }))), ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val { F64(f) => f as f32, - FInfer { f32: f, .. } | F32(f) => f + F32(f) => f }))), _ => Err(CannotCast), } } -fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult { +fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + val: ConstVal<'tcx>, + ty: Ty<'tcx>) + -> CastResult<'tcx> { match val { Integral(i) => cast_const_int(tcx, i, ty), - Bool(b) => cast_const_int(tcx, Infer(b as u128), ty), + Bool(b) => cast_const_int(tcx, U8(b as u8), ty), Float(f) => cast_const_float(tcx, f, ty), - Char(c) => cast_const_int(tcx, Infer(c as u128), ty), - Function(_) => Err(UnimplementedConstVal("casting fn pointers")), + Char(c) => cast_const_int(tcx, U32(c as u32), ty), + Function(..) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) @@ -1069,66 +843,56 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty_hint: Option<Ty<'tcx>>) - -> Result<ConstVal, ErrKind> { + mut ty: Ty<'tcx>) + -> Result<ConstVal<'tcx>, ErrKind<'tcx>> { use syntax::ast::*; use syntax::ast::LitIntType::*; + + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + ty = adt.repr.discr_type().to_ty(tcx) + } + } + match *lit { LitKind::Str(ref s, _) => Ok(Str(s.as_str())), LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), LitKind::Byte(n) => Ok(Integral(U8(n))), - LitKind::Int(n, Signed(ity)) => { - infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) - }, - - // FIXME: this should become u128. - LitKind::Int(n, Unsuffixed) => { - match ty_hint.map(|t| &t.sty) { - Some(&ty::TyInt(ity)) => { - infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) - }, - Some(&ty::TyUint(uty)) => { - infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral) - }, - None => Ok(Integral(Infer(n as u128))), - Some(&ty::TyAdt(adt, _)) => { - let int_ty = adt.repr.discr_type(); - infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral) - }, - Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), + LitKind::Int(n, hint) => { + match (&ty.sty, hint) { + (&ty::TyInt(ity), _) | + (_, Signed(ity)) => { + Ok(Integral(ConstInt::new_signed_truncating(n as i128, + ity, tcx.sess.target.int_type))) + } + (&ty::TyUint(uty), _) | + (_, Unsigned(uty)) => { + Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, + uty, tcx.sess.target.uint_type))) + } + _ => bug!() } - }, - LitKind::Int(n, Unsigned(ity)) => { - infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral) - }, - + } LitKind::Float(n, fty) => { - parse_float(&n.as_str(), Some(fty)).map(Float) + parse_float(&n.as_str(), fty).map(Float) } LitKind::FloatUnsuffixed(n) => { - let fty_hint = match ty_hint.map(|t| &t.sty) { - Some(&ty::TyFloat(fty)) => Some(fty), - _ => None + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() }; - parse_float(&n.as_str(), fty_hint).map(Float) + parse_float(&n.as_str(), fty).map(Float) } LitKind::Bool(b) => Ok(Bool(b)), LitKind::Char(c) => Ok(Char(c)), } } -fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>) - -> Result<ConstFloat, ErrKind> { - let val = match fty_hint { - Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32), - Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64), - None => { - num.parse::<f32>().and_then(|f32| { - num.parse::<f64>().map(|f64| { - FInfer { f32: f32, f64: f64 } - }) - }) - } +fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) + -> Result<ConstFloat, ErrKind<'tcx>> { + let val = match fty { + ast::FloatTy::F32 => num.parse::<f32>().map(F32), + ast::FloatTy::F64 => num.parse::<f64>().map(F64) }; val.map_err(|_| { // FIXME(#31407) this is only necessary because float parsing is buggy @@ -1168,17 +932,17 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { a: &Expr, b: &Expr) -> Result<Ordering, ErrorReported> { let tcx = self.tcx; - let a = match self.eval(a, ExprTypeChecked) { + let a = match self.eval(a) { Ok(a) => a, Err(e) => { - report_const_eval_err(tcx, &e, a.span, "expression").emit(); + report_const_eval_err(tcx, &e, a.span, "expression"); return Err(ErrorReported); } }; - let b = match self.eval(b, ExprTypeChecked) { + let b = match self.eval(b) { Ok(b) => b, Err(e) => { - report_const_eval_err(tcx, &e, b.span, "expression").emit(); + report_const_eval_err(tcx, &e, b.span, "expression"); return Err(ErrorReported); } }; @@ -1193,26 +957,17 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reason: &str) -> Result<usize, ErrorReported> { - let hint = UncheckedExprHint(tcx.types.usize); let count_expr = &tcx.hir.body(count).value; - match ConstContext::new(tcx, count).eval(count_expr, hint) { + match ConstContext::new(tcx, count).eval(count_expr) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); Ok(val as usize) }, - Ok(const_val) => { - struct_span_err!(tcx.sess, count_expr.span, E0306, - "expected `usize` for {}, found {}", - reason, - const_val.description()) - .span_label(count_expr.span, &format!("expected `usize`")) - .emit(); - - Err(ErrorReported) - } + Ok(_) | + Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), Err(err) => { - let mut diag = report_const_eval_err( + let mut diag = build_const_eval_err( tcx, &err, count_expr.span, reason); if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 198e49daabc..4434a901f94 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -21,6 +21,7 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] +#![deny(warnings)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 609fb3e39d6..72a47c00281 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -27,9 +27,9 @@ use syntax::ptr::P; use syntax_pos::Span; #[derive(Clone, Debug)] -pub enum PatternError { +pub enum PatternError<'tcx> { StaticInPattern(Span), - ConstEval(eval::ConstEvalErr), + ConstEval(eval::ConstEvalErr<'tcx>), } #[derive(Copy, Clone, Debug)] @@ -84,12 +84,12 @@ pub enum PatternKind<'tcx> { }, Constant { - value: ConstVal, + value: ConstVal<'tcx>, }, Range { - lo: ConstVal, - hi: ConstVal, + lo: ConstVal<'tcx>, + hi: ConstVal<'tcx>, end: RangeEnd, }, @@ -118,7 +118,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::Char(c) => write!(f, "{:?}", c), ConstVal::Struct(_) | ConstVal::Tuple(_) | - ConstVal::Function(_) | + ConstVal::Function(..) | ConstVal::Array(..) | ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value) } @@ -265,7 +265,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub tables: &'a ty::TypeckTables<'gcx>, - pub errors: Vec<PatternError>, + pub errors: Vec<PatternError<'tcx>>, } impl<'a, 'gcx, 'tcx> Pattern<'tcx> { @@ -582,11 +582,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let tcx = self.tcx.global_tcx(); let substs = self.tables.node_id_item_substs(id) .unwrap_or_else(|| tcx.intern_substs(&[])); - match eval::lookup_const_by_id(tcx, def_id, Some(substs)) { - Some((const_expr, const_tables, _const_ty)) => { + match eval::lookup_const_by_id(tcx, def_id, substs) { + Some((const_expr, const_tables)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = const_tables.expect("missing tables after typeck"); + self.tables = const_tables; let pat = self.lower_const_expr(const_expr, pat_id, span); self.tables = old_tables; return pat; @@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> { let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables); - match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) { + match const_cx.eval(expr) { Ok(value) => { PatternKind::Constant { value: value } } @@ -796,7 +796,7 @@ macro_rules! CloneImpls { } CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region, + Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, &'tcx Substs<'tcx>, &'tcx Kind<'tcx> } diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs index 4610c183e1b..f557edffbda 100644 --- a/src/librustc_const_math/float.rs +++ b/src/librustc_const_math/float.rs @@ -17,13 +17,7 @@ use super::err::*; #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ConstFloat { F32(f32), - F64(f64), - - // When the type isn't known, we have to operate on both possibilities. - FInfer { - f32: f32, - f64: f64 - } + F64(f64) } pub use self::ConstFloat::*; @@ -31,7 +25,6 @@ impl ConstFloat { /// Description of the type, not the value pub fn description(&self) -> &'static str { match *self { - FInfer {..} => "float", F32(_) => "f32", F64(_) => "f64", } @@ -41,17 +34,13 @@ impl ConstFloat { match *self { F32(f) => f.is_nan(), F64(f) => f.is_nan(), - FInfer { f32, f64 } => f32.is_nan() || f64.is_nan() } } /// Compares the values if they are of the same type pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> { match (self, rhs) { - (F64(a), F64(b)) | - (F64(a), FInfer { f64: b, .. }) | - (FInfer { f64: a, .. }, F64(b)) | - (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => { + (F64(a), F64(b)) => { // This is pretty bad but it is the existing behavior. Ok(if a == b { Ordering::Equal @@ -62,9 +51,7 @@ impl ConstFloat { }) } - (F32(a), F32(b)) | - (F32(a), FInfer { f32: b, .. }) | - (FInfer { f32: a, .. }, F32(b)) => { + (F32(a), F32(b)) => { Ok(if a == b { Ordering::Equal } else if a < b { @@ -86,10 +73,7 @@ impl ConstFloat { impl PartialEq for ConstFloat { fn eq(&self, other: &Self) -> bool { match (*self, *other) { - (F64(a), F64(b)) | - (F64(a), FInfer { f64: b, .. }) | - (FInfer { f64: a, .. }, F64(b)) | - (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => { + (F64(a), F64(b)) => { unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)} } (F32(a), F32(b)) => { @@ -105,7 +89,7 @@ impl Eq for ConstFloat {} impl hash::Hash for ConstFloat { fn hash<H: hash::Hasher>(&self, state: &mut H) { match *self { - F64(a) | FInfer { f64: a, .. } => { + F64(a) => { unsafe { transmute::<_,u64>(a) }.hash(state) } F32(a) => { @@ -118,7 +102,6 @@ impl hash::Hash for ConstFloat { impl ::std::fmt::Display for ConstFloat { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { match *self { - FInfer { f64, .. } => write!(fmt, "{}", f64), F32(f) => write!(fmt, "{}f32", f), F64(f) => write!(fmt, "{}f64", f), } @@ -131,20 +114,8 @@ macro_rules! derive_binop { type Output = Result<Self, ConstMathErr>; fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { match (self, rhs) { - (F32(a), F32(b)) | - (F32(a), FInfer { f32: b, .. }) | - (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))), - - (F64(a), F64(b)) | - (FInfer { f64: a, .. }, F64(b)) | - (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))), - - (FInfer { f32: a32, f64: a64 }, - FInfer { f32: b32, f64: b64 }) => Ok(FInfer { - f32: a32.$func(b32), - f64: a64.$func(b64) - }), - + (F32(a), F32(b)) => Ok(F32(a.$func(b))), + (F64(a), F64(b)) => Ok(F64(a.$func(b))), _ => Err(UnequalTypes(Op::$op)), } } @@ -164,10 +135,6 @@ impl ::std::ops::Neg for ConstFloat { match self { F32(f) => F32(-f), F64(f) => F64(-f), - FInfer { f32, f64 } => FInfer { - f32: -f32, - f64: -f64 - } } } } diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 17714f2fb2d..d97276da9bf 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -30,8 +30,6 @@ pub enum ConstInt { U64(u64), U128(u128), Usize(ConstUsize), - Infer(u128), - InferSigned(i128), } pub use self::ConstInt::*; @@ -92,7 +90,7 @@ impl ConstInt { } } - /// Creates a new unsigned ConstInt with matching type while also checking that overflow does + /// Creates a new signed ConstInt with matching type while also checking that overflow does /// not happen. pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> { match ty { @@ -107,103 +105,33 @@ impl ConstInt { } } - /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of - /// the other value. If both values have no type, don't do anything - pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> { - let inferred = match (self, other) { - (InferSigned(_), InferSigned(_)) - | (Infer(_), Infer(_)) => self, // no inference possible - // kindof wrong, you could have had values > I64MAX during computation of a - (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128), - (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange), - (_, InferSigned(_)) - | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)), - - (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8), - (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16), - (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32), - (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64), - (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128), - (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)), - (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)), - (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)), - (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8), - (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16), - (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32), - (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64), - (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128), - (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), - (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), - - (Infer(_), _) => return Err(ConstMathErr::NotInRange), - - (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8), - (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16), - (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32), - (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64), - (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128), - (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => { - Isize(Is16(a as i16)) - }, - (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => { - Isize(Is32(a as i32)) - }, - (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => { - Isize(Is64(a as i64)) - }, - (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8), - (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16), - (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32), - (InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64), - (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128), - (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), - (InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), - (InferSigned(_), _) => return Err(ConstMathErr::NotInRange), - _ => self, // already known types - }; - Ok((inferred, other)) + /// Creates a new unsigned ConstInt with matching type. + pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt { + match ty { + UintTy::U8 => U8(val as u8), + UintTy::U16 => U16(val as u16), + UintTy::U32 => U32(val as u32), + UintTy::U64 => U64(val as u64), + UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)), + UintTy::U128 => U128(val) + } } - /// Turn this value into an `Infer` or an `InferSigned` - pub fn erase_type(self) -> Self { - match self { - Infer(i) => Infer(i), - InferSigned(i) if i < 0 => InferSigned(i), - I8(i) if i < 0 => InferSigned(i as i128), - I16(i) if i < 0 => InferSigned(i as i128), - I32(i) if i < 0 => InferSigned(i as i128), - I64(i) if i < 0 => InferSigned(i as i128), - I128(i) if i < 0 => InferSigned(i as i128), - Isize(Is16(i)) if i < 0 => InferSigned(i as i128), - Isize(Is32(i)) if i < 0 => InferSigned(i as i128), - Isize(Is64(i)) if i < 0 => InferSigned(i as i128), - InferSigned(i) => Infer(i as u128), - I8(i) => Infer(i as u128), - I16(i) => Infer(i as u128), - I32(i) => Infer(i as u128), - I64(i) => Infer(i as u128), - I128(i) => Infer(i as u128), - Isize(Is16(i)) => Infer(i as u128), - Isize(Is32(i)) => Infer(i as u128), - Isize(Is64(i)) => Infer(i as u128), - U8(i) => Infer(i as u128), - U16(i) => Infer(i as u128), - U32(i) => Infer(i as u128), - U64(i) => Infer(i as u128), - U128(i) => Infer(i as u128), - Usize(Us16(i)) => Infer(i as u128), - Usize(Us32(i)) => Infer(i as u128), - Usize(Us64(i)) => Infer(i as u128), + /// Creates a new signed ConstInt with matching type. + pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt { + match ty { + IntTy::I8 => I8(val as i8), + IntTy::I16 => I16(val as i16), + IntTy::I32 => I32(val as i32), + IntTy::I64 => I64(val as i64), + IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)), + IntTy::I128 => I128(val) } } /// Description of the type, not the value pub fn description(&self) -> &'static str { match *self { - Infer(_) => "not yet inferred integral", - InferSigned(_) => "not yet inferred signed integral", I8(_) => "i8", I16(_) => "i16", I32(_) => "i32", @@ -222,10 +150,23 @@ impl ConstInt { /// Erases the type and returns a u128. /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128` pub fn to_u128_unchecked(self) -> u128 { - match self.erase_type() { - ConstInt::Infer(i) => i, - ConstInt::InferSigned(i) => i as u128, - _ => unreachable!(), + match self { + I8(i) => i as i128 as u128, + I16(i) => i as i128 as u128, + I32(i) => i as i128 as u128, + I64(i) => i as i128 as u128, + I128(i) => i as i128 as u128, + Isize(Is16(i)) => i as i128 as u128, + Isize(Is32(i)) => i as i128 as u128, + Isize(Is64(i)) => i as i128 as u128, + U8(i) => i as u128, + U16(i) => i as u128, + U32(i) => i as u128, + U64(i) => i as u128, + U128(i) => i as u128, + Usize(Us16(i)) => i as u128, + Usize(Us32(i)) => i as u128, + Usize(Us64(i)) => i as u128, } } @@ -250,8 +191,6 @@ impl ConstInt { /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX pub fn to_u128(&self) -> Option<u128> { match *self { - Infer(v) => Some(v), - InferSigned(v) if v >= 0 => Some(v as u128), I8(v) if v >= 0 => Some(v as u128), I16(v) if v >= 0 => Some(v as u128), I32(v) if v >= 0 => Some(v as u128), @@ -272,6 +211,48 @@ impl ConstInt { } } + pub fn to_f32(self) -> f32 { + match self { + I8(i) => i as f32, + I16(i) => i as f32, + I32(i) => i as f32, + I64(i) => i as f32, + I128(i) => i as f32, + Isize(Is16(i)) => i as f32, + Isize(Is32(i)) => i as f32, + Isize(Is64(i)) => i as f32, + U8(i) => i as f32, + U16(i) => i as f32, + U32(i) => i as f32, + U64(i) => i as f32, + U128(i) => i as f32, + Usize(Us16(i)) => i as f32, + Usize(Us32(i)) => i as f32, + Usize(Us64(i)) => i as f32, + } + } + + pub fn to_f64(self) -> f64 { + match self { + I8(i) => i as f64, + I16(i) => i as f64, + I32(i) => i as f64, + I64(i) => i as f64, + I128(i) => i as f64, + Isize(Is16(i)) => i as f64, + Isize(Is32(i)) => i as f64, + Isize(Is64(i)) => i as f64, + U8(i) => i as f64, + U16(i) => i as f64, + U32(i) => i as f64, + U64(i) => i as f64, + U128(i) => i as f64, + Usize(Us16(i)) => i as f64, + Usize(Us32(i)) => i as f64, + Usize(Us64(i)) => i as f64, + } + } + pub fn is_negative(&self) -> bool { match *self { I8(v) => v < 0, @@ -282,14 +263,13 @@ impl ConstInt { Isize(Is16(v)) => v < 0, Isize(Is32(v)) => v < 0, Isize(Is64(v)) => v < 0, - InferSigned(v) => v < 0, _ => false, } } /// Compares the values if they are of the same type pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> { - match self.infer(rhs)? { + match (self, rhs) { (I8(a), I8(b)) => Ok(a.cmp(&b)), (I16(a), I16(b)) => Ok(a.cmp(&b)), (I32(a), I32(b)) => Ok(a.cmp(&b)), @@ -306,8 +286,6 @@ impl ConstInt { (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)), (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)), (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)), - (Infer(a), Infer(b)) => Ok(a.cmp(&b)), - (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)), _ => Err(CmpBetweenUnequalTypes), } } @@ -334,25 +312,23 @@ impl ConstInt { ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))), ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))), ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))), - ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"), } } - pub fn int_type(self) -> Option<IntType> { + pub fn int_type(self) -> IntType { match self { - ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)), - ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)), - ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)), - ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)), - ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)), - ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)), - ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)), - ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)), - ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)), - ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)), - ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)), - ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)), - _ => None, + ConstInt::I8(_) => IntType::SignedInt(IntTy::I8), + ConstInt::I16(_) => IntType::SignedInt(IntTy::I16), + ConstInt::I32(_) => IntType::SignedInt(IntTy::I32), + ConstInt::I64(_) => IntType::SignedInt(IntTy::I64), + ConstInt::I128(_) => IntType::SignedInt(IntTy::I128), + ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is), + ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8), + ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16), + ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32), + ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64), + ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128), + ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us), } } } @@ -372,8 +348,6 @@ impl ::std::cmp::Ord for ConstInt { impl ::std::fmt::Display for ConstInt { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { match *self { - Infer(i) => write!(fmt, "{}", i), - InferSigned(i) => write!(fmt, "{}", i), I8(i) => write!(fmt, "{}i8", i), I16(i) => write!(fmt, "{}i16", i), I32(i) => write!(fmt, "{}i32", i), @@ -409,7 +383,7 @@ macro_rules! impl_binop { impl ::std::ops::$op for ConstInt { type Output = Result<Self, ConstMathErr>; fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { - match self.infer(rhs)? { + match (self, rhs) { (I8(a), I8(b)) => a.$checked_func(b).map(I8), (I16(a), I16(b)) => a.$checked_func(b).map(I16), (I32(a), I32(b)) => a.$checked_func(b).map(I32), @@ -426,8 +400,6 @@ macro_rules! impl_binop { (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize), (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize), (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize), - (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer), - (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned), _ => return Err(UnequalTypes(Op::$op)), }.ok_or(Overflow(Op::$op)) } @@ -440,7 +412,7 @@ macro_rules! derive_binop { impl ::std::ops::$op for ConstInt { type Output = Result<Self, ConstMathErr>; fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { - match self.infer(rhs)? { + match (self, rhs) { (I8(a), I8(b)) => Ok(I8(a.$func(b))), (I16(a), I16(b)) => Ok(I16(a.$func(b))), (I32(a), I32(b)) => Ok(I32(a.$func(b))), @@ -457,8 +429,6 @@ macro_rules! derive_binop { (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))), - (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))), - (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))), _ => Err(UnequalTypes(Op::$op)), } } @@ -490,7 +460,6 @@ fn check_division( (Isize(_), Isize(Is16(0))) => Err(zerr), (Isize(_), Isize(Is32(0))) => Err(zerr), (Isize(_), Isize(Is64(0))) => Err(zerr), - (InferSigned(_), InferSigned(0)) => Err(zerr), (U8(_), U8(0)) => Err(zerr), (U16(_), U16(0)) => Err(zerr), @@ -500,7 +469,6 @@ fn check_division( (Usize(_), Usize(Us16(0))) => Err(zerr), (Usize(_), Usize(Us32(0))) => Err(zerr), (Usize(_), Usize(Us64(0))) => Err(zerr), - (Infer(_), Infer(0)) => Err(zerr), (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)), (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)), @@ -510,7 +478,6 @@ fn check_division( (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)), (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)), (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)), - (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)), _ => Ok(()), } @@ -519,7 +486,7 @@ fn check_division( impl ::std::ops::Div for ConstInt { type Output = Result<Self, ConstMathErr>; fn div(self, rhs: Self) -> Result<Self, ConstMathErr> { - let (lhs, rhs) = self.infer(rhs)?; + let (lhs, rhs) = (self, rhs); check_division(lhs, rhs, Op::Div, DivisionByZero)?; match (lhs, rhs) { (I8(a), I8(b)) => Ok(I8(a/b)), @@ -530,7 +497,6 @@ impl ::std::ops::Div for ConstInt { (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))), - (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)), (U8(a), U8(b)) => Ok(U8(a/b)), (U16(a), U16(b)) => Ok(U16(a/b)), @@ -540,7 +506,6 @@ impl ::std::ops::Div for ConstInt { (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))), - (Infer(a), Infer(b)) => Ok(Infer(a/b)), _ => Err(UnequalTypes(Op::Div)), } @@ -550,7 +515,7 @@ impl ::std::ops::Div for ConstInt { impl ::std::ops::Rem for ConstInt { type Output = Result<Self, ConstMathErr>; fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> { - let (lhs, rhs) = self.infer(rhs)?; + let (lhs, rhs) = (self, rhs); // should INT_MIN%-1 be zero or an error? check_division(lhs, rhs, Op::Rem, RemainderByZero)?; match (lhs, rhs) { @@ -562,7 +527,6 @@ impl ::std::ops::Rem for ConstInt { (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))), - (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)), (U8(a), U8(b)) => Ok(U8(a%b)), (U16(a), U16(b)) => Ok(U16(a%b)), @@ -572,7 +536,6 @@ impl ::std::ops::Rem for ConstInt { (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))), - (Infer(a), Infer(b)) => Ok(Infer(a%b)), _ => Err(UnequalTypes(Op::Rem)), } @@ -600,8 +563,6 @@ impl ::std::ops::Shl<ConstInt> for ConstInt { Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))), Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))), Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))), - Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))), - InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))), } } } @@ -627,8 +588,6 @@ impl ::std::ops::Shr<ConstInt> for ConstInt { Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))), Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))), Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))), - Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))), - InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))), } } } @@ -648,9 +607,6 @@ impl ::std::ops::Neg for ConstInt { a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) | a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a), U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation), - Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))), - Infer(_) => Err(Overflow(Op::Neg)), - InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))), } } } @@ -675,8 +631,6 @@ impl ::std::ops::Not for ConstInt { Usize(Us16(a)) => Ok(Usize(Us16(!a))), Usize(Us32(a)) => Ok(Usize(Us32(!a))), Usize(Us64(a)) => Ok(Usize(Us64(!a))), - Infer(a) => Ok(Infer(!a)), - InferSigned(a) => Ok(InferSigned(!a)), } } } diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 13764ce5bbb..b7833a54403 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -21,7 +21,7 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] - +#![deny(warnings)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3301a98968e..529afe0215e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -17,7 +17,6 @@ use rustc::ty::layout::{Layout, Primitive}; use rustc::traits::Reveal; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; -use rustc_const_eval::EvalHint::ExprTypeChecked; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -109,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } else { let const_cx = ConstContext::with_tables(cx.tcx, cx.tables); - match const_cx.eval(&r, ExprTypeChecked) { + match const_cx.eval(&r) { Ok(ConstVal::Integral(i)) => { i.is_negative() || i.to_u64() diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index fa39b687355..26d907523a8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -230,9 +230,9 @@ pub enum EntryKind<'tcx> { Type, Enum(ReprOptions), Field, - Variant(Lazy<VariantData>), - Struct(Lazy<VariantData>, ReprOptions), - Union(Lazy<VariantData>, ReprOptions), + Variant(Lazy<VariantData<'tcx>>), + Struct(Lazy<VariantData<'tcx>>, ReprOptions), + Union(Lazy<VariantData<'tcx>>, ReprOptions), Fn(Lazy<FnData>), ForeignFn(Lazy<FnData>), Mod(Lazy<ModData>), @@ -263,10 +263,10 @@ pub struct FnData { } #[derive(RustcEncodable, RustcDecodable)] -pub struct VariantData { +pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, - pub evaluated_discr: Option<ConstVal>, + pub evaluated_discr: Option<ConstVal<'tcx>>, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index a28bc5d6ce3..6b6acb054b1 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -309,13 +309,13 @@ enum TestKind<'tcx> { // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec<ConstVal>, - indices: FxHashMap<ConstVal, usize>, + options: Vec<ConstVal<'tcx>>, + indices: FxHashMap<ConstVal<'tcx>, usize>, }, // test for equality Eq { - value: ConstVal, + value: ConstVal<'tcx>, ty: Ty<'tcx>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index fa8d7ffccde..f4fdf8ade90 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_lvalue: &Lvalue<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec<ConstVal>, - indices: &mut FxHashMap<ConstVal, usize>) + options: &mut Vec<ConstVal<'tcx>>, + indices: &mut FxHashMap<ConstVal<'tcx>, usize>) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index ecdc58ba55d..41374a00123 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -223,6 +223,17 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, builder.finish(vec![], ty) } +pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, + body_id: hir::BodyId) + -> Mir<'tcx> { + let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id)); + let ty = hir.tcx().types.err; + let mut builder = Builder::new(hir, span, 0, ty); + let source_info = builder.source_info(span); + builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); + builder.finish(vec![], ty) +} + impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 2cb26eed1ff..f2b89309e4a 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::map; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err}; +use rustc_const_eval::{ConstContext, fatal_const_eval_err}; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -594,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, count) => { let tcx = cx.tcx.global_tcx(); let c = &cx.tcx.hir.body(count).value; - let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) { + let count = match ConstContext::new(tcx, count).eval(c) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression") diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 852c34a544a..c555ce1ab9c 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -18,7 +18,7 @@ use hair::*; use rustc::mir::transform::MirSource; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err}; +use rustc_const_eval::{ConstContext, fatal_const_eval_err}; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::map::blocks::FnLikeNode; @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) { + match ConstContext::with_tables(tcx, self.tables()).eval(e) { Ok(value) => Literal::Value { value: value }, Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression") } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 0d7be189f88..e0eb09fbf5d 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -98,7 +98,9 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let src = MirSource::from_node(tcx, id); tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { let cx = Cx::new(&infcx, src); - let mut mir = if let MirSource::Fn(id) = src { + let mut mir = if cx.tables().tainted_by_errors { + build::construct_error(cx, body_id) + } else if let MirSource::Fn(id) = src { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index e3a77a93599..930a13e36bd 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -28,9 +28,8 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::CastKind; use rustc_const_eval::{ConstEvalErr, ConstContext}; use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}; -use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType}; -use rustc_const_eval::ErrKind::UnresolvedPath; -use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; +use rustc_const_eval::ErrKind::{TypeckError}; use rustc_const_math::{ConstMathErr, Op}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; @@ -66,12 +65,12 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> { impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn check_const_eval(&self, expr: &'gcx hir::Expr) { let const_cx = ConstContext::with_tables(self.tcx, self.tables); - if let Err(err) = const_cx.eval(expr, ExprTypeChecked) { + if let Err(err) = const_cx.eval(expr) { match err.kind { UnimplementedConstVal(_) => {} IndexOpFeatureGated => {} ErroneousReferencedConstant(_) => {} - BadType(_) => {} + TypeckError => {} _ => { self.tcx.sess.add_lint(CONST_ERR, expr.id, @@ -240,18 +239,17 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { if self.in_fn && self.promotable { let const_cx = ConstContext::with_tables(self.tcx, self.tables); - match const_cx.eval(ex, ExprTypeChecked) { + match const_cx.eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | Err(ConstEvalErr { kind: MiscCatchAll, .. }) | Err(ConstEvalErr { kind: MiscBinaryOp, .. }) | Err(ConstEvalErr { kind: NonConstPath, .. }) | - Err(ConstEvalErr { kind: UnresolvedPath, .. }) | Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) | Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) | Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) | Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {} - Err(ConstEvalErr { kind: BadType(_), .. }) => {} + Err(ConstEvalErr { kind: TypeckError, .. }) => {} Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index b68de7b46c8..011f7748f2c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -213,11 +213,11 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g } -pub fn trans_static(ccx: &CrateContext, - m: hir::Mutability, - id: ast::NodeId, - attrs: &[ast::Attribute]) - -> Result<ValueRef, ConstEvalErr> { +pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + m: hir::Mutability, + id: ast::NodeId, + attrs: &[ast::Attribute]) + -> Result<ValueRef, ConstEvalErr<'tcx>> { unsafe { let def_id = ccx.tcx().hir.local_def_id(id); let g = get_static(ccx, def_id); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d34b1aa2060..3cad2bc1d84 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { if switch_ty == bcx.tcx().types.bool { let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [ConstInt::Infer(0)] = values[..] { + if let [ConstInt::U8(0)] = values[..] { bcx.cond_br(discr.immediate(), llfalse, lltrue); } else { bcx.cond_br(discr.immediate(), lltrue, llfalse); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1f595cae6a8..771a5b7f366 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -83,7 +83,6 @@ impl<'tcx> Const<'tcx> { let u = v.as_u64(ccx.tcx().sess.target.uint_type); (C_integral(Type::int(ccx), u, false), tcx.types.usize) }, - Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci), }; Const { llval: llval, ty: ty } } @@ -97,14 +96,13 @@ impl<'tcx> Const<'tcx> { let val = match cv { ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty), ConstVal::Float(F64(v)) => C_floating_f64(v, llty), - ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv), ConstVal::Bool(v) => C_bool(ccx, v), ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Array(..) | ConstVal::Repeat(..) | - ConstVal::Function(_) => { + ConstVal::Function(..) => { bug!("MIR must not use `{:?}` (which refers to a local ID)", cv) } ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), @@ -249,7 +247,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, instance: Instance<'tcx>, args: IndexVec<mir::Local, Const<'tcx>>) - -> Result<Const<'tcx>, ConstEvalErr> { + -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { let instance = instance.resolve_const(ccx.shared()); let mir = ccx.tcx().item_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() @@ -263,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { value) } - fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> { + fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { let tcx = self.ccx.tcx(); let mut bb = mir::START_BLOCK; @@ -325,7 +323,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { }; let err = ConstEvalErr{ span: span, kind: err }; - report_const_eval_err(tcx, &err, span, "expression").emit(); + report_const_eval_err(tcx, &err, span, "expression"); failure = Err(err); } target @@ -373,7 +371,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) - -> Result<ConstLvalue<'tcx>, ConstEvalErr> { + -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> { let tcx = self.ccx.tcx(); if let mir::Lvalue::Local(index) = *lvalue { @@ -468,7 +466,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) - -> Result<Const<'tcx>, ConstEvalErr> { + -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { debug!("const_operand({:?} @ {:?})", operand, span); let result = match *operand { mir::Operand::Consume(ref lvalue) => { @@ -523,7 +521,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, dest_ty: Ty<'tcx>, span: Span) - -> Result<Const<'tcx>, ConstEvalErr> { + -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { let tcx = self.ccx.tcx(); debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span); let val = match *rvalue { @@ -961,8 +959,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } -pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId) - -> Result<ValueRef, ConstEvalErr> { +pub fn trans_static_initializer<'a, 'tcx>( + ccx: &CrateContext<'a, 'tcx>, + def_id: DefId) + -> Result<ValueRef, ConstEvalErr<'tcx>> +{ let instance = Instance::mono(ccx.shared(), def_id); MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index aae3947df14..577fe31eab0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -189,7 +189,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { &item_segment.parameters, None); - assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); + assoc_bindings.first().map(|b| self.prohibit_projection(b.span)); substs } @@ -446,7 +446,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_def_id, self_ty, trait_segment); - assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); + assoc_bindings.first().map(|b| self.prohibit_projection(b.span)); ty::TraitRef::new(trait_def_id, substs) } @@ -844,7 +844,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name); - tcx.prohibit_type_params(slice::ref_slice(item_segment)); + self.prohibit_type_params(slice::ref_slice(item_segment)); // Find the type of the associated item, and the trait where the associated // item is declared. @@ -917,7 +917,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { let tcx = self.tcx(); - tcx.prohibit_type_params(slice::ref_slice(item_segment)); + self.prohibit_type_params(slice::ref_slice(item_segment)); let self_ty = if let Some(ty) = opt_self_ty { ty @@ -942,6 +942,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.projected_ty(span, trait_ref, item_segment.name) } + pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) { + for segment in segments { + for typ in segment.parameters.types() { + struct_span_err!(self.tcx().sess, typ.span, E0109, + "type parameters are not allowed on this type") + .span_label(typ.span, &format!("type parameter not allowed")) + .emit(); + break; + } + for lifetime in segment.parameters.lifetimes() { + struct_span_err!(self.tcx().sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type") + .span_label(lifetime.span, + &format!("lifetime parameter not allowed on this type")) + .emit(); + break; + } + for binding in segment.parameters.bindings() { + self.prohibit_projection(binding.span); + break; + } + } + } + + pub fn prohibit_projection(&self, span: Span) { + let mut err = struct_span_err!(self.tcx().sess, span, E0229, + "associated type bindings are not allowed here"); + err.span_label(span, &format!("associate type not allowed here")).emit(); + } + // Check a type Path and convert it to a Ty. pub fn def_to_ty(&self, opt_self_ty: Option<Ty<'tcx>>, @@ -957,21 +987,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { match path.def { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(path.segments.split_last().unwrap().1); + self.prohibit_type_params(path.segments.split_last().unwrap().1); self.ast_path_to_ty(span, did, path.segments.last().unwrap()) } Def::Variant(did) if permit_variants => { // Convert "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(path.segments.split_last().unwrap().1); + self.prohibit_type_params(path.segments.split_last().unwrap().1); self.ast_path_to_ty(span, tcx.parent_def_id(did).unwrap(), path.segments.last().unwrap()) } Def::TyParam(did) => { assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(&path.segments); + self.prohibit_type_params(&path.segments); let node_id = tcx.hir.as_local_node_id(did).unwrap(); let item_id = tcx.hir.get_parent_node(node_id); @@ -984,7 +1014,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Self in impl (we know the concrete type). assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(&path.segments); + self.prohibit_type_params(&path.segments); let ty = ty::queries::ty::get(tcx, span, def_id); if let Some(free_substs) = self.get_free_substs() { @@ -996,11 +1026,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::SelfTy(Some(_), None) => { // Self in trait. assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(&path.segments); + self.prohibit_type_params(&path.segments); tcx.mk_self_type() } Def::AssociatedTy(def_id) => { - tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]); + self.prohibit_type_params(&path.segments[..path.segments.len()-2]); let trait_did = tcx.parent_def_id(def_id).unwrap(); self.qpath_to_ty(span, opt_self_ty, @@ -1010,7 +1040,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::PrimTy(prim_ty) => { assert_eq!(opt_self_ty, None); - tcx.prim_ty_to_ty(&path.segments, prim_ty) + self.prohibit_type_params(&path.segments); + match prim_ty { + hir::TyBool => tcx.types.bool, + hir::TyChar => tcx.types.char, + hir::TyInt(it) => tcx.mk_mach_int(it), + hir::TyUint(uit) => tcx.mk_mach_uint(uit), + hir::TyFloat(ft) => tcx.mk_mach_float(ft), + hir::TyStr => tcx.mk_str() + } } Def::Err => { self.set_tainted_by_errors(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aa1fc0f8579..0337727dcba 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -432,10 +432,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { body_id: ast::NodeId, - // This flag is set to true if, during the writeback phase, we encounter - // a type error in this function. - writeback_errors: Cell<bool>, - // Number of errors that had been reported when we started // checking this function. On exit, if we find that *more* errors // have been reported, we will skip regionck and other work that @@ -1493,7 +1489,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { ast_ty_to_ty_cache: RefCell::new(NodeMap()), body_id: body_id, - writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, @@ -1609,6 +1604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if ty.references_error() { self.has_errors.set(true); + self.set_tainted_by_errors(); } // FIXME(canndrew): This is_never should probably be an is_uninhabited @@ -4326,7 +4322,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // errors if type parameters are provided in an inappropriate place. let poly_segments = type_segment.is_some() as usize + fn_segment.is_some() as usize; - self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]); + AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]); match def { Def::Local(def_id) | Def::Upvar(def_id, ..) => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4f0cfa8d014..1382ab34ca5 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -20,7 +20,6 @@ use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::{DefIdMap, DefIdSet}; -use std::cell::Cell; use std::mem; use syntax::ast; @@ -35,8 +34,6 @@ use rustc::hir; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::TypeckTables<'gcx> { - assert_eq!(self.writeback_errors.get(), false); - let item_id = self.tcx.hir.body_owner(body.id()); let item_def_id = self.tcx.hir.local_def_id(item_id); @@ -59,6 +56,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports; + wbcx.tables.tainted_by_errors = self.is_tainted_by_errors(); + self.tcx.alloc_tables(wbcx.tables) } } @@ -195,19 +194,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_stmt(&mut self, s: &'gcx hir::Stmt) { - if self.fcx.writeback_errors.get() { - return; - } - self.visit_node_id(ResolvingExpr(s.span), s.node.id()); intravisit::walk_stmt(self, s); } fn visit_expr(&mut self, e: &'gcx hir::Expr) { - if self.fcx.writeback_errors.get() { - return; - } - self.fix_scalar_builtin_expr(e); self.visit_node_id(ResolvingExpr(e.span), e.id); @@ -227,29 +218,16 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_block(&mut self, b: &'gcx hir::Block) { - if self.fcx.writeback_errors.get() { - return; - } - self.visit_node_id(ResolvingExpr(b.span), b.id); intravisit::walk_block(self, b); } fn visit_pat(&mut self, p: &'gcx hir::Pat) { - if self.fcx.writeback_errors.get() { - return; - } - self.visit_node_id(ResolvingPattern(p.span), p.id); - intravisit::walk_pat(self, p); } fn visit_local(&mut self, l: &'gcx hir::Local) { - if self.fcx.writeback_errors.get() { - return; - } - let var_ty = self.fcx.local_ty(l.span, l.id); let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); self.write_ty_to_tables(l.id, var_ty); @@ -259,10 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_upvar_borrow_map(&mut self) { - if self.fcx.writeback_errors.get() { - return; - } - for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, @@ -281,10 +255,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_closures(&mut self) { - if self.fcx.writeback_errors.get() { - return - } - for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() { let closure_ty = self.resolve(closure_ty, ResolvingClosure(id)); self.tables.closure_tys.insert(id, closure_ty); @@ -296,27 +266,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_cast_types(&mut self) { - if self.fcx.writeback_errors.get() { - return - } - self.tables.cast_kinds.extend( self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value))); } fn visit_lints(&mut self) { - if self.fcx.writeback_errors.get() { - return - } - self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); } fn visit_anon_types(&mut self) { - if self.fcx.writeback_errors.get() { - return - } - let gcx = self.tcx().global_tcx(); for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { let reason = ResolvingAnonTy(node_id); @@ -542,7 +500,6 @@ impl<'a, 'gcx, 'tcx> ResolveReason { struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - writeback_errors: &'cx Cell<bool>, reason: ResolveReason, } @@ -551,22 +508,19 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { reason: ResolveReason) -> Resolver<'cx, 'gcx, 'tcx> { - Resolver::from_infcx(fcx, &fcx.writeback_errors, reason) + Resolver::from_infcx(fcx, reason) } fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - writeback_errors: &'cx Cell<bool>, reason: ResolveReason) -> Resolver<'cx, 'gcx, 'tcx> { Resolver { infcx: infcx, tcx: infcx.tcx, - writeback_errors: writeback_errors, reason: reason } } fn report_error(&self, e: FixupError) { - self.writeback_errors.set(true); if !self.tcx.sess.has_errors() { match self.reason { ResolvingExpr(span) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ecdbf170702..7f413a0dfc3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,7 +59,6 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{ConstContext, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; @@ -75,7 +74,7 @@ use rustc_const_math::ConstInt; use std::cell::RefCell; use std::collections::BTreeMap; -use syntax::{abi, ast, attr}; +use syntax::{abi, ast}; use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; use syntax_pos::{Span, DUMMY_SP}; @@ -596,6 +595,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_predicates(def_id); } +fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + body: hir::BodyId) + -> Result<ConstVal<'tcx>, ()> { + let e = &tcx.hir.body(body).value; + ConstContext::new(tcx, body).eval(e).map_err(|err| { + // enum variant evaluation happens before the global constant check + // so we need to report the real error + report_const_eval_err(tcx, &err, e.span, "enum discriminant"); + }) +} + fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { @@ -610,7 +620,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { - evaluate_disr_expr(tcx, repr_type, e).map(ConstVal::Integral) + evaluate_disr_expr(tcx, e) }); match result { @@ -738,60 +748,6 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.alloc_adt_def(def_id, kind, variants, repr) } -fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - repr_ty: attr::IntType, - body: hir::BodyId) - -> Result<ConstInt, ()> { - let e = &tcx.hir.body(body).value; - debug!("disr expr, checking {}", tcx.hir.node_to_pretty_string(e.id)); - - let ty_hint = repr_ty.to_ty(tcx); - let print_err = |cv: ConstVal| { - struct_span_err!(tcx.sess, e.span, E0079, "mismatched types") - .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) - .span_label(e.span, &format!("expected '{}' type", ty_hint)) - .emit(); - }; - - let hint = UncheckedExprHint(ty_hint); - match ConstContext::new(tcx, body).eval(e, hint) { - Ok(ConstVal::Integral(i)) => { - // FIXME: eval should return an error if the hint does not match the type of the body. - // i.e. eventually the match below would not exist. - match (repr_ty, i) { - (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) | - (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | - (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | - (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | - (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) | - (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | - (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | - (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | - (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | - (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | - (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | - (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Ok(i), - (_, i) => { - print_err(ConstVal::Integral(i)); - Err(()) - }, - } - }, - Ok(cv) => { - print_err(cv); - Err(()) - }, - // enum variant evaluation happens before the global constant check - // so we need to report the real error - Err(err) => { - let mut diag = report_const_eval_err( - tcx, &err, e.span, "enum discriminant"); - diag.emit(); - Err(()) - } - } -} - /// Ensures that the super-predicates of the trait with def-id /// trait_def_id are converted and stored. This also ensures that /// the transitive super-predicates are converted; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e8cb25cec4f..644e323a8db 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1039,45 +1039,6 @@ struct Good(u32, u32, u32); ``` "##, -E0079: r##" -Enum variants which contain no data can be given a custom integer -representation. This error indicates that the value provided is not an integer -literal and is therefore invalid. - -For example, in the following code: - -```compile_fail,E0079 -enum Foo { - Q = "32", -} -``` - -We try to set the representation to a string. - -There's no general fix for this; if you can work with an integer then just set -it to one: - -``` -enum Foo { - Q = 32, -} -``` - -However if you actually wanted a mapping between variants and non-integer -objects, it may be preferable to use a method with a match instead: - -``` -enum Foo { Q } -impl Foo { - fn get_str(&self) -> &'static str { - match *self { - Foo::Q => "32", - } - } -} -``` -"##, - E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -1427,6 +1388,44 @@ struct Baz<'a> { ``` "##, +E0109: r##" +You tried to give a type parameter to a type which doesn't need it. Erroneous +code example: + +```compile_fail,E0109 +type X = u32<i32>; // error: type parameters are not allowed on this type +``` + +Please check that you used the correct type and recheck its definition. Perhaps +it doesn't need the type parameter. + +Example: + +``` +type X = u32; // this compiles +``` + +Note that type parameters for enum-variant constructors go after the variant, +not after the enum (Option::None::<u32>, not Option::<u32>::None). +"##, + +E0110: r##" +You tried to give a lifetime parameter to a type which doesn't need it. +Erroneous code example: + +```compile_fail,E0110 +type X = u32<'static>; // error: lifetime parameters are not allowed on + // this type +``` + +Please check that the correct type was used and recheck its definition; perhaps +it doesn't need the lifetime parameter. Example: + +``` +type X = u32; // ok! +``` +"##, + E0116: r##" You can only define an inherent implementation for a type in the same crate where the type was defined. For example, an `impl` block as below is not allowed @@ -2649,6 +2648,41 @@ fn main() { ``` "##, +E0229: r##" +An associated type binding was done outside of the type parameter declaration +and `where` clause. Erroneous code example: + +```compile_fail,E0229 +pub trait Foo { + type A; + fn boo(&self) -> <Self as Foo>::A; +} + +struct Bar; + +impl Foo for isize { + type A = usize; + fn boo(&self) -> usize { 42 } +} + +fn baz<I>(x: &<I as Foo<A=Bar>>::A) {} +// error: associated type bindings are not allowed here +``` + +To solve this error, please move the type bindings in the type parameter +declaration: + +```ignore +fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok! +``` + +Or in the `where` clause: + +```ignore +fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {} +``` +"##, + E0230: r##" The trait has more type parameters specified than appear in its definition. diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs deleted file mode 100644 index 9ffaef7472b..00000000000 --- a/src/test/compile-fail/E0306.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -const A: [u32; "hello"] = []; -//~^ ERROR expected `usize` for array length, found string literal [E0306] -//~| NOTE expected `usize` - -const B: [u32; true] = []; -//~^ ERROR expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` - -const C: [u32; 0.0] = []; -//~^ ERROR expected `usize` for array length, found float [E0306] -//~| NOTE expected `usize` - -fn main() { -} diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs index 0239986f5ad..7f77ae2ec1f 100644 --- a/src/test/compile-fail/associated-const-array-len.rs +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -14,7 +14,8 @@ trait Foo { const ID: usize; } -const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080 +const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; +//~^ ERROR the trait bound `i32: Foo` is not satisfied fn main() { assert_eq!(1, X); diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs index 7c3f7a1d574..7fd9605ef2c 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -27,8 +27,6 @@ impl Foo for Def { pub fn test<A: Foo, B: Foo>() { let _array = [4; <A as Foo>::Y]; //~^ ERROR cannot use an outer type parameter in this context [E0402] - //~| ERROR constant evaluation error [E0080] - //~| non-constant path in constant } fn main() { diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs index dcf87d5f0fc..71c7a3965ec 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs @@ -27,8 +27,6 @@ impl Foo for Def { pub fn test<A: Foo, B: Foo>() { let _array: [u32; <A as Foo>::Y]; //~^ ERROR cannot use an outer type parameter in this context [E0402] - //~| ERROR constant evaluation error [E0080] - //~| non-constant path in constant } fn main() { diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs index b980bc02c85..108b7948dfc 100644 --- a/src/test/compile-fail/const-array-oob.rs +++ b/src/test/compile-fail/const-array-oob.rs @@ -12,8 +12,8 @@ #![feature(const_indexing)] -const FOO: [u32; 3] = [1, 2, 3]; -const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval +const FOO: [usize; 3] = [1, 2, 3]; +const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval const BLUB: [u32; FOO[4]] = [5, 6]; //~^ ERROR constant evaluation error [E0080] diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 9e7a5ecae10..02072e9a1a1 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -20,8 +20,9 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] - //~^ ERROR constant evaluation error [E0080] + //~^ ERROR mismatched types //~| expected i8, found u8 + //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied = [0; (i8::MAX as usize) + 1]; @@ -32,8 +33,7 @@ const A_CHAR_USIZE const A_BAD_CHAR_USIZE : [u32; 5i8 as char as usize] - //~^ ERROR constant evaluation error - //~| only `u8` can be cast as `char`, not `i8` + //~^ ERROR only `u8` can be cast as `char`, not `i8` = [0; 5]; fn main() {} diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 73351429b50..16f89606b01 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,12 +14,13 @@ struct S(i32); const CONSTANT: S = S(0); -//~^ ERROR E0080 -//~| unimplemented constant expression: tuple struct constructors enum E { V = CONSTANT, - //~^ NOTE: for enum discriminant here + //~^ ERROR mismatched types + //~| expected isize, found struct `S` + //~| NOTE expected type `isize` + //~| found type `S` } fn main() {} diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 398dc2f2215..29bc665a22e 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -8,52 +8,71 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const X: usize = 42 && 39; //~ ERROR E0080 - //~| can't do this op on integrals -const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here +const X: usize = 42 && 39; +//~^ ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected usize, found bool +const ARR: [i32; X] = [99; 34]; -const X1: usize = 42 || 39; //~ ERROR E0080 - //~| can't do this op on integrals -const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here +const X1: usize = 42 || 39; +//~^ ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected usize, found bool +const ARR1: [i32; X1] = [99; 47]; -const X2: usize = -42 || -39; //~ ERROR E0080 - //~| unary negation of unsigned integer -const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here +const X2: usize = -42 || -39; +//~^ ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected usize, found bool +const ARR2: [i32; X2] = [99; 18446744073709551607]; -const X3: usize = -42 && -39; //~ ERROR E0080 - //~| unary negation of unsigned integer -const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here +const X3: usize = -42 && -39; +//~^ ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected bool, found integral variable +//~| ERROR mismatched types +//~| expected usize, found bool +const ARR3: [i32; X3] = [99; 6]; const Y: usize = 42.0 == 42.0; +//~^ ERROR mismatched types +//~| expected usize, found bool const ARRR: [i32; Y] = [99; 1]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` const Y1: usize = 42.0 >= 42.0; -const ARRR1: [i32; Y] = [99; 1]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` +//~^ ERROR mismatched types +//~| expected usize, found bool +const ARRR1: [i32; Y1] = [99; 1]; const Y2: usize = 42.0 <= 42.0; -const ARRR2: [i32; Y] = [99; 1]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` +//~^ ERROR mismatched types +//~| expected usize, found bool +const ARRR2: [i32; Y2] = [99; 1]; const Y3: usize = 42.0 > 42.0; -const ARRR3: [i32; Y] = [99; 0]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` +//~^ ERROR mismatched types +//~| expected usize, found bool +const ARRR3: [i32; Y3] = [99; 0]; const Y4: usize = 42.0 < 42.0; -const ARRR4: [i32; Y] = [99; 0]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` +//~^ ERROR mismatched types +//~| expected usize, found bool +const ARRR4: [i32; Y4] = [99; 0]; const Y5: usize = 42.0 != 42.0; -const ARRR5: [i32; Y] = [99; 0]; -//~^ ERROR: expected `usize` for array length, found boolean [E0306] -//~| NOTE expected `usize` - +//~^ ERROR mismatched types +//~| expected usize, found bool +const ARRR5: [i32; Y5] = [99; 0]; fn main() { let _ = ARR; diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index f3fb92e2b22..b42c440f87d 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -11,8 +11,8 @@ // Test spans of errors const TUP: (usize,) = 5usize << 64; -//~^ ERROR E0080 -//~| attempt to shift left with overflow +//~^ ERROR mismatched types +//~| expected tuple, found usize const ARR: [i32; TUP.0] = []; fn main() { diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index c73b7e831b3..62e54c3f237 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -25,7 +25,7 @@ fn f_i8() { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected i8, found u8 } @@ -38,7 +38,7 @@ fn f_u8() { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected u8, found i8 } @@ -51,7 +51,7 @@ fn f_i16() { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected i16, found u16 } @@ -64,7 +64,7 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected u16, found i16 } @@ -77,7 +77,7 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected i32, found u32 } @@ -90,7 +90,7 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected u32, found i32 } @@ -103,7 +103,7 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected i64, found u64 } @@ -116,7 +116,7 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR E0080 + //~^ ERROR mismatched types //~| expected u64, found i64 } diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index bbdb3891d99..393a67be57f 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -13,32 +13,32 @@ enum Eu8 { Au8 = 23, Bu8 = 223, - Cu8 = -23, //~ ERROR E0080 - //~| unary negation of unsigned integer + Cu8 = -23, + //~^ ERROR cannot apply unary operator `-` to type `u8` } #[repr(u16)] enum Eu16 { Au16 = 23, Bu16 = 55555, - Cu16 = -22333, //~ ERROR E0080 - //~| unary negation of unsigned integer + Cu16 = -22333, + //~^ ERROR cannot apply unary operator `-` to type `u16` } #[repr(u32)] enum Eu32 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR E0080 - //~| unary negation of unsigned integer + Cu32 = -2_000_000_000, + //~^ ERROR cannot apply unary operator `-` to type `u32` } #[repr(u64)] enum Eu64 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR E0080 - //~| unary negation of unsigned integer + Cu32 = -2_000_000_000, + //~^ ERROR cannot apply unary operator `-` to type `u64` } // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs index 9a9358b787f..ab839e7630d 100644 --- a/src/test/compile-fail/invalid-path-in-const.rs +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -10,6 +10,5 @@ fn main() { fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR constant evaluation error - //~| unresolved path in constant expression + //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32` } diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index 54a24089354..c78e1f7f530 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -12,12 +12,10 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR constant evaluation error - //~| unresolved path in constant expression + //~^ ERROR no associated item named `PIE` found for type `Delicious` } const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR constant evaluation error -//~| unresolved path in constant expression +//~^ ERROR no associated item named `MIN` found for type `u8` fn main() {} diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs index c2bcbb9d54a..95f6526f115 100644 --- a/src/test/compile-fail/issue-23217.rs +++ b/src/test/compile-fail/issue-23217.rs @@ -10,8 +10,7 @@ pub enum SomeEnum { B = SomeEnum::A, - //~^ ERROR constant evaluation error - //~| unresolved path in constant expression + //~^ ERROR no associated item named `A` found for type `SomeEnum` } fn main() {} diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs index 1dfd146985f..b8571d2e85e 100644 --- a/src/test/compile-fail/issue-28586.rs +++ b/src/test/compile-fail/issue-28586.rs @@ -11,6 +11,7 @@ // Regression test for issue #28586 pub trait Foo {} -impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080 +impl Foo for [u8; usize::BYTES] {} +//~^ ERROR no associated item named `BYTES` found for type `usize` fn main() { } diff --git a/src/test/compile-fail/issue-31910.rs b/src/test/compile-fail/issue-31910.rs index 65fcd7df77e..aac8b89e882 100644 --- a/src/test/compile-fail/issue-31910.rs +++ b/src/test/compile-fail/issue-31910.rs @@ -11,7 +11,9 @@ #![feature(associated_consts)] enum Enum<T: Trait> { - X = Trait::Number, //~ ERROR constant evaluation error + X = Trait::Number, + //~^ ERROR mismatched types + //~| expected isize, found i32 } trait Trait { diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index e2acdcee3de..78af11a0b58 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -15,9 +15,7 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant - //~^^ ERROR constant evaluation error - //~| unresolved path in constant expression } - println!("{}", Stuff::Bar); + println!("{:?}", Stuff::Bar); } diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index a56a5e85489..bc492806b96 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -23,9 +23,13 @@ impl Dim for Dim3 { pub struct Vector<T, D: Dim> { entries: [T; D::dim()] //~^ ERROR cannot use an outer type parameter in this context - //~| ERROR constant evaluation error } fn main() { - let array: [usize; Dim3::dim()] = [0; Dim3::dim()]; + let array: [usize; Dim3::dim()] + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression + = [0; Dim3::dim()]; + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 91a07dd9ba6..f8424ea64ef 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -10,10 +10,10 @@ enum Foo { A = 1i64, - //~^ ERROR constant evaluation error + //~^ ERROR mismatched types //~| expected isize, found i64 B = 2u8 - //~^ ERROR constant evaluation error + //~^ ERROR mismatched types //~| expected isize, found u8 } diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs index 691d8d31b41..52cd4e8a3ed 100644 --- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs +++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs @@ -14,6 +14,5 @@ fn main() { fn bar(n: isize) { let _x: [isize; n]; //~^ ERROR attempt to use a non-constant value in a constant [E0435] - //~| ERROR constant evaluation error [E0080] } } diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs index f4769a78587..1eda5087784 100644 --- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs @@ -15,7 +15,5 @@ fn main() { let _x = [0; n]; //~^ ERROR attempt to use a non-constant value in a constant [E0435] //~| NOTE non-constant used with constant - //~| NOTE unresolved path in constant expression - //~| ERROR constant evaluation error [E0080] } } diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 0e8971269b0..6e80a917467 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyBranches.initial-before.mir // bb0: { -// switchInt(const false) -> [0: bb2, otherwise: bb1]; +// switchInt(const false) -> [0u8: bb2, otherwise: bb1]; // } // END rustc.node4.SimplifyBranches.initial-before.mir // START rustc.node4.SimplifyBranches.initial-after.mir diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/run-pass/issue-25145.rs index 93f75e9bfed..6f02f278381 100644 --- a/src/test/compile-fail/issue-25145.rs +++ b/src/test/run-pass/issue-25145.rs @@ -17,7 +17,7 @@ impl S { } static STUFF: [u8; S::N] = [0; S::N]; -//~^ ERROR constant evaluation error -//~| unresolved path in constant expression -fn main() {} +fn main() { + assert_eq!(STUFF, [0; 3]); +} diff --git a/src/test/compile-fail/E0079.rs b/src/test/run-pass/issue-39548.rs index c9b7f549d5a..7da50670d1d 100644 --- a/src/test/compile-fail/E0079.rs +++ b/src/test/run-pass/issue-39548.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Foo { - Q = "32" //~ ERROR E0079 - //~^ expected 'isize' type -} +type Array = [(); ((1 < 2) == false) as usize]; fn main() { + let _: Array = []; } diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index d01ffcb2839..c7c42bcf239 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -46,11 +46,5 @@ error[E0425]: cannot find value `second` in module `m` 32 | let b: m::first = m::second; // Misspelled item in module. | ^^^^^^^^^ did you mean `m::Second`? -error[E0080]: constant evaluation error - --> $DIR/levenshtein.rs:30:20 - | -30 | let v = [0u32; MAXITEM]; // Misspelled constant name. - | ^^^^^^^ unresolved path in constant expression - -error: aborting due to previous error +error: aborting due to 8 previous errors |
