Skip to content

Commit 799b15e

Browse files
committed
Evaluate repeat expression lengths as late as possible
1 parent 8ff7850 commit 799b15e

Some content is hidden

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

46 files changed

+279
-264
lines changed

src/librustc/mir/mod.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,7 +2066,7 @@ pub enum Rvalue<'tcx> {
20662066
Use(Operand<'tcx>),
20672067

20682068
/// [x; 32]
2069-
Repeat(Operand<'tcx>, u64),
2069+
Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>),
20702070

20712071
/// &x or &mut x
20722072
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@@ -2194,7 +2194,11 @@ impl<'tcx> Debug for Rvalue<'tcx> {
21942194

21952195
match *self {
21962196
Use(ref place) => write!(fmt, "{:?}", place),
2197-
Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
2197+
Repeat(ref a, ref b) => {
2198+
write!(fmt, "[{:?}; ", a)?;
2199+
pretty_print_const(b, fmt, false)?;
2200+
write!(fmt, "]")
2201+
}
21982202
Len(ref a) => write!(fmt, "Len({:?})", a),
21992203
Cast(ref kind, ref place, ref ty) => {
22002204
write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind)
@@ -2562,18 +2566,26 @@ impl<'tcx> Debug for Constant<'tcx> {
25622566

25632567
impl<'tcx> Display for Constant<'tcx> {
25642568
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
2565-
use crate::ty::print::PrettyPrinter;
25662569
write!(fmt, "const ")?;
2567-
ty::tls::with(|tcx| {
2568-
let literal = tcx.lift(&self.literal).unwrap();
2569-
let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
2570-
cx.print_alloc_ids = true;
2571-
cx.pretty_print_const(literal, true)?;
2572-
Ok(())
2573-
})
2570+
pretty_print_const(self.literal, fmt, true)
25742571
}
25752572
}
25762573

2574+
fn pretty_print_const(
2575+
c: &ty::Const<'tcx>,
2576+
fmt: &mut Formatter<'_>,
2577+
print_types: bool,
2578+
) -> fmt::Result {
2579+
use crate::ty::print::PrettyPrinter;
2580+
ty::tls::with(|tcx| {
2581+
let literal = tcx.lift(&c).unwrap();
2582+
let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
2583+
cx.print_alloc_ids = true;
2584+
cx.pretty_print_const(literal, print_types)?;
2585+
Ok(())
2586+
})
2587+
}
2588+
25772589
impl<'tcx> graph::DirectedGraph for Body<'tcx> {
25782590
type Node = BasicBlock;
25792591
}

src/librustc/mir/tcx.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ impl<'tcx> Rvalue<'tcx> {
149149
{
150150
match *self {
151151
Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
152-
Rvalue::Repeat(ref operand, count) => tcx.mk_array(operand.ty(local_decls, tcx), count),
152+
Rvalue::Repeat(ref operand, count) => {
153+
tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count))
154+
}
153155
Rvalue::Ref(reg, bk, ref place) => {
154156
let place_ty = place.ty(local_decls, tcx).ty;
155157
tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })

src/librustc/ty/sty.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use self::TyKind::*;
88
use crate::infer::canonical::Canonical;
99
use crate::middle::region;
1010
use crate::mir::interpret::ConstValue;
11-
use crate::mir::interpret::Scalar;
11+
use crate::mir::interpret::{LitToConstInput, Scalar};
1212
use crate::mir::Promoted;
1313
use crate::ty::layout::VariantIdx;
1414
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
@@ -2401,7 +2401,75 @@ pub struct Const<'tcx> {
24012401
#[cfg(target_arch = "x86_64")]
24022402
static_assert_size!(Const<'_>, 48);
24032403

2404+
/// Returns the `DefId` of the constant parameter that the provided expression is a path to.
2405+
fn const_param_def_id(expr: &hir::Expr<'_>) -> Option<DefId> {
2406+
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
2407+
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
2408+
let expr = match &expr.kind {
2409+
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
2410+
block.expr.as_ref().unwrap()
2411+
}
2412+
_ => expr,
2413+
};
2414+
2415+
match &expr.kind {
2416+
hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
2417+
hir::def::Res::Def(hir::def::DefKind::ConstParam, did) => Some(did),
2418+
_ => None,
2419+
},
2420+
_ => None,
2421+
}
2422+
}
2423+
24042424
impl<'tcx> Const<'tcx> {
2425+
pub fn from_hir_anon_const(
2426+
tcx: TyCtxt<'tcx>,
2427+
ast_const: &hir::AnonConst,
2428+
ty: Ty<'tcx>,
2429+
) -> &'tcx Self {
2430+
debug!("Const::from_hir_anon_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const);
2431+
2432+
let def_id = tcx.hir().local_def_id(ast_const.hir_id);
2433+
2434+
let expr = &tcx.hir().body(ast_const.body).value;
2435+
2436+
let lit_input = match expr.kind {
2437+
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
2438+
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
2439+
hir::ExprKind::Lit(ref lit) => {
2440+
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
2441+
}
2442+
_ => None,
2443+
},
2444+
_ => None,
2445+
};
2446+
2447+
if let Some(lit_input) = lit_input {
2448+
// If an error occurred, ignore that it's a literal and leave reporting the error up to
2449+
// mir.
2450+
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
2451+
return c;
2452+
} else {
2453+
tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const");
2454+
}
2455+
}
2456+
2457+
let kind = if let Some(def_id) = const_param_def_id(expr) {
2458+
// Find the name and index of the const parameter by indexing the generics of the
2459+
// parent item and construct a `ParamConst`.
2460+
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
2461+
let item_id = tcx.hir().get_parent_node(hir_id);
2462+
let item_def_id = tcx.hir().local_def_id(item_id);
2463+
let generics = tcx.generics_of(item_def_id);
2464+
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
2465+
let name = tcx.hir().name(hir_id);
2466+
ty::ConstKind::Param(ty::ParamConst::new(index, name))
2467+
} else {
2468+
ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None)
2469+
};
2470+
tcx.mk_const(ty::Const { val: kind, ty })
2471+
}
2472+
24052473
#[inline]
24062474
pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
24072475
tcx.mk_const(Self { val: ConstKind::Value(val), ty })

