Skip to content

unwrap_usize should at least try to evaluate the underlying constant #59369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 5, 2019
4 changes: 4 additions & 0 deletions src/librustc/infer/combine.rs
Original file line number Diff line number Diff line change
@@ -340,6 +340,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
ambient_variance,
needs_wf: false,
root_ty: ty,
param_env: self.param_env,
};

let ty = match generalize.relate(&ty, &ty) {
@@ -379,6 +380,8 @@ struct Generalizer<'cx, 'tcx> {

/// The root type that we are generalizing. Used when reporting cycles.
root_ty: Ty<'tcx>,

param_env: ty::ParamEnv<'tcx>,
}

/// Result from a generalization operation. This includes
@@ -419,6 +422,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }

fn tag(&self) -> &'static str {
"Generalizer"
2 changes: 2 additions & 0 deletions src/librustc/infer/equate.rs
Original file line number Diff line number Diff line change
@@ -30,6 +30,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {

fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }

fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }

fn a_is_expected(&self) -> bool { self.a_is_expected }

fn relate_item_substs(&mut self,
2 changes: 2 additions & 0 deletions src/librustc/infer/glb.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {

fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }

fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }

fn a_is_expected(&self) -> bool { self.a_is_expected }

fn relate_with_variance<T: Relate<'tcx>>(&mut self,
2 changes: 2 additions & 0 deletions src/librustc/infer/lub.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {

fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }

fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }

fn a_is_expected(&self) -> bool { self.a_is_expected }

fn relate_with_variance<T: Relate<'tcx>>(&mut self,
6 changes: 6 additions & 0 deletions src/librustc/infer/nll_relate/mod.rs
Original file line number Diff line number Diff line change
@@ -502,6 +502,9 @@ where
self.infcx.tcx
}

// FIXME(oli-obk): not sure how to get the correct ParamEnv
fn param_env(&self) -> ty::ParamEnv<'tcx> { ty::ParamEnv::empty() }

fn tag(&self) -> &'static str {
"nll::subtype"
}
@@ -831,6 +834,9 @@ where
self.infcx.tcx
}

// FIXME(oli-obk): not sure how to get the correct ParamEnv
fn param_env(&self) -> ty::ParamEnv<'tcx> { ty::ParamEnv::empty() }

fn tag(&self) -> &'static str {
"nll::generalizer"
}
2 changes: 1 addition & 1 deletion src/librustc/infer/outlives/env.rs
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ use crate::ty::{self, Ty};
/// interested in the `OutlivesEnvironment`. -nmatsakis
#[derive(Clone)]
pub struct OutlivesEnvironment<'tcx> {
param_env: ty::ParamEnv<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
free_region_map: FreeRegionMap<'tcx>,

// Contains, for each body B that we are checking (that is, the fn
3 changes: 3 additions & 0 deletions src/librustc/infer/sub.rs
Original file line number Diff line number Diff line change
@@ -35,6 +35,9 @@ impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> {
impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
fn tag(&self) -> &'static str { "Sub" }
fn tcx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx }

fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }

fn a_is_expected(&self) -> bool { self.a_is_expected }

fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
2 changes: 2 additions & 0 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
@@ -277,6 +277,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
) -> Self {
ExprUseVisitor {
mc: mc::MemCategorizationContext::new(tcx,
param_env,
body_owner,
region_scope_tree,
tables,
@@ -299,6 +300,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
ExprUseVisitor {
mc: mc::MemCategorizationContext::with_infer(
infcx,
param_env,
body_owner,
region_scope_tree,
tables,
9 changes: 7 additions & 2 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
@@ -214,6 +214,7 @@ impl HirNode for hir::Pat {
#[derive(Clone)]
pub struct MemCategorizationContext<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pub body_owner: DefId,
pub upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
pub region_scope_tree: &'a region::ScopeTree,
@@ -330,6 +331,7 @@ impl MutabilityCategory {
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
@@ -342,7 +344,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
region_scope_tree,
tables,
rvalue_promotable_map,
infcx: None
infcx: None,
param_env,
}
}
}
@@ -359,6 +362,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// known, the results around upvar accesses may be incorrect.
pub fn with_infer(
infcx: &'a InferCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
@@ -379,6 +383,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
tables,
rvalue_promotable_map,
infcx: Some(infcx),
param_env,
}
}

@@ -896,7 +901,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {

// Always promote `[T; 0]` (even when e.g., borrowed mutably).
let promotable = match expr_ty.sty {
ty::Array(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
ty::Array(_, len) if len.try_eval_usize(self.tcx, self.param_env) == Some(0) => true,
_ => promotable,
};

5 changes: 3 additions & 2 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
self.projection_ty_core(tcx, elem, |_, _, ty| ty)
self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty)
}

/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -68,6 +68,7 @@ impl<'tcx> PlaceTy<'tcx> {
pub fn projection_ty_core<V, T>(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
@@ -90,7 +91,7 @@ impl<'tcx> PlaceTy<'tcx> {
ProjectionElem::Subslice { from, to } => {
PlaceTy::from_ty(match self.ty.sty {
ty::Array(inner, size) => {
let size = size.unwrap_usize(tcx);
let size = size.eval_usize(tcx, param_env);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
2 changes: 1 addition & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -417,7 +417,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
));
let tcx = self.tcx;
if let Some(len) = len.assert_usize(tcx) {
if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
flags.push((
sym::_Self,
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
6 changes: 4 additions & 2 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -1082,7 +1082,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if unbound_input_types && stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
&& self.match_fresh_trait_refs(&stack.fresh_trait_ref, &prev.fresh_trait_ref)
&& self.match_fresh_trait_refs(
&stack.fresh_trait_ref, &prev.fresh_trait_ref, prev.obligation.param_env)
}) {
debug!(
"evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
@@ -3798,8 +3799,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&self,
previous: &ty::PolyTraitRef<'tcx>,
current: &ty::PolyTraitRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx());
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
matcher.relate(previous, current).is_ok()
}

6 changes: 4 additions & 2 deletions src/librustc/ty/_match.rs
Original file line number Diff line number Diff line change
@@ -21,17 +21,19 @@ use crate::mir::interpret::ConstValue;
/// affects any type variables or unification state.
pub struct Match<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}

impl Match<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Match<'tcx> {
Match { tcx }
pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
Match { tcx, param_env }
}
}

impl TypeRelation<'tcx> for Match<'tcx> {
fn tag(&self) -> &'static str { "Match" }
fn tcx(&self) -> TyCtxt<'tcx> { self.tcx }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
fn a_is_expected(&self) -> bool { true } // irrelevant

fn relate_with_variance<T: Relate<'tcx>>(&mut self,
2 changes: 1 addition & 1 deletion src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ impl<'tcx> ty::TyS<'tcx> {
ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
ty::Array(_, n) => {
let n = tcx.lift_to_global(&n).unwrap();
match n.assert_usize(tcx) {
match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
Some(n) => format!("array of {} elements", n).into(),
None => "array".into(),
}
3 changes: 2 additions & 1 deletion src/librustc/ty/inhabitedness/mod.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ use crate::ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
use crate::ty::{DefId, SubstsRef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::TyKind::*;
use crate::ty;

pub use self::def_id_forest::DefIdForest;

@@ -190,7 +191,7 @@ impl<'tcx> TyS<'tcx> {
}))
}

Array(ty, len) => match len.assert_usize(tcx) {
Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(tcx),
2 changes: 1 addition & 1 deletion src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -594,7 +594,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}

let count = count.assert_usize(tcx).ok_or(LayoutError::Unknown(ty))?;
let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
let element = self.layout_of(element)?;
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
4 changes: 2 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -2357,7 +2357,7 @@ impl<'tcx> AdtDef {

#[inline]
pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
let param_env = ParamEnv::empty();
let param_env = tcx.param_env(expr_did);
let repr_type = self.repr.discr_type();
let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), expr_did);
let instance = ty::Instance::new(expr_did, substs);
@@ -2368,7 +2368,7 @@ impl<'tcx> AdtDef {
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => {
// FIXME: Find the right type and use it instead of `val.ty` here
if let Some(b) = val.assert_bits(tcx.global_tcx(), param_env.and(val.ty)) {
if let Some(b) = val.try_eval_bits(tcx.global_tcx(), param_env, val.ty) {
trace!("discriminants: {} ({:?})", b, repr_type);
Some(Discr {
val: b,
3 changes: 2 additions & 1 deletion src/librustc/ty/print/obsolete.rs
Original file line number Diff line number Diff line change
@@ -89,7 +89,8 @@ impl DefPathBasedNames<'tcx> {
ty::Array(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output, debug);
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
write!(output, "; {}", len).unwrap();
output.push(']');
}
ty::Slice(inner_type) => {
9 changes: 7 additions & 2 deletions src/librustc/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -696,7 +696,12 @@ pub trait PrettyPrinter<'tcx>:
},
ty::Array(ty, sz) => {
p!(write("["), print(ty), write("; "));
if let Some(n) = sz.assert_usize(self.tcx()) {
if let ConstValue::Unevaluated(..) = sz.val {
// do not try to evalute unevaluated constants. If we are const evaluating an
// array length anon const, rustc will (with debug assertions) print the
// constant's path. Which will end up here again.
p!(write("_"));
} else if let Some(n) = sz.try_eval_usize(self.tcx(), ty::ParamEnv::empty()) {
p!(write("{}", n));
} else {
p!(write("_"));
@@ -915,7 +920,7 @@ pub trait PrettyPrinter<'tcx>:
if let ty::Ref(_, ref_ty, _) = ct.ty.sty {
let byte_str = match (ct.val, &ref_ty.sty) {
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
let n = n.unwrap_usize(self.tcx());
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
Some(self.tcx()
.alloc_map.lock()
.unwrap_memory(ptr.alloc_id)
6 changes: 5 additions & 1 deletion src/librustc/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@ pub enum Cause {
pub trait TypeRelation<'tcx>: Sized {
fn tcx(&self) -> TyCtxt<'tcx>;

fn param_env(&self) -> ty::ParamEnv<'tcx>;

/// Returns a static string we can use for printouts.
fn tag(&self) -> &'static str;

@@ -466,7 +468,9 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
Err(err) => {
// Check whether the lengths are both concrete/known values,
// but are unequal, for better diagnostics.
match (sz_a.assert_usize(tcx), sz_b.assert_usize(tcx)) {
let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) => {
Err(TypeError::FixedArraySize(
expected_found(relation, &sz_a_val, &sz_b_val)
Loading