rustc: evaluate fixed-length array length expressions lazily.

This commit is contained in:
Eduard-Mihai Burtescu 2017-08-07 08:08:53 +03:00
parent 88217618ec
commit 74349fa288
48 changed files with 517 additions and 122 deletions

View file

@ -235,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Pr
def_id.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher);
closure_kind.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); value.hash_stable(hcx, hasher);
times.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher);
} }
Unevaluated(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
} }
} }
} }

View file

@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize {
impl_trans_normalize!('gcx, impl_trans_normalize!('gcx,
Ty<'gcx>, Ty<'gcx>,
&'gcx ty::Const<'gcx>,
&'gcx Substs<'gcx>, &'gcx Substs<'gcx>,
ty::FnSig<'gcx>, ty::FnSig<'gcx>,
ty::PolyFnSig<'gcx>, ty::PolyFnSig<'gcx>,
@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
let param_env = ty::ParamEnv::empty(Reveal::All); let param_env = ty::ParamEnv::empty(Reveal::All);
let value = self.erase_regions(value); let value = self.erase_regions(value);
if !value.has_projection_types() { if !value.has_projections() {
return value; return value;
} }
@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
let value = self.erase_regions(value); let value = self.erase_regions(value);
if !value.has_projection_types() { if !value.has_projections() {
return value; return value;
} }

View file

@ -10,13 +10,9 @@
pub use rustc_const_math::ConstInt; pub use rustc_const_math::ConstInt;
use hir;
use hir::def::Def;
use hir::def_id::DefId; use hir::def_id::DefId;
use traits::Reveal;
use ty::{self, TyCtxt, layout}; use ty::{self, TyCtxt, layout};
use ty::subst::Substs; use ty::subst::Substs;
use util::common::ErrorReported;
use rustc_const_math::*; use rustc_const_math::*;
use graphviz::IntoCow; use graphviz::IntoCow;
@ -41,6 +37,7 @@ pub enum ConstVal<'tcx> {
Variant(DefId), Variant(DefId),
Function(DefId, &'tcx Substs<'tcx>), Function(DefId, &'tcx Substs<'tcx>),
Aggregate(ConstAggregate<'tcx>), Aggregate(ConstAggregate<'tcx>),
Unevaluated(DefId, &'tcx Substs<'tcx>),
} }
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)] #[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(); 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)
}
}
}

View file

@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
ty::Predicate::WellFormed(..) | ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) | ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => { ty::Predicate::TypeOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => {
// No region bounds here // No region bounds here
} }
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {

View file

@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// Always promote `[T; 0]` (even when e.g. borrowed mutably). // Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty { 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, _ => promotable,
}; };

View file

@ -1535,6 +1535,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
Variant(def_id) | Variant(def_id) |
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
Unevaluated(..) => write!(fmt, "{:?}", const_val)
} }
} }

View file

@ -19,6 +19,7 @@ use super::{
OnUnimplementedNote, OnUnimplementedNote,
OutputTypeParameterMismatch, OutputTypeParameterMismatch,
TraitNotObjectSafe, TraitNotObjectSafe,
ConstEvalFailure,
PredicateObligation, PredicateObligation,
Reveal, Reveal,
SelectionContext, SelectionContext,
@ -31,6 +32,7 @@ use hir;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::{self, InferCtxt}; use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin; use infer::type_variable::TypeVariableOrigin;
use middle::const_val;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use std::fmt; use std::fmt;
use syntax::ast; use syntax::ast;
@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// (which may fail). // (which may fail).
span_bug!(span, "WF predicate not satisfied for {:?}", ty); 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, self.tcx.report_object_safety_error(span, did,
violations) 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); self.note_obligation_cause(&mut err, obligation);
err.emit(); err.emit();

View file

@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation, Obligation}; use super::{ObligationCause, PredicateObligation, Obligation};
use super::project; use super::project;
use super::select::SelectionContext; use super::select::SelectionContext;
use super::Unimplemented; use super::{Unimplemented, ConstEvalFailure};
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
type Predicate = ty::Predicate<'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)))
}
}
}
}
}
}
} }
} }

View file