src/librustc_codegen_ssa/mir/rvalue.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
106106
}
107107
}
108108

109+
let count =
110+
self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
111+
109112
bx.write_operand_repeatedly(cg_elem, count, dest)
110113
}
111114

src/librustc_mir/borrow_check/type_check/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1986,7 +1986,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19861986
}
19871987

19881988
Rvalue::Repeat(operand, len) => {
1989-
if *len > 1 {
1989+
// If the length cannot be evaluated we must assume that the length can be larger
1990+
// than 1.
1991+
// If the length is larger than 1, the repeat expression will need to copy the
1992+
// element, so we require the `Copy` trait.
1993+
if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
19901994
if let Operand::Move(_) = operand {
19911995
// While this is located in `nll::typeck` this error is not an NLL error, it's
19921996
// a required check to make sure that repeated elements implement `Copy`.

src/librustc_mir_build/hair/cx/expr.rs

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::hair::cx::to_ref::ToRef;
33
use crate::hair::cx::Cx;
44
use crate::hair::util::UserAnnotatedTyHelpers;
55
use crate::hair::*;
6-
use rustc::mir::interpret::{ErrorHandled, Scalar};
6+
use rustc::mir::interpret::Scalar;
77
use rustc::mir::BorrowKind;
88
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast};
99
use rustc::ty::subst::{InternalSubsts, SubstsRef};
@@ -406,34 +406,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
406406

407407
// Now comes the rote stuff:
408408
hir::ExprKind::Repeat(ref v, ref count) => {
409-
let def_id = cx.tcx.hir().local_def_id(count.hir_id);
410-
let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
411-
let span = cx.tcx.def_span(def_id);
412-
let count = match cx.tcx.const_eval_resolve(
413-
ty::ParamEnv::reveal_all(),
414-
def_id,
415-
substs,
416-
None,
417-
Some(span),
418-
) {
419-
Ok(cv) => {
420-
if let Some(count) = cv.try_to_bits_for_ty(
421-
cx.tcx,
422-
ty::ParamEnv::reveal_all(),
423-
cx.tcx.types.usize,
424-
) {
425-
count as u64
426-
} else {
427-
bug!("repeat count constant value can't be converted to usize");
428-
}
429-
}
430-
Err(ErrorHandled::Reported) => 0,
431-
Err(ErrorHandled::TooGeneric) => {
432-
let span = cx.tcx.def_span(def_id);
433-
cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
434-
0
435-
}
436-
};
409+
let count = ty::Const::from_hir_anon_const(cx.tcx, count, cx.tcx.types.usize);
437410

438411
ExprKind::Repeat { value: v.to_ref(), count }
439412
}

src/librustc_mir_build/hair/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ crate enum ExprKind<'tcx> {
229229
},
230230
Repeat {
231231
value: ExprRef<'tcx>,
232-
count: u64,
232+
count: &'tcx Const<'tcx>,
233233
},
234234
Array {
235235
fields: Vec<ExprRef<'tcx>>,

src/librustc_typeck/astconv.rs

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
2222
use rustc_hir::def_id::DefId;
2323
use rustc_hir::intravisit::Visitor;
2424
use rustc_hir::print;
25-
use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs};
25+
use rustc_hir::{Constness, GenericArg, GenericArgs};
2626
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
2727
use rustc_session::parse::feature_err;
2828
use rustc_session::Session;
@@ -39,8 +39,6 @@ use std::collections::BTreeSet;
3939
use std::iter;
4040
use std::slice;
4141

42-
use rustc::mir::interpret::LitToConstInput;
43-
4442
#[derive(Debug)]
4543
pub struct PathSeg(pub DefId, pub usize);
4644

@@ -782,7 +780,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
782780
}
783781
}
784782
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
785-
self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into()
783+
ty::Const::from_hir_anon_const(tcx, &ct.value, tcx.type_of(param.def_id)).into()
786784
}
787785
_ => unreachable!(),
788786
},
@@ -2766,7 +2764,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27662764
.unwrap_or(tcx.types.err)
27672765
}
27682766
hir::TyKind::Array(ref ty, ref length) => {
2769-
let length = self.ast_const_to_const(length, tcx.types.usize);
2767+
let length = ty::Const::from_hir_anon_const(tcx, length, tcx.types.usize);
27702768
let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
27712769
self.normalize_ty(ast_ty.span, array_ty)
27722770
}
@@ -2798,75 +2796,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27982796
result_ty
27992797
}
28002798

