1 // Copyright 2012-2015 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)]
13 use self::ConstVal
::*;
15 use self::EvalHint
::*;
17 use front
::map
as ast_map
;
18 use front
::map
::blocks
::FnLikeNode
;
19 use middle
::cstore
::{self, CrateStore, InlinedItem}
;
20 use middle
::{infer, subst, traits}
;
22 use middle
::subst
::Subst
;
23 use middle
::def_id
::DefId
;
24 use middle
::pat_util
::def_to_path
;
25 use middle
::ty
::{self, Ty}
;
26 use middle
::astconv_util
::ast_ty_to_prim_ty
;
27 use util
::num
::ToPrimitive
;
28 use util
::nodemap
::NodeMap
;
31 use graphviz
::IntoCow
;
33 use rustc_front
::hir
::{Expr, PatKind}
;
35 use rustc_front
::intravisit
::FnKind
;
36 use syntax
::codemap
::Span
;
37 use syntax
::parse
::token
::InternedString
;
42 use std
::cmp
::Ordering
;
43 use std
::collections
::hash_map
::Entry
::Vacant
;
45 use std
::mem
::transmute
;
46 use std
::{i8, i16, i32, i64, u8, u16, u32, u64}
;
49 fn lookup_variant_by_id
<'a
>(tcx
: &'a ty
::ctxt
,
53 fn variant_expr
<'a
>(variants
: &'a
[hir
::Variant
], id
: ast
::NodeId
)
55 for variant
in variants
{
56 if variant
.node
.data
.id() == id
{
57 return variant
.node
.disr_expr
.as_ref().map(|e
| &**e
);
63 if let Some(enum_node_id
) = tcx
.map
.as_local_node_id(enum_def
) {
64 let variant_node_id
= tcx
.map
.as_local_node_id(variant_def
).unwrap();
65 match tcx
.map
.find(enum_node_id
) {
67 Some(ast_map
::NodeItem(it
)) => match it
.node
{
68 hir
::ItemEnum(hir
::EnumDef { ref variants }
, _
) => {
69 variant_expr(variants
, variant_node_id
)
80 /// * `def_id` is the id of the constant.
81 /// * `maybe_ref_id` is the id of the expr referencing the constant.
82 /// * `param_substs` is the monomorphization substitution for the expression.
84 /// `maybe_ref_id` and `param_substs` are optional and are used for
85 /// finding substitutions in associated constants. This generally
86 /// happens in late/trans const evaluation.
87 pub fn lookup_const_by_id
<'a
, 'tcx
: 'a
>(tcx
: &'a ty
::ctxt
<'tcx
>,
89 maybe_ref_id
: Option
<ast
::NodeId
>,
90 param_substs
: Option
<&'tcx subst
::Substs
<'tcx
>>)
91 -> Option
<&'tcx Expr
> {
92 if let Some(node_id
) = tcx
.map
.as_local_node_id(def_id
) {
93 match tcx
.map
.find(node_id
) {
95 Some(ast_map
::NodeItem(it
)) => match it
.node
{
96 hir
::ItemConst(_
, ref const_expr
) => {
101 Some(ast_map
::NodeTraitItem(ti
)) => match ti
.node
{
102 hir
::ConstTraitItem(_
, _
) => {
104 // If we have a trait item, and we know the expression
105 // that's the source of the obligation to resolve it,
106 // `resolve_trait_associated_const` will select an impl
109 let trait_id
= tcx
.trait_of_item(def_id
)
111 let mut substs
= tcx
.node_id_item_substs(ref_id
)
113 if let Some(param_substs
) = param_substs
{
114 substs
= substs
.subst(tcx
, param_substs
);
116 resolve_trait_associated_const(tcx
, ti
, trait_id
,
119 // Technically, without knowing anything about the
120 // expression that generates the obligation, we could
121 // still return the default if there is one. However,
122 // it's safer to return `None` than to return some value
123 // that may differ from what you would get from
124 // correctly selecting an impl.
130 Some(ast_map
::NodeImplItem(ii
)) => match ii
.node
{
131 hir
::ImplItemKind
::Const(_
, ref expr
) => {
139 match tcx
.extern_const_statics
.borrow().get(&def_id
) {
140 Some(&ast
::DUMMY_NODE_ID
) => return None
,
142 return Some(tcx
.map
.expect_expr(expr_id
));
146 let mut used_ref_id
= false;
147 let expr_id
= match tcx
.sess
.cstore
.maybe_get_item_ast(tcx
, def_id
) {
148 cstore
::FoundAst
::Found(&InlinedItem
::Item(ref item
)) => match item
.node
{
149 hir
::ItemConst(_
, ref const_expr
) => Some(const_expr
.id
),
152 cstore
::FoundAst
::Found(&InlinedItem
::TraitItem(trait_id
, ref ti
)) => match ti
.node
{
153 hir
::ConstTraitItem(_
, _
) => {
156 // As mentioned in the comments above for in-crate
157 // constants, we only try to find the expression for
158 // a trait-associated const if the caller gives us
159 // the expression that refers to it.
161 let mut substs
= tcx
.node_id_item_substs(ref_id
)
163 if let Some(param_substs
) = param_substs
{
164 substs
= substs
.subst(tcx
, param_substs
);
166 resolve_trait_associated_const(tcx
, ti
, trait_id
,
167 substs
).map(|e
| e
.id
)
174 cstore
::FoundAst
::Found(&InlinedItem
::ImplItem(_
, ref ii
)) => match ii
.node
{
175 hir
::ImplItemKind
::Const(_
, ref expr
) => Some(expr
.id
),
180 // If we used the reference expression, particularly to choose an impl
181 // of a trait-associated const, don't cache that, because the next
182 // lookup with the same def_id may yield a different result.
184 tcx
.extern_const_statics
185 .borrow_mut().insert(def_id
,
186 expr_id
.unwrap_or(ast
::DUMMY_NODE_ID
));
188 expr_id
.map(|id
| tcx
.map
.expect_expr(id
))
192 fn inline_const_fn_from_external_crate(tcx
: &ty
::ctxt
, def_id
: DefId
)
193 -> Option
<ast
::NodeId
> {
194 match tcx
.extern_const_fns
.borrow().get(&def_id
) {
195 Some(&ast
::DUMMY_NODE_ID
) => return None
,
196 Some(&fn_id
) => return Some(fn_id
),
200 if !tcx
.sess
.cstore
.is_const_fn(def_id
) {
201 tcx
.extern_const_fns
.borrow_mut().insert(def_id
, ast
::DUMMY_NODE_ID
);
205 let fn_id
= match tcx
.sess
.cstore
.maybe_get_item_ast(tcx
, def_id
) {
206 cstore
::FoundAst
::Found(&InlinedItem
::Item(ref item
)) => Some(item
.id
),
207 cstore
::FoundAst
::Found(&InlinedItem
::ImplItem(_
, ref item
)) => Some(item
.id
),
210 tcx
.extern_const_fns
.borrow_mut().insert(def_id
,
211 fn_id
.unwrap_or(ast
::DUMMY_NODE_ID
));
215 pub fn lookup_const_fn_by_id
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>, def_id
: DefId
)
216 -> Option
<FnLikeNode
<'tcx
>>
218 let fn_id
= if let Some(node_id
) = tcx
.map
.as_local_node_id(def_id
) {
221 if let Some(fn_id
) = inline_const_fn_from_external_crate(tcx
, def_id
) {
228 let fn_like
= match FnLikeNode
::from_node(tcx
.map
.get(fn_id
)) {
229 Some(fn_like
) => fn_like
,
233 match fn_like
.kind() {
234 FnKind
::ItemFn(_
, _
, _
, hir
::Constness
::Const
, _
, _
) => {
237 FnKind
::Method(_
, m
, _
) => {
238 if m
.constness
== hir
::Constness
::Const
{
248 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
254 ByteStr(Rc
<Vec
<u8>>),
259 Array(ast
::NodeId
, u64),
260 Repeat(ast
::NodeId
, u64),
263 impl hash
::Hash
for ConstVal
{
264 fn hash
<H
: hash
::Hasher
>(&self, state
: &mut H
) {
266 Float(a
) => unsafe { transmute::<_,u64>(a) }
.hash(state
),
267 Int(a
) => a
.hash(state
),
268 Uint(a
) => a
.hash(state
),
269 Str(ref a
) => a
.hash(state
),
270 ByteStr(ref a
) => a
.hash(state
),
271 Bool(a
) => a
.hash(state
),
272 Struct(a
) => a
.hash(state
),
273 Tuple(a
) => a
.hash(state
),
274 Function(a
) => a
.hash(state
),
275 Array(a
, n
) => { a.hash(state); n.hash(state) }
,
276 Repeat(a
, n
) => { a.hash(state); n.hash(state) }
,
281 /// Note that equality for `ConstVal` means that the it is the same
282 /// constant, not that the rust values are equal. In particular, `NaN
283 /// == NaN` (at least if it's the same NaN; distinct encodings for NaN
284 /// are considering unequal).
285 impl PartialEq
for ConstVal
{
286 fn eq(&self, other
: &ConstVal
) -> bool
{
287 match (self, other
) {
288 (&Float(a
), &Float(b
)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
,
289 (&Int(a
), &Int(b
)) => a
== b
,
290 (&Uint(a
), &Uint(b
)) => a
== b
,
291 (&Str(ref a
), &Str(ref b
)) => a
== b
,
292 (&ByteStr(ref a
), &ByteStr(ref b
)) => a
== b
,
293 (&Bool(a
), &Bool(b
)) => a
== b
,
294 (&Struct(a
), &Struct(b
)) => a
== b
,
295 (&Tuple(a
), &Tuple(b
)) => a
== b
,
296 (&Function(a
), &Function(b
)) => a
== b
,
297 (&Array(a
, an
), &Array(b
, bn
)) => (a
== b
) && (an
== bn
),
298 (&Repeat(a
, an
), &Repeat(b
, bn
)) => (a
== b
) && (an
== bn
),
304 impl Eq
for ConstVal { }
307 pub fn description(&self) -> &'
static str {
310 Int(i
) if i
< 0 => "negative integer",
311 Int(_
) => "positive integer",
312 Uint(_
) => "unsigned integer",
313 Str(_
) => "string literal",
314 ByteStr(_
) => "byte string literal",
315 Bool(_
) => "boolean",
316 Struct(_
) => "struct",
318 Function(_
) => "function definition",
319 Array(..) => "array",
320 Repeat(..) => "repeat",
325 pub fn const_expr_to_pat(tcx
: &ty
::ctxt
, expr
: &Expr
, span
: Span
) -> P
<hir
::Pat
> {
326 let pat
= match expr
.node
{
327 hir
::ExprTup(ref exprs
) =>
328 PatKind
::Tup(exprs
.iter().map(|expr
| const_expr_to_pat(tcx
, &expr
, span
)).collect()),
330 hir
::ExprCall(ref callee
, ref args
) => {
331 let def
= *tcx
.def_map
.borrow().get(&callee
.id
).unwrap();
332 if let Vacant(entry
) = tcx
.def_map
.borrow_mut().entry(expr
.id
) {
335 let path
= match def
.full_def() {
336 Def
::Struct(def_id
) => def_to_path(tcx
, def_id
),
337 Def
::Variant(_
, variant_did
) => def_to_path(tcx
, variant_did
),
338 Def
::Fn(..) => return P(hir
::Pat
{
340 node
: PatKind
::Lit(P(expr
.clone())),
345 let pats
= args
.iter().map(|expr
| const_expr_to_pat(tcx
, &expr
, span
)).collect();
346 PatKind
::TupleStruct(path
, Some(pats
))
349 hir
::ExprStruct(ref path
, ref fields
, None
) => {
350 let field_pats
= fields
.iter().map(|field
| codemap
::Spanned
{
351 span
: codemap
::DUMMY_SP
,
352 node
: hir
::FieldPat
{
353 name
: field
.name
.node
,
354 pat
: const_expr_to_pat(tcx
, &field
.expr
, span
),
358 PatKind
::Struct(path
.clone(), field_pats
, false)
361 hir
::ExprVec(ref exprs
) => {
362 let pats
= exprs
.iter().map(|expr
| const_expr_to_pat(tcx
, &expr
, span
)).collect();
363 PatKind
::Vec(pats
, None
, hir
::HirVec
::new())
366 hir
::ExprPath(_
, ref path
) => {
367 let opt_def
= tcx
.def_map
.borrow().get(&expr
.id
).map(|d
| d
.full_def());
369 Some(Def
::Struct(..)) | Some(Def
::Variant(..)) =>
370 PatKind
::Path(path
.clone()),
371 Some(Def
::Const(def_id
)) |
372 Some(Def
::AssociatedConst(def_id
)) => {
373 let expr
= lookup_const_by_id(tcx
, def_id
, Some(expr
.id
), None
).unwrap();
374 return const_expr_to_pat(tcx
, expr
, span
);
380 _
=> PatKind
::Lit(P(expr
.clone()))
382 P(hir
::Pat { id: expr.id, node: pat, span: span }
)
385 pub fn eval_const_expr(tcx
: &ty
::ctxt
, e
: &Expr
) -> ConstVal
{
386 match eval_const_expr_partial(tcx
, e
, ExprTypeChecked
, None
) {
388 Err(s
) => tcx
.sess
.span_fatal(s
.span
, &s
.description())
392 pub type FnArgMap
<'a
> = Option
<&'a NodeMap
<ConstVal
>>;
395 pub struct ConstEvalErr
{
403 CannotCastTo(&'
static str),
404 InvalidOpForInts(hir
::BinOp_
),
405 InvalidOpForUInts(hir
::BinOp_
),
406 InvalidOpForBools(hir
::BinOp_
),
407 InvalidOpForFloats(hir
::BinOp_
),
408 InvalidOpForIntUint(hir
::BinOp_
),
409 InvalidOpForUintInt(hir
::BinOp_
),
414 NegateWithOverflow(i64),
415 AddiWithOverflow(i64, i64),
416 SubiWithOverflow(i64, i64),
417 MuliWithOverflow(i64, i64),
418 AdduWithOverflow(u64, u64),
419 SubuWithOverflow(u64, u64),
420 MuluWithOverflow(u64, u64),
425 ShiftLeftWithOverflow
,
426 ShiftRightWithOverflow
,
429 UnimplementedConstVal(&'
static str),
433 TupleIndexOutOfBounds
,
438 RepeatCountNotNatural
,
448 pub fn description(&self) -> Cow
<str> {
449 use self::ErrKind
::*;
452 CannotCast
=> "can't cast this type".into_cow(),
453 CannotCastTo(s
) => format
!("can't cast this type to {}", s
).into_cow(),
454 InvalidOpForInts(_
) => "can't do this op on signed integrals".into_cow(),
455 InvalidOpForUInts(_
) => "can't do this op on unsigned integrals".into_cow(),
456 InvalidOpForBools(_
) => "can't do this op on bools".into_cow(),
457 InvalidOpForFloats(_
) => "can't do this op on floats".into_cow(),
458 InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
459 InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
460 NegateOn(ref const_val
) => format
!("negate on {}", const_val
.description()).into_cow(),
461 NotOn(ref const_val
) => format
!("not on {}", const_val
.description()).into_cow(),
462 CallOn(ref const_val
) => format
!("call on {}", const_val
.description()).into_cow(),
464 NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
465 AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
466 SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
467 MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
468 AdduWithOverflow(..) => "attempted to add with overflow".into_cow(),
469 SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(),
470 MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(),
471 DivideByZero
=> "attempted to divide by zero".into_cow(),
472 DivideWithOverflow
=> "attempted to divide with overflow".into_cow(),
473 ModuloByZero
=> "attempted remainder with a divisor of zero".into_cow(),
474 ModuloWithOverflow
=> "attempted remainder with overflow".into_cow(),
475 ShiftLeftWithOverflow
=> "attempted left shift with overflow".into_cow(),
476 ShiftRightWithOverflow
=> "attempted right shift with overflow".into_cow(),
477 MissingStructField
=> "nonexistent struct field".into_cow(),
478 NonConstPath
=> "non-constant path in constant expression".into_cow(),
479 UnimplementedConstVal(what
) =>
480 format
!("unimplemented constant expression: {}", what
).into_cow(),
481 UnresolvedPath
=> "unresolved path in constant expression".into_cow(),
482 ExpectedConstTuple
=> "expected constant tuple".into_cow(),
483 ExpectedConstStruct
=> "expected constant struct".into_cow(),
484 TupleIndexOutOfBounds
=> "tuple index out of bounds".into_cow(),
485 IndexedNonVec
=> "indexing is only supported for arrays".into_cow(),
486 IndexNegative
=> "indices must be non-negative integers".into_cow(),
487 IndexNotInt
=> "indices must be integers".into_cow(),
488 IndexOutOfBounds
=> "array index out of bounds".into_cow(),
489 RepeatCountNotNatural
=> "repeat count must be a natural number".into_cow(),
490 RepeatCountNotInt
=> "repeat count must be integers".into_cow(),
492 MiscBinaryOp
=> "bad operands for binary".into_cow(),
493 MiscCatchAll
=> "unsupported constant expr".into_cow(),
494 IndexOpFeatureGated
=> "the index operation on const values is unstable".into_cow(),
499 pub type EvalResult
= Result
<ConstVal
, ConstEvalErr
>;
500 pub type CastResult
= Result
<ConstVal
, ErrKind
>;
502 // FIXME: Long-term, this enum should go away: trying to evaluate
503 // an expression which hasn't been type-checked is a recipe for
504 // disaster. That said, it's not clear how to fix ast_ty_to_ty
505 // to avoid the ordering issue.
507 /// Hint to determine how to evaluate constant expressions which
508 /// might not be type-checked.
509 #[derive(Copy, Clone, Debug)]
510 pub enum EvalHint
<'tcx
> {
511 /// We have a type-checked expression.
513 /// We have an expression which hasn't been type-checked, but we have
514 /// an idea of what the type will be because of the context. For example,
515 /// the length of an array is always `usize`. (This is referred to as
516 /// a hint because it isn't guaranteed to be consistent with what
517 /// type-checking would compute.)
518 UncheckedExprHint(Ty
<'tcx
>),
519 /// We have an expression which has not yet been type-checked, and
520 /// and we have no clue what the type will be.
524 impl<'tcx
> EvalHint
<'tcx
> {
525 fn erase_hint(&self) -> EvalHint
<'tcx
> {
527 ExprTypeChecked
=> ExprTypeChecked
,
528 UncheckedExprHint(_
) | UncheckedExprNoHint
=> UncheckedExprNoHint
,
531 fn checked_or(&self, ty
: Ty
<'tcx
>) -> EvalHint
<'tcx
> {
533 ExprTypeChecked
=> ExprTypeChecked
,
534 _
=> UncheckedExprHint(ty
),
539 #[derive(Copy, Clone, PartialEq, Debug)]
540 pub enum IntTy { I8, I16, I32, I64 }
541 #[derive(Copy, Clone, PartialEq, Debug)]
542 pub enum UintTy { U8, U16, U32, U64 }
545 pub fn from(tcx
: &ty
::ctxt
, t
: ast
::IntTy
) -> IntTy
{
546 let t
= if let ast
::IntTy
::Is
= t
{
547 tcx
.sess
.target
.int_type
552 ast
::IntTy
::Is
=> unreachable
!(),
553 ast
::IntTy
::I8
=> IntTy
::I8
,
554 ast
::IntTy
::I16
=> IntTy
::I16
,
555 ast
::IntTy
::I32
=> IntTy
::I32
,
556 ast
::IntTy
::I64
=> IntTy
::I64
,
562 pub fn from(tcx
: &ty
::ctxt
, t
: ast
::UintTy
) -> UintTy
{
563 let t
= if let ast
::UintTy
::Us
= t
{
564 tcx
.sess
.target
.uint_type
569 ast
::UintTy
::Us
=> unreachable
!(),
570 ast
::UintTy
::U8
=> UintTy
::U8
,
571 ast
::UintTy
::U16
=> UintTy
::U16
,
572 ast
::UintTy
::U32
=> UintTy
::U32
,
573 ast
::UintTy
::U64
=> UintTy
::U64
,
578 macro_rules
! signal
{
579 ($e
:expr
, $exn
:expr
) => {
580 return Err(ConstEvalErr { span: $e.span, kind: $exn }
)
584 // The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
585 // of functions catch and signal overflow errors during constant
588 // They all take the operator's arguments (`a` and `b` if binary), the
589 // overall expression (`e`) and, if available, whole expression's
590 // concrete type (`opt_ety`).
592 // If the whole expression's concrete type is None, then this is a
593 // constant evaluation happening before type check (e.g. in the check
594 // to confirm that a pattern range's left-side is not greater than its
595 // right-side). We do not do arithmetic modulo the type's bitwidth in
596 // such a case; we just do 64-bit arithmetic and assume that later
597 // passes will do it again with the type information, and thus do the
598 // overflow checks then.
600 pub fn const_int_checked_neg
<'a
>(
601 a
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
603 let (min
,max
) = match opt_ety
{
604 // (-i8::MIN is itself not an i8, etc, but this is an easy way
605 // to allow literals to pass the check. Of course that does
606 // not work for i64::MIN.)
607 Some(IntTy
::I8
) => (-(i8::MAX
as i64), -(i8::MIN
as i64)),
608 Some(IntTy
::I16
) => (-(i16::MAX
as i64), -(i16::MIN
as i64)),
609 Some(IntTy
::I32
) => (-(i32::MAX
as i64), -(i32::MIN
as i64)),
610 None
| Some(IntTy
::I64
) => (-i64::MAX
, -(i64::MIN
+1)),
613 let oflo
= a
< min
|| a
> max
;
615 signal
!(e
, NegateWithOverflow(a
));
621 pub fn const_uint_checked_neg
<'a
>(
622 a
: u64, _e
: &'a Expr
, _opt_ety
: Option
<UintTy
>) -> EvalResult
{
623 // This always succeeds, and by definition, returns `(!a)+1`.
624 Ok(Uint((!a
).wrapping_add(1)))
627 fn const_uint_not(a
: u64, opt_ety
: Option
<UintTy
>) -> ConstVal
{
628 let mask
= match opt_ety
{
629 Some(UintTy
::U8
) => u8::MAX
as u64,
630 Some(UintTy
::U16
) => u16::MAX
as u64,
631 Some(UintTy
::U32
) => u32::MAX
as u64,
632 None
| Some(UintTy
::U64
) => u64::MAX
,
637 macro_rules
! overflow_checking_body
{
638 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
,
639 lhs
: $to_8_lhs
:ident $to_16_lhs
:ident $to_32_lhs
:ident
,
640 rhs
: $to_8_rhs
:ident $to_16_rhs
:ident $to_32_rhs
:ident $to_64_rhs
:ident
,
641 $EnumTy
:ident $T8
: ident $T16
: ident $T32
: ident $T64
: ident
,
642 $result_type
: ident
) => { {
643 let (a
,b
,opt_ety
) = ($a
,$b
,$ety
);
645 Some($EnumTy
::$T8
) => match (a
.$
to_8_lhs(), b
.$
to_8_rhs()) {
646 (Some(a
), Some(b
)) => {
647 let (a
, oflo
) = a
.$
overflowing_op(b
);
648 (a
as $result_type
, oflo
)
650 (None
, _
) | (_
, None
) => (0, true)
652 Some($EnumTy
::$T16
) => match (a
.$
to_16_lhs(), b
.$
to_16_rhs()) {
653 (Some(a
), Some(b
)) => {
654 let (a
, oflo
) = a
.$
overflowing_op(b
);
655 (a
as $result_type
, oflo
)
657 (None
, _
) | (_
, None
) => (0, true)
659 Some($EnumTy
::$T32
) => match (a
.$
to_32_lhs(), b
.$
to_32_rhs()) {
660 (Some(a
), Some(b
)) => {
661 let (a
, oflo
) = a
.$
overflowing_op(b
);
662 (a
as $result_type
, oflo
)
664 (None
, _
) | (_
, None
) => (0, true)
666 None
| Some($EnumTy
::$T64
) => match b
.$
to_64_rhs() {
667 Some(b
) => a
.$
overflowing_op(b
),
674 macro_rules
! int_arith_body
{
675 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
676 overflow_checking_body
!(
677 $a
, $b
, $ety
, $overflowing_op
,
678 lhs
: to_i8 to_i16 to_i32
,
679 rhs
: to_i8 to_i16 to_i32 to_i64
, IntTy I8 I16 I32 I64
, i64)
683 macro_rules
! uint_arith_body
{
684 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
685 overflow_checking_body
!(
686 $a
, $b
, $ety
, $overflowing_op
,
687 lhs
: to_u8 to_u16 to_u32
,
688 rhs
: to_u8 to_u16 to_u32 to_u64
, UintTy U8 U16 U32 U64
, u64)
692 macro_rules
! int_shift_body
{
693 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
694 overflow_checking_body
!(
695 $a
, $b
, $ety
, $overflowing_op
,
696 lhs
: to_i8 to_i16 to_i32
,
697 rhs
: to_u32 to_u32 to_u32 to_u32
, IntTy I8 I16 I32 I64
, i64)
701 macro_rules
! uint_shift_body
{
702 ($a
:ident
, $b
:ident
, $ety
:ident
, $overflowing_op
:ident
) => {
703 overflow_checking_body
!(
704 $a
, $b
, $ety
, $overflowing_op
,
705 lhs
: to_u8 to_u16 to_u32
,
706 rhs
: to_u32 to_u32 to_u32 to_u32
, UintTy U8 U16 U32 U64
, u64)
710 macro_rules
! pub_fn_checked_op
{
711 {$fn_name
:ident ($a
:ident
: $a_ty
:ty
, $b
:ident
: $b_ty
:ty
,.. $WhichTy
:ident
) {
712 $ret_oflo_body
:ident $overflowing_op
:ident
713 $const_ty
:ident $signal_exn
:expr
715 pub fn $fn_name
<'a
>($a
: $a_ty
,
718 opt_ety
: Option
<$WhichTy
>) -> EvalResult
{
719 let (ret
, oflo
) = $ret_oflo_body
!($a
, $b
, opt_ety
, $overflowing_op
);
720 if !oflo { Ok($const_ty(ret)) }
else { signal!(e, $signal_exn) }
725 pub_fn_checked_op
!{ const_int_checked_add(a
: i64, b
: i64,.. IntTy
) {
726 int_arith_body overflowing_add Int
AddiWithOverflow(a
, b
)
729 pub_fn_checked_op
!{ const_int_checked_sub(a
: i64, b
: i64,.. IntTy
) {
730 int_arith_body overflowing_sub Int
SubiWithOverflow(a
, b
)
733 pub_fn_checked_op
!{ const_int_checked_mul(a
: i64, b
: i64,.. IntTy
) {
734 int_arith_body overflowing_mul Int
MuliWithOverflow(a
, b
)
737 pub fn const_int_checked_div
<'a
>(
738 a
: i64, b
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
739 if b
== 0 { signal!(e, DivideByZero); }
740 let (ret
, oflo
) = int_arith_body
!(a
, b
, opt_ety
, overflowing_div
);
741 if !oflo { Ok(Int(ret)) }
else { signal!(e, DivideWithOverflow) }
744 pub fn const_int_checked_rem
<'a
>(
745 a
: i64, b
: i64, e
: &'a Expr
, opt_ety
: Option
<IntTy
>) -> EvalResult
{
746 if b
== 0 { signal!(e, ModuloByZero); }
747 let (ret
, oflo
) = int_arith_body
!(a
, b
, opt_ety
, overflowing_rem
);
748 if !oflo { Ok(Int(ret)) }
else { signal!(e, ModuloWithOverflow) }
751 pub_fn_checked_op
!{ const_int_checked_shl(a
: i64, b
: i64,.. IntTy
) {
752 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
755 pub_fn_checked_op
!{ const_int_checked_shl_via_uint(a
: i64, b
: u64,.. IntTy
) {
756 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
759 pub_fn_checked_op
!{ const_int_checked_shr(a
: i64, b
: i64,.. IntTy
) {
760 int_shift_body overflowing_shr Int ShiftRightWithOverflow
763 pub_fn_checked_op
!{ const_int_checked_shr_via_uint(a
: i64, b
: u64,.. IntTy
) {
764 int_shift_body overflowing_shr Int ShiftRightWithOverflow
767 pub_fn_checked_op
!{ const_uint_checked_add(a
: u64, b
: u64,.. UintTy
) {
768 uint_arith_body overflowing_add Uint
AdduWithOverflow(a
, b
)
771 pub_fn_checked_op
!{ const_uint_checked_sub(a
: u64, b
: u64,.. UintTy
) {
772 uint_arith_body overflowing_sub Uint
SubuWithOverflow(a
, b
)
775 pub_fn_checked_op
!{ const_uint_checked_mul(a
: u64, b
: u64,.. UintTy
) {
776 uint_arith_body overflowing_mul Uint
MuluWithOverflow(a
, b
)
779 pub fn const_uint_checked_div
<'a
>(
780 a
: u64, b
: u64, e
: &'a Expr
, opt_ety
: Option
<UintTy
>) -> EvalResult
{
781 if b
== 0 { signal!(e, DivideByZero); }
782 let (ret
, oflo
) = uint_arith_body
!(a
, b
, opt_ety
, overflowing_div
);
783 if !oflo { Ok(Uint(ret)) }
else { signal!(e, DivideWithOverflow) }
786 pub fn const_uint_checked_rem
<'a
>(
787 a
: u64, b
: u64, e
: &'a Expr
, opt_ety
: Option
<UintTy
>) -> EvalResult
{
788 if b
== 0 { signal!(e, ModuloByZero); }
789 let (ret
, oflo
) = uint_arith_body
!(a
, b
, opt_ety
, overflowing_rem
);
790 if !oflo { Ok(Uint(ret)) }
else { signal!(e, ModuloWithOverflow) }
793 pub_fn_checked_op
!{ const_uint_checked_shl(a
: u64, b
: u64,.. UintTy
) {
794 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
797 pub_fn_checked_op
!{ const_uint_checked_shl_via_int(a
: u64, b
: i64,.. UintTy
) {
798 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
801 pub_fn_checked_op
!{ const_uint_checked_shr(a
: u64, b
: u64,.. UintTy
) {
802 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
805 pub_fn_checked_op
!{ const_uint_checked_shr_via_int(a
: u64, b
: i64,.. UintTy
) {
806 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
809 /// Evaluate a constant expression in a context where the expression isn't
810 /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
811 /// but a few places need to evaluate constants during type-checking, like
812 /// computing the length of an array. (See also the FIXME above EvalHint.)
813 pub fn eval_const_expr_partial
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>,
815 ty_hint
: EvalHint
<'tcx
>,
816 fn_args
: FnArgMap
) -> EvalResult
{
817 // Try to compute the type of the expression based on the EvalHint.
818 // (See also the definition of EvalHint, and the FIXME above EvalHint.)
819 let ety
= match ty_hint
{
821 // After type-checking, expr_ty is guaranteed to succeed.
824 UncheckedExprHint(ty
) => {
825 // Use the type hint; it's not guaranteed to be right, but it's
826 // usually good enough.
829 UncheckedExprNoHint
=> {
830 // This expression might not be type-checked, and we have no hint.
831 // Try to query the context for a type anyway; we might get lucky
832 // (for example, if the expression was imported from another crate).
837 // If type of expression itself is int or uint, normalize in these
838 // bindings so that isize/usize is mapped to a type with an
839 // inherently known bitwidth.
840 let expr_int_type
= ety
.and_then(|ty
| {
841 if let ty
::TyInt(t
) = ty
.sty
{
842 Some(IntTy
::from(tcx
, t
)) } else { None }
844 let expr_uint_type
= ety
.and_then(|ty
| {
845 if let ty
::TyUint(t
) = ty
.sty
{
846 Some(UintTy
::from(tcx
, t
)) } else { None }
849 let result
= match e
.node
{
850 hir
::ExprUnary(hir
::UnNeg
, ref inner
) => {
851 match try
!(eval_const_expr_partial(tcx
, &inner
, ty_hint
, fn_args
)) {
852 Float(f
) => Float(-f
),
853 Int(n
) => try
!(const_int_checked_neg(n
, e
, expr_int_type
)),
855 try
!(const_uint_checked_neg(i
, e
, expr_uint_type
))
857 const_val
=> signal
!(e
, NegateOn(const_val
)),
860 hir
::ExprUnary(hir
::UnNot
, ref inner
) => {
861 match try
!(eval_const_expr_partial(tcx
, &inner
, ty_hint
, fn_args
)) {
863 Uint(i
) => const_uint_not(i
, expr_uint_type
),
865 const_val
=> signal
!(e
, NotOn(const_val
)),
868 hir
::ExprBinary(op
, ref a
, ref b
) => {
869 let b_ty
= match op
.node
{
870 hir
::BiShl
| hir
::BiShr
=> ty_hint
.checked_or(tcx
.types
.usize),
873 match (try
!(eval_const_expr_partial(tcx
, &a
, ty_hint
, fn_args
)),
874 try
!(eval_const_expr_partial(tcx
, &b
, b_ty
, fn_args
))) {
875 (Float(a
), Float(b
)) => {
877 hir
::BiAdd
=> Float(a
+ b
),
878 hir
::BiSub
=> Float(a
- b
),
879 hir
::BiMul
=> Float(a
* b
),
880 hir
::BiDiv
=> Float(a
/ b
),
881 hir
::BiRem
=> Float(a
% b
),
882 hir
::BiEq
=> Bool(a
== b
),
883 hir
::BiLt
=> Bool(a
< b
),
884 hir
::BiLe
=> Bool(a
<= b
),
885 hir
::BiNe
=> Bool(a
!= b
),
886 hir
::BiGe
=> Bool(a
>= b
),
887 hir
::BiGt
=> Bool(a
> b
),
888 _
=> signal
!(e
, InvalidOpForFloats(op
.node
)),
891 (Int(a
), Int(b
)) => {
893 hir
::BiAdd
=> try
!(const_int_checked_add(a
,b
,e
,expr_int_type
)),
894 hir
::BiSub
=> try
!(const_int_checked_sub(a
,b
,e
,expr_int_type
)),
895 hir
::BiMul
=> try
!(const_int_checked_mul(a
,b
,e
,expr_int_type
)),
896 hir
::BiDiv
=> try
!(const_int_checked_div(a
,b
,e
,expr_int_type
)),
897 hir
::BiRem
=> try
!(const_int_checked_rem(a
,b
,e
,expr_int_type
)),
898 hir
::BiBitAnd
=> Int(a
& b
),
899 hir
::BiBitOr
=> Int(a
| b
),
900 hir
::BiBitXor
=> Int(a ^ b
),
901 hir
::BiShl
=> try
!(const_int_checked_shl(a
,b
,e
,expr_int_type
)),
902 hir
::BiShr
=> try
!(const_int_checked_shr(a
,b
,e
,expr_int_type
)),
903 hir
::BiEq
=> Bool(a
== b
),
904 hir
::BiLt
=> Bool(a
< b
),
905 hir
::BiLe
=> Bool(a
<= b
),
906 hir
::BiNe
=> Bool(a
!= b
),
907 hir
::BiGe
=> Bool(a
>= b
),
908 hir
::BiGt
=> Bool(a
> b
),
909 _
=> signal
!(e
, InvalidOpForInts(op
.node
)),
912 (Uint(a
), Uint(b
)) => {
914 hir
::BiAdd
=> try
!(const_uint_checked_add(a
,b
,e
,expr_uint_type
)),
915 hir
::BiSub
=> try
!(const_uint_checked_sub(a
,b
,e
,expr_uint_type
)),
916 hir
::BiMul
=> try
!(const_uint_checked_mul(a
,b
,e
,expr_uint_type
)),
917 hir
::BiDiv
=> try
!(const_uint_checked_div(a
,b
,e
,expr_uint_type
)),
918 hir
::BiRem
=> try
!(const_uint_checked_rem(a
,b
,e
,expr_uint_type
)),
919 hir
::BiBitAnd
=> Uint(a
& b
),
920 hir
::BiBitOr
=> Uint(a
| b
),
921 hir
::BiBitXor
=> Uint(a ^ b
),
922 hir
::BiShl
=> try
!(const_uint_checked_shl(a
,b
,e
,expr_uint_type
)),
923 hir
::BiShr
=> try
!(const_uint_checked_shr(a
,b
,e
,expr_uint_type
)),
924 hir
::BiEq
=> Bool(a
== b
),
925 hir
::BiLt
=> Bool(a
< b
),
926 hir
::BiLe
=> Bool(a
<= b
),
927 hir
::BiNe
=> Bool(a
!= b
),
928 hir
::BiGe
=> Bool(a
>= b
),
929 hir
::BiGt
=> Bool(a
> b
),
930 _
=> signal
!(e
, InvalidOpForUInts(op
.node
)),
933 // shifts can have any integral type as their rhs
934 (Int(a
), Uint(b
)) => {
936 hir
::BiShl
=> try
!(const_int_checked_shl_via_uint(a
,b
,e
,expr_int_type
)),
937 hir
::BiShr
=> try
!(const_int_checked_shr_via_uint(a
,b
,e
,expr_int_type
)),
938 _
=> signal
!(e
, InvalidOpForIntUint(op
.node
)),
941 (Uint(a
), Int(b
)) => {
943 hir
::BiShl
=> try
!(const_uint_checked_shl_via_int(a
,b
,e
,expr_uint_type
)),
944 hir
::BiShr
=> try
!(const_uint_checked_shr_via_int(a
,b
,e
,expr_uint_type
)),
945 _
=> signal
!(e
, InvalidOpForUintInt(op
.node
)),
948 (Bool(a
), Bool(b
)) => {
950 hir
::BiAnd
=> a
&& b
,
952 hir
::BiBitXor
=> a ^ b
,
953 hir
::BiBitAnd
=> a
& b
,
954 hir
::BiBitOr
=> a
| b
,
957 _
=> signal
!(e
, InvalidOpForBools(op
.node
)),
961 _
=> signal
!(e
, MiscBinaryOp
),
964 hir
::ExprCast(ref base
, ref target_ty
) => {
965 let ety
= ety
.or_else(|| ast_ty_to_prim_ty(tcx
, &target_ty
))
967 tcx
.sess
.span_fatal(target_ty
.span
,
968 "target type not found for const cast")
971 let base_hint
= if let ExprTypeChecked
= ty_hint
{
974 // FIXME (#23833): the type-hint can cause problems,
975 // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
976 // type to the sum, and thus no overflow is signaled.
977 match tcx
.expr_ty_opt(&base
) {
978 Some(t
) => UncheckedExprHint(t
),
983 let val
= try
!(eval_const_expr_partial(tcx
, &base
, base_hint
, fn_args
));
984 match cast_const(tcx
, val
, ety
) {
986 Err(kind
) => return Err(ConstEvalErr { span: e.span, kind: kind }
),
989 hir
::ExprPath(..) => {
990 let opt_def
= if let Some(def
) = tcx
.def_map
.borrow().get(&e
.id
) {
991 // After type-checking, def_map contains definition of the
992 // item referred to by the path. During type-checking, it
993 // can contain the raw output of path resolution, which
994 // might be a partially resolved path.
995 // FIXME: There's probably a better way to make sure we don't
998 signal
!(e
, UnresolvedPath
);
1000 Some(def
.full_def())
1004 let (const_expr
, const_ty
) = match opt_def
{
1005 Some(Def
::Const(def_id
)) => {
1006 if let Some(node_id
) = tcx
.map
.as_local_node_id(def_id
) {
1007 match tcx
.map
.find(node_id
) {
1008 Some(ast_map
::NodeItem(it
)) => match it
.node
{
1009 hir
::ItemConst(ref ty
, ref expr
) => {
1010 (Some(&**expr
), Some(&**ty
))
1017 (lookup_const_by_id(tcx
, def_id
, Some(e
.id
), None
), None
)
1020 Some(Def
::AssociatedConst(def_id
)) => {
1021 if let Some(node_id
) = tcx
.map
.as_local_node_id(def_id
) {
1022 match impl_or_trait_container(tcx
, def_id
) {
1023 ty
::TraitContainer(trait_id
) => match tcx
.map
.find(node_id
) {
1024 Some(ast_map
::NodeTraitItem(ti
)) => match ti
.node
{
1025 hir
::ConstTraitItem(ref ty
, _
) => {
1026 if let ExprTypeChecked
= ty_hint
{
1027 let substs
= tcx
.node_id_item_substs(e
.id
).substs
;
1028 (resolve_trait_associated_const(tcx
,
1041 ty
::ImplContainer(_
) => match tcx
.map
.find(node_id
) {
1042 Some(ast_map
::NodeImplItem(ii
)) => match ii
.node
{
1043 hir
::ImplItemKind
::Const(ref ty
, ref expr
) => {
1044 (Some(&**expr
), Some(&**ty
))
1052 (lookup_const_by_id(tcx
, def_id
, Some(e
.id
), None
), None
)
1055 Some(Def
::Variant(enum_def
, variant_def
)) => {
1056 (lookup_variant_by_id(tcx
, enum_def
, variant_def
), None
)
1058 Some(Def
::Struct(..)) => {
1059 return Ok(ConstVal
::Struct(e
.id
))
1061 Some(Def
::Local(_
, id
)) => {
1062 debug
!("Def::Local({:?}): {:?}", id
, fn_args
);
1063 if let Some(val
) = fn_args
.and_then(|args
| args
.get(&id
)) {
1064 return Ok(val
.clone());
1069 Some(Def
::Method(id
)) | Some(Def
::Fn(id
)) => return Ok(Function(id
)),
1072 let const_expr
= match const_expr
{
1073 Some(actual_e
) => actual_e
,
1074 None
=> signal
!(e
, NonConstPath
)
1076 let item_hint
= if let UncheckedExprNoHint
= ty_hint
{
1078 Some(ty
) => match ast_ty_to_prim_ty(tcx
, ty
) {
1079 Some(ty
) => UncheckedExprHint(ty
),
1080 None
=> UncheckedExprNoHint
1082 None
=> UncheckedExprNoHint
1087 try
!(eval_const_expr_partial(tcx
, const_expr
, item_hint
, fn_args
))
1089 hir
::ExprCall(ref callee
, ref args
) => {
1090 let sub_ty_hint
= ty_hint
.erase_hint();
1091 let callee_val
= try
!(eval_const_expr_partial(tcx
, callee
, sub_ty_hint
, fn_args
));
1092 let did
= match callee_val
{
1093 Function(did
) => did
,
1094 callee
=> signal
!(e
, CallOn(callee
)),
1096 let (decl
, result
) = if let Some(fn_like
) = lookup_const_fn_by_id(tcx
, did
) {
1097 (fn_like
.decl(), &fn_like
.body().expr
)
1099 signal
!(e
, NonConstPath
)
1101 let result
= result
.as_ref().expect("const fn has no result expression");
1102 assert_eq
!(decl
.inputs
.len(), args
.len());
1104 let mut call_args
= NodeMap();
1105 for (arg
, arg_expr
) in decl
.inputs
.iter().zip(args
.iter()) {
1106 let arg_val
= try
!(eval_const_expr_partial(
1112 debug
!("const call arg: {:?}", arg
);
1113 let old
= call_args
.insert(arg
.pat
.id
, arg_val
);
1114 assert
!(old
.is_none());
1116 debug
!("const call({:?})", call_args
);
1117 try
!(eval_const_expr_partial(tcx
, &result
, ty_hint
, Some(&call_args
)))
1119 hir
::ExprLit(ref lit
) => lit_to_const(tcx
.sess
, e
.span
, &lit
, ety
),
1120 hir
::ExprBlock(ref block
) => {
1122 Some(ref expr
) => try
!(eval_const_expr_partial(tcx
, &expr
, ty_hint
, fn_args
)),
1123 None
=> unreachable
!(),
1126 hir
::ExprType(ref e
, _
) => try
!(eval_const_expr_partial(tcx
, &e
, ty_hint
, fn_args
)),
1127 hir
::ExprTup(_
) => Tuple(e
.id
),
1128 hir
::ExprStruct(..) => Struct(e
.id
),
1129 hir
::ExprIndex(ref arr
, ref idx
) => {
1130 if !tcx
.sess
.features
.borrow().const_indexing
{
1131 signal
!(e
, IndexOpFeatureGated
);
1133 let arr_hint
= ty_hint
.erase_hint();
1134 let arr
= try
!(eval_const_expr_partial(tcx
, arr
, arr_hint
, fn_args
));
1135 let idx_hint
= ty_hint
.checked_or(tcx
.types
.usize);
1136 let idx
= match try
!(eval_const_expr_partial(tcx
, idx
, idx_hint
, fn_args
)) {
1137 Int(i
) if i
>= 0 => i
as u64,
1138 Int(_
) => signal
!(idx
, IndexNegative
),
1140 _
=> signal
!(idx
, IndexNotInt
),
1143 Array(_
, n
) if idx
>= n
=> signal
!(e
, IndexOutOfBounds
),
1144 Array(v
, _
) => if let hir
::ExprVec(ref v
) = tcx
.map
.expect_expr(v
).node
{
1145 try
!(eval_const_expr_partial(tcx
, &v
[idx
as usize], ty_hint
, fn_args
))
1150 Repeat(_
, n
) if idx
>= n
=> signal
!(e
, IndexOutOfBounds
),
1151 Repeat(elem
, _
) => try
!(eval_const_expr_partial(
1153 &tcx
.map
.expect_expr(elem
),
1158 ByteStr(ref data
) if idx
as usize >= data
.len()
1159 => signal
!(e
, IndexOutOfBounds
),
1160 ByteStr(data
) => Uint(data
[idx
as usize] as u64),
1162 Str(ref s
) if idx
as usize >= s
.len()
1163 => signal
!(e
, IndexOutOfBounds
),
1164 Str(_
) => unimplemented
!(), // there's no const_char type
1165 _
=> signal
!(e
, IndexedNonVec
),
1168 hir
::ExprVec(ref v
) => Array(e
.id
, v
.len() as u64),
1169 hir
::ExprRepeat(_
, ref n
) => {
1170 let len_hint
= ty_hint
.checked_or(tcx
.types
.usize);
1173 match try
!(eval_const_expr_partial(tcx
, &n
, len_hint
, fn_args
)) {
1174 Int(i
) if i
>= 0 => i
as u64,
1175 Int(_
) => signal
!(e
, RepeatCountNotNatural
),
1177 _
=> signal
!(e
, RepeatCountNotInt
),
1181 hir
::ExprTupField(ref base
, index
) => {
1182 let base_hint
= ty_hint
.erase_hint();
1183 let c
= try
!(eval_const_expr_partial(tcx
, base
, base_hint
, fn_args
));
1184 if let Tuple(tup_id
) = c
{
1185 if let hir
::ExprTup(ref fields
) = tcx
.map
.expect_expr(tup_id
).node
{
1186 if index
.node
< fields
.len() {
1187 return eval_const_expr_partial(tcx
, &fields
[index
.node
], base_hint
, fn_args
)
1189 signal
!(e
, TupleIndexOutOfBounds
);
1195 signal
!(base
, ExpectedConstTuple
);
1198 hir
::ExprField(ref base
, field_name
) => {
1199 let base_hint
= ty_hint
.erase_hint();
1200 // Get the base expression if it is a struct and it is constant
1201 let c
= try
!(eval_const_expr_partial(tcx
, base
, base_hint
, fn_args
));
1202 if let Struct(struct_id
) = c
{
1203 if let hir
::ExprStruct(_
, ref fields
, _
) = tcx
.map
.expect_expr(struct_id
).node
{
1204 // Check that the given field exists and evaluate it
1205 // if the idents are compared run-pass/issue-19244 fails
1206 if let Some(f
) = fields
.iter().find(|f
| f
.name
.node
1207 == field_name
.node
) {
1208 return eval_const_expr_partial(tcx
, &f
.expr
, base_hint
, fn_args
)
1210 signal
!(e
, MissingStructField
);
1216 signal
!(base
, ExpectedConstStruct
);
1219 _
=> signal
!(e
, MiscCatchAll
)
1225 fn impl_or_trait_container(tcx
: &ty
::ctxt
, def_id
: DefId
) -> ty
::ImplOrTraitItemContainer
{
1226 // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container()
1227 // for local def_id, but it can be called before tcx.impl_or_trait_items is complete.
1228 if let Some(node_id
) = tcx
.map
.as_local_node_id(def_id
) {
1229 if let Some(ast_map
::NodeItem(item
)) = tcx
.map
.find(tcx
.map
.get_parent_node(node_id
)) {
1230 let container_id
= tcx
.map
.local_def_id(item
.id
);
1232 hir
::ItemImpl(..) => return ty
::ImplContainer(container_id
),
1233 hir
::ItemTrait(..) => return ty
::TraitContainer(container_id
),
1237 panic
!("No impl or trait container for {:?}", def_id
);
1239 panic
!("{:?} is not local", def_id
);
1242 fn resolve_trait_associated_const
<'a
, 'tcx
: 'a
>(tcx
: &'a ty
::ctxt
<'tcx
>,
1243 ti
: &'tcx hir
::TraitItem
,
1245 rcvr_substs
: subst
::Substs
<'tcx
>)
1246 -> Option
<&'tcx Expr
>
1248 let trait_ref
= ty
::Binder(
1249 rcvr_substs
.erase_regions().to_trait_ref(tcx
, trait_id
)
1251 debug
!("resolve_trait_associated_const: trait_ref={:?}",
1254 tcx
.populate_implementations_for_trait_if_necessary(trait_ref
.def_id());
1255 let infcx
= infer
::new_infer_ctxt(tcx
, &tcx
.tables
, None
);
1257 let mut selcx
= traits
::SelectionContext
::new(&infcx
);
1258 let obligation
= traits
::Obligation
::new(traits
::ObligationCause
::dummy(),
1259 trait_ref
.to_poly_trait_predicate());
1260 let selection
= match selcx
.select(&obligation
) {
1261 Ok(Some(vtable
)) => vtable
,
1262 // Still ambiguous, so give up and let the caller decide whether this
1263 // expression is really needed yet. Some associated constant values
1264 // can't be evaluated until monomorphization is done in trans.
1274 traits
::VtableImpl(ref impl_data
) => {
1275 match tcx
.associated_consts(impl_data
.impl_def_id
)
1276 .iter().find(|ic
| ic
.name
== ti
.name
) {
1277 Some(ic
) => lookup_const_by_id(tcx
, ic
.def_id
, None
, None
),
1278 None
=> match ti
.node
{
1279 hir
::ConstTraitItem(_
, Some(ref expr
)) => Some(&*expr
),
1287 "resolve_trait_associated_const: unexpected vtable type")
1292 fn cast_const
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>, val
: ConstVal
, ty
: Ty
) -> CastResult
{
1293 macro_rules
! convert_val
{
1294 ($intermediate_ty
:ty
, $const_type
:ident
, $target_ty
:ty
) => {
1296 Bool(b
) => Ok($
const_type(b
as u64 as $intermediate_ty
as $target_ty
)),
1297 Uint(u
) => Ok($
const_type(u
as $intermediate_ty
as $target_ty
)),
1298 Int(i
) => Ok($
const_type(i
as $intermediate_ty
as $target_ty
)),
1299 Float(f
) => Ok($
const_type(f
as $intermediate_ty
as $target_ty
)),
1300 _
=> Err(ErrKind
::CannotCastTo(stringify
!($const_type
))),
1305 // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
1306 match (&ty
.sty
, tcx
.sess
.target
.int_type
, tcx
.sess
.target
.uint_type
) {
1307 (&ty
::TyInt(ast
::IntTy
::Is
), ast
::IntTy
::I32
, _
) => return convert_val
!(i32, Int
, i64),
1308 (&ty
::TyInt(ast
::IntTy
::Is
), ast
::IntTy
::I64
, _
) => return convert_val
!(i64, Int
, i64),
1309 (&ty
::TyInt(ast
::IntTy
::Is
), _
, _
) => panic
!("unexpected target.int_type"),
1311 (&ty
::TyUint(ast
::UintTy
::Us
), _
, ast
::UintTy
::U32
) => return convert_val
!(u32, Uint
, u64),
1312 (&ty
::TyUint(ast
::UintTy
::Us
), _
, ast
::UintTy
::U64
) => return convert_val
!(u64, Uint
, u64),
1313 (&ty
::TyUint(ast
::UintTy
::Us
), _
, _
) => panic
!("unexpected target.uint_type"),
1319 ty
::TyInt(ast
::IntTy
::Is
) => unreachable
!(),
1320 ty
::TyUint(ast
::UintTy
::Us
) => unreachable
!(),
1322 ty
::TyInt(ast
::IntTy
::I8
) => convert_val
!(i8, Int
, i64),
1323 ty
::TyInt(ast
::IntTy
::I16
) => convert_val
!(i16, Int
, i64),
1324 ty
::TyInt(ast
::IntTy
::I32
) => convert_val
!(i32, Int
, i64),
1325 ty
::TyInt(ast
::IntTy
::I64
) => convert_val
!(i64, Int
, i64),
1327 ty
::TyUint(ast
::UintTy
::U8
) => convert_val
!(u8, Uint
, u64),
1328 ty
::TyUint(ast
::UintTy
::U16
) => convert_val
!(u16, Uint
, u64),
1329 ty
::TyUint(ast
::UintTy
::U32
) => convert_val
!(u32, Uint
, u64),
1330 ty
::TyUint(ast
::UintTy
::U64
) => convert_val
!(u64, Uint
, u64),
1332 ty
::TyFloat(ast
::FloatTy
::F32
) => convert_val
!(f32, Float
, f64),
1333 ty
::TyFloat(ast
::FloatTy
::F64
) => convert_val
!(f64, Float
, f64),
1334 _
=> Err(ErrKind
::CannotCast
),
1338 fn lit_to_const(sess
: &Session
, span
: Span
, lit
: &ast
::Lit
, ty_hint
: Option
<Ty
>) -> ConstVal
{
1340 ast
::LitKind
::Str(ref s
, _
) => Str((*s
).clone()),
1341 ast
::LitKind
::ByteStr(ref data
) => {
1342 ByteStr(data
.clone())
1344 ast
::LitKind
::Byte(n
) => Uint(n
as u64),
1345 ast
::LitKind
::Char(n
) => Uint(n
as u64),
1346 ast
::LitKind
::Int(n
, ast
::LitIntType
::Signed(_
)) => Int(n
as i64),
1347 ast
::LitKind
::Int(n
, ast
::LitIntType
::Unsuffixed
) => {
1348 match ty_hint
.map(|ty
| &ty
.sty
) {
1349 Some(&ty
::TyUint(_
)) => Uint(n
),
1353 ast
::LitKind
::Int(n
, ast
::LitIntType
::Unsigned(_
)) => Uint(n
),
1354 ast
::LitKind
::Float(ref n
, _
) |
1355 ast
::LitKind
::FloatUnsuffixed(ref n
) => {
1356 if let Ok(x
) = n
.parse
::<f64>() {
1359 // FIXME(#31407) this is only necessary because float parsing is buggy
1360 sess
.span_bug(span
, "could not evaluate float literal (see issue #31407)");
1363 ast
::LitKind
::Bool(b
) => Bool(b
)
1367 pub fn compare_const_vals(a
: &ConstVal
, b
: &ConstVal
) -> Option
<Ordering
> {
1369 (&Int(a
), &Int(b
)) => a
.cmp(&b
),
1370 (&Uint(a
), &Uint(b
)) => a
.cmp(&b
),
1371 (&Float(a
), &Float(b
)) => {
1372 // This is pretty bad but it is the existing behavior.
1381 (&Str(ref a
), &Str(ref b
)) => a
.cmp(b
),
1382 (&Bool(a
), &Bool(b
)) => a
.cmp(&b
),
1383 (&ByteStr(ref a
), &ByteStr(ref b
)) => a
.cmp(b
),
1388 pub fn compare_lit_exprs
<'tcx
>(tcx
: &ty
::ctxt
<'tcx
>,
1390 b
: &Expr
) -> Option
<Ordering
> {
1391 let a
= match eval_const_expr_partial(tcx
, a
, ExprTypeChecked
, None
) {
1394 tcx
.sess
.span_err(a
.span
, &e
.description());
1398 let b
= match eval_const_expr_partial(tcx
, b
, ExprTypeChecked
, None
) {
1401 tcx
.sess
.span_err(b
.span
, &e
.description());
1405 compare_const_vals(&a
, &b
)