@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;
use hir; use hir;
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::ConstEvalErr;
use middle::region; use middle::region;
use middle::free_region::FreeRegionMap; use middle::free_region::FreeRegionMap;
use ty::subst::Substs; use ty::subst::Substs;
@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> {
ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>), ty::error::TypeError<'tcx>),
TraitNotObjectSafe(DefId), TraitNotObjectSafe(DefId),
ConstEvalFailure(ConstEvalErr<'tcx>),
} }
pub struct FulfillmentError<'tcx> { pub struct FulfillmentError<'tcx> {

View file

@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::RegionOutlives(..) | ty::Predicate::RegionOutlives(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::Subtype(..) | ty::Predicate::Subtype(..) |
ty::Predicate::Equate(..) => { ty::Predicate::Equate(..) |
ty::Predicate::ConstEvaluatable(..) => {
false false
} }
} }
@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::WellFormed(..) | ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) | ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => { ty::Predicate::TypeOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => {
false false
} }
} }

View file

@ -27,10 +27,11 @@ use super::util;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::{InferCtxt, InferOk}; use infer::{InferCtxt, InferOk};
use infer::type_variable::TypeVariableOrigin; use infer::type_variable::TypeVariableOrigin;
use middle::const_val::ConstVal;
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::ast; use syntax::ast;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use ty::subst::Subst; use ty::subst::{Subst, Substs};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder}; use ty::fold::{TypeFoldable, TypeFolder};
use util::common::FN_OUTPUT_NAME; use util::common::FN_OUTPUT_NAME;
@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T { fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
let value = self.selcx.infcx().resolve_type_vars_if_possible(value); let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
if !value.has_projection_types() { if !value.has_projections() {
value.clone() value.clone()
} else { } else {
value.fold_with(self) 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)] #[derive(Clone)]
@ -520,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
depth, depth,
obligations); obligations);
let result = if projected_ty.has_projection_types() { let result = if projected_ty.has_projections() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx, let mut normalizer = AssociatedTypeNormalizer::new(selcx,
param_env, param_env,
cause, cause,

View file

@ -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
}
}
}
} }
} }

View file

@ -173,6 +173,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
super::TraitNotObjectSafe(def_id) => { super::TraitNotObjectSafe(def_id) => {
Some(super::TraitNotObjectSafe(def_id)) Some(super::TraitNotObjectSafe(def_id))
} }
super::ConstEvalFailure(ref err) => {
tcx.lift(err).map(super::ConstEvalFailure)
}
} }
} }
} }

View file

