1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![allow(non_camel_case_types)]
12 #![allow(unsigned_negation)]
14 pub use self::const_val
::*;
18 use metadata
::csearch
;
19 use middle
::{astencode, def, infer, subst, traits}
;
20 use middle
::pat_util
::def_to_path
;
21 use middle
::ty
::{self, Ty}
;
22 use middle
::astconv_util
::ast_ty_to_prim_ty
;
23 use util
::num
::ToPrimitive
;
24 use util
::ppaux
::Repr
;
26 use syntax
::ast
::{self, Expr}
;
27 use syntax
::codemap
::Span
;
28 use syntax
::feature_gate
;
29 use syntax
::parse
::token
::InternedString
;
31 use syntax
::{ast_map, ast_util, codemap}
;
33 use std
::borrow
::{Cow, IntoCow}
;
34 use std
::num
::wrapping
::OverflowingOps
;
35 use std
::cmp
::Ordering
;
36 use std
::collections
::hash_map
::Entry
::Vacant
;
37 use std
::{i8, i16, i32, i64}
;
40 fn lookup_const
<'a
>(tcx
: &'a ty
::ctxt
, e
: &Expr
) -> Option
<&'a Expr
> {
41 let opt_def
= tcx
.def_map
.borrow().get(&e
.id
).map(|d
| d
.full_def());
43 Some(def
::DefConst(def_id
)) |
44 Some(def
::DefAssociatedConst(def_id
, _
)) => {
45 lookup_const_by_id(tcx
, def_id
, Some(e
.id
))
47 Some(def
::DefVariant(enum_def
, variant_def
, _
)) => {
48 lookup_variant_by_id(tcx
, enum_def
, variant_def
)
54 fn lookup_variant_by_id
<'a
>(tcx
: &'a ty
::ctxt
,
56 variant_def
: ast
::DefId
)
58 fn variant_expr
<'a
>(variants
: &'a
[P
<ast
::Variant
>], id
: ast
::NodeId
)
60 for variant
in variants
{
61 if variant
.node
.id
== id
{
62 return variant
.node
.disr_expr
.as_ref().map(|e
| &**e
);
68 if ast_util
::is_local(enum_def
) {
69 match tcx
.map
.find(enum_def
.node
) {
71 Some(ast_map
::NodeItem(it
)) => match it
.node
{
72 ast
::ItemEnum(ast
::EnumDef { ref variants }
, _
) => {
73 variant_expr(&variants
[..], variant_def
.node
)
80 match tcx
.extern_const_variants
.borrow().get(&variant_def
) {
81 Some(&ast
::DUMMY_NODE_ID
) => return None
,
83 return Some(tcx
.map
.expect_expr(expr_id
));
87 let expr_id
= match csearch
::maybe_get_item_ast(tcx
, enum_def
,
88 Box
::new(|a
, b
, c
, d
| astencode
::decode_inlined_item(a
, b
, c
, d
))) {
89 csearch
::FoundAst
::Found(&ast
::IIItem(ref item
)) => match item
.node
{
90 ast
::ItemEnum(ast
::EnumDef { ref variants }
, _
) => {
91 // NOTE this doesn't do the right thing, it compares inlined
92 // NodeId's to the original variant_def's NodeId, but they
93 // come from different crates, so they will likely never match.
94 variant_expr(&variants
[..], variant_def
.node
).map(|e
| e
.id
)
100 tcx
.extern_const_variants
.borrow_mut().insert(variant_def
,
101 expr_id
.unwrap_or(ast
::DUMMY_NODE_ID
));
102 expr_id
.map(|id
| tcx
.map
.expect_expr(id
))
106 pub fn lookup_const_by_id
<'a
, 'tcx
: 'a
>(tcx
: &'a ty
::ctxt
<'tcx
>,
108 maybe_ref_id
: Option
<ast
::NodeId
>)
109 -> Option
<&'tcx Expr
> {
110 if ast_util
::is_local(def_id
) {
111 match tcx
.map
.find(def_id
.node
) {
113 Some(ast_map
::NodeItem(it
)) => match it
.node
{
114 ast
::ItemConst(_
, ref const_expr
) => {
119 Some(ast_map
::NodeTraitItem(ti
)) => match ti
.node
{
120 ast
::ConstTraitItem(_
, _
) => {
122 // If we have a trait item, and we know the expression
123 // that's the source of the obligation to resolve it,
124 // `resolve_trait_associated_const` will select an impl
127 let trait_id
= ty
::trait_of_item(tcx
, def_id
)
129 resolve_trait_associated_const(tcx
, ti
, trait_id
,
132 // Technically, without knowing anything about the
133 // expression that generates the obligation, we could
134 // still return the default if there is one. However,
135 // it's safer to return `None` than to return some value
136 // that may differ from what you would get from
137 // correctly selecting an impl.
143 Some(ast_map
::NodeImplItem(ii
)) => match ii
.node
{
144 ast
::ConstImplItem(_
, ref expr
) => {
152 match tcx
.extern_const_statics
.borrow().get(&def_id
) {
153 Some(&ast
::DUMMY_NODE_ID
) => return None
,
155 return Some(tcx
.map
.expect_expr(expr_id
));
159 let mut used_ref_id
= false;
160 let expr_id
= match csearch
::maybe_get_item_ast(tcx
, def_id
,
161 Box
::new(|a
, b
, c
, d
| astencode
::decode_inlined_item(a
, b
, c
, d
))) {
162 csearch
::FoundAst
::Found(&ast
::IIItem(ref item
)) => match item
.node
{
163 ast
::ItemConst(_
, ref const_expr
) => Some(const_expr
.id
),
166 csearch
::FoundAst
::Found(&ast
::IITraitItem(trait_id
, ref ti
)) => match ti
.node
{
167 ast
::ConstTraitItem(_
, _
) => {
170 // As mentioned in the comments above for in-crate
171 // constants, we only try to find the expression for
172 // a trait-associated const if the caller gives us
173 // the expression that refers to it.
175 resolve_trait_associated_const(tcx
, ti
, trait_id
,
176 ref_id
).map(|e
| e
.id
)
183 csearch
::FoundAst
::Found(&ast
::IIImplItem(_
, ref ii
)) => match ii
.node
{
184 ast
::ConstImplItem(_
, ref expr
) => Some(expr
.id
),
189 // If we used the reference expression, particularly to choose an impl
190 // of a trait-associated const, don't cache that, because the next
191 // lookup with the same def_id may yield a different result.
193 tcx
.extern_const_statics
194 .borrow_mut().insert(def_id
,
195 expr_id
.unwrap_or(ast
::DUMMY_NODE_ID
));
197 expr_id
.map(|id
| tcx
.map
.expect_expr(id
))
201 #[derive(Clone, PartialEq)]
206 const_str(InternedString
),
207 const_binary(Rc
<Vec
<u8>>),
213 pub fn const_expr_to_pat(tcx
: &ty
::ctxt
, expr
: &Expr
, span
: Span
) -> P
<ast
::Pat
> {
214 let pat
= match expr
.node
{
215 ast
::ExprTup(ref exprs
) =>
216 ast
::PatTup(exprs
.iter().map(|expr
| const_expr_to_pat(tcx
, &**expr
, span
)).collect()),
218 ast
::ExprCall(ref callee
, ref args
) => {
219 let def
= *tcx
.def_map
.borrow().get(&callee
.id
).unwrap();
220 if let Vacant(entry
) = tcx
.def_map
.borrow_mut().entry(expr
.id
) {
223 let path
= match def
.full_def() {
224 def
::DefStruct(def_id
) => def_to_path(tcx
, def_id
),
225 def
::DefVariant(_
, variant_did
, _
) => def_to_path(tcx
, variant_did
),
228 let pats
= args
.iter().map(|expr
| const_expr_to_pat(tcx
, &**expr
, span
)).collect();
229 ast
::PatEnum(path
, Some(pats
))
232 ast
::ExprStruct(ref path
, ref fields
, None
) => {
233 let field_pats
= fields
.iter().map(|field
| codemap
::Spanned
{
234 span
: codemap
::DUMMY_SP
,
235 node
: ast
::FieldPat
{
236 ident
: field
.ident
.node
,
237 pat
: const_expr_to_pat(tcx
, &*field
.expr
, span
),
241 ast
::PatStruct(path
.clone(), field_pats
, false)
244 ast
::ExprVec(ref exprs
) => {
245 let pats
= exprs
.iter().map(|expr
| const_expr_to_pat(tcx
, &**expr
, span
)).collect();
246 ast
::PatVec(pats
, None
, vec
![])
249 ast
::ExprPath(_
, ref path
) => {
250 let opt_def
= tcx
.def_map
.borrow().get(&expr
.id
).map(|d
| d
.full_def());
252 Some(def
::DefStruct(..)) =>
253 ast
::PatStruct(path
.clone(), vec
![], false),
254 Some(def
::DefVariant(..)) =>
255 ast
::PatEnum(path
.clone(), None
),
257 match lookup_const(tcx
, expr
) {
258 Some(actual
) => return const_expr_to_pat(tcx
, actual
, span
),
265 _
=> ast
::PatLit(P(expr
.clone()))
267 P(ast
::Pat { id: expr.id, node: pat, span: span }
)
270 pub fn eval_const_expr(tcx
: &ty
::ctxt
, e
: &Expr
) -> const_val
{
271 match eval_const_expr_partial(tcx
, e
, None
) {
273 Err(s
) => tcx
.sess
.span_fatal(s
.span
, &s
.description())
279 pub struct ConstEvalErr
{
287 CannotCastTo(&'
static str),
288 InvalidOpForBools(ast
::BinOp_
),
289 InvalidOpForFloats(ast
::BinOp_
),
290 InvalidOpForIntUint(ast
::BinOp_
),
291 InvalidOpForUintInt(ast
::BinOp_
),
303 NegateWithOverflow(i64),
304 AddiWithOverflow(i64, i64),
305 SubiWithOverflow(i64, i64),
306 MuliWithOverflow(i64, i64),
307 AdduWithOverflow(u64, u64),
308 SubuWithOverflow(u64, u64),
309 MuluWithOverflow(u64, u64),
314 ShiftLeftWithOverflow
,
315 ShiftRightWithOverflow
,
320 TupleIndexOutOfBounds
,
327 pub fn description(&self) -> Cow
<str> {
328 use self::ErrKind
::*;
331 CannotCast
=> "can't cast this type".into_cow(),
332 CannotCastTo(s
) => format
!("can't cast this type to {}", s
).into_cow(),
333 InvalidOpForBools(_
) => "can't do this op on bools".into_cow(),
334 InvalidOpForFloats(_
) => "can't do this op on floats".into_cow(),
335 InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
336 InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
337 NegateOnString
=> "negate on string".into_cow(),
338 NegateOnBoolean
=> "negate on boolean".into_cow(),
339 NegateOnBinary
=> "negate on binary literal".into_cow(),
340 NegateOnStruct
=> "negate on struct".into_cow(),
341 NegateOnTuple
=> "negate on tuple".into_cow(),
342 NotOnFloat
=> "not on float or string".into_cow(),
343 NotOnString
=> "not on float or string".into_cow(),
344 NotOnBinary
=> "not on binary literal".into_cow(),
345 NotOnStruct
=> "not on struct".into_cow(),
346 NotOnTuple
=> "not on tuple".into_cow(),
348 NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
349 AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
350 SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
351 MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
352 AdduWithOverflow(..) => "attempted to add with overflow".into_cow(),
353 SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(),
354 MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(),
355 DivideByZero
=> "attempted to divide by zero".into_cow(),
356 DivideWithOverflow
=> "attempted to divide with overflow".into_cow(),
357 ModuloByZero
=> "attempted remainder with a divisor of zero".into_cow(),
358 ModuloWithOverflow
=> "attempted remainder with overflow".into_cow(),
359 ShiftLeftWithOverflow
=> "attempted left shift with overflow".into_cow(),
360 ShiftRightWithOverflow
=> "attempted right shift with overflow".into_cow(),
361 MissingStructField
=> "nonexistent struct field".into_cow(),
362 NonConstPath
=> "non-constant path in constant expr".into_cow(),
363 ExpectedConstTuple
=> "expected constant tuple".into_cow(),
364 ExpectedConstStruct
=> "expected constant struct".into_cow(),
365 TupleIndexOutOfBounds
=> "tuple index out of bounds".into_cow(),
367 MiscBinaryOp
=> "bad operands for binary".into_cow(),
368 MiscCatchAll
=> "unsupported constant expr".into_cow(),
373 pub type EvalResult
= Result
<const_val
, ConstEvalErr
>;
374 pub type CastResult
= Result
<const_val
, ErrKind
>;
376 #[derive(Copy, Clone, PartialEq, Debug)]
377 pub enum IntTy { I8, I16, I32, I64 }
378 #[derive(Copy, Clone, PartialEq, Debug)]
379 pub enum UintTy { U8, U16, U32, U64 }
382 pub fn from(tcx
: &ty
::ctxt
, t
: ast
::IntTy
) -> IntTy
{
383 let t
= if let ast
::TyIs
= t
{
384 tcx
.sess
.target
.int_type
389 ast
::TyIs
=> unreachable
!(),
390 ast
::TyI8
=> IntTy
::I8
,
391 ast
::TyI16
=> IntTy
::I16
,
392 ast
::TyI32
=> IntTy
::I32
,
393 ast
::TyI64
=> IntTy
::I64
,
399 pub fn from(tcx
: &ty
::ctxt
, t
: ast
::UintTy
) -> UintTy
{
400 let t
= if let ast
::TyUs
= t
{
401 tcx
.sess
.target
.uint_type
406 ast
::TyUs
=> unreachable
!(),
407 ast
::TyU8
=> UintTy
::U8
,
408 ast
::TyU16
=> UintTy
::U16
,
409 ast
::TyU32
=> UintTy
::U32
,
410 ast
::TyU64
=> UintTy
::U64
,
415 macro_rules
! signal
{
416 ($e
:expr
, $exn
:expr
) => {
417 return Err(ConstEvalErr { span: $e.span, kind: $exn }
)
421 // The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
422 // of functions catch and signal overflow errors during constant
425 // They all take the operator's arguments (`a` and `b` if binary), the
426 // overall expression (`e`) and, if available, whole expression's
427 // concrete type (`opt_ety`).
429 // If the whole expression's concrete type is None, then this is a
430 // constant evaluation happening before type check (e.g. in the check
431 // to confirm that a pattern range's left-side is not greater than its
432 // right-side). We do not do arithmetic modulo the type's bitwidth in
433 // such a case; we just do 64-bit arithmetic and assume that later
434 // passes will do it again with the type information, and thus do the
435 // overflow checks then.
437 pub fn const_int_checked_neg
<'a
>(
438 a
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
440 let (min
,max
) = match opt_ety
{
441 // (-i8::MIN is itself not an i8, etc, but this is an easy way
442 // to allow literals to pass the check. Of course that does
443 // not work for i64::MIN.)
444 Some(IntTy
::I8
) => (-(i8::MAX
as i64), -(i8::MIN
as i64)),
445 Some(IntTy
::I16
) => (-(i16::MAX
as i64), -(i16::MIN
as i64)),
446 Some(IntTy
::I32
) => (-(i32::MAX
as i64), -(i32::MIN
as i64)),
447 None
| Some(IntTy
::I64
) => (-i64::MAX
, -(i64::MIN
+1)),
450 let oflo
= a
< min
|| a
> max
;
452 signal
!(e
, NegateWithOverflow(a
));
458 pub fn const_uint_checked_neg
<'a
>(
459 a
: u64, _e
: &'a Expr
, _opt_ety
: Option
<UintTy
>) -> EvalResult
{
460 // This always succeeds, and by definition, returns `(!a)+1`.
461 Ok(const_uint((!a
).wrapping_add(1)))
464 macro_rules
! overflow_checking_body
{
465 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
,
466 lhs
: $to_8_lhs
:ident $to_16_lhs
:ident $to_32_lhs
:ident
,
467 rhs
: $to_8_rhs
:ident $to_16_rhs
:ident $to_32_rhs
:ident $to_64_rhs
:ident
,
468 $EnumTy
:ident $T8
: ident $T16
: ident $T32
: ident $T64
: ident
,
469 $result_type
: ident
) => { {
470 let (a
,b
,opt_ety
) = ($a
,$b
,$ety
);
472 Some($EnumTy
::$T8
) => match (a
.$
to_8_lhs(), b
.$
to_8_rhs()) {
473 (Some(a
), Some(b
)) => {
474 let (a
, oflo
) = a
.$
overflowing_op(b
);
475 (a
as $result_type
, oflo
)
477 (None
, _
) | (_
, None
) => (0, true)
479 Some($EnumTy
::$T16
) => match (a
.$
to_16_lhs(), b
.$
to_16_rhs()) {
480 (Some(a
), Some(b
)) => {
481 let (a
, oflo
) = a
.$
overflowing_op(b
);
482 (a
as $result_type
, oflo
)
484 (None
, _
) | (_
, None
) => (0, true)
486 Some($EnumTy
::$T32
) => match (a
.$
to_32_lhs(), b
.$
to_32_rhs()) {
487 (Some(a
), Some(b
)) => {
488 let (a
, oflo
) = a
.$
overflowing_op(b
);
489 (a
as $result_type
, oflo
)
491 (None
, _
) | (_
, None
) => (0, true)
493 None
| Some($EnumTy
::$T64
) => match b
.$
to_64_rhs() {
494 Some(b
) => a
.$
overflowing_op(b
),
501 macro_rules
! int_arith_body
{
502 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
503 overflow_checking_body
!(
504 $a
, $b
, $ety
, $overflowing_op
,
505 lhs
: to_i8 to_i16 to_i32
,
506 rhs
: to_i8 to_i16 to_i32 to_i64
, IntTy I8 I16 I32 I64
, i64)
510 macro_rules
! uint_arith_body
{
511 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
512 overflow_checking_body
!(
513 $a
, $b
, $ety
, $overflowing_op
,
514 lhs
: to_u8 to_u16 to_u32
,
515 rhs
: to_u8 to_u16 to_u32 to_u64
, UintTy U8 U16 U32 U64
, u64)
519 macro_rules
! int_shift_body
{
520 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
521 overflow_checking_body
!(
522 $a
, $b
, $ety
, $overflowing_op
,
523 lhs
: to_i8 to_i16 to_i32
,
524 rhs
: to_u32 to_u32 to_u32 to_u32
, IntTy I8 I16 I32 I64
, i64)
528 macro_rules
! uint_shift_body
{
529 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
530 overflow_checking_body
!(
531 $a
, $b
, $ety
, $overflowing_op
,
532 lhs
: to_u8 to_u16 to_u32
,
533 rhs
: to_u32 to_u32 to_u32 to_u32
, UintTy U8 U16 U32 U64
, u64)
537 macro_rules
! pub_fn_checked_op
{
538 {$fn_name
:ident ($a
:ident
: $a_ty
:ty
, $b
:ident
: $b_ty
:ty
,.. $WhichTy
:ident
) {
539 $ret_oflo_body
:ident $overflowing_op
:ident
540 $const_ty
:ident $signal_exn
:expr
542 pub fn $fn_name
<'a
>($a
: $a_ty
,
545 opt_ety
: Option
<$WhichTy
>) -> EvalResult
{
546 let (ret
, oflo
) = $ret_oflo_body
!($a
, $b
, opt_ety
, $overflowing_op
);
547 if !oflo { Ok($const_ty(ret)) }
else { signal!(e, $signal_exn) }
552 pub_fn_checked_op
!{ const_int_checked_add(a
: i64, b
: i64,.. IntTy
) {
553 int_arith_body overflowing_add const_int
AddiWithOverflow(a
, b
)
556 pub_fn_checked_op
!{ const_int_checked_sub(a
: i64, b
: i64,.. IntTy
) {
557 int_arith_body overflowing_sub const_int
SubiWithOverflow(a
, b
)
560 pub_fn_checked_op
!{ const_int_checked_mul(a
: i64, b
: i64,.. IntTy
) {
561 int_arith_body overflowing_mul const_int
MuliWithOverflow(a
, b
)
564 pub fn const_int_checked_div
<'a
>(
565 a
: i64, b
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
566 if b
== 0 { signal!(e, DivideByZero); }
567 let (ret
, oflo
) = int_arith_body
!(a
, b
, opt_ety
, overflowing_div
);
568 if !oflo { Ok(const_int(ret)) }
else { signal!(e, DivideWithOverflow) }
571 pub fn const_int_checked_rem
<'a
>(
572 a
: i64, b
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
573 if b
== 0 { signal!(e, ModuloByZero); }
574 let (ret
, oflo
) = int_arith_body
!(a
, b
, opt_ety
, overflowing_rem
);
575 if !oflo { Ok(const_int(ret)) }
else { signal!(e, ModuloWithOverflow) }
578 pub_fn_checked_op
!{ const_int_checked_shl(a
: i64, b
: i64,.. IntTy
) {
579 int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
582 pub_fn_checked_op
!{ const_int_checked_shl_via_uint(a
: i64, b
: u64,.. IntTy
) {
583 int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
586 pub_fn_checked_op
!{ const_int_checked_shr(a
: i64, b
: i64,.. IntTy
) {
587 int_shift_body overflowing_shr const_int ShiftRightWithOverflow
590 pub_fn_checked_op
!{ const_int_checked_shr_via_uint(a
: i64, b
: u64,.. IntTy
) {
591 int_shift_body overflowing_shr const_int ShiftRightWithOverflow
594 pub_fn_checked_op
!{ const_uint_checked_add(a
: u64, b
: u64,.. UintTy
) {
595 uint_arith_body overflowing_add const_uint
AdduWithOverflow(a
, b
)
598 pub_fn_checked_op
!{ const_uint_checked_sub(a
: u64, b
: u64,.. UintTy
) {
599 uint_arith_body overflowing_sub const_uint
SubuWithOverflow(a
, b
)
602 pub_fn_checked_op
!{ const_uint_checked_mul(a
: u64, b
: u64,.. UintTy
) {
603 uint_arith_body overflowing_mul const_uint
MuluWithOverflow(a
, b
)
606 pub fn const_uint_checked_div
<'a
>(
607 a
: u64, b
: u64, e
: &'a Expr
, opt_ety
: Option
<UintTy
>) -> EvalResult
{
608 if b
== 0 { signal!(e, DivideByZero); }
609 let (ret
, oflo
) = uint_arith_body
!(a
, b
, opt_ety
, overflowing_div
);
610 if !oflo { Ok(const_uint(ret)) }
else { signal!(e, DivideWithOverflow) }
613 pub fn const_uint_checked_rem
<'a
>(
614 a
: u64, b
: u64, e
: &'a Expr
, opt_ety
: Option
<UintTy
>) -> EvalResult
{
615 if b
== 0 { signal!(e, ModuloByZero); }
616 let (ret
, oflo
) = uint_arith_body
!(a
, b
, opt_ety
, overflowing_rem
);
617 if !oflo { Ok(const_uint(ret)) }
else { signal!(e, ModuloWithOverflow) }
620 pub_fn_checked_op
!{ const_uint_checked_shl(a
: u64, b
: u64,.. UintTy
) {
621 uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
624 pub_fn_checked_op
!{ const_uint_checked_shl_via_int(a
: u64, b
: i64,.. UintTy
) {
625 uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
628 pub_fn_checked_op
!{ const_uint_checked_shr(a
: u64, b
: u64,.. UintTy
) {
629 uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
632 pub_fn_checked_op
!{ const_uint_checked_shr_via_int(a
: u64, b
: i64,.. UintTy
) {
633 uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
636 pub fn eval_const_expr_partial
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>,
638 ty_hint
: Option
<Ty
<'tcx
>>) -> EvalResult
{
639 fn fromb(b
: bool
) -> const_val { const_int(b as i64) }
641 let ety
= ty_hint
.or_else(|| ty
::expr_ty_opt(tcx
, e
));
643 // If type of expression itself is int or uint, normalize in these
644 // bindings so that isize/usize is mapped to a type with an
645 // inherently known bitwidth.
646 let expr_int_type
= ety
.and_then(|ty
| {
647 if let ty
::ty_int(t
) = ty
.sty
{
648 Some(IntTy
::from(tcx
, t
)) } else { None }
650 let expr_uint_type
= ety
.and_then(|ty
| {
651 if let ty
::ty_uint(t
) = ty
.sty
{
652 Some(UintTy
::from(tcx
, t
)) } else { None }
655 let result
= match e
.node
{
656 ast
::ExprUnary(ast
::UnNeg
, ref inner
) => {
657 match try
!(eval_const_expr_partial(tcx
, &**inner
, ety
)) {
658 const_float(f
) => const_float(-f
),
659 const_int(n
) => try
!(const_int_checked_neg(n
, e
, expr_int_type
)),
661 if !tcx
.sess
.features
.borrow().negate_unsigned
{
662 feature_gate
::emit_feature_err(
663 &tcx
.sess
.parse_sess
.span_diagnostic
,
666 "unary negation of unsigned integers may be removed in the future");
668 try
!(const_uint_checked_neg(i
, e
, expr_uint_type
))
670 const_str(_
) => signal
!(e
, NegateOnString
),
671 const_bool(_
) => signal
!(e
, NegateOnBoolean
),
672 const_binary(_
) => signal
!(e
, NegateOnBinary
),
673 const_val
::Tuple(_
) => signal
!(e
, NegateOnTuple
),
674 const_val
::Struct(..) => signal
!(e
, NegateOnStruct
),
677 ast
::ExprUnary(ast
::UnNot
, ref inner
) => {
678 match try
!(eval_const_expr_partial(tcx
, &**inner
, ety
)) {
679 const_int(i
) => const_int(!i
),
680 const_uint(i
) => const_uint(!i
),
681 const_bool(b
) => const_bool(!b
),
682 const_str(_
) => signal
!(e
, NotOnString
),
683 const_float(_
) => signal
!(e
, NotOnFloat
),
684 const_binary(_
) => signal
!(e
, NotOnBinary
),
685 const_val
::Tuple(_
) => signal
!(e
, NotOnTuple
),
686 const_val
::Struct(..) => signal
!(e
, NotOnStruct
),
689 ast
::ExprBinary(op
, ref a
, ref b
) => {
690 let b_ty
= match op
.node
{
691 ast
::BiShl
| ast
::BiShr
=> Some(tcx
.types
.usize),
694 match (try
!(eval_const_expr_partial(tcx
, &**a
, ety
)),
695 try
!(eval_const_expr_partial(tcx
, &**b
, b_ty
))) {
696 (const_float(a
), const_float(b
)) => {
698 ast
::BiAdd
=> const_float(a
+ b
),
699 ast
::BiSub
=> const_float(a
- b
),
700 ast
::BiMul
=> const_float(a
* b
),
701 ast
::BiDiv
=> const_float(a
/ b
),
702 ast
::BiRem
=> const_float(a
% b
),
703 ast
::BiEq
=> fromb(a
== b
),
704 ast
::BiLt
=> fromb(a
< b
),
705 ast
::BiLe
=> fromb(a
<= b
),
706 ast
::BiNe
=> fromb(a
!= b
),
707 ast
::BiGe
=> fromb(a
>= b
),
708 ast
::BiGt
=> fromb(a
> b
),
709 _
=> signal
!(e
, InvalidOpForFloats(op
.node
))
712 (const_int(a
), const_int(b
)) => {
714 ast
::BiAdd
=> try
!(const_int_checked_add(a
,b
,e
,expr_int_type
)),
715 ast
::BiSub
=> try
!(const_int_checked_sub(a
,b
,e
,expr_int_type
)),
716 ast
::BiMul
=> try
!(const_int_checked_mul(a
,b
,e
,expr_int_type
)),
717 ast
::BiDiv
=> try
!(const_int_checked_div(a
,b
,e
,expr_int_type
)),
718 ast
::BiRem
=> try
!(const_int_checked_rem(a
,b
,e
,expr_int_type
)),
719 ast
::BiAnd
| ast
::BiBitAnd
=> const_int(a
& b
),
720 ast
::BiOr
| ast
::BiBitOr
=> const_int(a
| b
),
721 ast
::BiBitXor
=> const_int(a ^ b
),
722 ast
::BiShl
=> try
!(const_int_checked_shl(a
,b
,e
,expr_int_type
)),
723 ast
::BiShr
=> try
!(const_int_checked_shr(a
,b
,e
,expr_int_type
)),
724 ast
::BiEq
=> fromb(a
== b
),
725 ast
::BiLt
=> fromb(a
< b
),
726 ast
::BiLe
=> fromb(a
<= b
),
727 ast
::BiNe
=> fromb(a
!= b
),
728 ast
::BiGe
=> fromb(a
>= b
),
729 ast
::BiGt
=> fromb(a
> b
)
732 (const_uint(a
), const_uint(b
)) => {
734 ast
::BiAdd
=> try
!(const_uint_checked_add(a
,b
,e
,expr_uint_type
)),
735 ast
::BiSub
=> try
!(const_uint_checked_sub(a
,b
,e
,expr_uint_type
)),
736 ast
::BiMul
=> try
!(const_uint_checked_mul(a
,b
,e
,expr_uint_type
)),
737 ast
::BiDiv
=> try
!(const_uint_checked_div(a
,b
,e
,expr_uint_type
)),
738 ast
::BiRem
=> try
!(const_uint_checked_rem(a
,b
,e
,expr_uint_type
)),
739 ast
::BiAnd
| ast
::BiBitAnd
=> const_uint(a
& b
),
740 ast
::BiOr
| ast
::BiBitOr
=> const_uint(a
| b
),
741 ast
::BiBitXor
=> const_uint(a ^ b
),
742 ast
::BiShl
=> try
!(const_uint_checked_shl(a
,b
,e
,expr_uint_type
)),
743 ast
::BiShr
=> try
!(const_uint_checked_shr(a
,b
,e
,expr_uint_type
)),
744 ast
::BiEq
=> fromb(a
== b
),
745 ast
::BiLt
=> fromb(a
< b
),
746 ast
::BiLe
=> fromb(a
<= b
),
747 ast
::BiNe
=> fromb(a
!= b
),
748 ast
::BiGe
=> fromb(a
>= b
),
749 ast
::BiGt
=> fromb(a
> b
),
752 // shifts can have any integral type as their rhs
753 (const_int(a
), const_uint(b
)) => {
755 ast
::BiShl
=> try
!(const_int_checked_shl_via_uint(a
,b
,e
,expr_int_type
)),
756 ast
::BiShr
=> try
!(const_int_checked_shr_via_uint(a
,b
,e
,expr_int_type
)),
757 _
=> signal
!(e
, InvalidOpForIntUint(op
.node
)),
760 (const_uint(a
), const_int(b
)) => {
762 ast
::BiShl
=> try
!(const_uint_checked_shl_via_int(a
,b
,e
,expr_uint_type
)),
763 ast
::BiShr
=> try
!(const_uint_checked_shr_via_int(a
,b
,e
,expr_uint_type
)),
764 _
=> signal
!(e
, InvalidOpForUintInt(op
.node
)),
767 (const_bool(a
), const_bool(b
)) => {
768 const_bool(match op
.node
{
769 ast
::BiAnd
=> a
&& b
,
771 ast
::BiBitXor
=> a ^ b
,
772 ast
::BiBitAnd
=> a
& b
,
773 ast
::BiBitOr
=> a
| b
,
776 _
=> signal
!(e
, InvalidOpForBools(op
.node
)),
780 _
=> signal
!(e
, MiscBinaryOp
),
783 ast
::ExprCast(ref base
, ref target_ty
) => {
784 // This tends to get called w/o the type actually having been
785 // populated in the ctxt, which was causing things to blow up
786 // (#5900). Fall back to doing a limited lookup to get past it.
787 let ety
= ety
.or_else(|| ast_ty_to_prim_ty(tcx
, &**target_ty
))
789 tcx
.sess
.span_fatal(target_ty
.span
,
790 "target type not found for const cast")
793 // Prefer known type to noop, but always have a type hint.
795 // FIXME (#23833): the type-hint can cause problems,
796 // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
797 // type to the sum, and thus no overflow is signaled.
798 let base_hint
= ty
::expr_ty_opt(tcx
, &**base
).unwrap_or(ety
);
799 let val
= try
!(eval_const_expr_partial(tcx
, &**base
, Some(base_hint
)));
800 match cast_const(tcx
, val
, ety
) {
802 Err(kind
) => return Err(ConstEvalErr { span: e.span, kind: kind }
),
805 ast
::ExprPath(..) => {
806 let opt_def
= tcx
.def_map
.borrow().get(&e
.id
).map(|d
| d
.full_def());
807 let (const_expr
, const_ty
) = match opt_def
{
808 Some(def
::DefConst(def_id
)) => {
809 if ast_util
::is_local(def_id
) {
810 match tcx
.map
.find(def_id
.node
) {
811 Some(ast_map
::NodeItem(it
)) => match it
.node
{
812 ast
::ItemConst(ref ty
, ref expr
) => {
813 (Some(&**expr
), Some(&**ty
))
820 (lookup_const_by_id(tcx
, def_id
, Some(e
.id
)), None
)
823 Some(def
::DefAssociatedConst(def_id
, provenance
)) => {
824 if ast_util
::is_local(def_id
) {
826 def
::FromTrait(trait_id
) => match tcx
.map
.find(def_id
.node
) {
827 Some(ast_map
::NodeTraitItem(ti
)) => match ti
.node
{
828 ast
::ConstTraitItem(ref ty
, _
) => {
829 (resolve_trait_associated_const(tcx
, ti
,
837 def
::FromImpl(_
) => match tcx
.map
.find(def_id
.node
) {
838 Some(ast_map
::NodeImplItem(ii
)) => match ii
.node
{
839 ast
::ConstImplItem(ref ty
, ref expr
) => {
840 (Some(&**expr
), Some(&**ty
))
848 (lookup_const_by_id(tcx
, def_id
, Some(e
.id
)), None
)
851 Some(def
::DefVariant(enum_def
, variant_def
, _
)) => {
852 (lookup_variant_by_id(tcx
, enum_def
, variant_def
), None
)
856 let const_expr
= match const_expr
{
857 Some(actual_e
) => actual_e
,
858 None
=> signal
!(e
, NonConstPath
)
860 let ety
= ety
.or_else(|| const_ty
.and_then(|ty
| ast_ty_to_prim_ty(tcx
, ty
)));
861 try
!(eval_const_expr_partial(tcx
, const_expr
, ety
))
863 ast
::ExprLit(ref lit
) => {
864 lit_to_const(&**lit
, ety
)
866 ast
::ExprParen(ref e
) => try
!(eval_const_expr_partial(tcx
, &**e
, ety
)),
867 ast
::ExprBlock(ref block
) => {
869 Some(ref expr
) => try
!(eval_const_expr_partial(tcx
, &**expr
, ety
)),
874 const_val
::Tuple(e
.id
)
876 ast
::ExprStruct(..) => {
877 const_val
::Struct(e
.id
)
879 ast
::ExprTupField(ref base
, index
) => {
880 if let Ok(c
) = eval_const_expr_partial(tcx
, base
, None
) {
881 if let const_val
::Tuple(tup_id
) = c
{
882 if let ast
::ExprTup(ref fields
) = tcx
.map
.expect_expr(tup_id
).node
{
883 if index
.node
< fields
.len() {
884 return eval_const_expr_partial(tcx
, &fields
[index
.node
], None
)
886 signal
!(e
, TupleIndexOutOfBounds
);
892 signal
!(base
, ExpectedConstTuple
);
895 signal
!(base
, NonConstPath
)
898 ast
::ExprField(ref base
, field_name
) => {
899 // Get the base expression if it is a struct and it is constant
900 if let Ok(c
) = eval_const_expr_partial(tcx
, base
, None
) {
901 if let const_val
::Struct(struct_id
) = c
{
902 if let ast
::ExprStruct(_
, ref fields
, _
) = tcx
.map
.expect_expr(struct_id
).node
{
903 // Check that the given field exists and evaluate it
904 if let Some(f
) = fields
.iter().find(|f
| f
.ident
.node
.as_str()
905 == field_name
.node
.as_str()) {
906 return eval_const_expr_partial(tcx
, &*f
.expr
, None
)
908 signal
!(e
, MissingStructField
);
914 signal
!(base
, ExpectedConstStruct
);
917 signal
!(base
, NonConstPath
);
920 _
=> signal
!(e
, MiscCatchAll
)
926 fn resolve_trait_associated_const
<'a
, 'tcx
: 'a
>(tcx
: &'a ty
::ctxt
<'tcx
>,
927 ti
: &'tcx ast
::TraitItem
,
928 trait_id
: ast
::DefId
,
930 -> Option
<&'tcx Expr
>
932 let rcvr_substs
= ty
::node_id_item_substs(tcx
, ref_id
).substs
;
933 let subst
::SeparateVecsPerParamSpace
{
937 } = rcvr_substs
.types
.split();
939 subst
::Substs
::erased(subst
::VecPerParamSpace
::new(rcvr_type
,
942 let trait_substs
= tcx
.mk_substs(trait_substs
);
943 debug
!("resolve_trait_associated_const: trait_substs={}",
944 trait_substs
.repr(tcx
));
945 let trait_ref
= ty
::Binder(ty
::TraitRef
{ def_id
: trait_id
,
946 substs
: trait_substs
});
948 ty
::populate_implementations_for_trait_if_necessary(tcx
, trait_ref
.def_id());
949 let infcx
= infer
::new_infer_ctxt(tcx
);
951 let param_env
= ty
::empty_parameter_environment(tcx
);
952 let mut selcx
= traits
::SelectionContext
::new(&infcx
, ¶m_env
);
953 let obligation
= traits
::Obligation
::new(traits
::ObligationCause
::dummy(),
954 trait_ref
.to_poly_trait_predicate());
955 let selection
= match selcx
.select(&obligation
) {
956 Ok(Some(vtable
)) => vtable
,
957 // Still ambiguous, so give up and let the caller decide whether this
958 // expression is really needed yet. Some associated constant values
959 // can't be evaluated until monomorphization is done in trans.
964 tcx
.sess
.span_bug(ti
.span
,
965 &format
!("Encountered error `{}` when trying \
966 to select an implementation for \
967 constant trait item reference.",
973 traits
::VtableImpl(ref impl_data
) => {
974 match ty
::associated_consts(tcx
, impl_data
.impl_def_id
)
975 .iter().find(|ic
| ic
.name
== ti
.ident
.name
) {
976 Some(ic
) => lookup_const_by_id(tcx
, ic
.def_id
, None
),
977 None
=> match ti
.node
{
978 ast
::ConstTraitItem(_
, Some(ref expr
)) => Some(&*expr
),
986 &format
!("resolve_trait_associated_const: unexpected vtable type"))
991 fn cast_const
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>, val
: const_val
, ty
: Ty
) -> CastResult
{
992 macro_rules
! convert_val
{
993 ($intermediate_ty
:ty
, $const_type
:ident
, $target_ty
:ty
) => {
995 const_bool(b
) => Ok($
const_type(b
as $intermediate_ty
as $target_ty
)),
996 const_uint(u
) => Ok($
const_type(u
as $intermediate_ty
as $target_ty
)),
997 const_int(i
) => Ok($
const_type(i
as $intermediate_ty
as $target_ty
)),
998 const_float(f
) => Ok($
const_type(f
as $intermediate_ty
as $target_ty
)),
999 _
=> Err(ErrKind
::CannotCastTo(stringify
!($const_type
))),
1004 // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
1005 match (&ty
.sty
, tcx
.sess
.target
.int_type
, tcx
.sess
.target
.uint_type
) {
1006 (&ty
::ty_int(ast
::TyIs
), ast
::TyI32
, _
) => return convert_val
!(i32, const_int
, i64),
1007 (&ty
::ty_int(ast
::TyIs
), ast
::TyI64
, _
) => return convert_val
!(i64, const_int
, i64),
1008 (&ty
::ty_int(ast
::TyIs
), _
, _
) => panic
!("unexpected target.int_type"),
1010 (&ty
::ty_uint(ast
::TyUs
), _
, ast
::TyU32
) => return convert_val
!(u32, const_uint
, u64),
1011 (&ty
::ty_uint(ast
::TyUs
), _
, ast
::TyU64
) => return convert_val
!(u64, const_uint
, u64),
1012 (&ty
::ty_uint(ast
::TyUs
), _
, _
) => panic
!("unexpected target.uint_type"),
1018 ty
::ty_int(ast
::TyIs
) => unreachable
!(),
1019 ty
::ty_uint(ast
::TyUs
) => unreachable
!(),
1021 ty
::ty_int(ast
::TyI8
) => convert_val
!(i8, const_int
, i64),
1022 ty
::ty_int(ast
::TyI16
) => convert_val
!(i16, const_int
, i64),
1023 ty
::ty_int(ast
::TyI32
) => convert_val
!(i32, const_int
, i64),
1024 ty
::ty_int(ast
::TyI64
) => convert_val
!(i64, const_int
, i64),
1026 ty
::ty_uint(ast
::TyU8
) => convert_val
!(u8, const_uint
, u64),
1027 ty
::ty_uint(ast
::TyU16
) => convert_val
!(u16, const_uint
, u64),
1028 ty
::ty_uint(ast
::TyU32
) => convert_val
!(u32, const_uint
, u64),
1029 ty
::ty_uint(ast
::TyU64
) => convert_val
!(u64, const_uint
, u64),
1031 ty
::ty_float(ast
::TyF32
) => convert_val
!(f32, const_float
, f64),
1032 ty
::ty_float(ast
::TyF64
) => convert_val
!(f64, const_float
, f64),
1033 _
=> Err(ErrKind
::CannotCast
),
1037 fn lit_to_const(lit
: &ast
::Lit
, ty_hint
: Option
<Ty
>) -> const_val
{
1039 ast
::LitStr(ref s
, _
) => const_str((*s
).clone()),
1040 ast
::LitBinary(ref data
) => {
1041 const_binary(data
.clone())
1043 ast
::LitByte(n
) => const_uint(n
as u64),
1044 ast
::LitChar(n
) => const_uint(n
as u64),
1045 ast
::LitInt(n
, ast
::SignedIntLit(_
, ast
::Plus
)) => const_int(n
as i64),
1046 ast
::LitInt(n
, ast
::UnsuffixedIntLit(ast
::Plus
)) => {
1047 match ty_hint
.map(|ty
| &ty
.sty
) {
1048 Some(&ty
::ty_uint(_
)) => const_uint(n
),
1049 _
=> const_int(n
as i64)
1052 ast
::LitInt(n
, ast
::SignedIntLit(_
, ast
::Minus
)) |
1053 ast
::LitInt(n
, ast
::UnsuffixedIntLit(ast
::Minus
)) => const_int(-(n
as i64)),
1054 ast
::LitInt(n
, ast
::UnsignedIntLit(_
)) => const_uint(n
),
1055 ast
::LitFloat(ref n
, _
) |
1056 ast
::LitFloatUnsuffixed(ref n
) => {
1057 const_float(n
.parse
::<f64>().unwrap() as f64)
1059 ast
::LitBool(b
) => const_bool(b
)
1063 pub fn compare_const_vals(a
: &const_val
, b
: &const_val
) -> Option
<Ordering
> {
1065 (&const_int(a
), &const_int(b
)) => a
.cmp(&b
),
1066 (&const_uint(a
), &const_uint(b
)) => a
.cmp(&b
),
1067 (&const_float(a
), &const_float(b
)) => {
1068 // This is pretty bad but it is the existing behavior.
1077 (&const_str(ref a
), &const_str(ref b
)) => a
.cmp(b
),
1078 (&const_bool(a
), &const_bool(b
)) => a
.cmp(&b
),
1079 (&const_binary(ref a
), &const_binary(ref b
)) => a
.cmp(b
),
1084 pub fn compare_lit_exprs
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>,
1087 ty_hint
: Option
<Ty
<'tcx
>>)
1088 -> Option
<Ordering
> {
1089 let a
= match eval_const_expr_partial(tcx
, a
, ty_hint
) {
1092 tcx
.sess
.span_err(a
.span
, &e
.description());
1096 let b
= match eval_const_expr_partial(tcx
, b
, ty_hint
) {
1099 tcx
.sess
.span_err(b
.span
, &e
.description());
1103 compare_const_vals(&a
, &b
)