Skip to content

Commit acd89e7

Browse files
committed
rustc: evaluate fixed-length array length expressions lazily.
1 parent 99f0df0 commit acd89e7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+486
-76
lines changed

src/librustc/ich/impls_ty.rs

+8
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Pr
234234
def_id.hash_stable(hcx, hasher);
235235
closure_kind.hash_stable(hcx, hasher);
236236
}
237+
ty::Predicate::ConstEvaluatable(def_id, substs) => {
238+
def_id.hash_stable(hcx, hasher);
239+
substs.hash_stable(hcx, hasher);
240+
}
237241
}
238242
}
239243
}
@@ -316,6 +320,10 @@ for ::middle::const_val::ConstVal<'gcx> {
316320
value.hash_stable(hcx, hasher);
317321
times.hash_stable(hcx, hasher);
318322
}
323+
Unevaluated(def_id, substs) => {
324+
def_id.hash_stable(hcx, hasher);
325+
substs.hash_stable(hcx, hasher);
326+
}
319327
}
320328
}
321329
}

src/librustc/infer/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize {
442442

443443
impl_trans_normalize!('gcx,
444444
Ty<'gcx>,
445+
&'gcx ty::Const<'gcx>,
445446
&'gcx Substs<'gcx>,
446447
ty::FnSig<'gcx>,
447448
ty::PolyFnSig<'gcx>,
@@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
493494
let param_env = ty::ParamEnv::empty(Reveal::All);
494495
let value = self.erase_regions(value);
495496

496-
if !value.has_projection_types() {
497+
if !value.has_projections() {
497498
return value;
498499
}
499500

@@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
515516

516517
let value = self.erase_regions(value);
517518

518-
if !value.has_projection_types() {
519+
if !value.has_projections() {
519520
return value;
520521
}
521522

src/librustc/middle/const_val.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub enum ConstVal<'tcx> {
4141
Variant(DefId),
4242
Function(DefId, &'tcx Substs<'tcx>),
4343
Aggregate(ConstAggregate<'tcx>),
44+
Unevaluated(DefId, &'tcx Substs<'tcx>),
4445
}
4546

4647
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]

src/librustc/middle/free_region.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
147147
ty::Predicate::WellFormed(..) |
148148
ty::Predicate::ObjectSafe(..) |
149149
ty::Predicate::ClosureKind(..) |
150-
ty::Predicate::TypeOutlives(..) => {
150+
ty::Predicate::TypeOutlives(..) |
151+
ty::Predicate::ConstEvaluatable(..) => {
151152
// No region bounds here
152153
}
153154
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {

src/librustc/middle/mem_categorization.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
879879

880880
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
881881
let promotable = match expr_ty.sty {
882-
ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true,
882+
ty::TyArray(_, len) if
883+
len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
883884
_ => promotable,
884885
};
885886

src/librustc/mir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
15391539
Variant(def_id) |
15401540
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
15411541
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
1542+
Unevaluated(..) => write!(fmt, "{:?}", const_val)
15421543
}
15431544
}
15441545

src/librustc/traits/error_reporting.rs

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::{
1717
ObligationCauseCode,
1818
OutputTypeParameterMismatch,
1919
TraitNotObjectSafe,
20+
ConstEvalFailure,
2021
PredicateObligation,
2122
Reveal,
2223
SelectionContext,
@@ -30,6 +31,7 @@ use hir;
3031
use hir::def_id::DefId;
3132
use infer::{self, InferCtxt};
3233
use infer::type_variable::TypeVariableOrigin;
34+
use middle::const_val;
3335
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
3436
use std::fmt;
3537
use syntax::ast;
@@ -712,6 +714,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
712714
// (which may fail).
713715
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
714716
}
717+
718+
ty::Predicate::ConstEvaluatable(..) => {
719+
// Errors for `ConstEvaluatable` predicates show up as
720+
// `SelectionError::ConstEvalFailure`,
721+
// not `Unimplemented`.
722+
span_bug!(span,
723+
"const-evaluatable requirement gave wrong error: `{:?}`", obligation)
724+
}
715725
}
716726
}
717727

@@ -776,6 +786,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
776786
self.tcx.report_object_safety_error(span, did,
777787
violations)
778788
}
789+
790+
ConstEvalFailure(ref err) => {
791+
if let const_val::ErrKind::TypeckError = err.kind {
792+
return;
793+
}
794+
err.struct_error(self.tcx, span, "constant expression")
795+
}
779796
};
780797
self.note_obligation_cause(&mut err, obligation);
781798
err.emit();

