From 74349fa2884013389ace2ed0a098cb08983d8740 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 7 Aug 2017 08:08:53 +0300 Subject: [PATCH] rustc: evaluate fixed-length array length expressions lazily. --- src/librustc/ich/impls_ty.rs | 8 ++ src/librustc/infer/mod.rs | 5 +- src/librustc/middle/const_val.rs | 39 +----- src/librustc/middle/free_region.rs | 3 +- src/librustc/middle/mem_categorization.rs | 3 +- src/librustc/mir/mod.rs | 1 + src/librustc/traits/error_reporting.rs | 17 +++ src/librustc/traits/fulfill.rs | 25 +++- src/librustc/traits/mod.rs | 2 + src/librustc/traits/object_safety.rs | 6 +- src/librustc/traits/project.rs | 40 +++++- src/librustc/traits/select.rs | 15 +++ src/librustc/traits/structural_impls.rs | 3 + src/librustc/traits/trans/mod.rs | 4 +- src/librustc/traits/util.rs | 7 + src/librustc/ty/context.rs | 12 -- src/librustc/ty/flags.rs | 4 + src/librustc/ty/fold.rs | 22 +++- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 31 ++++- src/librustc/ty/maps.rs | 11 +- src/librustc/ty/mod.rs | 11 +- src/librustc/ty/relate.rs | 46 ++++++- src/librustc/ty/structural_impls.rs | 120 +++++++++++++++++- src/librustc/ty/util.rs | 11 +- src/librustc/ty/walk.rs | 3 + src/librustc/ty/wf.rs | 47 ++++++- src/librustc/util/ppaux.rs | 11 ++ src/librustc_const_eval/_match.rs | 18 +-- src/librustc_const_eval/eval.rs | 3 +- src/librustc_const_eval/pattern.rs | 3 +- src/librustc_metadata/encoder.rs | 13 +- src/librustc_trans/mir/constant.rs | 3 +- src/librustc_typeck/astconv.rs | 15 ++- src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 10 +- src/librustc_typeck/check/regionck.rs | 3 +- src/librustdoc/clean/mod.rs | 10 +- .../const-block-non-item-statement-3.rs | 15 +++ .../const-block-non-item-statement.rs | 4 - src/test/compile-fail/const-fn-error.rs | 2 +- .../const-len-underflow-separate-spans.rs | 2 +- src/test/compile-fail/const-size_of-cycle.rs | 3 +- src/test/compile-fail/issue-22933-2.rs | 3 - src/test/compile-fail/issue-22933-3.rs | 14 ++ src/test/compile-fail/issue-39559.rs | 3 +- src/test/ui/issue-38875/issue_38875.stderr | 2 +- 48 files changed, 517 insertions(+), 122 deletions(-) create mode 100644 src/test/compile-fail/const-block-non-item-statement-3.rs create mode 100644 src/test/compile-fail/issue-22933-3.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c9fb754287f..e933ca4c2b5 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -235,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable> for ty::Pr def_id.hash_stable(hcx, hasher); closure_kind.hash_stable(hcx, hasher); } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } } } } @@ -317,6 +321,10 @@ for ::middle::const_val::ConstVal<'gcx> { value.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher); } + Unevaluated(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 3fe3a3dc585..6ccf7e42fd5 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize { impl_trans_normalize!('gcx, Ty<'gcx>, + &'gcx ty::Const<'gcx>, &'gcx Substs<'gcx>, ty::FnSig<'gcx>, ty::PolyFnSig<'gcx>, @@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let param_env = ty::ParamEnv::empty(Reveal::All); let value = self.erase_regions(value); - if !value.has_projection_types() { + if !value.has_projections() { return value; } @@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let value = self.erase_regions(value); - if !value.has_projection_types() { + if !value.has_projections() { return value; } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 469aed7e8ce..7b239980467 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -10,13 +10,9 @@ pub use rustc_const_math::ConstInt; -use hir; -use hir::def::Def; use hir::def_id::DefId; -use traits::Reveal; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; -use util::common::ErrorReported; use rustc_const_math::*; use graphviz::IntoCow; @@ -41,6 +37,7 @@ pub enum ConstVal<'tcx> { Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), + Unevaluated(DefId, &'tcx Substs<'tcx>), } #[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)] @@ -221,37 +218,3 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_error(tcx, primary_span, primary_kind).emit(); } } - -/// Returns the value of the length-valued expression -pub fn eval_length<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - count: hir::BodyId, - reason: &str) - -> Result<&'gcx ty::Const<'gcx>, ErrorReported> -{ - let count_expr = &tcx.hir.body(count).value; - let count_def_id = tcx.hir.body_owner_def_id(count); - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); - let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); - match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) { - Ok(count) => { - // Elsewhere in the compiler this is enforced even in the presence - // of erroneous code (type mismatch error has already been emitted). - assert_eq!(count.ty, tcx.types.usize); - Ok(count) - } - Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported), - Err(err) => { - let mut diag = err.struct_error(tcx, count_expr.span, reason); - - if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { - if let Def::Local(..) = path.def { - diag.note(&format!("`{}` is a variable", - tcx.hir.node_to_pretty_string(count_expr.id))); - } - } - - diag.emit(); - Err(ErrorReported) - } - } -} diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index d4cee25bb8f..4de86b66916 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { // No region bounds here } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a270e0873c1..5102b41598d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true, + ty::TyArray(_, len) if + len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1985dcbd1f7..d9ca5ddf46b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1535,6 +1535,7 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), + Unevaluated(..) => write!(fmt, "{:?}", const_val) } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index cfbd4ba055e..b491baadd7c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -19,6 +19,7 @@ use super::{ OnUnimplementedNote, OutputTypeParameterMismatch, TraitNotObjectSafe, + ConstEvalFailure, PredicateObligation, Reveal, SelectionContext, @@ -31,6 +32,7 @@ use hir; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; +use middle::const_val; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; @@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } + + ty::Predicate::ConstEvaluatable(..) => { + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!(span, + "const-evaluatable requirement gave wrong error: `{:?}`", obligation) + } } } @@ -762,6 +772,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.report_object_safety_error(span, did, violations) } + + ConstEvalFailure(ref err) => { + if let const_val::ErrKind::TypeckError = err.kind { + return; + } + err.struct_error(self.tcx, span, "constant expression") + } }; self.note_obligation_cause(&mut err, obligation); err.emit(); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index fbc393cbd96..cc2506d1afc 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation, Obligation}; use super::project; use super::select::SelectionContext; -use super::Unimplemented; +use super::{Unimplemented, ConstEvalFailure}; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; @@ -540,6 +540,29 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match selcx.tcx().lift_to_global(&obligation.param_env) { + None => { + Ok(None) + } + Some(param_env) => { + match selcx.tcx().lift_to_global(&substs) { + None => { + pending_obligation.stalled_on = substs.types().collect(); + Ok(None) + } + Some(substs) => { + match selcx.tcx().at(obligation.cause.span) + .const_eval(param_env.and((def_id, substs))) { + Ok(_) => Ok(Some(vec![])), + Err(e) => Err(CodeSelectionError(ConstEvalFailure(e))) + } + } + } + } + } + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 22c92776c5e..fb71d9cc49b 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*; use hir; use hir::def_id::DefId; +use middle::const_val::ConstEvalErr; use middle::region; use middle::free_region::FreeRegionMap; use ty::subst::Substs; @@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> { ty::PolyTraitRef<'tcx>, ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), + ConstEvalFailure(ConstEvalErr<'tcx>), } pub struct FulfillmentError<'tcx> { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index fd6d5a86a7f..1e9816095ea 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) | - ty::Predicate::Equate(..) => { + ty::Predicate::Equate(..) | + ty::Predicate::ConstEvaluatable(..) => { false } } @@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { false } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9a0d7614436..54e31aed272 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -27,10 +27,11 @@ use super::util; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use infer::type_variable::TypeVariableOrigin; +use middle::const_val::ConstVal; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::ast; use syntax::symbol::Symbol; -use ty::subst::Subst; +use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; @@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { fn fold>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_type_vars_if_possible(value); - if !value.has_projection_types() { + if !value.has_projections() { value.clone() } else { value.fold_with(self) @@ -332,6 +333,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, } } } + + fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ConstVal::Unevaluated(def_id, substs) = constant.val { + if substs.needs_infer() { + let identity_substs = Substs::identity_for_item(self.tcx(), def_id); + let data = self.param_env.and((def_id, identity_substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => { + match self.tcx().const_eval(data) { + Ok(evaluated) => { + let evaluated = evaluated.subst(self.tcx(), substs); + return self.fold_const(evaluated); + } + Err(_) => {} + } + } + None => {} + } + } else { + let data = self.param_env.and((def_id, substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => { + match self.tcx().const_eval(data) { + Ok(evaluated) => return self.fold_const(evaluated), + Err(_) => {} + } + } + None => {} + } + } + } + constant + } } #[derive(Clone)] @@ -520,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( depth, obligations); - let result = if projected_ty.has_projection_types() { + let result = if projected_ty.has_projections() { let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 98bb3fb0ba9..f5f69ad0a7c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -732,6 +732,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match self.tcx().lift_to_global(&(obligation.param_env, substs)) { + Some((param_env, substs)) => { + match self.tcx().const_eval(param_env.and((def_id, substs))) { + Ok(_) => EvaluatedToOk, + Err(_) => EvaluatedToErr + } + } + None => { + // Inference variables still left in param_env or substs. + EvaluatedToAmbig + } + } + } } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 674da297cd9..19ed03aa149 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -173,6 +173,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { super::TraitNotObjectSafe(def_id) => { Some(super::TraitNotObjectSafe(def_id)) } + super::ConstEvalFailure(ref err) => { + tcx.lift(err).map(super::ConstEvalFailure) + } } } } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 827a5092c00..9c4a260b35d 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { } fn fold>(&mut self, value: &T) -> T { - if !value.has_projection_types() { + if !value.has_projections() { value.clone() } else { value.fold_with(self) @@ -134,7 +134,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { } fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { + if !ty.has_projections() { ty } else { self.tcx.trans_trait_caches.project_cache.memoize(ty, || { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index b0d6f4d5a31..42e0834e8e4 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::Subtype(ref data) => ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::ConstEvaluatable(def_id, substs) => + ty::Predicate::ConstEvaluatable(def_id, substs), } } @@ -175,6 +178,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { ty::Predicate::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } + ty::Predicate::ConstEvaluatable(..) => { + // Currently, we do not elaborate const-evaluatable + // predicates. + } ty::Predicate::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e02493add31..6d12731307d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1190,18 +1190,6 @@ pub trait Lift<'tcx> { fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } -impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { - type Lifted = ty::ParamEnv<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| { - Some(ty::ParamEnv { - reveal: self.reveal, - caller_bounds, - }) - }) - } -} - impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { type Lifted = Ty<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 62e39a507f2..9ece719c764 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -235,6 +235,10 @@ impl FlagComputation { ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { self.add_const(v); } + ConstVal::Unevaluated(_, substs) => { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_substs(substs); + } } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index a1cd92c7609..543e8f3e2f0 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,6 +39,7 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. +use middle::const_val::ConstVal; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; @@ -67,7 +68,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { flags: flags }) } - fn has_projection_types(&self) -> bool { + fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) } fn references_error(&self) -> bool { @@ -139,6 +140,10 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } + + fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + c.super_fold_with(self) + } } pub trait TypeVisitor<'tcx> : Sized { @@ -153,6 +158,10 @@ pub trait TypeVisitor<'tcx> : Sized { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { r.super_visit_with(self) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + c.super_visit_with(self) + } } /////////////////////////////////////////////////////////////////////////// @@ -603,6 +612,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); flags.intersects(self.flags) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ConstVal::Unevaluated(..) = c.val { + let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION | + TypeFlags::HAS_PROJECTION; + if projection_flags.intersects(self.flags) { + return true; + } + } + c.super_visit_with(self) + } } /// Collects all the late-bound regions it finds into a hash set. diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index e10a4fb9f93..a829814e090 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 { + if len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) { DefIdForest::empty() } else { ty.uninhabited_from(visited, tcx) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bb16413c17f..0106d98b641 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -837,12 +837,22 @@ impl<'a, 'tcx> Struct { // Is this a fixed-size array of something non-zero // with at least one element? - (_, &ty::TyArray(ety, d)) if d.val.to_const_int().unwrap().to_u64().unwrap() != 0 => { - Struct::non_zero_field_paths( - tcx, - param_env, - Some(ety).into_iter(), - None) + (_, &ty::TyArray(ety, mut count)) => { + if count.has_projections() { + count = tcx.normalize_associated_type_in_env(&count, param_env); + if count.has_projections() { + return Err(LayoutError::Unknown(ty)); + } + } + if count.val.to_const_int().unwrap().to_u64().unwrap() != 0 { + Struct::non_zero_field_paths( + tcx, + param_env, + Some(ety).into_iter(), + None) + } else { + Ok(None) + } } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { @@ -1174,7 +1184,14 @@ impl<'a, 'tcx> Layout { } // Arrays and slices. - ty::TyArray(element, count) => { + ty::TyArray(element, mut count) => { + if count.has_projections() { + count = tcx.normalize_associated_type_in_env(&count, param_env); + if count.has_projections() { + return Err(LayoutError::Unknown(ty)); + } + } + let element = element.layout(tcx, param_env)?; let element_size = element.size(dl); let count = count.val.to_const_int().unwrap().to_u64().unwrap(); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 48b92d101ed..83b4fbb4f80 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -159,7 +159,7 @@ impl Key for (MirSuite, MirPassIndex, DefId) { } } -impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> { +impl<'tcx> Key for Ty<'tcx> { fn map_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -168,6 +168,15 @@ impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> { } } +impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + fn map_crate(&self) -> CrateNum { + self.value.map_crate() + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.value.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6634af59e78..bdd4c003de7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -846,6 +846,9 @@ pub enum Predicate<'tcx> { /// `T1 <: T2` Subtype(PolySubtypePredicate<'tcx>), + + /// Constant initializer must evaluate successfully. + ConstEvaluatable(DefId, &'tcx Substs<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -938,6 +941,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::ObjectSafe(trait_def_id), Predicate::ClosureKind(closure_def_id, kind) => Predicate::ClosureKind(closure_def_id, kind), + Predicate::ConstEvaluatable(def_id, const_substs) => + Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), } } } @@ -1120,6 +1125,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::ClosureKind(_closure_def_id, _kind) => { vec![] } + ty::Predicate::ConstEvaluatable(_, substs) => { + substs.types().collect() + } }; // The only reason to collect into a vector here is that I was @@ -1142,7 +1150,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | - Predicate::TypeOutlives(..) => { + Predicate::TypeOutlives(..) | + Predicate::ConstEvaluatable(..) => { None } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index eb465ed16a2..309880ba063 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,9 +14,12 @@ //! type equality, etc. use hir::def_id::DefId; +use middle::const_val::ConstVal; +use traits::Reveal; use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; +use util::common::ErrorReported; use std::rc::Rc; use std::iter; use syntax::abi; @@ -430,12 +433,43 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let t = relation.relate(&a_t, &b_t)?; assert_eq!(sz_a.ty, tcx.types.usize); assert_eq!(sz_b.ty, tcx.types.usize); - let sz_a_u64 = sz_a.val.to_const_int().unwrap().to_u64().unwrap(); - let sz_b_u64 = sz_b.val.to_const_int().unwrap().to_u64().unwrap(); - if sz_a_u64 == sz_b_u64 { - Ok(tcx.mk_ty(ty::TyArray(t, sz_a))) - } else { - Err(TypeError::FixedArraySize(expected_found(relation, &sz_a_u64, &sz_b_u64))) + let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { + match x.val { + ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Unevaluated(def_id, substs) => { + // FIXME(eddyb) get the right param_env. + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + match tcx.lift_to_global(&substs) { + Some(substs) => { + match tcx.const_eval(param_env.and((def_id, substs))) { + Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { + return Ok(x.to_u64().unwrap()); + } + _ => {} + } + } + None => {} + } + tcx.sess.delay_span_bug(tcx.def_span(def_id), + "array length could not be evaluated"); + Err(ErrorReported) + } + _ => bug!("arrays should not have {:?} as length", x) + } + }; + match (to_u64(sz_a), to_u64(sz_b)) { + (Ok(sz_a_u64), Ok(sz_b_u64)) => { + if sz_a_u64 == sz_b_u64 { + Ok(tcx.mk_ty(ty::TyArray(t, sz_a))) + } else { + Err(TypeError::FixedArraySize( + expected_found(relation, &sz_a_u64, &sz_b_u64))) + } + } + // We reported an error or will ICE, so we can return TyError. + (Err(ErrorReported), _) | (_, Err(ErrorReported)) => { + Ok(tcx.types.err) + } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 758edd7d0c3..54d55748c8e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,7 @@ // except according to those terms. use infer::type_variable; -use middle::const_val::{ConstVal, ConstAggregate}; +use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -59,6 +59,13 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result { } } +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box { + type Lifted = Box; + fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + tcx.lift(&**self).map(Box::new) + } +} + impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { type Lifted = Vec; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -210,6 +217,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::ObjectSafe(trait_def_id) => { Some(ty::Predicate::ObjectSafe(trait_def_id)) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + tcx.lift(&substs).map(|substs| { + ty::Predicate::ConstEvaluatable(def_id, substs) + }) + } } } } @@ -221,6 +233,32 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { } } +impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { + type Lifted = ty::ParamEnv<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.caller_bounds).map(|caller_bounds| { + ty::ParamEnv { + reveal: self.reveal, + caller_bounds, + } + }) + } +} + +impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> { + type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.param_env).and_then(|param_env| { + tcx.lift(&self.value).map(|value| { + ty::ParamEnvAnd { + param_env, + value, + } + }) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -395,6 +433,64 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { + type Lifted = ConstEvalErr<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.kind).map(|kind| { + ConstEvalErr { + span: self.span, + kind, + } + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { + type Lifted = const_val::ErrKind<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + use middle::const_val::ErrKind::*; + + Some(match *self { + CannotCast => CannotCast, + MissingStructField => MissingStructField, + NonConstPath => NonConstPath, + UnimplementedConstVal(s) => UnimplementedConstVal(s), + ExpectedConstTuple => ExpectedConstTuple, + ExpectedConstStruct => ExpectedConstStruct, + IndexedNonVec => IndexedNonVec, + IndexNotUsize => IndexNotUsize, + IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, + MiscBinaryOp => MiscBinaryOp, + MiscCatchAll => MiscCatchAll, + IndexOpFeatureGated => IndexOpFeatureGated, + Math(ref e) => Math(e.clone()), + + LayoutError(ref e) => { + return tcx.lift(e).map(LayoutError) + } + ErroneousReferencedConstant(ref e) => { + return tcx.lift(e).map(ErroneousReferencedConstant) + } + + TypeckError => TypeckError, + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> { + type Lifted = ty::layout::LayoutError<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ty::layout::LayoutError::Unknown(ref ty) => { + tcx.lift(ty).map(ty::layout::LayoutError::Unknown) + } + ty::layout::LayoutError::SizeOverflow(ref ty) => { + tcx.lift(ty).map(ty::layout::LayoutError::SizeOverflow) + } + } + } +} + /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // @@ -409,6 +505,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { macro_rules! CopyImpls { ($($ty:ty),+) => { $( + impl<'tcx> Lift<'tcx> for $ty { + type Lifted = Self; + fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + Some(*self) + } + } + impl<'tcx> TypeFoldable<'tcx> for $ty { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty { *self @@ -866,6 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind), ty::Predicate::ObjectSafe(trait_def_id) => ty::Predicate::ObjectSafe(trait_def_id), + ty::Predicate::ConstEvaluatable(def_id, substs) => + ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)), } } @@ -880,6 +985,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::WellFormed(data) => data.visit_with(visitor), ty::Predicate::ClosureKind(_closure_def_id, _kind) => false, ty::Predicate::ObjectSafe(_trait_def_id) => false, + ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), } } } @@ -1153,6 +1259,9 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { let v = v.fold_with(folder); ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) } + ConstVal::Unevaluated(def_id, substs) => { + ConstVal::Unevaluated(def_id, substs.fold_with(folder)) + } } } @@ -1176,6 +1285,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { v.visit_with(visitor) } + ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor), } } } @@ -1190,7 +1300,15 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { }) } + fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + folder.fold_const(*self) + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { self.ty.visit_with(visitor) || self.val.visit_with(visitor) } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_const(self) + } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 95618717e0e..16ae3cdbf17 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,6 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use ich::{StableHashingContext, NodeIdHashingMode}; +use middle::const_val::ConstVal; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; @@ -388,7 +389,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::RegionOutlives(..) => { + ty::Predicate::RegionOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { None } ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { @@ -698,7 +700,12 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), TyArray(_, n) => { - self.hash(n.val.to_const_int().unwrap().to_u64().unwrap()) + self.hash_discriminant_u8(&n.val); + match n.val { + ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), + _ => bug!("arrays should not have {:?} as length", n) + } } TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 4d7eb37ca26..df07844cceb 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -160,6 +160,9 @@ fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { push_const(stack, v); } + ConstVal::Unevaluated(_, substs) => { + stack.extend(substs.types().rev()); + } } stack.push(constant.ty); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 4d2b15b6bf0..41e27fca3f3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -9,6 +9,7 @@ // except according to those terms. use hir::def_id::DefId; +use middle::const_val::{ConstVal, ConstAggregate}; use infer::InferCtxt; use ty::subst::Substs; use traits; @@ -101,6 +102,14 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, wf.compute(data.skip_binder().a); // (*) wf.compute(data.skip_binder().b); // (*) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + let obligations = wf.nominal_obligations(def_id, substs); + wf.out.extend(obligations); + + for ty in substs.types() { + wf.compute(ty); + } + } } wf.normalize() @@ -209,7 +218,43 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// Pushes the obligations required for a constant value to be WF /// into `self.out`. - fn compute_const(&mut self, _constant: &'tcx ty::Const<'tcx>) {} + fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { + self.require_sized(constant.ty, traits::ConstSized); + match constant.val { + ConstVal::Integral(_) | + ConstVal::Float(_) | + ConstVal::Str(_) | + ConstVal::ByteStr(_) | + ConstVal::Bool(_) | + ConstVal::Char(_) | + ConstVal::Variant(_) | + ConstVal::Function(..) => {} + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + for &(_, v) in fields { + self.compute_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + for v in fields { + self.compute_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { + self.compute_const(v); + } + ConstVal::Unevaluated(def_id, substs) => { + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + + let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new(cause, + self.param_env, + predicate)); + } + } + } fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_regions() { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6b74022806c..cf7a29d2845 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -430,6 +430,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind) => { write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) + } } } } @@ -894,6 +897,9 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { ConstVal::Integral(ConstInt::Usize(sz)) => { write!(f, "{}", sz)?; } + ConstVal::Unevaluated(_def_id, substs) => { + write!(f, "", &substs[..])?; + } _ => { write!(f, "{:?}", sz)?; } @@ -1048,6 +1054,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { write!(f, "the closure `{}` implements the trait `{}`", tcx.item_path_str(closure_def_id), kind) }), + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "the constant `")?; + parameterized(f, substs, def_id, &[])?; + write!(f, "` can be evaluated") + } } } } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index efe6cfb5464..b836b71e74b 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -415,14 +415,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, })) }).collect() } - ty::TySlice(ref sub_ty) => { - if cx.is_uninhabited(sub_ty) { - vec![Slice(0)] - } else { - (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() - } - } - ty::TyArray(ref sub_ty, len) => { + ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { let len = len.val.to_const_int().unwrap().to_u64().unwrap(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] @@ -430,6 +423,15 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, vec![Slice(len)] } } + // Treat arrays of a constant but unknown length like slices. + ty::TyArray(ref sub_ty, _) | + ty::TySlice(ref sub_ty) => { + if cx.is_uninhabited(sub_ty) { + vec![Slice(0)] + } else { + (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() + } + } ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => { def.variants.iter() .filter(|v| !cx.is_variant_uninhabited(v, substs)) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 1ad00a9e7b3..61eb5dfd18b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -334,7 +334,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { let layout_of = |ty: Ty<'tcx>| { - ty.layout(tcx, cx.param_env).map_err(|err| { + let ty = tcx.erase_regions(&ty); + tcx.at(e.span).layout_raw(cx.param_env.reveal_all().and(ty)).map_err(|err| { ConstEvalErr { span: e.span, kind: LayoutError(err) } }) }; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 0a2e78dd51a..a87fa0c2746 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -117,7 +117,8 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::Char(c) => write!(f, "{:?}", c), ConstVal::Variant(_) | ConstVal::Function(..) | - ConstVal::Aggregate(_) => bug!("{:?} not printable in a pattern", value) + ConstVal::Aggregate(_) | + ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3b07177b1b5..c96615064c8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1521,9 +1521,16 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { - if let hir::TyImplTrait(_) = ty.node { - let def_id = self.tcx.hir.local_def_id(ty.id); - self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); + match ty.node { + hir::TyImplTrait(_) => { + let def_id = self.tcx.hir.local_def_id(ty.id); + self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); + } + hir::TyArray(_, len) => { + let def_id = self.tcx.hir.body_owner_def_id(len); + self.record(def_id, IsolatedEncoder::encode_info_for_embedded_const, def_id); + } + _ => {} } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 072d351dd61..6e975941e8e 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -103,7 +103,8 @@ impl<'tcx> Const<'tcx> { ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64), ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), ConstVal::Variant(_) | - ConstVal::Aggregate(..) => { + ConstVal::Aggregate(..) | + ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6759b6a422d..8f8663385b0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,7 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc::middle::const_val::eval_length; +use rustc::middle::const_val::ConstVal; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1082,11 +1082,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0 } hir::TyArray(ref ty, length) => { - if let Ok(length) = eval_length(tcx, length, "array length") { - tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)) - } else { - self.tcx().types.err - } + let length_def_id = tcx.hir.body_owner_def_id(length); + let substs = Substs::identity_for_item(tcx, length_def_id); + let length = tcx.mk_const(ty::Const { + val: ConstVal::Unevaluated(length_def_id, substs), + ty: tcx.types.usize + }); + let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)); + self.normalize_ty(ast_ty.span, array_ty) } hir::TyTypeof(ref _e) => { struct_span_err!(tcx.sess, ast_ty.span, E0516, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index aa2b9c1e038..07159770d5b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::ConstEvaluatable(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3771d330f6d..7b947818325 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -590,7 +590,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => None, } }) .collect(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0ed3cc1e905..ae2430990ba 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -128,7 +128,6 @@ use rustc::hir::map::Node; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; -use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; mod autoderef; @@ -3898,7 +3897,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_array(element_ty, args.len() as u64) } hir::ExprRepeat(ref element, count) => { - let count = eval_length(self.tcx, count, "repeat count"); + let count_def_id = tcx.hir.body_owner_def_id(count); + let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing); + let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); + let count = tcx.const_eval(param_env.and((count_def_id, substs))); + + if let Err(ref err) = count { + err.report(tcx, tcx.def_span(count_def_id), "constant expression"); + } let uty = match expected { ExpectHasType(uty) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d475c37ed8c..609af638e97 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -511,7 +511,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) => + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ConstEvaluatable(..) => vec![], ty::Predicate::WellFormed(subty) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 69c05050dac..ce3bf896256 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -33,6 +33,7 @@ use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::traits::Reveal; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind}; use rustc::middle::stability; @@ -936,6 +937,7 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), + Predicate::ConstEvaluatable(..) => panic!("not user writable"), } } } @@ -1784,9 +1786,11 @@ impl Clean for hir::Ty { type_: box m.ty.clean(cx)} } TySlice(ref ty) => Slice(box ty.clean(cx)), - TyArray(ref ty, length) => { - use rustc::middle::const_val::eval_length; - let n = eval_length(cx.tcx, length, "array length").unwrap(); + TyArray(ref ty, n) => { + let def_id = cx.tcx.hir.body_owner_def_id(n); + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let substs = Substs::identity_for_item(cx.tcx, def_id); + let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap(); let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { n.to_string() } else { diff --git a/src/test/compile-fail/const-block-non-item-statement-3.rs b/src/test/compile-fail/const-block-non-item-statement-3.rs new file mode 100644 index 00000000000..70703791101 --- /dev/null +++ b/src/test/compile-fail/const-block-non-item-statement-3.rs @@ -0,0 +1,15 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Array = [u32; { let x = 2; 5 }]; +//~^ ERROR: blocks in constants are limited to items and tail expressions +//~^^ ERROR: blocks in constants are limited to items and tail expressions + +pub fn main() {} diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs index bdc69c937c6..802e660b904 100644 --- a/src/test/compile-fail/const-block-non-item-statement.rs +++ b/src/test/compile-fail/const-block-non-item-statement.rs @@ -14,8 +14,4 @@ enum Foo { //~^^ ERROR: blocks in constants are limited to items and tail expressions } -type Array = [u32; { let x = 2; 5 }]; -//~^ ERROR: blocks in constants are limited to items and tail expressions -//~^^ ERROR: blocks in constants are limited to items and tail expressions - pub fn main() {} diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index dd0f058f2c9..385daef44df 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -23,5 +23,5 @@ const fn f(x: usize) -> usize { #[allow(unused_variables)] fn main() { - let a : [i32; f(X)]; //~ NOTE for array length here + let a : [i32; f(X)]; //~ NOTE for constant expression here } diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index c01bb826763..3c848105542 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -20,5 +20,5 @@ const LEN: usize = ONE - TWO; fn main() { let a: [i8; LEN] = unimplemented!(); - //~^ NOTE for array length here + //~^ NOTE for constant expression here } diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs index a58be33b1ae..cbeafdfe6ac 100644 --- a/src/test/compile-fail/const-size_of-cycle.rs +++ b/src/test/compile-fail/const-size_of-cycle.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: unsupported cyclic reference between types/traits detected + #![feature(const_fn)] struct Foo { bytes: [u8; std::mem::size_of::()] - //~^ ERROR unsupported cyclic reference between types/traits detected } fn main() {} diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index c78e1f7f530..97456c2da87 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -15,7 +15,4 @@ enum Delicious { //~^ ERROR no associated item named `PIE` found for type `Delicious` } -const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR no associated item named `MIN` found for type `u8` - fn main() {} diff --git a/src/test/compile-fail/issue-22933-3.rs b/src/test/compile-fail/issue-22933-3.rs new file mode 100644 index 00000000000..62adae41adf --- /dev/null +++ b/src/test/compile-fail/issue-22933-3.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: [u32; u8::MIN as usize] = []; +//~^ ERROR no associated item named `MIN` found for type `u8` + +fn main() {} diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index 8bc1cc7bd1a..2da21fb14bd 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -21,8 +21,9 @@ impl Dim for Dim3 { } pub struct Vector { - entries: [T; D::dim()] + entries: [T; D::dim()], //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope + _dummy: D, } fn main() {} diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr index 10bb61ee22a..d49741f25b9 100644 --- a/src/test/ui/issue-38875/issue_38875.stderr +++ b/src/test/ui/issue-38875/issue_38875.stderr @@ -4,7 +4,7 @@ error[E0080]: constant evaluation error 11 | pub const FOO: usize = *&0; | ^^^ unimplemented constant expression: deref operation | -note: for repeat count here +note: for constant expression here --> $DIR/issue_38875.rs:16:22 | 16 | let test_x = [0; issue_38875_b::FOO];