@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
} }
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T { fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
if !value.has_projection_types() { if !value.has_projections() {
value.clone() value.clone()
} else { } else {
value.fold_with(self) 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> { fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projection_types() { if !ty.has_projections() {
ty ty
} else { } else {
self.tcx.trans_trait_caches.project_cache.memoize(ty, || { self.tcx.trans_trait_caches.project_cache.memoize(ty, || {

View file

@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty::Predicate::Subtype(ref data) => ty::Predicate::Subtype(ref data) =>
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(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(..) => { ty::Predicate::ClosureKind(..) => {
// Nothing to elaborate when waiting for a closure's kind to be inferred. // 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(..) => { ty::Predicate::RegionOutlives(..) => {
// Nothing to elaborate from `'a: 'b`. // Nothing to elaborate from `'a: 'b`.

View file

@ -1190,18 +1190,6 @@ pub trait Lift<'tcx> {
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
} }
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<ty::ParamEnv<'tcx>> {
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> { impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
type Lifted = Ty<'tcx>; type Lifted = Ty<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {

View file

@ -235,6 +235,10 @@ impl FlagComputation {
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
self.add_const(v); self.add_const(v);
} }
ConstVal::Unevaluated(_, substs) => {
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_substs(substs);
}
} }
} }

View file

@ -39,6 +39,7 @@
//! These methods return true to indicate that the visitor has found what it is looking for //! These methods return true to indicate that the visitor has found what it is looking for
//! and does not need to visit anything else. //! and does not need to visit anything else.
use middle::const_val::ConstVal;
use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
use std::fmt; use std::fmt;
@ -67,7 +68,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn has_type_flags(&self, flags: TypeFlags) -> bool { fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { flags: flags }) 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) self.has_type_flags(TypeFlags::HAS_PROJECTION)
} }
fn references_error(&self) -> bool { 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> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
r.super_fold_with(self) 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 { pub trait TypeVisitor<'tcx> : Sized {
@ -153,6 +158,10 @@ pub trait TypeVisitor<'tcx> : Sized {
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
r.super_visit_with(self) 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); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
flags.intersects(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. /// Collects all the late-bound regions it finds into a hash set.

View file

@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
})) }))
}, },
TyArray(ty, len) => { 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() DefIdForest::empty()
} else { } else {
ty.uninhabited_from(visited, tcx) ty.uninhabited_from(visited, tcx)

View file

@ -837,12 +837,22 @@ impl<'a, 'tcx> Struct {
// Is this a fixed-size array of something non-zero // Is this a fixed-size array of something non-zero
// with at least one element? // with at least one element?
(_, &ty::TyArray(ety, d)) if d.val.to_const_int().unwrap().to_u64().unwrap() != 0 => { (_, &ty::TyArray(ety, mut count)) => {
Struct::non_zero_field_paths( if count.has_projections() {
tcx, count = tcx.normalize_associated_type_in_env(&count, param_env);
param_env, if count.has_projections() {
Some(ety).into_iter(), return Err(LayoutError::Unknown(ty));
None) }
}
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(..)) => { (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
@ -1174,7 +1184,14 @@ impl<'a, 'tcx> Layout {
} }
// Arrays and slices. // 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 = element.layout(tcx, param_env)?;
let element_size = element.size(dl); let element_size = element.size(dl);
let count = count.val.to_const_int().unwrap().to_u64().unwrap(); let count = count.val.to_const_int().unwrap().to_u64().unwrap();

View file

@ -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 { fn map_crate(&self) -> CrateNum {
LOCAL_CRATE 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 { trait Value<'tcx>: Sized {
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
} }

View file

@ -846,6 +846,9 @@ pub enum Predicate<'tcx> {
/// `T1 <: T2` /// `T1 <: T2`
Subtype(PolySubtypePredicate<'tcx>), Subtype(PolySubtypePredicate<'tcx>),
/// Constant initializer must evaluate successfully.
ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
} }
impl<'a, 'gcx, 'tcx> Predicate<'tcx> { impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
@ -938,6 +941,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
Predicate::ObjectSafe(trait_def_id), Predicate::ObjectSafe(trait_def_id),
Predicate::ClosureKind(closure_def_id, kind) => Predicate::ClosureKind(closure_def_id, kind) =>
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) => { ty::Predicate::ClosureKind(_closure_def_id, _kind) => {
vec![] vec![]
} }
ty::Predicate::ConstEvaluatable(_, substs) => {
substs.types().collect()
}
}; };
// The only reason to collect into a vector here is that I was // The only reason to collect into a vector here is that I was
@ -1142,7 +1150,8 @@ impl<'tcx> Predicate<'tcx> {
Predicate::WellFormed(..) | Predicate::WellFormed(..) |
Predicate::ObjectSafe(..) | Predicate::ObjectSafe(..) |
Predicate::ClosureKind(..) | Predicate::ClosureKind(..) |
Predicate::TypeOutlives(..) => { Predicate::TypeOutlives(..) |
Predicate::ConstEvaluatable(..) => {
None None
} }
} }

View file

