Skip to content

Commit

Permalink
rustc: use ty::Const for the length of TyArray.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Sep 11, 2017
1 parent 3ce31eb commit 8a9b78f
Show file tree
Hide file tree
Showing 34 changed files with 215 additions and 60 deletions.
17 changes: 11 additions & 6 deletions src/librustc/middle/const_val.rs
Expand Up @@ -247,18 +247,23 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
}

/// Returns the value of the length-valued expression
pub fn eval_length(tcx: TyCtxt,
count: hir::BodyId,
reason: &str)
-> Result<ConstUsize, ErrorReported>
pub fn eval_length<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
count: hir::BodyId,
reason: &str)
-> Result<&'gcx ty::Const<'gcx>, ErrorReported>
{
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(param_env.and((count_def_id, substs))) {
Ok(&ty::Const { val: Integral(Usize(count)), .. }) => Ok(count),
Ok(_) | Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
Ok(count) => {
// Elsewhere in the compiler this is enforced even in the presence
// of erroneous code (type mismatch error has already been emitted).
assert_eq!(count.ty, tcx.types.usize);
Ok(count)
}
Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
Err(err) => {
let mut diag = err.struct_error(tcx, count_expr.span, reason);

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -876,7 +876,7 @@ 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.as_u64() == 0 => true,
ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true,
_ => promotable,
};

Expand Down
5 changes: 3 additions & 2 deletions src/librustc/mir/tcx.rs
Expand Up @@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
LvalueTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
let len = size.as_u64() - (from as u64) - (to as u64);
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
ty::TySlice(..) => ty,
Expand Down Expand Up @@ -148,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> {
match *self {
Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
Rvalue::Repeat(ref operand, count) => {
tcx.mk_array(operand.ty(local_decls, tcx), count.as_u64())
tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count)
}
Rvalue::Ref(reg, bk, ref lv) => {
let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
Expand Down
12 changes: 10 additions & 2 deletions src/librustc/ty/context.rs
Expand Up @@ -21,6 +21,7 @@ use hir::map as hir_map;
use hir::map::DefPathHash;
use lint::{self, Lint};
use ich::{self, StableHashingContext, NodeIdHashingMode};
use middle::const_val::ConstVal;
use middle::free_region::FreeRegionMap;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
Expand Down Expand Up @@ -49,7 +50,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
StableHasherResult};

use arena::{TypedArena, DroplessArena};
use rustc_const_math::ConstUsize;
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_data_structures::indexed_vec::IndexVec;
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
Expand Down Expand Up @@ -1757,7 +1758,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {

pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
self.mk_ty(TyArray(ty, n))
self.mk_array_const_usize(ty, n)
}

pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::Usize(n)),
ty: self.types.usize
})))
}

pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
Expand Down
13 changes: 10 additions & 3 deletions src/librustc/ty/error.rs
Expand Up @@ -10,6 +10,7 @@

use hir::def_id::DefId;
use infer::type_variable;
use middle::const_val::ConstVal;
use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};

use std::fmt;
Expand All @@ -18,7 +19,7 @@ use syntax::ast;
use errors::DiagnosticBuilder;
use syntax_pos::Span;

use rustc_const_math::ConstUsize;
use rustc_const_math::ConstInt;

use hir;

Expand All @@ -36,7 +37,7 @@ pub enum TypeError<'tcx> {
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<ConstUsize>),
FixedArraySize(ExpectedFound<u64>),
ArgCount,

RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
Expand Down Expand Up @@ -181,7 +182,13 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),

ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyArray(_, n) => format!("array of {} elements", n),
ty::TyArray(_, n) => {
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
format!("array of {} elements", n)
} else {
"array".to_string()
}
}
ty::TySlice(_) => "slice".to_string(),
ty::TyRawPtr(_) => "*-ptr".to_string(),
ty::TyRef(region, tymut) => {
Expand Down
38 changes: 37 additions & 1 deletion src/librustc/ty/flags.rs
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use middle::const_val::{ConstVal, ConstAggregate};
use ty::subst::Substs;
use ty::{self, Ty, TypeFlags, TypeFoldable};

Expand Down Expand Up @@ -145,7 +146,12 @@ impl FlagComputation {
self.add_region(r);
}

&ty::TyArray(tt, _) | &ty::TySlice(tt) => {
&ty::TyArray(tt, len) => {
self.add_ty(tt);
self.add_const(len);
}

&ty::TySlice(tt) => {
self.add_ty(tt)
}

Expand Down Expand Up @@ -202,6 +208,36 @@ impl FlagComputation {
}
}

fn add_const(&mut self, constant: &ty::Const) {
self.add_ty(constant.ty);
match constant.val {
ConstVal::Integral(_) |
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) => {}
ConstVal::Function(_, substs) => {
self.add_substs(substs);
}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
for &(_, v) in fields {
self.add_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
for v in fields {
self.add_const(v);
}
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
self.add_const(v);
}
}
}

fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) {
self.add_substs(projection.substs);
self.add_ty(projection.ty);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/inhabitedness/mod.rs
Expand Up @@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}))
},
TyArray(ty, len) => {
if len.as_u64() == 0 {
if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 {
DefIdForest::empty()
} else {
ty.uninhabited_from(visited, tcx)
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/layout.rs
Expand Up @@ -837,7 +837,7 @@ impl<'a, 'tcx> Struct {

// Is this a fixed-size array of something non-zero
// with at least one element?
(_, &ty::TyArray(ety, d)) if d.as_u64() > 0 => {
(_, &ty::TyArray(ety, d)) if d.val.to_const_int().unwrap().to_u64().unwrap() != 0 => {
Struct::non_zero_field_paths(
tcx,
param_env,
Expand Down Expand Up @@ -1177,7 +1177,7 @@ impl<'a, 'tcx> Layout {
ty::TyArray(element, count) => {
let element = element.layout(tcx, param_env)?;
let element_size = element.size(dl);
let count = count.as_u64();
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
if element_size.checked_mul(count, dl).is_none() {
return Err(LayoutError::SizeOverflow(ty));
}
Expand Down
10 changes: 7 additions & 3 deletions src/librustc/ty/relate.rs
Expand Up @@ -428,10 +428,14 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
(&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
{
let t = relation.relate(&a_t, &b_t)?;
if sz_a == sz_b {
Ok(tcx.mk_array(t, sz_a.as_u64()))
assert_eq!(sz_a.ty, tcx.types.usize);
assert_eq!(sz_b.ty, tcx.types.usize);
let sz_a_u64 = sz_a.val.to_const_int().unwrap().to_u64().unwrap();
let sz_b_u64 = sz_b.val.to_const_int().unwrap().to_u64().unwrap();
if sz_a_u64 == sz_b_u64 {
Ok(tcx.mk_ty(ty::TyArray(t, sz_a)))
} else {
Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b)))
Err(TypeError::FixedArraySize(expected_found(relation, &sz_a_u64, &sz_b_u64)))
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/structural_impls.rs
Expand Up @@ -552,7 +552,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let sty = match self.sty {
ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)),
ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz.fold_with(folder)),
ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
ty::TyDynamic(ref trait_ty, ref region) =>
Expand Down Expand Up @@ -590,7 +590,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match self.sty {
ty::TyRawPtr(ref tm) => tm.visit_with(visitor),
ty::TyArray(typ, _sz) => typ.visit_with(visitor),
ty::TyArray(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor),
ty::TySlice(typ) => typ.visit_with(visitor),
ty::TyAdt(_, substs) => substs.visit_with(visitor),
ty::TyDynamic(ref trait_ty, ref reg) =>
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/ty/sty.rs
Expand Up @@ -27,8 +27,6 @@ use syntax::ast::{self, Name};
use syntax::symbol::keywords;
use util::nodemap::FxHashMap;

use rustc_const_math::ConstUsize;

use serialize;

use hir;
Expand Down Expand Up @@ -112,7 +110,7 @@ pub enum TypeVariants<'tcx> {
TyStr,

/// An array with the given length. Written as `[T; n]`.
TyArray(Ty<'tcx>, ConstUsize),
TyArray(Ty<'tcx>, &'tcx ty::Const<'tcx>),

/// The pointee of an array slice. Written as `[T]`.
TySlice(Ty<'tcx>),
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/ty/util.rs
Expand Up @@ -697,7 +697,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
TyInt(i) => self.hash(i),
TyUint(u) => self.hash(u),
TyFloat(f) => self.hash(f),
TyArray(_, n) => self.hash(n),
TyArray(_, n) => {
self.hash(n.val.to_const_int().unwrap().to_u64().unwrap())
}
TyRawPtr(m) |
TyRef(_, m) => self.hash(m.mutbl),
TyClosure(def_id, _) |
Expand Down
43 changes: 37 additions & 6 deletions src/librustc/ty/walk.rs
Expand Up @@ -11,6 +11,7 @@
//! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.

use middle::const_val::{ConstVal, ConstAggregate};
use ty::{self, Ty};
use rustc_data_structures::small_vec::SmallVec;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
Expand Down Expand Up @@ -83,7 +84,11 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
}
ty::TyArray(ty, _) | ty::TySlice(ty) => {
ty::TyArray(ty, len) => {
push_const(stack, len);
stack.push(ty);
}
ty::TySlice(ty) => {
stack.push(ty);
}
ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => {
Expand Down Expand Up @@ -122,13 +127,39 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
ty::TyFnDef(_, substs) => {
stack.extend(substs.types().rev());
}
ty::TyFnPtr(ft) => {
push_sig_subtypes(stack, ft);
ty::TyFnPtr(sig) => {
stack.push(sig.skip_binder().output());
stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
}
}
}

fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
stack.push(sig.skip_binder().output());
stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
match constant.val {
ConstVal::Integral(_) |
ConstVal::Float(_) |
ConstVal::Str(_) |
ConstVal::ByteStr(_) |
ConstVal::Bool(_) |
ConstVal::Char(_) |
ConstVal::Variant(_) => {}
ConstVal::Function(_, substs) => {
stack.extend(substs.types().rev());
}
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
for &(_, v) in fields.iter().rev() {
push_const(stack, v);
}
}
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
for v in fields.iter().rev() {
push_const(stack, v);
}
}
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
push_const(stack, v);
}
}
stack.push(constant.ty);
}
13 changes: 11 additions & 2 deletions src/librustc/ty/wf.rs
Expand Up @@ -207,6 +207,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
}
}

/// Pushes the obligations required for a constant value to be WF
/// into `self.out`.
fn compute_const(&mut self, _constant: &'tcx ty::Const<'tcx>) {}

fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
if !subty.has_escaping_regions() {
let cause = self.cause(cause);
Expand Down Expand Up @@ -239,9 +243,14 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
// WfScalar, WfParameter, etc
}

ty::TySlice(subty) |
ty::TyArray(subty, _) => {
ty::TySlice(subty) => {
self.require_sized(subty, traits::SliceOrArrayElem);
}

ty::TyArray(subty, len) => {
self.require_sized(subty, traits::SliceOrArrayElem);
assert_eq!(len.ty, self.infcx.tcx.types.usize);
self.compute_const(len);
}

ty::TyTuple(ref tys, _) => {
Expand Down

0 comments on commit 8a9b78f

Please sign in to comment.