src/librustc/traits/fulfill.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode};
2525
use super::{ObligationCause, PredicateObligation, Obligation};
2626
use super::project;
2727
use super::select::SelectionContext;
28-
use super::Unimplemented;
28+
use super::{Unimplemented, ConstEvalFailure};
2929

3030
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
3131
type Predicate = ty::Predicate<'tcx>;
@@ -540,6 +540,29 @@ fn process_predicate<'a, 'gcx, 'tcx>(
540540
}
541541
}
542542
}
543+
544+
ty::Predicate::ConstEvaluatable(def_id, substs) => {
545+
match selcx.tcx().lift_to_global(&obligation.param_env) {
546+
None => {
547+
Ok(None)
548+
}
549+
Some(param_env) => {
550+
match selcx.tcx().lift_to_global(&substs) {
551+
None => {
552+
pending_obligation.stalled_on = substs.types().collect();
553+
Ok(None)
554+
}
555+
Some(substs) => {
556+
match selcx.tcx().at(obligation.cause.span)
557+
.const_eval(param_env.and((def_id, substs))) {
558+
Ok(_) => Ok(Some(vec![])),
559+
Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
560+
}
561+
}
562+
}
563+
}
564+
}
565+
}
543566
}
544567
}
545568

src/librustc/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;
1717

1818
use hir;
1919
use hir::def_id::DefId;
20+
use middle::const_val::ConstEvalErr;
2021
use middle::region::RegionMaps;
2122
use middle::free_region::FreeRegionMap;
2223
use ty::subst::Substs;
@@ -217,6 +218,7 @@ pub enum SelectionError<'tcx> {
217218
ty::PolyTraitRef<'tcx>,
218219
ty::error::TypeError<'tcx>),
219220
TraitNotObjectSafe(DefId),
221+
ConstEvalFailure(ConstEvalErr<'tcx>),
220222
}
221223

222224
pub struct FulfillmentError<'tcx> {

src/librustc/traits/object_safety.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
169169
ty::Predicate::RegionOutlives(..) |
170170
ty::Predicate::ClosureKind(..) |
171171
ty::Predicate::Subtype(..) |
172-
ty::Predicate::Equate(..) => {
172+
ty::Predicate::Equate(..) |
173+
ty::Predicate::ConstEvaluatable(..) => {
173174
false
174175
}
175176
}
@@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
203204
ty::Predicate::WellFormed(..) |
204205
ty::Predicate::ObjectSafe(..) |
205206
ty::Predicate::ClosureKind(..) |
206-
ty::Predicate::TypeOutlives(..) => {
207+
ty::Predicate::TypeOutlives(..) |
208+
ty::Predicate::ConstEvaluatable(..) => {
207209
false
208210
}
209211
}

src/librustc/traits/project.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ use super::util;
2727
use hir::def_id::DefId;
2828
use infer::InferOk;
2929
use infer::type_variable::TypeVariableOrigin;
30+
use middle::const_val::ConstVal;
3031
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
3132
use syntax::ast;
3233
use syntax::symbol::Symbol;
33-
use ty::subst::Subst;
34+
use ty::subst::{Subst, Substs};
3435
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
3536
use ty::fold::{TypeFoldable, TypeFolder};
3637
use util::common::FN_OUTPUT_NAME;
@@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
260261
fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
261262
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
262263