@ -14,9 +14,12 @@
//! type equality, etc. //! type equality, etc.
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::ConstVal;
use traits::Reveal;
use ty::subst::{Kind, Substs}; use ty::subst::{Kind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError}; use ty::error::{ExpectedFound, TypeError};
use util::common::ErrorReported;
use std::rc::Rc; use std::rc::Rc;
use std::iter; use std::iter;
use syntax::abi; 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)?; let t = relation.relate(&a_t, &b_t)?;
assert_eq!(sz_a.ty, tcx.types.usize); assert_eq!(sz_a.ty, tcx.types.usize);
assert_eq!(sz_b.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 to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
let sz_b_u64 = sz_b.val.to_const_int().unwrap().to_u64().unwrap(); match x.val {
if sz_a_u64 == sz_b_u64 { ConstVal::Integral(x) => Ok(x.to_u64().unwrap()),
Ok(tcx.mk_ty(ty::TyArray(t, sz_a))) ConstVal::Unevaluated(def_id, substs) => {
} else { // FIXME(eddyb) get the right param_env.
Err(TypeError::FixedArraySize(expected_found(relation, &sz_a_u64, &sz_b_u64))) 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)
}
} }
} }

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use infer::type_variable; 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::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::accumulate_vec::AccumulateVec;
@ -59,6 +59,13 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
} }
} }
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
type Lifted = Box<T::Lifted>;
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&**self).map(Box::new)
}
}
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
type Lifted = Vec<T::Lifted>; type Lifted = Vec<T::Lifted>;
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> { fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@ -210,6 +217,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
ty::Predicate::ObjectSafe(trait_def_id) => { ty::Predicate::ObjectSafe(trait_def_id) => {
Some(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<T> {
} }
} }
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::Lifted> {
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<Self::Lifted> {
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> { impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
type Lifted = ty::ClosureSubsts<'tcx>; type Lifted = ty::ClosureSubsts<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@ -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<Self::Lifted> {
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<Self::Lifted> {
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<Self::Lifted> {
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. // TypeFoldable implementations.
// //
@ -409,6 +505,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
macro_rules! CopyImpls { macro_rules! CopyImpls {
($($ty:ty),+) => { ($($ty:ty),+) => {
$( $(
impl<'tcx> Lift<'tcx> for $ty {
type Lifted = Self;
fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self> {
Some(*self)
}
}
impl<'tcx> TypeFoldable<'tcx> for $ty { impl<'tcx> TypeFoldable<'tcx> for $ty {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty {
*self *self
@ -866,6 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
ty::Predicate::ClosureKind(closure_def_id, kind), ty::Predicate::ClosureKind(closure_def_id, kind),
ty::Predicate::ObjectSafe(trait_def_id) => ty::Predicate::ObjectSafe(trait_def_id) =>
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::WellFormed(data) => data.visit_with(visitor),
ty::Predicate::ClosureKind(_closure_def_id, _kind) => false, ty::Predicate::ClosureKind(_closure_def_id, _kind) => false,
ty::Predicate::ObjectSafe(_trait_def_id) => 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); let v = v.fold_with(folder);
ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) 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, _)) => { ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
v.visit_with(visitor) 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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor) || self.val.visit_with(visitor) self.ty.visit_with(visitor) || self.val.visit_with(visitor)
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
visitor.visit_const(self)
}
} }

View file

@ -13,6 +13,7 @@
use hir::def_id::{DefId, LOCAL_CRATE}; use hir::def_id::{DefId, LOCAL_CRATE};
use hir::map::DefPathData; use hir::map::DefPathData;
use ich::{StableHashingContext, NodeIdHashingMode}; use ich::{StableHashingContext, NodeIdHashingMode};
use middle::const_val::ConstVal;
use traits::{self, Reveal}; use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeVisitor; use ty::fold::TypeVisitor;
@ -388,7 +389,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::WellFormed(..) | ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) | ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::RegionOutlives(..) => { ty::Predicate::RegionOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => {
None None
} }
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { 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), TyUint(u) => self.hash(u),
TyFloat(f) => self.hash(f), TyFloat(f) => self.hash(f),
TyArray(_, n) => { 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) | TyRawPtr(m) |
TyRef(_, m) => self.hash(m.mutbl), TyRef(_, m) => self.hash(m.mutbl),

View file

@ -160,6 +160,9 @@ fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
push_const(stack, v); push_const(stack, v);
} }
ConstVal::Unevaluated(_, substs) => {
stack.extend(substs.types().rev());
}
} }
stack.push(constant.ty); stack.push(constant.ty);
} }

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::const_val::{ConstVal, ConstAggregate};
use infer::InferCtxt; use infer::InferCtxt;
use ty::subst::Substs; use ty::subst::Substs;
use traits; 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().a); // (*)
wf.compute(data.skip_binder().b); // (*) 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() 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 /// Pushes the obligations required for a constant value to be WF
/// into `self.out`. /// 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>) { fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
if !subty.has_escaping_regions() { if !subty.has_escaping_regions() {

View file

@ -430,6 +430,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
ty::Predicate::ClosureKind(closure_def_id, kind) => { ty::Predicate::ClosureKind(closure_def_id, kind) => {
write!(f, "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)) => { ConstVal::Integral(ConstInt::Usize(sz)) => {
write!(f, "{}", sz)?; write!(f, "{}", sz)?;
} }
ConstVal::Unevaluated(_def_id, substs) => {
write!(f, "<unevaluated{:?}>", &substs[..])?;
}
_ => { _ => {
write!(f, "{:?}", sz)?; write!(f, "{:?}", sz)?;
} }
@ -1048,6 +1054,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
write!(f, "the closure `{}` implements the trait `{}`", write!(f, "the closure `{}` implements the trait `{}`",
tcx.item_path_str(closure_def_id), kind) 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")
}
} }
} }
} }

