1 // Copyright 2012-2016 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 use rustc
::middle
::const_val
::ConstVal
::*;
12 use rustc
::middle
::const_val
::ErrKind
::*;
13 use rustc
::middle
::const_val
::{ConstVal, ConstEvalErr, EvalResult, ErrKind}
;
15 use rustc
::hir
::map
as hir_map
;
16 use rustc
::hir
::map
::blocks
::FnLikeNode
;
18 use rustc
::hir
::def
::{Def, CtorKind}
;
19 use rustc
::hir
::def_id
::DefId
;
20 use rustc
::ty
::{self, Ty, TyCtxt}
;
21 use rustc
::ty
::maps
::Providers
;
22 use rustc
::ty
::util
::IntTypeExt
;
23 use rustc
::ty
::subst
::{Substs, Subst}
;
24 use rustc
::traits
::Reveal
;
25 use rustc
::util
::common
::ErrorReported
;
26 use rustc
::util
::nodemap
::DefIdMap
;
29 use rustc
::hir
::{self, Expr}
;
32 use std
::cmp
::Ordering
;
34 use rustc_const_math
::*;
37 ($e
:expr
, $exn
:expr
) => {
38 return Err(ConstEvalErr { span: $e.span, kind: $exn }
)
43 ($e
:expr
, $op
:expr
) => {
46 Err(e
) => signal
!($e
, ErrKind
::from(e
)),
51 /// * `def_id` is the id of the constant.
52 /// * `substs` is the monomorphized substitutions for the expression.
54 /// `substs` is optional and is used for associated constants.
55 /// This generally happens in late/trans const evaluation.
56 pub fn lookup_const_by_id
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
58 substs
: &'tcx Substs
<'tcx
>)
59 -> Option
<(DefId
, &'tcx Substs
<'tcx
>)> {
60 if let Some(node_id
) = tcx
.hir
.as_local_node_id(def_id
) {
61 match tcx
.hir
.find(node_id
) {
62 Some(hir_map
::NodeTraitItem(_
)) => {
63 // If we have a trait item and the substitutions for it,
64 // `resolve_trait_associated_const` will select an impl
66 resolve_trait_associated_const(tcx
, def_id
, substs
)
68 _
=> Some((def_id
, substs
))
71 match tcx
.describe_def(def_id
) {
72 Some(Def
::AssociatedConst(_
)) => {
73 // As mentioned in the comments above for in-crate
74 // constants, we only try to find the expression for a
75 // trait-associated const if the caller gives us the
76 // substitutions for the reference to it.
77 if tcx
.trait_of_item(def_id
).is_some() {
78 resolve_trait_associated_const(tcx
, def_id
, substs
)
80 Some((def_id
, substs
))
83 _
=> Some((def_id
, substs
))
88 pub struct ConstContext
<'a
, 'tcx
: 'a
> {
89 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
90 tables
: &'a ty
::TypeckTables
<'tcx
>,
91 substs
: &'tcx Substs
<'tcx
>,
92 fn_args
: Option
<DefIdMap
<ConstVal
<'tcx
>>>
95 impl<'a
, 'tcx
> ConstContext
<'a
, 'tcx
> {
96 pub fn with_tables(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>, tables
: &'a ty
::TypeckTables
<'tcx
>) -> Self {
100 substs
: tcx
.intern_substs(&[]),
105 /// Evaluate a constant expression in a context where the expression isn't
106 /// guaranteed to be evaluatable.
107 pub fn eval(&self, e
: &Expr
) -> EvalResult
<'tcx
> {
108 if self.tables
.tainted_by_errors
{
109 signal
!(e
, TypeckError
);
111 eval_const_expr_partial(self, e
)
115 type CastResult
<'tcx
> = Result
<ConstVal
<'tcx
>, ErrKind
<'tcx
>>;
117 fn eval_const_expr_partial
<'a
, 'tcx
>(cx
: &ConstContext
<'a
, 'tcx
>,
118 e
: &Expr
) -> EvalResult
<'tcx
> {
120 let ety
= cx
.tables
.expr_ty(e
);
122 // Avoid applying substitutions if they're empty, that'd ICE.
123 let ety
= if cx
.substs
.is_empty() {
126 ety
.subst(tcx
, cx
.substs
)
129 let result
= match e
.node
{
130 hir
::ExprUnary(hir
::UnNeg
, ref inner
) => {
131 // unary neg literals already got their sign during creation
132 if let hir
::ExprLit(ref lit
) = inner
.node
{
134 use syntax
::ast
::LitIntType
::*;
135 const I8_OVERFLOW
: u128
= i8::min_value() as u8 as u128
;
136 const I16_OVERFLOW
: u128
= i16::min_value() as u16 as u128
;
137 const I32_OVERFLOW
: u128
= i32::min_value() as u32 as u128
;
138 const I64_OVERFLOW
: u128
= i64::min_value() as u64 as u128
;
139 const I128_OVERFLOW
: u128
= i128
::min_value() as u128
;
140 match (&lit
.node
, &ety
.sty
) {
141 (&LitKind
::Int(I8_OVERFLOW
, _
), &ty
::TyInt(IntTy
::I8
)) |
142 (&LitKind
::Int(I8_OVERFLOW
, Signed(IntTy
::I8
)), _
) => {
143 return Ok(Integral(I8(i8::min_value())))
145 (&LitKind
::Int(I16_OVERFLOW
, _
), &ty
::TyInt(IntTy
::I16
)) |
146 (&LitKind
::Int(I16_OVERFLOW
, Signed(IntTy
::I16
)), _
) => {
147 return Ok(Integral(I16(i16::min_value())))
149 (&LitKind
::Int(I32_OVERFLOW
, _
), &ty
::TyInt(IntTy
::I32
)) |
150 (&LitKind
::Int(I32_OVERFLOW
, Signed(IntTy
::I32
)), _
) => {
151 return Ok(Integral(I32(i32::min_value())))
153 (&LitKind
::Int(I64_OVERFLOW
, _
), &ty
::TyInt(IntTy
::I64
)) |
154 (&LitKind
::Int(I64_OVERFLOW
, Signed(IntTy
::I64
)), _
) => {
155 return Ok(Integral(I64(i64::min_value())))
157 (&LitKind
::Int(I128_OVERFLOW
, _
), &ty
::TyInt(IntTy
::I128
)) |
158 (&LitKind
::Int(I128_OVERFLOW
, Signed(IntTy
::I128
)), _
) => {
159 return Ok(Integral(I128(i128
::min_value())))
161 (&LitKind
::Int(n
, _
), &ty
::TyInt(IntTy
::Is
)) |
162 (&LitKind
::Int(n
, Signed(IntTy
::Is
)), _
) => {
163 match tcx
.sess
.target
.int_type
{
164 IntTy
::I16
=> if n
== I16_OVERFLOW
{
165 return Ok(Integral(Isize(Is16(i16::min_value()))));
167 IntTy
::I32
=> if n
== I32_OVERFLOW
{
168 return Ok(Integral(Isize(Is32(i32::min_value()))));
170 IntTy
::I64
=> if n
== I64_OVERFLOW
{
171 return Ok(Integral(Isize(Is64(i64::min_value()))));
173 _
=> span_bug
!(e
.span
, "typeck error")
179 match cx
.eval(inner
)?
{
180 Float(f
) => Float(-f
),
181 Integral(i
) => Integral(math
!(e
, -i
)),
182 const_val
=> signal
!(e
, NegateOn(const_val
)),
185 hir
::ExprUnary(hir
::UnNot
, ref inner
) => {
186 match cx
.eval(inner
)?
{
187 Integral(i
) => Integral(math
!(e
, !i
)),
189 const_val
=> signal
!(e
, NotOn(const_val
)),
192 hir
::ExprUnary(hir
::UnDeref
, _
) => signal
!(e
, UnimplementedConstVal("deref operation")),
193 hir
::ExprBinary(op
, ref a
, ref b
) => {
194 // technically, if we don't have type hints, but integral eval
195 // gives us a type through a type-suffix, cast or const def type
196 // we need to re-eval the other value of the BinOp if it was
198 match (cx
.eval(a
)?
, cx
.eval(b
)?
) {
199 (Float(a
), Float(b
)) => {
200 use std
::cmp
::Ordering
::*;
202 hir
::BiAdd
=> Float(math
!(e
, a
+ b
)),
203 hir
::BiSub
=> Float(math
!(e
, a
- b
)),
204 hir
::BiMul
=> Float(math
!(e
, a
* b
)),
205 hir
::BiDiv
=> Float(math
!(e
, a
/ b
)),
206 hir
::BiRem
=> Float(math
!(e
, a
% b
)),
207 hir
::BiEq
=> Bool(math
!(e
, a
.try_cmp(b
)) == Equal
),
208 hir
::BiLt
=> Bool(math
!(e
, a
.try_cmp(b
)) == Less
),
209 hir
::BiLe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Greater
),
210 hir
::BiNe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Equal
),
211 hir
::BiGe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Less
),
212 hir
::BiGt
=> Bool(math
!(e
, a
.try_cmp(b
)) == Greater
),
213 _
=> span_bug
!(e
.span
, "typeck error"),
216 (Integral(a
), Integral(b
)) => {
217 use std
::cmp
::Ordering
::*;
219 hir
::BiAdd
=> Integral(math
!(e
, a
+ b
)),
220 hir
::BiSub
=> Integral(math
!(e
, a
- b
)),
221 hir
::BiMul
=> Integral(math
!(e
, a
* b
)),
222 hir
::BiDiv
=> Integral(math
!(e
, a
/ b
)),
223 hir
::BiRem
=> Integral(math
!(e
, a
% b
)),
224 hir
::BiBitAnd
=> Integral(math
!(e
, a
& b
)),
225 hir
::BiBitOr
=> Integral(math
!(e
, a
| b
)),
226 hir
::BiBitXor
=> Integral(math
!(e
, a ^ b
)),
227 hir
::BiShl
=> Integral(math
!(e
, a
<< b
)),
228 hir
::BiShr
=> Integral(math
!(e
, a
>> b
)),
229 hir
::BiEq
=> Bool(math
!(e
, a
.try_cmp(b
)) == Equal
),
230 hir
::BiLt
=> Bool(math
!(e
, a
.try_cmp(b
)) == Less
),
231 hir
::BiLe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Greater
),
232 hir
::BiNe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Equal
),
233 hir
::BiGe
=> Bool(math
!(e
, a
.try_cmp(b
)) != Less
),
234 hir
::BiGt
=> Bool(math
!(e
, a
.try_cmp(b
)) == Greater
),
235 _
=> span_bug
!(e
.span
, "typeck error"),
238 (Bool(a
), Bool(b
)) => {
240 hir
::BiAnd
=> a
&& b
,
242 hir
::BiBitXor
=> a ^ b
,
243 hir
::BiBitAnd
=> a
& b
,
244 hir
::BiBitOr
=> a
| b
,
251 _
=> span_bug
!(e
.span
, "typeck error"),
254 (Char(a
), Char(b
)) => {
262 _
=> span_bug
!(e
.span
, "typeck error"),
266 _
=> signal
!(e
, MiscBinaryOp
),
269 hir
::ExprCast(ref base
, _
) => {
270 let base_val
= cx
.eval(base
)?
;
271 let base_ty
= cx
.tables
.expr_ty(base
);
273 // Avoid applying substitutions if they're empty, that'd ICE.
274 let base_ty
= if cx
.substs
.is_empty() {
277 base_ty
.subst(tcx
, cx
.substs
)
282 match cast_const(tcx
, base_val
, ety
) {
284 Err(kind
) => signal
!(e
, kind
),
288 hir
::ExprPath(ref qpath
) => {
289 let substs
= cx
.tables
.node_substs(e
.id
);
291 // Avoid applying substitutions if they're empty, that'd ICE.
292 let substs
= if cx
.substs
.is_empty() {
295 substs
.subst(tcx
, cx
.substs
)
298 match cx
.tables
.qpath_def(qpath
, e
.id
) {
300 Def
::AssociatedConst(def_id
) => {
301 match tcx
.at(e
.span
).const_eval((def_id
, substs
)) {
303 Err(ConstEvalErr { kind: TypeckError, .. }
) => {
304 signal
!(e
, TypeckError
);
307 debug
!("bad reference: {:?}, {:?}", err
.description(), err
.span
);
308 signal
!(e
, ErroneousReferencedConstant(box err
))
312 Def
::VariantCtor(variant_def
, CtorKind
::Const
) => {
315 Def
::VariantCtor(_
, CtorKind
::Fn
) => {
316 signal
!(e
, UnimplementedConstVal("enum variants"));
318 Def
::StructCtor(_
, CtorKind
::Const
) => {
319 ConstVal
::Struct(Default
::default())
321 Def
::StructCtor(_
, CtorKind
::Fn
) => {
322 signal
!(e
, UnimplementedConstVal("tuple struct constructors"))
324 Def
::Local(def_id
) => {
325 debug
!("Def::Local({:?}): {:?}", def_id
, cx
.fn_args
);
326 if let Some(val
) = cx
.fn_args
.as_ref().and_then(|args
| args
.get(&def_id
)) {
329 signal
!(e
, NonConstPath
);
332 Def
::Method(id
) | Def
::Fn(id
) => Function(id
, substs
),
333 Def
::Err
=> span_bug
!(e
.span
, "typeck error"),
334 _
=> signal
!(e
, NonConstPath
),
337 hir
::ExprCall(ref callee
, ref args
) => {
338 let (def_id
, substs
) = match cx
.eval(callee
)?
{
339 Function(def_id
, substs
) => (def_id
, substs
),
340 _
=> signal
!(e
, TypeckError
),
343 let body
= if let Some(node_id
) = tcx
.hir
.as_local_node_id(def_id
) {
344 if let Some(fn_like
) = FnLikeNode
::from_node(tcx
.hir
.get(node_id
)) {
345 if fn_like
.constness() == hir
::Constness
::Const
{
346 tcx
.hir
.body(fn_like
.body())
348 signal
!(e
, TypeckError
)
351 signal
!(e
, TypeckError
)
354 if tcx
.is_const_fn(def_id
) {
355 tcx
.sess
.cstore
.item_body(tcx
, def_id
)
357 signal
!(e
, TypeckError
)
361 let arg_defs
= body
.arguments
.iter().map(|arg
| match arg
.pat
.node
{
362 hir
::PatKind
::Binding(_
, def_id
, _
, _
) => Some(def_id
),
364 }).collect
::<Vec
<_
>>();
365 assert_eq
!(arg_defs
.len(), args
.len());
367 let mut call_args
= DefIdMap();
368 for (arg
, arg_expr
) in arg_defs
.into_iter().zip(args
.iter()) {
369 let arg_val
= cx
.eval(arg_expr
)?
;
370 debug
!("const call arg: {:?}", arg
);
371 if let Some(def_id
) = arg
{
372 assert
!(call_args
.insert(def_id
, arg_val
).is_none());
375 debug
!("const call({:?})", call_args
);
376 let callee_cx
= ConstContext
{
378 tables
: tcx
.typeck_tables_of(def_id
),
380 fn_args
: Some(call_args
)
382 callee_cx
.eval(&body
.value
)?
384 hir
::ExprLit(ref lit
) => match lit_to_const(&lit
.node
, tcx
, ety
) {
386 Err(err
) => signal
!(e
, err
),
388 hir
::ExprBlock(ref block
) => {
390 Some(ref expr
) => cx
.eval(expr
)?
,
391 None
=> Tuple(vec
![]),
394 hir
::ExprType(ref e
, _
) => cx
.eval(e
)?
,
395 hir
::ExprTup(ref fields
) => {
396 Tuple(fields
.iter().map(|e
| cx
.eval(e
)).collect
::<Result
<_
, _
>>()?
)
398 hir
::ExprStruct(_
, ref fields
, _
) => {
399 Struct(fields
.iter().map(|f
| {
400 cx
.eval(&f
.expr
).map(|v
| (f
.name
.node
, v
))
401 }).collect
::<Result
<_
, _
>>()?
)
403 hir
::ExprIndex(ref arr
, ref idx
) => {
404 if !tcx
.sess
.features
.borrow().const_indexing
{
405 signal
!(e
, IndexOpFeatureGated
);
407 let arr
= cx
.eval(arr
)?
;
408 let idx
= match cx
.eval(idx
)?
{
409 Integral(Usize(i
)) => i
.as_u64(tcx
.sess
.target
.uint_type
),
410 _
=> signal
!(idx
, IndexNotUsize
),
412 assert_eq
!(idx
as usize as u64, idx
);
415 if let Some(elem
) = v
.get(idx
as usize) {
418 let n
= v
.len() as u64;
419 assert_eq
!(n
as usize as u64, n
);
420 signal
!(e
, IndexOutOfBounds { len: n, index: idx }
)
424 Repeat(.., n
) if idx
>= n
=> {
425 signal
!(e
, IndexOutOfBounds { len: n, index: idx }
)
427 Repeat(ref elem
, _
) => (**elem
).clone(),
429 ByteStr(ref data
) if idx
>= data
.len() as u64 => {
430 signal
!(e
, IndexOutOfBounds { len: data.len() as u64, index: idx }
)
433 Integral(U8(data
[idx
as usize]))
436 _
=> signal
!(e
, IndexedNonVec
),
439 hir
::ExprArray(ref v
) => {
440 Array(v
.iter().map(|e
| cx
.eval(e
)).collect
::<Result
<_
, _
>>()?
)
442 hir
::ExprRepeat(ref elem
, _
) => {
443 let n
= match ety
.sty
{
444 ty
::TyArray(_
, n
) => n
as u64,
445 _
=> span_bug
!(e
.span
, "typeck error")
447 Repeat(Box
::new(cx
.eval(elem
)?
), n
)
449 hir
::ExprTupField(ref base
, index
) => {
450 let c
= cx
.eval(base
)?
;
451 if let Tuple(ref fields
) = c
{
452 fields
[index
.node
].clone()
454 signal
!(base
, ExpectedConstTuple
);
457 hir
::ExprField(ref base
, field_name
) => {
458 let c
= cx
.eval(base
)?
;
459 if let Struct(ref fields
) = c
{
460 if let Some(f
) = fields
.get(&field_name
.node
) {
463 signal
!(e
, MissingStructField
);
466 signal
!(base
, ExpectedConstStruct
);
469 hir
::ExprAddrOf(..) => signal
!(e
, UnimplementedConstVal("address operator")),
470 _
=> signal
!(e
, MiscCatchAll
)
476 fn resolve_trait_associated_const
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
478 substs
: &'tcx Substs
<'tcx
>)
479 -> Option
<(DefId
, &'tcx Substs
<'tcx
>)> {
480 let trait_item
= tcx
.associated_item(def_id
);
481 let trait_id
= trait_item
.container
.id();
482 let trait_ref
= ty
::Binder(ty
::TraitRef
::new(trait_id
, substs
));
483 debug
!("resolve_trait_associated_const: trait_ref={:?}",
486 tcx
.infer_ctxt().enter(|infcx
| {
487 let param_env
= ty
::ParamEnv
::empty(Reveal
::UserFacing
);
488 let mut selcx
= traits
::SelectionContext
::new(&infcx
);
489 let obligation
= traits
::Obligation
::new(traits
::ObligationCause
::dummy(),
491 trait_ref
.to_poly_trait_predicate());
492 let selection
= match selcx
.select(&obligation
) {
493 Ok(Some(vtable
)) => vtable
,
494 // Still ambiguous, so give up and let the caller decide whether this
495 // expression is really needed yet. Some associated constant values
496 // can't be evaluated until monomorphization is done in trans.
505 // NOTE: this code does not currently account for specialization, but when
506 // it does so, it should hook into the Reveal to determine when the
507 // constant should resolve; this will also require plumbing through to this
508 // function whether we are in "trans mode" to pick the right Reveal
509 // when constructing the inference context above.
511 traits
::VtableImpl(ref impl_data
) => {
512 let name
= trait_item
.name
;
513 let ac
= tcx
.associated_items(impl_data
.impl_def_id
)
514 .find(|item
| item
.kind
== ty
::AssociatedKind
::Const
&& item
.name
== name
);
516 // FIXME(eddyb) Use proper Instance resolution to
517 // get the correct Substs returned from here.
518 Some(ic
) => Some((ic
.def_id
, Substs
::empty())),
520 if trait_item
.defaultness
.has_value() {
521 Some((def_id
, substs
))
529 bug
!("resolve_trait_associated_const: unexpected vtable type")
535 fn cast_const_int
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
538 -> CastResult
<'tcx
> {
539 let v
= val
.to_u128_unchecked();
541 ty
::TyBool
if v
== 0 => Ok(Bool(false)),
542 ty
::TyBool
if v
== 1 => Ok(Bool(true)),
543 ty
::TyInt(ast
::IntTy
::I8
) => Ok(Integral(I8(v
as i128
as i8))),
544 ty
::TyInt(ast
::IntTy
::I16
) => Ok(Integral(I16(v
as i128
as i16))),
545 ty
::TyInt(ast
::IntTy
::I32
) => Ok(Integral(I32(v
as i128
as i32))),
546 ty
::TyInt(ast
::IntTy
::I64
) => Ok(Integral(I64(v
as i128
as i64))),
547 ty
::TyInt(ast
::IntTy
::I128
) => Ok(Integral(I128(v
as i128
))),
548 ty
::TyInt(ast
::IntTy
::Is
) => {
549 Ok(Integral(Isize(ConstIsize
::new_truncating(v
as i128
, tcx
.sess
.target
.int_type
))))
551 ty
::TyUint(ast
::UintTy
::U8
) => Ok(Integral(U8(v
as u8))),
552 ty
::TyUint(ast
::UintTy
::U16
) => Ok(Integral(U16(v
as u16))),
553 ty
::TyUint(ast
::UintTy
::U32
) => Ok(Integral(U32(v
as u32))),
554 ty
::TyUint(ast
::UintTy
::U64
) => Ok(Integral(U64(v
as u64))),
555 ty
::TyUint(ast
::UintTy
::U128
) => Ok(Integral(U128(v
as u128
))),
556 ty
::TyUint(ast
::UintTy
::Us
) => {
557 Ok(Integral(Usize(ConstUsize
::new_truncating(v
, tcx
.sess
.target
.uint_type
))))
559 ty
::TyFloat(ast
::FloatTy
::F64
) => Ok(Float(F64(val
.to_f64()))),
560 ty
::TyFloat(ast
::FloatTy
::F32
) => Ok(Float(F32(val
.to_f32()))),
561 ty
::TyRawPtr(_
) => Err(ErrKind
::UnimplementedConstVal("casting an address to a raw ptr")),
562 ty
::TyChar
=> match val
{
563 U8(u
) => Ok(Char(u
as char)),
566 _
=> Err(CannotCast
),
570 fn cast_const_float
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
572 ty
: Ty
<'tcx
>) -> CastResult
<'tcx
> {
574 ty
::TyInt(_
) | ty
::TyUint(_
) => {
576 F32(f
) if f
>= 0.0 => U128(f
as u128
),
577 F64(f
) if f
>= 0.0 => U128(f
as u128
),
579 F32(f
) => I128(f
as i128
),
580 F64(f
) => I128(f
as i128
)
583 if let (I128(_
), &ty
::TyUint(_
)) = (i
, &ty
.sty
) {
584 return Err(CannotCast
);
587 cast_const_int(tcx
, i
, ty
)
589 ty
::TyFloat(ast
::FloatTy
::F64
) => Ok(Float(F64(match val
{
593 ty
::TyFloat(ast
::FloatTy
::F32
) => Ok(Float(F32(match val
{
597 _
=> Err(CannotCast
),
601 fn cast_const
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
604 -> CastResult
<'tcx
> {
606 Integral(i
) => cast_const_int(tcx
, i
, ty
),
607 Bool(b
) => cast_const_int(tcx
, U8(b
as u8), ty
),
608 Float(f
) => cast_const_float(tcx
, f
, ty
),
609 Char(c
) => cast_const_int(tcx
, U32(c
as u32), ty
),
611 let adt
= tcx
.adt_def(tcx
.parent_def_id(v
).unwrap());
612 let idx
= adt
.variant_index_with_id(v
);
613 cast_const_int(tcx
, adt
.discriminant_for_variant(tcx
, idx
), ty
)
615 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
616 ByteStr(b
) => match ty
.sty
{
618 Err(ErrKind
::UnimplementedConstVal("casting a bytestr to a raw ptr"))
620 ty
::TyRef(_
, ty
::TypeAndMut { ref ty, mutbl: hir::MutImmutable }
) => match ty
.sty
{
621 ty
::TyArray(ty
, n
) if ty
== tcx
.types
.u8 && n
== b
.len() => Ok(ByteStr(b
)),
623 Err(ErrKind
::UnimplementedConstVal("casting a bytestr to slice"))
625 _
=> Err(CannotCast
),
627 _
=> Err(CannotCast
),
629 Str(s
) => match ty
.sty
{
630 ty
::TyRawPtr(_
) => Err(ErrKind
::UnimplementedConstVal("casting a str to a raw ptr")),
631 ty
::TyRef(_
, ty
::TypeAndMut { ref ty, mutbl: hir::MutImmutable }
) => match ty
.sty
{
632 ty
::TyStr
=> Ok(Str(s
)),
633 _
=> Err(CannotCast
),
635 _
=> Err(CannotCast
),
637 _
=> Err(CannotCast
),
641 fn lit_to_const
<'a
, 'tcx
>(lit
: &ast
::LitKind
,
642 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
644 -> Result
<ConstVal
<'tcx
>, ErrKind
<'tcx
>> {
646 use syntax
::ast
::LitIntType
::*;
648 if let ty
::TyAdt(adt
, _
) = ty
.sty
{
650 ty
= adt
.repr
.discr_type().to_ty(tcx
)
655 LitKind
::Str(ref s
, _
) => Ok(Str(s
.as_str())),
656 LitKind
::ByteStr(ref data
) => Ok(ByteStr(data
.clone())),
657 LitKind
::Byte(n
) => Ok(Integral(U8(n
))),
658 LitKind
::Int(n
, hint
) => {
659 match (&ty
.sty
, hint
) {
660 (&ty
::TyInt(ity
), _
) |
661 (_
, Signed(ity
)) => {
662 Ok(Integral(ConstInt
::new_signed_truncating(n
as i128
,
663 ity
, tcx
.sess
.target
.int_type
)))
665 (&ty
::TyUint(uty
), _
) |
666 (_
, Unsigned(uty
)) => {
667 Ok(Integral(ConstInt
::new_unsigned_truncating(n
as u128
,
668 uty
, tcx
.sess
.target
.uint_type
)))
673 LitKind
::Float(n
, fty
) => {
674 parse_float(&n
.as_str(), fty
).map(Float
)
676 LitKind
::FloatUnsuffixed(n
) => {
677 let fty
= match ty
.sty
{
678 ty
::TyFloat(fty
) => fty
,
681 parse_float(&n
.as_str(), fty
).map(Float
)
683 LitKind
::Bool(b
) => Ok(Bool(b
)),
684 LitKind
::Char(c
) => Ok(Char(c
)),
688 fn parse_float
<'tcx
>(num
: &str, fty
: ast
::FloatTy
)
689 -> Result
<ConstFloat
, ErrKind
<'tcx
>> {
690 let val
= match fty
{
691 ast
::FloatTy
::F32
=> num
.parse
::<f32>().map(F32
),
692 ast
::FloatTy
::F64
=> num
.parse
::<f64>().map(F64
)
695 // FIXME(#31407) this is only necessary because float parsing is buggy
696 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
700 pub fn compare_const_vals(tcx
: TyCtxt
, span
: Span
, a
: &ConstVal
, b
: &ConstVal
)
701 -> Result
<Ordering
, ErrorReported
>
703 let result
= match (a
, b
) {
704 (&Integral(a
), &Integral(b
)) => a
.try_cmp(b
).ok(),
705 (&Float(a
), &Float(b
)) => a
.try_cmp(b
).ok(),
706 (&Str(ref a
), &Str(ref b
)) => Some(a
.cmp(b
)),
707 (&Bool(a
), &Bool(b
)) => Some(a
.cmp(&b
)),
708 (&ByteStr(ref a
), &ByteStr(ref b
)) => Some(a
.cmp(b
)),
709 (&Char(a
), &Char(ref b
)) => Some(a
.cmp(b
)),
714 Some(result
) => Ok(result
),
716 // FIXME: can this ever be reached?
717 span_err
!(tcx
.sess
, span
, E0298
,
718 "type mismatch comparing {} and {}",
726 impl<'a
, 'tcx
> ConstContext
<'a
, 'tcx
> {
727 pub fn compare_lit_exprs(&self,
730 b
: &Expr
) -> Result
<Ordering
, ErrorReported
> {
732 let a
= match self.eval(a
) {
735 e
.report(tcx
, a
.span
, "expression");
736 return Err(ErrorReported
);
739 let b
= match self.eval(b
) {
742 e
.report(tcx
, b
.span
, "expression");
743 return Err(ErrorReported
);
746 compare_const_vals(tcx
, span
, &a
, &b
)
750 pub fn provide(providers
: &mut Providers
) {
751 *providers
= Providers
{
757 fn const_eval
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
758 (def_id
, substs
): (DefId
, &'tcx Substs
<'tcx
>))
759 -> EvalResult
<'tcx
> {
760 let (def_id
, substs
) = if let Some(resolved
) = lookup_const_by_id(tcx
, def_id
, substs
) {
763 return Err(ConstEvalErr
{
764 span
: tcx
.def_span(def_id
),
769 let cx
= ConstContext
{
771 tables
: tcx
.typeck_tables_of(def_id
),
776 let body
= if let Some(id
) = tcx
.hir
.as_local_node_id(def_id
) {
777 tcx
.mir_const_qualif(def_id
);
778 tcx
.hir
.body(tcx
.hir
.body_owned_by(id
))
780 tcx
.sess
.cstore
.item_body(tcx
, def_id
)