Skip to content

Commit

Permalink
rustc_const_eval: keep track of the appropriate ParamEnv.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Jul 27, 2017
1 parent 4c900c5 commit 60cf542
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 64 deletions.
6 changes: 4 additions & 2 deletions src/librustc/middle/const_val.rs
Expand Up @@ -14,7 +14,8 @@ pub use rustc_const_math::ConstInt;
use hir;
use hir::def::Def;
use hir::def_id::DefId;
use ty::{TyCtxt, layout};
use traits::Reveal;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
use util::common::ErrorReported;
use rustc_const_math::*;
Expand Down Expand Up @@ -229,8 +230,9 @@ pub fn eval_length(tcx: TyCtxt,
{
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((count_def_id, substs)) {
match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
Expand Down
9 changes: 5 additions & 4 deletions src/librustc/ty/maps.rs
Expand Up @@ -372,8 +372,8 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
}

impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String {
format!("const-evaluating `{}`", tcx.item_path_str(def_id))
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String {
format!("const-evaluating `{}`", tcx.item_path_str(key.value.0))
}
}

Expand Down Expand Up @@ -935,7 +935,7 @@ define_maps! { <'tcx>

/// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants).
[] const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
[] const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> const_val::EvalResult<'tcx>,

/// Performs the privacy check and computes "access levels".
Expand Down Expand Up @@ -1032,8 +1032,9 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::TypeckBodiesKrate
}

fn const_eval_dep_node<'tcx>((def_id, substs): (DefId, &'tcx Substs<'tcx>))
fn const_eval_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> DepConstructor<'tcx> {
let (def_id, substs) = key.value;
DepConstructor::ConstEval { def_id, substs }
}

Expand Down
6 changes: 4 additions & 2 deletions src/librustc/ty/mod.rs
Expand Up @@ -1582,14 +1582,15 @@ impl<'a, 'gcx, 'tcx> AdtDef {
#[inline]
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> impl Iterator<Item=ConstInt> + 'a {
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
let repr_type = self.repr.discr_type();
let initial = repr_type.initial_discriminant(tcx.global_tcx());
let mut prev_discr = None::<ConstInt>;
self.variants.iter().map(move |v| {
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
if let VariantDiscr::Explicit(expr_did) = v.discr {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval((expr_did, substs)) {
match tcx.const_eval(param_env.and((expr_did, substs))) {
Ok(ConstVal::Integral(v)) => {
discr = v;
}
Expand Down Expand Up @@ -1617,6 +1618,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
variant_index: usize)
-> ConstInt {
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
let repr_type = self.repr.discr_type();
let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
let mut explicit_index = variant_index;
Expand All @@ -1628,7 +1630,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
ty::VariantDiscr::Explicit(expr_did) => {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval((expr_did, substs)) {
match tcx.const_eval(param_env.and((expr_did, substs))) {
Ok(ConstVal::Integral(v)) => {
explicit_value = v;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/structural_impls.rs
Expand Up @@ -398,7 +398,7 @@ macro_rules! CopyImpls {
}
}

CopyImpls! { (), hir::Unsafety, abi::Abi }
CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId }

impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
Expand Down
10 changes: 6 additions & 4 deletions src/librustc_const_eval/check_match.rs
Expand Up @@ -165,8 +165,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {

let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
arm.pats.iter().map(|pat| {
let substs = self.identity_substs;
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
let mut patcx = PatternContext::new(self.tcx,
self.param_env.and(self.identity_substs),
self.tables);
let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
if !patcx.errors.is_empty() {
patcx.report_inlining_errors(pat.span);
Expand Down Expand Up @@ -233,8 +234,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
fn check_irrefutable(&self, pat: &Pat, origin: &str) {
let module = self.tcx.hir.get_module_parent(pat.id);
MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
let substs = self.identity_substs;
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
let mut patcx = PatternContext::new(self.tcx,
self.param_env.and(self.identity_substs),
self.tables);
let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty;
let pats : Matrix = vec![vec![
Expand Down
68 changes: 33 additions & 35 deletions src/librustc_const_eval/eval.rs
Expand Up @@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::{Substs, Subst};
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::DefIdMap;

Expand Down Expand Up @@ -49,24 +48,21 @@ macro_rules! math {
}
}

/// * `def_id` is the id of the constant.
/// * `substs` is the monomorphized substitutions for the expression.
///
/// `substs` is optional and is used for associated constants.
/// This generally happens in late/trans const evaluation.
/// * `DefId` is the id of the constant.
/// * `Substs` is the monomorphized substitutions for the expression.
pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> Option<(DefId, &'tcx Substs<'tcx>)> {
let (def_id, _) = key.value;
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
match tcx.hir.find(node_id) {
Some(hir_map::NodeTraitItem(_)) => {
// If we have a trait item and the substitutions for it,
// `resolve_trait_associated_const` will select an impl
// or the default.
resolve_trait_associated_const(tcx, def_id, substs)
resolve_trait_associated_const(tcx, key)
}
_ => Some((def_id, substs))
_ => Some(key.value)
}
} else {
match tcx.describe_def(def_id) {
Expand All @@ -76,31 +72,34 @@ pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if tcx.trait_of_item(def_id).is_some() {
resolve_trait_associated_const(tcx, def_id, substs)
resolve_trait_associated_const(tcx, key)
} else {
Some((def_id, substs))
Some(key.value)
}
}
_ => Some((def_id, substs))
_ => Some(key.value)
}
}
}

pub struct ConstContext<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
substs: &'tcx Substs<'tcx>,
fn_args: Option<DefIdMap<ConstVal<'tcx>>>
}

impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>) -> Self {
param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
tables: &'a ty::TypeckTables<'tcx>)
-> Self {
ConstContext {
tcx,
param_env: param_env_and_substs.param_env,
tables,
substs,
substs: param_env_and_substs.value,
fn_args: None
}
}
Expand Down Expand Up @@ -279,7 +278,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
match cx.tables.qpath_def(qpath, e.id) {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
match tcx.at(e.span).const_eval((def_id, substs)) {
match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
Ok(val) => val,
Err(ConstEvalErr { kind: TypeckError, .. }) => {
signal!(e, TypeckError);
Expand Down Expand Up @@ -323,10 +322,9 @@ 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, ty::ParamEnv::empty(traits::Reveal::All))
.map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
ty.layout(tcx, cx.param_env).map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
};
match &tcx.item_name(def_id).as_str()[..] {
"size_of" => {
Expand Down Expand Up @@ -377,7 +375,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}
debug!("const call({:?})", call_args);
let callee_cx = ConstContext {
tcx: tcx,
tcx,
param_env: cx.param_env,
tables: tcx.typeck_tables_of(def_id),
substs: substs,
fn_args: Some(call_args)
Expand Down Expand Up @@ -477,17 +476,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}

fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> Option<(DefId, &'tcx Substs<'tcx>)> {
let param_env = key.param_env;
let (def_id, substs) = key.value;
let trait_item = tcx.associated_item(def_id);
let trait_id = trait_item.container.id();
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
debug!("resolve_trait_associated_const: trait_ref={:?}",
trait_ref);

tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
param_env,
Expand All @@ -506,10 +505,8 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};

// NOTE: this code does not currently account for specialization, but when
// it does so, it should hook into the Reveal to determine when the
// constant should resolve; this will also require plumbing through to this
// function whether we are in "trans mode" to pick the right Reveal
// when constructing the inference context above.
// it does so, it should hook into the param_env.reveal to determine when the
// constant should resolve.
match selection {
traits::VtableImpl(ref impl_data) => {
let name = trait_item.name;
Expand All @@ -524,15 +521,16 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
None => {
if trait_item.defaultness.has_value() {
Some((def_id, substs))
Some(key.value)
} else {
None
}
}
}
}
traits::VtableParam(_) => None,
_ => {
bug!("resolve_trait_associated_const: unexpected vtable type")
bug!("resolve_trait_associated_const: unexpected vtable type {:?}", selection)
}
}
})
Expand Down Expand Up @@ -761,13 +759,13 @@ pub fn provide(providers: &mut Providers) {
}

fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
(def_id, substs): (DefId, &'tcx Substs<'tcx>))
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-> EvalResult<'tcx> {
let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) {
let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
resolved
} else {
return Err(ConstEvalErr {
span: tcx.def_span(def_id),
span: tcx.def_span(key.value.0),
kind: TypeckError
});
};
Expand All @@ -779,5 +777,5 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} else {
tcx.sess.cstore.item_body(tcx, def_id)
};
ConstContext::new(tcx, tables, substs).eval(&body.value)
ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value)
}
23 changes: 16 additions & 7 deletions src/librustc_const_eval/pattern.rs
Expand Up @@ -268,17 +268,18 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {

pub struct PatternContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
pub tables: &'a ty::TypeckTables<'tcx>,
pub substs: &'tcx Substs<'tcx>,
pub errors: Vec<PatternError<'tcx>>,
}

impl<'a, 'tcx> Pattern<'tcx> {
pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>,
pat: &hir::Pat) -> Self {
let mut pcx = PatternContext::new(tcx, tables, substs);
let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
Expand All @@ -290,9 +291,15 @@ impl<'a, 'tcx> Pattern<'tcx> {

impl<'a, 'tcx> PatternContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>) -> Self {
PatternContext { tcx, tables, substs, errors: vec![] }
param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
tables: &'a ty::TypeckTables<'tcx>) -> Self {
PatternContext {
tcx,
param_env: param_env_and_substs.param_env,
tables,
substs: param_env_and_substs.value,
errors: vec![]
}
}

pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
Expand Down Expand Up @@ -588,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
let kind = match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = self.tables.node_substs(id);
match eval::lookup_const_by_id(self.tcx, def_id, substs) {
match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) {
Some((def_id, substs)) => {
// Enter the inlined constant's tables&substs temporarily.
let old_tables = self.tables;
Expand Down Expand Up @@ -622,7 +629,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}

fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
let const_cx = eval::ConstContext::new(self.tcx, self.tables, self.substs);
let const_cx = eval::ConstContext::new(self.tcx,
self.param_env.and(self.substs),
self.tables);
match const_cx.eval(expr) {
Ok(value) => {
if let ConstVal::Variant(def_id) = value {
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_lint/types.rs
Expand Up @@ -113,7 +113,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
let parent_item = cx.tcx.hir.get_parent(e.id);
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
let const_cx = ConstContext::new(cx.tcx, cx.tables, substs);
let const_cx = ConstContext::new(cx.tcx,
cx.param_env.and(substs),
cx.tables);
match const_cx.eval(&r) {
Ok(ConstVal::Integral(i)) => {
i.is_negative() ||
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/mod.rs
Expand Up @@ -514,8 +514,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

if let Some(pattern) = pattern {
let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
self.hir.param_env.and(self.hir.identity_substs),
self.hir.tables(),
self.hir.identity_substs,
pattern);
scope = self.declare_bindings(scope, ast_body.span, &pattern);
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/hair/cx/block.rs
Expand Up @@ -71,8 +71,8 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
});

let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
cx.param_env.and(cx.identity_substs),
cx.tables(),
cx.identity_substs,
&local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span,
Expand Down

0 comments on commit 60cf542

Please sign in to comment.