Skip to content

Commit

Permalink
rustc: evaluate fixed-length array length expressions lazily.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Sep 2, 2017
1 parent 99f0df0 commit acd89e7
Showing 44 changed files with 486 additions and 76 deletions.
8 changes: 8 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
@@ -234,6 +234,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);
}
}
}
}
@@ -316,6 +320,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);
}
}
}
}
5 changes: 3 additions & 2 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
}

1 change: 1 addition & 0 deletions src/librustc/middle/const_val.rs
Original file line number Diff line number Diff line change
@@ -41,6 +41,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)]
3 changes: 2 additions & 1 deletion src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
@@ -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))) => {
3 changes: 2 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
@@ -879,7 +879,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,
};

1 change: 1 addition & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -1539,6 +1539,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)
}
}

17 changes: 17 additions & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ use super::{
ObligationCauseCode,
OutputTypeParameterMismatch,
TraitNotObjectSafe,
ConstEvalFailure,
PredicateObligation,
Reveal,
SelectionContext,
@@ -30,6 +31,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;
@@ -712,6 +714,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)
}
}
}

@@ -776,6 +786,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 changes: 24 additions & 1 deletion src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -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)))
}
}
}
}
}
}
}
}

2 changes: 2 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;

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

pub struct FulfillmentError<'tcx> {
6 changes: 4 additions & 2 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
40 changes: 37 additions & 3 deletions src/librustc/traits/project.rs
Original file line number Diff line number Diff line change
@@ -27,10 +27,11 @@ use super::util;
use hir::def_id::DefId;
use infer::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)]
@@ -504,7 +538,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,
15 changes: 15 additions & 0 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -687,6 +687,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
}
}
}
}
}

3 changes: 3 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
}
4 changes: 2 additions & 2 deletions src/librustc/traits/trans/mod.rs
Original file line number Diff line number Diff line change
@@ -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, || {
7 changes: 7 additions & 0 deletions src/librustc/traits/util.rs
Original file line number Diff line number Diff line change
@@ -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`.
12 changes: 0 additions & 12 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1176,18 +1176,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>> {
4 changes: 4 additions & 0 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}

Loading

0 comments on commit acd89e7

Please sign in to comment.