Skip to content

Commit 74349fa

Browse files
committed
rustc: evaluate fixed-length array length expressions lazily.
1 parent 8821761 commit 74349fa

Some content is hidden

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

48 files changed

+517
-122
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Pr
235235
def_id.hash_stable(hcx, hasher);
236236
closure_kind.hash_stable(hcx, hasher);
237237
}
238+
ty::Predicate::ConstEvaluatable(def_id, substs) => {
239+
def_id.hash_stable(hcx, hasher);
240+
substs.hash_stable(hcx, hasher);
241+
}
238242
}
239243
}
240244
}
@@ -317,6 +321,10 @@ for ::middle::const_val::ConstVal<'gcx> {
317321
value.hash_stable(hcx, hasher);
318322
times.hash_stable(hcx, hasher);
319323
}
324+
Unevaluated(def_id, substs) => {
325+
def_id.hash_stable(hcx, hasher);
326+
substs.hash_stable(hcx, hasher);
327+
}
320328
}
321329
}
322330
}

src/librustc/infer/mod.rs

Lines changed: 3 additions & 2 deletions
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

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@
1010

1111
pub use rustc_const_math::ConstInt;
1212

13-
use hir;
14-
use hir::def::Def;
1513
use hir::def_id::DefId;
16-
use traits::Reveal;
1714
use ty::{self, TyCtxt, layout};
1815
use ty::subst::Substs;
19-
use util::common::ErrorReported;
2016
use rustc_const_math::*;
2117

2218
use graphviz::IntoCow;
@@ -41,6 +37,7 @@ pub enum ConstVal<'tcx> {
4137
Variant(DefId),
4238
Function(DefId, &'tcx Substs<'tcx>),
4339
Aggregate(ConstAggregate<'tcx>),
40+
Unevaluated(DefId, &'tcx Substs<'tcx>),
4441
}
4542

4643
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
@@ -221,37 +218,3 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
221218
self.struct_error(tcx, primary_span, primary_kind).emit();
222219
}
223220
}
224-
225-
/// Returns the value of the length-valued expression
226-
pub fn eval_length<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
227-
count: hir::BodyId,
228-
reason: &str)
229-
-> Result<&'gcx ty::Const<'gcx>, ErrorReported>
230-
{
231-
let count_expr = &tcx.hir.body(count).value;
232-
let count_def_id = tcx.hir.body_owner_def_id(count);
233-
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
234-
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
235-
match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
236-
Ok(count) => {
237-
// Elsewhere in the compiler this is enforced even in the presence
238-
// of erroneous code (type mismatch error has already been emitted).
239-
assert_eq!(count.ty, tcx.types.usize);
240-
Ok(count)
241-
}
242-
Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
243-
Err(err) => {
244-
let mut diag = err.struct_error(tcx, count_expr.span, reason);
245-
246-
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
247-
if let Def::Local(..) = path.def {
248-
diag.note(&format!("`{}` is a variable",
249-
tcx.hir.node_to_pretty_string(count_expr.id)));
250-
}
251-
}
252-
253-
diag.emit();
254-
Err(ErrorReported)
255-
}
256-
}
257-
}

src/librustc/middle/free_region.rs

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
876876

877877
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
878878
let promotable = match expr_ty.sty {
879-
ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true,
879+
ty::TyArray(_, len) if
880+
len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
880881
_ => promotable,
881882
};
882883

src/librustc/mir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
15351535
Variant(def_id) |
15361536
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
15371537
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
1538+
Unevaluated(..) => write!(fmt, "{:?}", const_val)
15381539
}
15391540
}
15401541

src/librustc/traits/error_reporting.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use super::{
1919
OnUnimplementedNote,
2020
OutputTypeParameterMismatch,
2121
TraitNotObjectSafe,
22+
ConstEvalFailure,
2223
PredicateObligation,
2324
Reveal,
2425
SelectionContext,
@@ -31,6 +32,7 @@ use hir;
3132
use hir::def_id::DefId;
3233
use infer::{self, InferCtxt};
3334
use infer::type_variable::TypeVariableOrigin;
35+
use middle::const_val;
3436
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
3537
use std::fmt;
3638
use syntax::ast;
@@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
698700
// (which may fail).
699701
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
700702
}
703+
704+
ty::Predicate::ConstEvaluatable(..) => {
705+
// Errors for `ConstEvaluatable` predicates show up as
706+
// `SelectionError::ConstEvalFailure`,
707+
// not `Unimplemented`.
708+
span_bug!(span,
709+
"const-evaluatable requirement gave wrong error: `{:?}`", obligation)
710+
}
701711
}
702712
}
703713

@@ -762,6 +772,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
762772
self.tcx.report_object_safety_error(span, did,
763773
violations)
764774
}
775+
776+
ConstEvalFailure(ref err) => {
777+
if let const_val::ErrKind::TypeckError = err.kind {
778+
return;
779+
}
780+
err.struct_error(self.tcx, span, "constant expression")
781+
}
765782
};
766783
self.note_obligation_cause(&mut err, obligation);
767784
err.emit();

src/librustc/traits/fulfill.rs

Lines changed: 24 additions & 1 deletion
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

Lines changed: 2 additions & 0 deletions
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;
2122
use middle::free_region::FreeRegionMap;
2223
use ty::subst::Substs;
@@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> {
218219
ty::PolyTraitRef<'tcx>,
219220
ty::error::TypeError<'tcx>),
220221
TraitNotObjectSafe(DefId),
222+
ConstEvalFailure(ConstEvalErr<'tcx>),
221223
}
222224

223225
pub struct FulfillmentError<'tcx> {

src/librustc/traits/object_safety.rs

Lines changed: 4 additions & 2 deletions
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
}

0 commit comments

Comments
 (0)