2801-
/// Returns the `DefId` of the constant parameter that the provided expression is a path to.
2802-
pub fn const_param_def_id(&self, expr: &hir::Expr<'_>) -> Option<DefId> {
2803-
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
2804-
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
2805-
let expr = match &expr.kind {
2806-
ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
2807-
block.expr.as_ref().unwrap()
2808-
}
2809-
_ => expr,
2810-
};
2811-
2812-
match &expr.kind {
2813-
ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
2814-
Res::Def(DefKind::ConstParam, did) => Some(did),
2815-
_ => None,
2816-
},
2817-
_ => None,
2818-
}
2819-
}
2820-
2821-
pub fn ast_const_to_const(
2822-
&self,
2823-
ast_const: &hir::AnonConst,
2824-
ty: Ty<'tcx>,
2825-
) -> &'tcx ty::Const<'tcx> {
2826-
debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const);
2827-
2828-
let tcx = self.tcx();
2829-
let def_id = tcx.hir().local_def_id(ast_const.hir_id);
2830-
2831-
let expr = &tcx.hir().body(ast_const.body).value;
2832-
2833-
let lit_input = match expr.kind {
2834-
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
2835-
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
2836-
hir::ExprKind::Lit(ref lit) => {
2837-
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
2838-
}
2839-
_ => None,
2840-
},
2841-
_ => None,
2842-
};
2843-
2844-
if let Some(lit_input) = lit_input {
2845-
// If an error occurred, ignore that it's a literal and leave reporting the error up to
2846-
// mir.
2847-
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
2848-
return c;
2849-
} else {
2850-
tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const");
2851-
}
2852-
}
2853-
2854-
let kind = if let Some(def_id) = self.const_param_def_id(expr) {
2855-
// Find the name and index of the const parameter by indexing the generics of the
2856-
// parent item and construct a `ParamConst`.
2857-
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
2858-
let item_id = tcx.hir().get_parent_node(hir_id);
2859-
let item_def_id = tcx.hir().local_def_id(item_id);
2860-
let generics = tcx.generics_of(item_def_id);
2861-
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
2862-
let name = tcx.hir().name(hir_id);
2863-
ty::ConstKind::Param(ty::ParamConst::new(index, name))
2864-
} else {
2865-
ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None)
2866-
};
2867-
tcx.mk_const(ty::Const { val: kind, ty })
2868-
}
2869-
28702799
pub fn impl_trait_ty_to_ty(
28712800
&self,
28722801
def_id: DefId,

src/librustc_typeck/check/expr.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use crate::type_error_struct;
1818
use crate::util::common::ErrorReported;
1919

2020
use rustc::middle::lang_items;
21-
use rustc::mir::interpret::ErrorHandled;
2221
use rustc::ty;
2322
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
2423
use rustc::ty::Ty;
@@ -1009,12 +1008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10091008
) -> Ty<'tcx> {
10101009
let tcx = self.tcx;
10111010
let count_def_id = tcx.hir().local_def_id(count.hir_id);
1012-
let count = if self.const_param_def_id(count).is_some() {
1013-
Ok(self.to_const(count, tcx.type_of(count_def_id)))
1014-
} else {
1015-
tcx.const_eval_poly(count_def_id)
1016-
.map(|val| ty::Const::from_value(tcx, val, tcx.type_of(count_def_id)))
1017-
};
1011+
let count = self.to_const(count, tcx.type_of(count_def_id));
10181012