263-
if !value.has_projection_types() {
264+
if !value.has_projections() {
264265
value.clone()
265266
} else {
266267
value.fold_with(self)
@@ -332,6 +333,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
332333
}
333334
}
334335
}
336+
337+
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
338+
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
339+
if substs.needs_infer() {
340+
let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
341+
let data = self.param_env.and((def_id, identity_substs));
342+
match self.tcx().lift_to_global(&data) {
343+
Some(data) => {
344+
match self.tcx().const_eval(data) {
345+
Ok(evaluated) => {
346+
let evaluated = evaluated.subst(self.tcx(), substs);
347+
return self.fold_const(evaluated);
348+
}
349+
Err(_) => {}
350+
}
351+
}
352+
None => {}
353+
}
354+
} else {
355+
let data = self.param_env.and((def_id, substs));
356+
match self.tcx().lift_to_global(&data) {
357+
Some(data) => {
358+
match self.tcx().const_eval(data) {
359+
Ok(evaluated) => return self.fold_const(evaluated),
360+
Err(_) => {}
361+
}
362+
}
363+
None => {}
364+
}
365+
}
366+
}
367+
constant
368+
}
335369
}
336370

337371
#[derive(Clone)]
@@ -504,7 +538,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
504538
depth,
505539
obligations);
506540

507-
let result = if projected_ty.has_projection_types() {
541+
let result = if projected_ty.has_projections() {
508542
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
509543
param_env,
510544
cause,

src/librustc/traits/select.rs

+15
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
687687
}
688688
}
689689
}
690+
691+
ty::Predicate::ConstEvaluatable(def_id, substs) => {
692+
match self.tcx().lift_to_global(&(obligation.param_env, substs)) {
693+
Some((param_env, substs)) => {
694+
match self.tcx().const_eval(param_env.and((def_id, substs))) {
695+
Ok(_) => EvaluatedToOk,
696+
Err(_) => EvaluatedToErr
697+
}
698+
}
699+
None => {
700+
// Inference variables still left in param_env or substs.
701+
EvaluatedToAmbig
702+
}
703+
}
704+
}
690705
}
691706
}
692707

src/librustc/traits/structural_impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
173173
super::TraitNotObjectSafe(def_id) => {
174174
Some(super::TraitNotObjectSafe(def_id))
175175
}
176+
super::ConstEvalFailure(ref err) => {
177+
tcx.lift(err).map(super::ConstEvalFailure)
178+
}
176179
}
177180
}
178181
}

src/librustc/traits/trans/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
120120
}
121121

122122
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
123-
if !value.has_projection_types() {
123+
if !value.has_projections() {
124124
value.clone()
125125
} else {
126126
value.fold_with(self)
@@ -134,7 +134,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
134134
}
135135

136136
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
137-
if !ty.has_projection_types() {
137+
if !ty.has_projections() {
138138
ty
139139
} else {
140140
self.tcx.trans_trait_caches.project_cache.memoize(ty, || {

src/librustc/traits/util.rs

+7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
4848

4949
ty::Predicate::Subtype(ref data) =>
5050
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)),
51+
52+
ty::Predicate::ConstEvaluatable(def_id, substs) =>
53+
ty::Predicate::ConstEvaluatable(def_id, substs),
5154
}
5255
}
5356

@@ -175,6 +178,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
175178
ty::Predicate::ClosureKind(..) => {
176179
// Nothing to elaborate when waiting for a closure's kind to be inferred.
177180
}
181+
ty::Predicate::ConstEvaluatable(..) => {
182+
// Currently, we do not elaborate const-evaluatable
183+
// predicates.
184+
}
178185

179186
ty::Predicate::RegionOutlives(..) => {
180187
// Nothing to elaborate from `'a: 'b`.

src/librustc/ty/context.rs

-12
Original file line numberDiff line numberDiff line change
@@ -1176,18 +1176,6 @@ pub trait Lift<'tcx> {
11761176
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
11771177
}
11781178

1179-
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
1180-
type Lifted = ty::ParamEnv<'tcx>;
1181-
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::ParamEnv<'tcx>> {
1182-
self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| {
1183-
Some(ty::ParamEnv {
1184-
reveal: self.reveal,
1185-
caller_bounds,
1186-
})
1187-
})
1188-
}
1189-
}
1190-
11911179
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
11921180
type Lifted = Ty<'tcx>;
11931181
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {

src/librustc/ty/flags.rs

+4
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ impl FlagComputation {
235235
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
236236
self.add_const(v);
237237
}
238+
ConstVal::Unevaluated(_, substs) => {
239+
self.add_flags(TypeFlags::HAS_PROJECTION);
240+
self.add_substs(substs);
241+
}
238242
}
239243
}
240244

0 commit comments

Comments
 (0)