View file

@ -415,14 +415,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
})) }))
}).collect() }).collect()
} }
ty::TySlice(ref sub_ty) => { ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
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) => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap(); let len = len.val.to_const_int().unwrap().to_u64().unwrap();
if len != 0 && cx.is_uninhabited(sub_ty) { if len != 0 && cx.is_uninhabited(sub_ty) {
vec![] vec![]
@ -430,6 +423,15 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
vec![Slice(len)] 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 => { ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
def.variants.iter() def.variants.iter()
.filter(|v| !cx.is_variant_uninhabited(v, substs)) .filter(|v| !cx.is_variant_uninhabited(v, substs))

View file

@ -334,7 +334,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
let layout_of = |ty: Ty<'tcx>| { 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) } ConstEvalErr { span: e.span, kind: LayoutError(err) }
}) })
}; };

View file

@ -117,7 +117,8 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
ConstVal::Char(c) => write!(f, "{:?}", c), ConstVal::Char(c) => write!(f, "{:?}", c),
ConstVal::Variant(_) | ConstVal::Variant(_) |
ConstVal::Function(..) | ConstVal::Function(..) |
ConstVal::Aggregate(_) => bug!("{:?} not printable in a pattern", value) ConstVal::Aggregate(_) |
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
} }
} }

View file

@ -1521,9 +1521,16 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
} }
fn encode_info_for_ty(&mut self, ty: &hir::Ty) { fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
if let hir::TyImplTrait(_) = ty.node { match ty.node {
let def_id = self.tcx.hir.local_def_id(ty.id); hir::TyImplTrait(_) => {
self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); 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);
}
_ => {}
} }
} }

View file

@ -103,7 +103,8 @@ impl<'tcx> Const<'tcx> {
ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64), ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
ConstVal::Variant(_) | ConstVal::Variant(_) |
ConstVal::Aggregate(..) => { ConstVal::Aggregate(..) |
ConstVal::Unevaluated(..) => {
bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
} }
}; };

View file

@ -12,7 +12,7 @@
//! representation. The main routine here is `ast_ty_to_ty()`: each use //! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`. //! 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 rustc_data_structures::accumulate_vec::AccumulateVec;
use hir; use hir;
use hir::def::Def; 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 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
} }
hir::TyArray(ref ty, length) => { hir::TyArray(ref ty, length) => {
if let Ok(length) = eval_length(tcx, length, "array length") { let length_def_id = tcx.hir.body_owner_def_id(length);
tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)) let substs = Substs::identity_for_item(tcx, length_def_id);
} else { let length = tcx.mk_const(ty::Const {
self.tcx().types.err 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) => { hir::TyTypeof(ref _e) => {
struct_span_err!(tcx.sess, ast_ty.span, E0516, struct_span_err!(tcx.sess, ast_ty.span, E0516,

View file

@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::TypeOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None,
ty::Predicate::WellFormed(..) => None, ty::Predicate::WellFormed(..) => None,
ty::Predicate::ObjectSafe(..) => None, ty::Predicate::ObjectSafe(..) => None,
ty::Predicate::ConstEvaluatable(..) => None,
// NB: This predicate is created by breaking down a // NB: This predicate is created by breaking down a
// `ClosureType: FnFoo()` predicate, where // `ClosureType: FnFoo()` predicate, where

View file

@ -590,7 +590,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
ty::Predicate::WellFormed(..) | ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) | ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => None, ty::Predicate::TypeOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => None,
} }
}) })
.collect(); .collect();

View file