10191013
let uty = match expected {
10201014
ExpectHasType(uty) => match uty.kind {
@@ -1042,17 +1036,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10421036
if element_ty.references_error() {
10431037
return tcx.types.err;
10441038
}
1045-
match count {
1046-
Ok(count) => tcx.mk_ty(ty::Array(t, count)),
1047-
Err(ErrorHandled::TooGeneric) => {
1048-
self.tcx.sess.span_err(
1049-
tcx.def_span(count_def_id),
1050-
"array lengths can't depend on generic parameters",
1051-
);
1052-
tcx.types.err
1053-
}
1054-
Err(ErrorHandled::Reported) => tcx.types.err,
1055-
}
1039+
1040+
tcx.mk_ty(ty::Array(t, count))
10561041
}
10571042

10581043
fn check_expr_tuple(

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,13 +3279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32793279
ty
32803280
}
32813281

3282-
/// Returns the `DefId` of the constant parameter that the provided expression is a path to.
3283-
pub fn const_param_def_id(&self, hir_c: &hir::AnonConst) -> Option<DefId> {
3284-
AstConv::const_param_def_id(self, &self.tcx.hir().body(hir_c.body).value)
3285-
}
3286-
32873282
pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
3288-
AstConv::ast_const_to_const(self, ast_c, ty)
3283+
ty::Const::from_hir_anon_const(self.tcx, ast_c, ty)
32893284
}
32903285

32913286
// If the type given by the user has free regions, save it for later, since

0 commit comments

Comments
 (0)