rustc: evaluate fixed-length array length expressions lazily.
This commit is contained in:
parent
88217618ec
commit
74349fa288
@ -235,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))) => {
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -1535,6 +1535,7 @@ fn fmt_const_val<W: Write>(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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<T:TypeFoldable<'tcx>>(&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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
|
||||
}
|
||||
|
||||
fn fold<T:TypeFoldable<'gcx>>(&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, || {
|
||||
|
@ -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`.
|
||||
|
@ -1190,18 +1190,6 @@ pub trait Lift<'tcx> {
|
||||
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> {
|
||||
type Lifted = Ty<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<u64, ErrorReported> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<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] {
|
||||
type Lifted = Vec<T::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) => {
|
||||
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> {
|
||||
type Lifted = ty::ClosureSubsts<'tcx>;
|
||||
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.
|
||||
//
|
||||
@ -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<Self> {
|
||||
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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, "<unevaluated{:?}>", &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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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) }
|
||||
})
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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) => {
|
||||
|
@ -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) => {
|
||||
|
@ -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<WherePredicate> 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<Type> 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 {
|
||||
|
15
src/test/compile-fail/const-block-non-item-statement-3.rs
Normal file
15
src/test/compile-fail/const-block-non-item-statement-3.rs
Normal 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() {}
|
@ -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() {}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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::<Foo>()]
|
||||
//~^ ERROR unsupported cyclic reference between types/traits detected
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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() {}
|
||||
|
14
src/test/compile-fail/issue-22933-3.rs
Normal file
14
src/test/compile-fail/issue-22933-3.rs
Normal 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() {}
|
@ -21,8 +21,9 @@ impl Dim for Dim3 {
|
||||
}
|
||||
|
||||
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
|
||||
_dummy: D,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user