@ -128,7 +128,6 @@ use rustc::hir::map::Node;
use rustc::hir::{self, PatKind}; use rustc::hir::{self, PatKind};
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc_back::slice; use rustc_back::slice;
use rustc::middle::const_val::eval_length;
use rustc_const_math::ConstInt; use rustc_const_math::ConstInt;
mod autoderef; mod autoderef;
@ -3898,7 +3897,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
tcx.mk_array(element_ty, args.len() as u64) tcx.mk_array(element_ty, args.len() as u64)
} }
hir::ExprRepeat(ref element, count) => { 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 { let uty = match expected {
ExpectHasType(uty) => { ExpectHasType(uty) => {

View file

@ -511,7 +511,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::Subtype(..) | ty::Predicate::Subtype(..) |
ty::Predicate::Projection(..) | ty::Predicate::Projection(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::ObjectSafe(..) => ty::Predicate::ObjectSafe(..) |
ty::Predicate::ConstEvaluatable(..) =>
vec![], vec![],
ty::Predicate::WellFormed(subty) => { ty::Predicate::WellFormed(subty) => {

View file

@ -33,6 +33,7 @@ use rustc::middle::resolve_lifetime as rl;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::traits::Reveal;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind}; use rustc::ty::{self, AdtKind};
use rustc::middle::stability; use rustc::middle::stability;
@ -936,6 +937,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
Predicate::WellFormed(_) => panic!("not user writable"), Predicate::WellFormed(_) => panic!("not user writable"),
Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"),
Predicate::ClosureKind(..) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"),
Predicate::ConstEvaluatable(..) => panic!("not user writable"),
} }
} }
} }
@ -1784,9 +1786,11 @@ impl Clean<Type> for hir::Ty {
type_: box m.ty.clean(cx)} type_: box m.ty.clean(cx)}
} }
TySlice(ref ty) => Slice(box ty.clean(cx)), TySlice(ref ty) => Slice(box ty.clean(cx)),
TyArray(ref ty, length) => { TyArray(ref ty, n) => {
use rustc::middle::const_val::eval_length; let def_id = cx.tcx.hir.body_owner_def_id(n);
let n = eval_length(cx.tcx, length, "array length").unwrap(); 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 { let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
n.to_string() n.to_string()
} else { } else {

View file

@ -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 <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.
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() {}

View file

@ -14,8 +14,4 @@ enum Foo {
//~^^ ERROR: blocks in constants are limited to items and tail expressions //~^^ 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() {} pub fn main() {}

View file

@ -23,5 +23,5 @@ const fn f(x: usize) -> usize {
#[allow(unused_variables)] #[allow(unused_variables)]
fn main() { fn main() {
let a : [i32; f(X)]; //~ NOTE for array length here let a : [i32; f(X)]; //~ NOTE for constant expression here
} }

View file

@ -20,5 +20,5 @@ const LEN: usize = ONE - TWO;
fn main() { fn main() {
let a: [i8; LEN] = unimplemented!(); let a: [i8; LEN] = unimplemented!();
//~^ NOTE for array length here //~^ NOTE for constant expression here
} }

View file

@ -8,11 +8,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern: unsupported cyclic reference between types/traits detected
#![feature(const_fn)] #![feature(const_fn)]
struct Foo { struct Foo {
bytes: [u8; std::mem::size_of::<Foo>()] bytes: [u8; std::mem::size_of::<Foo>()]
//~^ ERROR unsupported cyclic reference between types/traits detected
} }
fn main() {} fn main() {}

View file

@ -15,7 +15,4 @@ enum Delicious {
//~^ ERROR no associated item named `PIE` found for type `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() {} fn main() {}

View file

@ -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 <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 FOO: [u32; u8::MIN as usize] = [];
//~^ ERROR no associated item named `MIN` found for type `u8`
fn main() {}

View file

@ -21,8 +21,9 @@ impl Dim for Dim3 {
} }
pub struct Vector<T, D: Dim> { pub struct Vector<T, D: Dim> {
entries: [T; D::dim()] entries: [T; D::dim()],
//~^ ERROR no function or associated item named `dim` found for type `D` in the current scope //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope
_dummy: D,
} }
fn main() {} fn main() {}

View file

@ -4,7 +4,7 @@ error[E0080]: constant evaluation error
11 | pub const FOO: usize = *&0; 11 | pub const FOO: usize = *&0;
| ^^^ unimplemented constant expression: deref operation | ^^^ unimplemented constant expression: deref operation
| |
note: for repeat count here note: for constant expression here
--> $DIR/issue_38875.rs:16:22 --> $DIR/issue_38875.rs:16:22
| |
16 | let test_x = [0; issue_38875_b::FOO]; 16 | let test_x = [0; issue_38875_b::FOO];