]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
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. | |
4 | // | |
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. | |
10 | ||
11 | //#![allow(non_camel_case_types)] | |
12 | ||
13 | use rustc::middle::const_val::ConstVal::*; | |
14 | use rustc::middle::const_val::ConstVal; | |
15 | use self::ErrKind::*; | |
16 | use self::EvalHint::*; | |
17 | ||
18 | use rustc::hir::map as ast_map; | |
19 | use rustc::hir::map::blocks::FnLikeNode; | |
5bcae85e | 20 | use rustc::middle::cstore::InlinedItem; |
a7813a04 | 21 | use rustc::traits; |
3157f602 | 22 | use rustc::hir::def::{Def, PathResolution}; |
54a0048b SL |
23 | use rustc::hir::def_id::DefId; |
24 | use rustc::hir::pat_util::def_to_path; | |
9e0c209e | 25 | use rustc::ty::{self, Ty, TyCtxt}; |
54a0048b | 26 | use rustc::ty::util::IntTypeExt; |
9e0c209e | 27 | use rustc::ty::subst::Substs; |
5bcae85e SL |
28 | use rustc::traits::Reveal; |
29 | use rustc::util::common::ErrorReported; | |
54a0048b SL |
30 | use rustc::util::nodemap::NodeMap; |
31 | use rustc::lint; | |
32 | ||
33 | use graphviz::IntoCow; | |
34 | use syntax::ast; | |
35 | use rustc::hir::{Expr, PatKind}; | |
36 | use rustc::hir; | |
37 | use rustc::hir::intravisit::FnKind; | |
54a0048b SL |
38 | use syntax::ptr::P; |
39 | use syntax::codemap; | |
40 | use syntax::attr::IntType; | |
3157f602 | 41 | use syntax_pos::{self, Span}; |
54a0048b SL |
42 | |
43 | use std::borrow::Cow; | |
44 | use std::cmp::Ordering; | |
45 | use std::collections::hash_map::Entry::Vacant; | |
46 | ||
47 | use rustc_const_math::*; | |
5bcae85e | 48 | use rustc_errors::DiagnosticBuilder; |
54a0048b SL |
49 | |
50 | macro_rules! math { | |
51 | ($e:expr, $op:expr) => { | |
52 | match $op { | |
53 | Ok(val) => val, | |
54 | Err(e) => signal!($e, Math(e)), | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
a7813a04 | 59 | fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
a7813a04 XL |
60 | variant_def: DefId) |
61 | -> Option<&'tcx Expr> { | |
54a0048b SL |
62 | fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId) |
63 | -> Option<&'a Expr> { | |
64 | for variant in variants { | |
65 | if variant.node.data.id() == id { | |
66 | return variant.node.disr_expr.as_ref().map(|e| &**e); | |
67 | } | |
68 | } | |
69 | None | |
70 | } | |
71 | ||
9e0c209e SL |
72 | if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) { |
73 | let enum_node_id = tcx.map.get_parent(variant_node_id); | |
54a0048b SL |
74 | match tcx.map.find(enum_node_id) { |
75 | None => None, | |
76 | Some(ast_map::NodeItem(it)) => match it.node { | |
77 | hir::ItemEnum(hir::EnumDef { ref variants }, _) => { | |
78 | variant_expr(variants, variant_node_id) | |
79 | } | |
80 | _ => None | |
81 | }, | |
82 | Some(_) => None | |
83 | } | |
84 | } else { | |
85 | None | |
86 | } | |
87 | } | |
88 | ||
89 | /// * `def_id` is the id of the constant. | |
90 | /// * `substs` is the monomorphized substitutions for the expression. | |
91 | /// | |
92 | /// `substs` is optional and is used for associated constants. | |
93 | /// This generally happens in late/trans const evaluation. | |
a7813a04 | 94 | pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
54a0048b | 95 | def_id: DefId, |
9e0c209e | 96 | substs: Option<&'tcx Substs<'tcx>>) |
54a0048b SL |
97 | -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> { |
98 | if let Some(node_id) = tcx.map.as_local_node_id(def_id) { | |
99 | match tcx.map.find(node_id) { | |
100 | None => None, | |
101 | Some(ast_map::NodeItem(it)) => match it.node { | |
102 | hir::ItemConst(ref ty, ref const_expr) => { | |
a7813a04 | 103 | Some((&const_expr, tcx.ast_ty_to_prim_ty(ty))) |
54a0048b SL |
104 | } |
105 | _ => None | |
106 | }, | |
107 | Some(ast_map::NodeTraitItem(ti)) => match ti.node { | |
9e0c209e | 108 | hir::ConstTraitItem(..) => { |
54a0048b SL |
109 | if let Some(substs) = substs { |
110 | // If we have a trait item and the substitutions for it, | |
111 | // `resolve_trait_associated_const` will select an impl | |
112 | // or the default. | |
9e0c209e SL |
113 | let trait_id = tcx.map.get_parent(node_id); |
114 | let trait_id = tcx.map.local_def_id(trait_id); | |
54a0048b SL |
115 | resolve_trait_associated_const(tcx, ti, trait_id, substs) |
116 | } else { | |
117 | // Technically, without knowing anything about the | |
118 | // expression that generates the obligation, we could | |
119 | // still return the default if there is one. However, | |
120 | // it's safer to return `None` than to return some value | |
121 | // that may differ from what you would get from | |
122 | // correctly selecting an impl. | |
123 | None | |
124 | } | |
125 | } | |
126 | _ => None | |
127 | }, | |
128 | Some(ast_map::NodeImplItem(ii)) => match ii.node { | |
129 | hir::ImplItemKind::Const(ref ty, ref expr) => { | |
a7813a04 | 130 | Some((&expr, tcx.ast_ty_to_prim_ty(ty))) |
54a0048b SL |
131 | } |
132 | _ => None | |
133 | }, | |
134 | Some(_) => None | |
135 | } | |
136 | } else { | |
137 | match tcx.extern_const_statics.borrow().get(&def_id) { | |
138 | Some(&None) => return None, | |
139 | Some(&Some((expr_id, ty))) => { | |
140 | return Some((tcx.map.expect_expr(expr_id), ty)); | |
141 | } | |
142 | None => {} | |
143 | } | |
144 | let mut used_substs = false; | |
145 | let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { | |
5bcae85e | 146 | Some((&InlinedItem::Item(_, ref item), _)) => match item.node { |
54a0048b | 147 | hir::ItemConst(ref ty, ref const_expr) => { |
a7813a04 | 148 | Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty))) |
54a0048b SL |
149 | }, |
150 | _ => None | |
151 | }, | |
5bcae85e | 152 | Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node { |
9e0c209e | 153 | hir::ConstTraitItem(..) => { |
54a0048b SL |
154 | used_substs = true; |
155 | if let Some(substs) = substs { | |
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 substitutions for the reference to it. | |
160 | resolve_trait_associated_const(tcx, ti, trait_id, substs) | |
161 | } else { | |
162 | None | |
163 | } | |
164 | } | |
165 | _ => None | |
166 | }, | |
5bcae85e | 167 | Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node { |
54a0048b | 168 | hir::ImplItemKind::Const(ref ty, ref expr) => { |
a7813a04 | 169 | Some((&**expr, tcx.ast_ty_to_prim_ty(ty))) |
54a0048b SL |
170 | }, |
171 | _ => None | |
172 | }, | |
173 | _ => None | |
174 | }; | |
175 | // If we used the substitutions, particularly to choose an impl | |
176 | // of a trait-associated const, don't cache that, because the next | |
177 | // lookup with the same def_id may yield a different result. | |
178 | if !used_substs { | |
179 | tcx.extern_const_statics | |
180 | .borrow_mut() | |
181 | .insert(def_id, expr_ty.map(|(e, t)| (e.id, t))); | |
182 | } | |
183 | expr_ty | |
184 | } | |
185 | } | |
186 | ||
a7813a04 XL |
187 | fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
188 | def_id: DefId) | |
189 | -> Option<ast::NodeId> { | |
54a0048b SL |
190 | match tcx.extern_const_fns.borrow().get(&def_id) { |
191 | Some(&ast::DUMMY_NODE_ID) => return None, | |
192 | Some(&fn_id) => return Some(fn_id), | |
193 | None => {} | |
194 | } | |
195 | ||
196 | if !tcx.sess.cstore.is_const_fn(def_id) { | |
197 | tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID); | |
198 | return None; | |
199 | } | |
200 | ||
201 | let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { | |
5bcae85e SL |
202 | Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id), |
203 | Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id), | |
54a0048b SL |
204 | _ => None |
205 | }; | |
206 | tcx.extern_const_fns.borrow_mut().insert(def_id, | |
207 | fn_id.unwrap_or(ast::DUMMY_NODE_ID)); | |
208 | fn_id | |
209 | } | |
210 | ||
a7813a04 XL |
211 | pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) |
212 | -> Option<FnLikeNode<'tcx>> | |
54a0048b SL |
213 | { |
214 | let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) { | |
215 | node_id | |
216 | } else { | |
217 | if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) { | |
218 | fn_id | |
219 | } else { | |
220 | return None; | |
221 | } | |
222 | }; | |
223 | ||
224 | let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) { | |
225 | Some(fn_like) => fn_like, | |
226 | None => return None | |
227 | }; | |
228 | ||
229 | match fn_like.kind() { | |
9e0c209e | 230 | FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => { |
54a0048b SL |
231 | Some(fn_like) |
232 | } | |
9e0c209e | 233 | FnKind::Method(_, m, ..) => { |
54a0048b SL |
234 | if m.constness == hir::Constness::Const { |
235 | Some(fn_like) | |
236 | } else { | |
237 | None | |
238 | } | |
239 | } | |
240 | _ => None | |
241 | } | |
242 | } | |
243 | ||
a7813a04 XL |
244 | pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
245 | expr: &Expr, | |
246 | pat_id: ast::NodeId, | |
247 | span: Span) | |
248 | -> Result<P<hir::Pat>, DefId> { | |
54a0048b SL |
249 | let pat_ty = tcx.expr_ty(expr); |
250 | debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); | |
251 | match pat_ty.sty { | |
252 | ty::TyFloat(_) => { | |
253 | tcx.sess.add_lint( | |
254 | lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN, | |
255 | pat_id, | |
256 | span, | |
257 | format!("floating point constants cannot be used in patterns")); | |
258 | } | |
9e0c209e SL |
259 | ty::TyAdt(adt_def, _) if adt_def.is_union() => { |
260 | // Matching on union fields is unsafe, we can't hide it in constants | |
261 | tcx.sess.span_err(span, "cannot use unions in constant patterns"); | |
262 | } | |
263 | ty::TyAdt(adt_def, _) => { | |
54a0048b SL |
264 | if !tcx.has_attr(adt_def.did, "structural_match") { |
265 | tcx.sess.add_lint( | |
266 | lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, | |
267 | pat_id, | |
268 | span, | |
269 | format!("to use a constant of type `{}` \ | |
270 | in a pattern, \ | |
271 | `{}` must be annotated with `#[derive(PartialEq, Eq)]`", | |
272 | tcx.item_path_str(adt_def.did), | |
273 | tcx.item_path_str(adt_def.did))); | |
274 | } | |
275 | } | |
276 | _ => { } | |
277 | } | |
278 | let pat = match expr.node { | |
279 | hir::ExprTup(ref exprs) => | |
9e0c209e SL |
280 | PatKind::Tuple(exprs.iter() |
281 | .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) | |
282 | .collect::<Result<_, _>>()?, None), | |
54a0048b SL |
283 | |
284 | hir::ExprCall(ref callee, ref args) => { | |
3157f602 | 285 | let def = tcx.expect_def(callee.id); |
54a0048b | 286 | if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) { |
3157f602 | 287 | entry.insert(PathResolution::new(def)); |
54a0048b | 288 | } |
3157f602 | 289 | let path = match def { |
54a0048b | 290 | Def::Struct(def_id) => def_to_path(tcx, def_id), |
9e0c209e | 291 | Def::Variant(variant_did) => def_to_path(tcx, variant_did), |
a7813a04 | 292 | Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat { |
54a0048b SL |
293 | id: expr.id, |
294 | node: PatKind::Lit(P(expr.clone())), | |
295 | span: span, | |
296 | })), | |
297 | _ => bug!() | |
298 | }; | |
9e0c209e SL |
299 | let pats = args.iter() |
300 | .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span)) | |
301 | .collect::<Result<_, _>>()?; | |
3157f602 | 302 | PatKind::TupleStruct(path, pats, None) |
54a0048b SL |
303 | } |
304 | ||
305 | hir::ExprStruct(ref path, ref fields, None) => { | |
306 | let field_pats = | |
9e0c209e SL |
307 | fields.iter() |
308 | .map(|field| Ok(codemap::Spanned { | |
309 | span: syntax_pos::DUMMY_SP, | |
310 | node: hir::FieldPat { | |
311 | name: field.name.node, | |
312 | pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?, | |
313 | is_shorthand: false, | |
314 | }, | |
315 | })) | |
316 | .collect::<Result<_, _>>()?; | |
54a0048b SL |
317 | PatKind::Struct(path.clone(), field_pats, false) |
318 | } | |
319 | ||
320 | hir::ExprVec(ref exprs) => { | |
9e0c209e SL |
321 | let pats = exprs.iter() |
322 | .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) | |
323 | .collect::<Result<_, _>>()?; | |
54a0048b SL |
324 | PatKind::Vec(pats, None, hir::HirVec::new()) |
325 | } | |
326 | ||
327 | hir::ExprPath(_, ref path) => { | |
3157f602 | 328 | match tcx.expect_def(expr.id) { |
5bcae85e | 329 | Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()), |
3157f602 | 330 | Def::Const(def_id) | Def::AssociatedConst(def_id) => { |
54a0048b SL |
331 | let substs = Some(tcx.node_id_item_substs(expr.id).substs); |
332 | let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap(); | |
333 | return const_expr_to_pat(tcx, expr, pat_id, span); | |
334 | }, | |
335 | _ => bug!(), | |
336 | } | |
337 | } | |
338 | ||
339 | _ => PatKind::Lit(P(expr.clone())) | |
340 | }; | |
341 | Ok(P(hir::Pat { id: expr.id, node: pat, span: span })) | |
342 | } | |
343 | ||
5bcae85e SL |
344 | pub fn report_const_eval_err<'a, 'tcx>( |
345 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
346 | err: &ConstEvalErr, | |
347 | primary_span: Span, | |
348 | primary_kind: &str) | |
349 | -> DiagnosticBuilder<'tcx> | |
350 | { | |
351 | let mut err = err; | |
352 | while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { | |
353 | err = i_err; | |
354 | } | |
355 | ||
356 | let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); | |
357 | note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); | |
358 | diag | |
359 | } | |
360 | ||
361 | pub fn fatal_const_eval_err<'a, 'tcx>( | |
362 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
363 | err: &ConstEvalErr, | |
364 | primary_span: Span, | |
365 | primary_kind: &str) | |
366 | -> ! | |
367 | { | |
368 | report_const_eval_err(tcx, err, primary_span, primary_kind).emit(); | |
369 | tcx.sess.abort_if_errors(); | |
370 | unreachable!() | |
371 | } | |
372 | ||
373 | pub fn note_const_eval_err<'a, 'tcx>( | |
374 | _tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
375 | err: &ConstEvalErr, | |
376 | primary_span: Span, | |
377 | primary_kind: &str, | |
378 | diag: &mut DiagnosticBuilder) | |
379 | { | |
380 | match err.description() { | |
381 | ConstEvalErrDescription::Simple(message) => { | |
382 | diag.span_label(err.span, &message); | |
383 | } | |
384 | } | |
385 | ||
386 | if !primary_span.contains(err.span) { | |
387 | diag.span_note(primary_span, | |
388 | &format!("for {} here", primary_kind)); | |
389 | } | |
390 | } | |
391 | ||
a7813a04 XL |
392 | pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
393 | e: &Expr) -> ConstVal { | |
54a0048b SL |
394 | match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { |
395 | Ok(r) => r, | |
396 | // non-const path still needs to be a fatal error, because enums are funky | |
397 | Err(s) => { | |
5bcae85e | 398 | report_const_eval_err(tcx, &s, e.span, "expression").emit(); |
54a0048b SL |
399 | match s.kind { |
400 | NonConstPath | | |
5bcae85e SL |
401 | UnimplementedConstVal(_) => tcx.sess.abort_if_errors(), |
402 | _ => {} | |
54a0048b | 403 | } |
5bcae85e | 404 | Dummy |
54a0048b SL |
405 | }, |
406 | } | |
407 | } | |
408 | ||
409 | pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>; | |
410 | ||
411 | #[derive(Clone)] | |
412 | pub struct ConstEvalErr { | |
413 | pub span: Span, | |
414 | pub kind: ErrKind, | |
415 | } | |
416 | ||
a7813a04 | 417 | #[derive(Clone)] |
54a0048b SL |
418 | pub enum ErrKind { |
419 | CannotCast, | |
420 | CannotCastTo(&'static str), | |
421 | InvalidOpForInts(hir::BinOp_), | |
422 | InvalidOpForBools(hir::BinOp_), | |
423 | InvalidOpForFloats(hir::BinOp_), | |
424 | InvalidOpForIntUint(hir::BinOp_), | |
425 | InvalidOpForUintInt(hir::BinOp_), | |
426 | NegateOn(ConstVal), | |
427 | NotOn(ConstVal), | |
428 | CallOn(ConstVal), | |
429 | ||
54a0048b SL |
430 | MissingStructField, |
431 | NonConstPath, | |
432 | UnimplementedConstVal(&'static str), | |
433 | UnresolvedPath, | |
434 | ExpectedConstTuple, | |
435 | ExpectedConstStruct, | |
436 | TupleIndexOutOfBounds, | |
437 | IndexedNonVec, | |
438 | IndexNegative, | |
439 | IndexNotInt, | |
3157f602 | 440 | IndexOutOfBounds { len: u64, index: u64 }, |
54a0048b SL |
441 | RepeatCountNotNatural, |
442 | RepeatCountNotInt, | |
443 | ||
444 | MiscBinaryOp, | |
445 | MiscCatchAll, | |
446 | ||
447 | IndexOpFeatureGated, | |
448 | Math(ConstMathErr), | |
449 | ||
450 | IntermediateUnsignedNegative, | |
451 | /// Expected, Got | |
452 | TypeMismatch(String, ConstInt), | |
5bcae85e | 453 | |
54a0048b | 454 | BadType(ConstVal), |
a7813a04 XL |
455 | ErroneousReferencedConstant(Box<ConstEvalErr>), |
456 | CharCast(ConstInt), | |
54a0048b SL |
457 | } |
458 | ||
459 | impl From<ConstMathErr> for ErrKind { | |
460 | fn from(err: ConstMathErr) -> ErrKind { | |
461 | Math(err) | |
462 | } | |
463 | } | |
464 | ||
5bcae85e SL |
465 | #[derive(Clone, Debug)] |
466 | pub enum ConstEvalErrDescription<'a> { | |
467 | Simple(Cow<'a, str>), | |
468 | } | |
469 | ||
470 | impl<'a> ConstEvalErrDescription<'a> { | |
471 | /// Return a one-line description of the error, for lints and such | |
472 | pub fn into_oneline(self) -> Cow<'a, str> { | |
473 | match self { | |
474 | ConstEvalErrDescription::Simple(simple) => simple, | |
475 | } | |
476 | } | |
477 | } | |
478 | ||
54a0048b | 479 | impl ConstEvalErr { |
5bcae85e | 480 | pub fn description(&self) -> ConstEvalErrDescription { |
54a0048b | 481 | use self::ErrKind::*; |
5bcae85e SL |
482 | use self::ConstEvalErrDescription::*; |
483 | ||
484 | macro_rules! simple { | |
485 | ($msg:expr) => ({ Simple($msg.into_cow()) }); | |
486 | ($fmt:expr, $($arg:tt)+) => ({ | |
487 | Simple(format!($fmt, $($arg)+).into_cow()) | |
488 | }) | |
489 | } | |
54a0048b SL |
490 | |
491 | match self.kind { | |
5bcae85e SL |
492 | CannotCast => simple!("can't cast this type"), |
493 | CannotCastTo(s) => simple!("can't cast this type to {}", s), | |
494 | InvalidOpForInts(_) => simple!("can't do this op on integrals"), | |
495 | InvalidOpForBools(_) => simple!("can't do this op on bools"), | |
496 | InvalidOpForFloats(_) => simple!("can't do this op on floats"), | |
497 | InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"), | |
498 | InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"), | |
499 | NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), | |
500 | NotOn(ref const_val) => simple!("not on {}", const_val.description()), | |
501 | CallOn(ref const_val) => simple!("call on {}", const_val.description()), | |
502 | ||
503 | MissingStructField => simple!("nonexistent struct field"), | |
504 | NonConstPath => simple!("non-constant path in constant expression"), | |
54a0048b | 505 | UnimplementedConstVal(what) => |
5bcae85e SL |
506 | simple!("unimplemented constant expression: {}", what), |
507 | UnresolvedPath => simple!("unresolved path in constant expression"), | |
508 | ExpectedConstTuple => simple!("expected constant tuple"), | |
509 | ExpectedConstStruct => simple!("expected constant struct"), | |
510 | TupleIndexOutOfBounds => simple!("tuple index out of bounds"), | |
511 | IndexedNonVec => simple!("indexing is only supported for arrays"), | |
512 | IndexNegative => simple!("indices must be non-negative integers"), | |
513 | IndexNotInt => simple!("indices must be integers"), | |
3157f602 | 514 | IndexOutOfBounds { len, index } => { |
5bcae85e SL |
515 | simple!("index out of bounds: the len is {} but the index is {}", |
516 | len, index) | |
3157f602 | 517 | } |
5bcae85e SL |
518 | RepeatCountNotNatural => simple!("repeat count must be a natural number"), |
519 | RepeatCountNotInt => simple!("repeat count must be integers"), | |
54a0048b | 520 | |
5bcae85e SL |
521 | MiscBinaryOp => simple!("bad operands for binary"), |
522 | MiscCatchAll => simple!("unsupported constant expr"), | |
523 | IndexOpFeatureGated => simple!("the index operation on const values is unstable"), | |
524 | Math(ref err) => Simple(err.description().into_cow()), | |
54a0048b | 525 | |
5bcae85e SL |
526 | IntermediateUnsignedNegative => simple!( |
527 | "during the computation of an unsigned a negative \ | |
528 | number was encountered. This is most likely a bug in\ | |
529 | the constant evaluator"), | |
54a0048b SL |
530 | |
531 | TypeMismatch(ref expected, ref got) => { | |
5bcae85e | 532 | simple!("expected {}, found {}", expected, got.description()) |
54a0048b | 533 | }, |
5bcae85e SL |
534 | BadType(ref i) => simple!("value of wrong type: {:?}", i), |
535 | ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), | |
a7813a04 | 536 | CharCast(ref got) => { |
5bcae85e | 537 | simple!("only `u8` can be cast as `char`, not `{}`", got.description()) |
a7813a04 | 538 | }, |
54a0048b SL |
539 | } |
540 | } | |
541 | } | |
542 | ||
543 | pub type EvalResult = Result<ConstVal, ConstEvalErr>; | |
544 | pub type CastResult = Result<ConstVal, ErrKind>; | |
545 | ||
546 | // FIXME: Long-term, this enum should go away: trying to evaluate | |
547 | // an expression which hasn't been type-checked is a recipe for | |
548 | // disaster. That said, it's not clear how to fix ast_ty_to_ty | |
549 | // to avoid the ordering issue. | |
550 | ||
551 | /// Hint to determine how to evaluate constant expressions which | |
552 | /// might not be type-checked. | |
553 | #[derive(Copy, Clone, Debug)] | |
554 | pub enum EvalHint<'tcx> { | |
555 | /// We have a type-checked expression. | |
556 | ExprTypeChecked, | |
557 | /// We have an expression which hasn't been type-checked, but we have | |
558 | /// an idea of what the type will be because of the context. For example, | |
559 | /// the length of an array is always `usize`. (This is referred to as | |
560 | /// a hint because it isn't guaranteed to be consistent with what | |
561 | /// type-checking would compute.) | |
562 | UncheckedExprHint(Ty<'tcx>), | |
563 | /// We have an expression which has not yet been type-checked, and | |
564 | /// and we have no clue what the type will be. | |
565 | UncheckedExprNoHint, | |
566 | } | |
567 | ||
568 | impl<'tcx> EvalHint<'tcx> { | |
569 | fn erase_hint(&self) -> EvalHint<'tcx> { | |
570 | match *self { | |
571 | ExprTypeChecked => ExprTypeChecked, | |
572 | UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint, | |
573 | } | |
574 | } | |
575 | fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> { | |
576 | match *self { | |
577 | ExprTypeChecked => ExprTypeChecked, | |
578 | _ => UncheckedExprHint(ty), | |
579 | } | |
580 | } | |
581 | } | |
582 | ||
583 | macro_rules! signal { | |
584 | ($e:expr, $exn:expr) => { | |
585 | return Err(ConstEvalErr { span: $e.span, kind: $exn }) | |
586 | } | |
587 | } | |
588 | ||
589 | /// Evaluate a constant expression in a context where the expression isn't | |
590 | /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked, | |
591 | /// but a few places need to evaluate constants during type-checking, like | |
592 | /// computing the length of an array. (See also the FIXME above EvalHint.) | |
a7813a04 XL |
593 | pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
594 | e: &Expr, | |
595 | ty_hint: EvalHint<'tcx>, | |
596 | fn_args: FnArgMap) -> EvalResult { | |
54a0048b SL |
597 | // Try to compute the type of the expression based on the EvalHint. |
598 | // (See also the definition of EvalHint, and the FIXME above EvalHint.) | |
599 | let ety = match ty_hint { | |
600 | ExprTypeChecked => { | |
601 | // After type-checking, expr_ty is guaranteed to succeed. | |
602 | Some(tcx.expr_ty(e)) | |
603 | } | |
604 | UncheckedExprHint(ty) => { | |
605 | // Use the type hint; it's not guaranteed to be right, but it's | |
606 | // usually good enough. | |
607 | Some(ty) | |
608 | } | |
609 | UncheckedExprNoHint => { | |
610 | // This expression might not be type-checked, and we have no hint. | |
611 | // Try to query the context for a type anyway; we might get lucky | |
612 | // (for example, if the expression was imported from another crate). | |
613 | tcx.expr_ty_opt(e) | |
614 | } | |
615 | }; | |
616 | let result = match e.node { | |
617 | hir::ExprUnary(hir::UnNeg, ref inner) => { | |
618 | // unary neg literals already got their sign during creation | |
619 | if let hir::ExprLit(ref lit) = inner.node { | |
620 | use syntax::ast::*; | |
621 | use syntax::ast::LitIntType::*; | |
622 | const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1; | |
623 | const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1; | |
624 | const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1; | |
625 | const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1; | |
626 | match (&lit.node, ety.map(|t| &t.sty)) { | |
627 | (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) | | |
628 | (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { | |
629 | return Ok(Integral(I8(::std::i8::MIN))) | |
630 | }, | |
631 | (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) | | |
632 | (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { | |
633 | return Ok(Integral(I16(::std::i16::MIN))) | |
634 | }, | |
635 | (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) | | |
636 | (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { | |
637 | return Ok(Integral(I32(::std::i32::MIN))) | |
638 | }, | |
639 | (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) | | |
640 | (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { | |
641 | return Ok(Integral(I64(::std::i64::MIN))) | |
642 | }, | |
643 | (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) | | |
644 | (&LitKind::Int(n, Signed(IntTy::Is)), _) => { | |
645 | match tcx.sess.target.int_type { | |
3157f602 XL |
646 | IntTy::I16 => if n == I16_OVERFLOW { |
647 | return Ok(Integral(Isize(Is16(::std::i16::MIN)))); | |
648 | }, | |
54a0048b SL |
649 | IntTy::I32 => if n == I32_OVERFLOW { |
650 | return Ok(Integral(Isize(Is32(::std::i32::MIN)))); | |
651 | }, | |
652 | IntTy::I64 => if n == I64_OVERFLOW { | |
653 | return Ok(Integral(Isize(Is64(::std::i64::MIN)))); | |
654 | }, | |
655 | _ => bug!(), | |
656 | } | |
657 | }, | |
658 | _ => {}, | |
659 | } | |
660 | } | |
661 | match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? { | |
662 | Float(f) => Float(-f), | |
663 | Integral(i) => Integral(math!(e, -i)), | |
664 | const_val => signal!(e, NegateOn(const_val)), | |
665 | } | |
666 | } | |
667 | hir::ExprUnary(hir::UnNot, ref inner) => { | |
668 | match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? { | |
669 | Integral(i) => Integral(math!(e, !i)), | |
670 | Bool(b) => Bool(!b), | |
671 | const_val => signal!(e, NotOn(const_val)), | |
672 | } | |
673 | } | |
674 | hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")), | |
675 | hir::ExprBinary(op, ref a, ref b) => { | |
676 | let b_ty = match op.node { | |
677 | hir::BiShl | hir::BiShr => ty_hint.erase_hint(), | |
678 | _ => ty_hint | |
679 | }; | |
680 | // technically, if we don't have type hints, but integral eval | |
681 | // gives us a type through a type-suffix, cast or const def type | |
682 | // we need to re-eval the other value of the BinOp if it was | |
683 | // not inferred | |
684 | match (eval_const_expr_partial(tcx, &a, ty_hint, fn_args)?, | |
685 | eval_const_expr_partial(tcx, &b, b_ty, fn_args)?) { | |
686 | (Float(a), Float(b)) => { | |
3157f602 | 687 | use std::cmp::Ordering::*; |
54a0048b | 688 | match op.node { |
3157f602 XL |
689 | hir::BiAdd => Float(math!(e, a + b)), |
690 | hir::BiSub => Float(math!(e, a - b)), | |
691 | hir::BiMul => Float(math!(e, a * b)), | |
692 | hir::BiDiv => Float(math!(e, a / b)), | |
693 | hir::BiRem => Float(math!(e, a % b)), | |
694 | hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal), | |
695 | hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less), | |
696 | hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater), | |
697 | hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), | |
698 | hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), | |
699 | hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), | |
54a0048b SL |
700 | _ => signal!(e, InvalidOpForFloats(op.node)), |
701 | } | |
702 | } | |
703 | (Integral(a), Integral(b)) => { | |
704 | use std::cmp::Ordering::*; | |
705 | match op.node { | |
706 | hir::BiAdd => Integral(math!(e, a + b)), | |
707 | hir::BiSub => Integral(math!(e, a - b)), | |
708 | hir::BiMul => Integral(math!(e, a * b)), | |
709 | hir::BiDiv => Integral(math!(e, a / b)), | |
710 | hir::BiRem => Integral(math!(e, a % b)), | |
711 | hir::BiBitAnd => Integral(math!(e, a & b)), | |
712 | hir::BiBitOr => Integral(math!(e, a | b)), | |
713 | hir::BiBitXor => Integral(math!(e, a ^ b)), | |
714 | hir::BiShl => Integral(math!(e, a << b)), | |
715 | hir::BiShr => Integral(math!(e, a >> b)), | |
716 | hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal), | |
717 | hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less), | |
718 | hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater), | |
719 | hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), | |
720 | hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), | |
721 | hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), | |
722 | _ => signal!(e, InvalidOpForInts(op.node)), | |
723 | } | |
724 | } | |
725 | (Bool(a), Bool(b)) => { | |
726 | Bool(match op.node { | |
727 | hir::BiAnd => a && b, | |
728 | hir::BiOr => a || b, | |
729 | hir::BiBitXor => a ^ b, | |
730 | hir::BiBitAnd => a & b, | |
731 | hir::BiBitOr => a | b, | |
732 | hir::BiEq => a == b, | |
733 | hir::BiNe => a != b, | |
734 | _ => signal!(e, InvalidOpForBools(op.node)), | |
735 | }) | |
736 | } | |
737 | ||
738 | _ => signal!(e, MiscBinaryOp), | |
739 | } | |
740 | } | |
741 | hir::ExprCast(ref base, ref target_ty) => { | |
a7813a04 | 742 | let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety) |
54a0048b SL |
743 | .unwrap_or_else(|| { |
744 | tcx.sess.span_fatal(target_ty.span, | |
745 | "target type not found for const cast") | |
746 | }); | |
747 | ||
748 | let base_hint = if let ExprTypeChecked = ty_hint { | |
749 | ExprTypeChecked | |
750 | } else { | |
751 | match tcx.expr_ty_opt(&base) { | |
752 | Some(t) => UncheckedExprHint(t), | |
753 | None => ty_hint | |
754 | } | |
755 | }; | |
756 | ||
757 | let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) { | |
758 | Ok(val) => val, | |
a7813a04 XL |
759 | Err(ConstEvalErr { kind: ErroneousReferencedConstant( |
760 | box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) | | |
54a0048b SL |
761 | Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => { |
762 | // Something like `5i8 as usize` doesn't need a type hint for the base | |
763 | // instead take the type hint from the inner value | |
764 | let hint = match val.int_type() { | |
765 | Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)), | |
766 | Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)), | |
767 | // we had a type hint, so we can't have an unknown type | |
768 | None => bug!(), | |
769 | }; | |
770 | eval_const_expr_partial(tcx, &base, hint, fn_args)? | |
771 | }, | |
772 | Err(e) => return Err(e), | |
773 | }; | |
774 | match cast_const(tcx, val, ety) { | |
775 | Ok(val) => val, | |
776 | Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), | |
777 | } | |
778 | } | |
779 | hir::ExprPath(..) => { | |
3157f602 XL |
780 | // This function can be used before type checking when not all paths are fully resolved. |
781 | // FIXME: There's probably a better way to make sure we don't panic here. | |
782 | let resolution = tcx.expect_resolution(e.id); | |
783 | if resolution.depth != 0 { | |
784 | signal!(e, UnresolvedPath); | |
785 | } | |
786 | match resolution.base_def { | |
54a0048b SL |
787 | Def::Const(def_id) | |
788 | Def::AssociatedConst(def_id) => { | |
789 | let substs = if let ExprTypeChecked = ty_hint { | |
790 | Some(tcx.node_id_item_substs(e.id).substs) | |
791 | } else { | |
792 | None | |
793 | }; | |
a7813a04 | 794 | if let Some((expr, ty)) = lookup_const_by_id(tcx, def_id, substs) { |
54a0048b SL |
795 | let item_hint = match ty { |
796 | Some(ty) => ty_hint.checked_or(ty), | |
797 | None => ty_hint, | |
798 | }; | |
a7813a04 XL |
799 | match eval_const_expr_partial(tcx, expr, item_hint, None) { |
800 | Ok(val) => val, | |
801 | Err(err) => { | |
802 | debug!("bad reference: {:?}, {:?}", err.description(), err.span); | |
803 | signal!(e, ErroneousReferencedConstant(box err)) | |
804 | }, | |
805 | } | |
54a0048b SL |
806 | } else { |
807 | signal!(e, NonConstPath); | |
808 | } | |
809 | }, | |
9e0c209e SL |
810 | Def::Variant(variant_def) => { |
811 | if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) { | |
a7813a04 XL |
812 | match eval_const_expr_partial(tcx, const_expr, ty_hint, None) { |
813 | Ok(val) => val, | |
814 | Err(err) => { | |
815 | debug!("bad reference: {:?}, {:?}", err.description(), err.span); | |
816 | signal!(e, ErroneousReferencedConstant(box err)) | |
817 | }, | |
818 | } | |
54a0048b SL |
819 | } else { |
820 | signal!(e, UnimplementedConstVal("enum variants")); | |
821 | } | |
822 | } | |
823 | Def::Struct(..) => { | |
824 | ConstVal::Struct(e.id) | |
825 | } | |
9e0c209e SL |
826 | Def::Local(def_id) => { |
827 | let id = tcx.map.as_local_node_id(def_id).unwrap(); | |
54a0048b SL |
828 | debug!("Def::Local({:?}): {:?}", id, fn_args); |
829 | if let Some(val) = fn_args.and_then(|args| args.get(&id)) { | |
830 | val.clone() | |
831 | } else { | |
832 | signal!(e, NonConstPath); | |
833 | } | |
834 | }, | |
835 | Def::Method(id) | Def::Fn(id) => Function(id), | |
836 | _ => signal!(e, NonConstPath), | |
837 | } | |
838 | } | |
839 | hir::ExprCall(ref callee, ref args) => { | |
840 | let sub_ty_hint = ty_hint.erase_hint(); | |
841 | let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?; | |
842 | let did = match callee_val { | |
843 | Function(did) => did, | |
844 | Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), | |
845 | callee => signal!(e, CallOn(callee)), | |
846 | }; | |
847 | let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { | |
848 | (fn_like.decl(), &fn_like.body().expr) | |
849 | } else { | |
850 | signal!(e, NonConstPath) | |
851 | }; | |
852 | let result = result.as_ref().expect("const fn has no result expression"); | |
853 | assert_eq!(decl.inputs.len(), args.len()); | |
854 | ||
855 | let mut call_args = NodeMap(); | |
856 | for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { | |
857 | let arg_hint = ty_hint.erase_hint(); | |
858 | let arg_val = eval_const_expr_partial( | |
859 | tcx, | |
860 | arg_expr, | |
861 | arg_hint, | |
862 | fn_args | |
863 | )?; | |
864 | debug!("const call arg: {:?}", arg); | |
865 | let old = call_args.insert(arg.pat.id, arg_val); | |
866 | assert!(old.is_none()); | |
867 | } | |
868 | debug!("const call({:?})", call_args); | |
869 | eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))? | |
870 | }, | |
9e0c209e | 871 | hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) { |
a7813a04 XL |
872 | Ok(val) => val, |
873 | Err(err) => signal!(e, err), | |
874 | }, | |
54a0048b SL |
875 | hir::ExprBlock(ref block) => { |
876 | match block.expr { | |
877 | Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?, | |
878 | None => signal!(e, UnimplementedConstVal("empty block")), | |
879 | } | |
880 | } | |
881 | hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?, | |
882 | hir::ExprTup(_) => Tuple(e.id), | |
883 | hir::ExprStruct(..) => Struct(e.id), | |
884 | hir::ExprIndex(ref arr, ref idx) => { | |
885 | if !tcx.sess.features.borrow().const_indexing { | |
886 | signal!(e, IndexOpFeatureGated); | |
887 | } | |
888 | let arr_hint = ty_hint.erase_hint(); | |
889 | let arr = eval_const_expr_partial(tcx, arr, arr_hint, fn_args)?; | |
890 | let idx_hint = ty_hint.checked_or(tcx.types.usize); | |
891 | let idx = match eval_const_expr_partial(tcx, idx, idx_hint, fn_args)? { | |
892 | Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type), | |
893 | Integral(_) => bug!(), | |
894 | _ => signal!(idx, IndexNotInt), | |
895 | }; | |
896 | assert_eq!(idx as usize as u64, idx); | |
897 | match arr { | |
3157f602 XL |
898 | Array(_, n) if idx >= n => { |
899 | signal!(e, IndexOutOfBounds { len: n, index: idx }) | |
900 | } | |
54a0048b SL |
901 | Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node { |
902 | assert_eq!(n as usize as u64, n); | |
903 | eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)? | |
904 | } else { | |
905 | bug!() | |
906 | }, | |
907 | ||
3157f602 XL |
908 | Repeat(_, n) if idx >= n => { |
909 | signal!(e, IndexOutOfBounds { len: n, index: idx }) | |
910 | } | |
54a0048b SL |
911 | Repeat(elem, _) => eval_const_expr_partial( |
912 | tcx, | |
913 | &tcx.map.expect_expr(elem), | |
914 | ty_hint, | |
915 | fn_args, | |
916 | )?, | |
917 | ||
3157f602 XL |
918 | ByteStr(ref data) if idx >= data.len() as u64 => { |
919 | signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx }) | |
920 | } | |
54a0048b SL |
921 | ByteStr(data) => { |
922 | Integral(U8(data[idx as usize])) | |
923 | }, | |
924 | ||
54a0048b SL |
925 | _ => signal!(e, IndexedNonVec), |
926 | } | |
927 | } | |
928 | hir::ExprVec(ref v) => Array(e.id, v.len() as u64), | |
929 | hir::ExprRepeat(_, ref n) => { | |
930 | let len_hint = ty_hint.checked_or(tcx.types.usize); | |
931 | Repeat( | |
932 | e.id, | |
933 | match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? { | |
934 | Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type), | |
935 | Integral(_) => signal!(e, RepeatCountNotNatural), | |
936 | _ => signal!(e, RepeatCountNotInt), | |
937 | }, | |
938 | ) | |
939 | }, | |
940 | hir::ExprTupField(ref base, index) => { | |
941 | let base_hint = ty_hint.erase_hint(); | |
942 | let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?; | |
943 | if let Tuple(tup_id) = c { | |
944 | if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node { | |
945 | if index.node < fields.len() { | |
946 | eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)? | |
947 | } else { | |
948 | signal!(e, TupleIndexOutOfBounds); | |
949 | } | |
950 | } else { | |
951 | bug!() | |
952 | } | |
953 | } else { | |
954 | signal!(base, ExpectedConstTuple); | |
955 | } | |
956 | } | |
957 | hir::ExprField(ref base, field_name) => { | |
958 | let base_hint = ty_hint.erase_hint(); | |
959 | // Get the base expression if it is a struct and it is constant | |
960 | let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?; | |
961 | if let Struct(struct_id) = c { | |
962 | if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node { | |
963 | // Check that the given field exists and evaluate it | |
964 | // if the idents are compared run-pass/issue-19244 fails | |
965 | if let Some(f) = fields.iter().find(|f| f.name.node | |
966 | == field_name.node) { | |
967 | eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)? | |
968 | } else { | |
969 | signal!(e, MissingStructField); | |
970 | } | |
971 | } else { | |
972 | bug!() | |
973 | } | |
974 | } else { | |
975 | signal!(base, ExpectedConstStruct); | |
976 | } | |
977 | } | |
978 | hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")), | |
979 | _ => signal!(e, MiscCatchAll) | |
980 | }; | |
981 | ||
982 | match (ety.map(|t| &t.sty), result) { | |
a7813a04 XL |
983 | (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) { |
984 | Ok(inferred) => Ok(Integral(inferred)), | |
985 | Err(err) => signal!(e, err), | |
986 | }, | |
54a0048b SL |
987 | (_, result) => Ok(result), |
988 | } | |
989 | } | |
990 | ||
a7813a04 XL |
991 | fn infer<'a, 'tcx>(i: ConstInt, |
992 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
993 | ty_hint: &ty::TypeVariants<'tcx>) | |
994 | -> Result<ConstInt, ErrKind> { | |
54a0048b SL |
995 | use syntax::ast::*; |
996 | ||
54a0048b SL |
997 | match (ty_hint, i) { |
998 | (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result), | |
999 | (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), | |
1000 | (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result), | |
1001 | (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result), | |
1002 | (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result), | |
1003 | ||
1004 | (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result), | |
1005 | (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result), | |
1006 | (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result), | |
1007 | (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result), | |
1008 | (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result), | |
1009 | ||
1010 | (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)), | |
1011 | (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)), | |
1012 | (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)), | |
1013 | (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)), | |
1014 | (&ty::TyInt(IntTy::Is), Infer(i)) => { | |
3157f602 | 1015 | Ok(Isize(ConstIsize::new_truncating(i as i64, tcx.sess.target.int_type))) |
54a0048b SL |
1016 | }, |
1017 | ||
1018 | (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)), | |
1019 | (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)), | |
1020 | (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)), | |
1021 | (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)), | |
1022 | (&ty::TyInt(IntTy::Is), InferSigned(i)) => { | |
3157f602 | 1023 | Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type))) |
54a0048b SL |
1024 | }, |
1025 | ||
1026 | (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)), | |
1027 | (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)), | |
1028 | (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)), | |
1029 | (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)), | |
1030 | (&ty::TyUint(UintTy::Us), Infer(i)) => { | |
3157f602 | 1031 | Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type))) |
54a0048b | 1032 | }, |
a7813a04 | 1033 | (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative), |
54a0048b | 1034 | |
a7813a04 XL |
1035 | (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), |
1036 | (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), | |
54a0048b | 1037 | |
9e0c209e | 1038 | (&ty::TyAdt(adt, _), i) if adt.is_enum() => { |
54a0048b SL |
1039 | let hints = tcx.lookup_repr_hints(adt.did); |
1040 | let int_ty = tcx.enum_repr_type(hints.iter().next()); | |
a7813a04 | 1041 | infer(i, tcx, &int_ty.to_ty(tcx).sty) |
54a0048b | 1042 | }, |
a7813a04 | 1043 | (_, i) => Err(BadType(ConstVal::Integral(i))), |
54a0048b SL |
1044 | } |
1045 | } | |
1046 | ||
a7813a04 | 1047 | fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
54a0048b SL |
1048 | ti: &'tcx hir::TraitItem, |
1049 | trait_id: DefId, | |
9e0c209e | 1050 | rcvr_substs: &'tcx Substs<'tcx>) |
54a0048b SL |
1051 | -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> |
1052 | { | |
9e0c209e | 1053 | let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); |
54a0048b SL |
1054 | debug!("resolve_trait_associated_const: trait_ref={:?}", |
1055 | trait_ref); | |
1056 | ||
9e0c209e | 1057 | tcx.populate_implementations_for_trait_if_necessary(trait_id); |
5bcae85e | 1058 | tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { |
a7813a04 XL |
1059 | let mut selcx = traits::SelectionContext::new(&infcx); |
1060 | let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), | |
1061 | trait_ref.to_poly_trait_predicate()); | |
1062 | let selection = match selcx.select(&obligation) { | |
1063 | Ok(Some(vtable)) => vtable, | |
1064 | // Still ambiguous, so give up and let the caller decide whether this | |
1065 | // expression is really needed yet. Some associated constant values | |
1066 | // can't be evaluated until monomorphization is done in trans. | |
1067 | Ok(None) => { | |
1068 | return None | |
1069 | } | |
1070 | Err(_) => { | |
1071 | return None | |
1072 | } | |
1073 | }; | |
54a0048b | 1074 | |
a7813a04 | 1075 | // NOTE: this code does not currently account for specialization, but when |
5bcae85e | 1076 | // it does so, it should hook into the Reveal to determine when the |
a7813a04 | 1077 | // constant should resolve; this will also require plumbing through to this |
5bcae85e | 1078 | // function whether we are in "trans mode" to pick the right Reveal |
a7813a04 XL |
1079 | // when constructing the inference context above. |
1080 | match selection { | |
1081 | traits::VtableImpl(ref impl_data) => { | |
9e0c209e SL |
1082 | let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) |
1083 | .iter().filter_map(|&def_id| { | |
1084 | match tcx.impl_or_trait_item(def_id) { | |
1085 | ty::ConstTraitItem(ic) => Some(ic), | |
1086 | _ => None | |
1087 | } | |
1088 | }).find(|ic| ic.name == ti.name); | |
1089 | match ac { | |
a7813a04 XL |
1090 | Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), |
1091 | None => match ti.node { | |
1092 | hir::ConstTraitItem(ref ty, Some(ref expr)) => { | |
1093 | Some((&*expr, tcx.ast_ty_to_prim_ty(ty))) | |
1094 | }, | |
1095 | _ => None, | |
54a0048b | 1096 | }, |
a7813a04 XL |
1097 | } |
1098 | } | |
1099 | _ => { | |
1100 | span_bug!(ti.span, | |
1101 | "resolve_trait_associated_const: unexpected vtable type") | |
54a0048b SL |
1102 | } |
1103 | } | |
a7813a04 | 1104 | }) |
54a0048b SL |
1105 | } |
1106 | ||
a7813a04 | 1107 | fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult { |
54a0048b SL |
1108 | let v = val.to_u64_unchecked(); |
1109 | match ty.sty { | |
1110 | ty::TyBool if v == 0 => Ok(Bool(false)), | |
1111 | ty::TyBool if v == 1 => Ok(Bool(true)), | |
1112 | ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))), | |
1113 | ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))), | |
1114 | ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))), | |
1115 | ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))), | |
1116 | ty::TyInt(ast::IntTy::Is) => { | |
3157f602 | 1117 | Ok(Integral(Isize(ConstIsize::new_truncating(v as i64, tcx.sess.target.int_type)))) |
54a0048b SL |
1118 | }, |
1119 | ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))), | |
1120 | ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))), | |
1121 | ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))), | |
1122 | ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))), | |
1123 | ty::TyUint(ast::UintTy::Us) => { | |
3157f602 | 1124 | Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type)))) |
54a0048b | 1125 | }, |
a7813a04 | 1126 | ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { |
3157f602 XL |
1127 | Infer(u) => Ok(Float(F64(u as f64))), |
1128 | InferSigned(i) => Ok(Float(F64(i as f64))), | |
a7813a04 | 1129 | _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), |
54a0048b | 1130 | }, |
a7813a04 | 1131 | ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { |
3157f602 XL |
1132 | Infer(u) => Ok(Float(F32(u as f32))), |
1133 | InferSigned(i) => Ok(Float(F32(i as f32))), | |
a7813a04 | 1134 | _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), |
54a0048b | 1135 | }, |
54a0048b | 1136 | ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), |
a7813a04 XL |
1137 | ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) { |
1138 | Ok(U8(u)) => Ok(Char(u as char)), | |
1139 | // can only occur before typeck, typeck blocks `T as char` for `T` != `u8` | |
1140 | _ => Err(CharCast(val)), | |
1141 | }, | |
54a0048b SL |
1142 | _ => Err(CannotCast), |
1143 | } | |
1144 | } | |
1145 | ||
3157f602 XL |
1146 | fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
1147 | val: ConstFloat, | |
1148 | ty: ty::Ty) -> CastResult { | |
54a0048b | 1149 | match ty.sty { |
3157f602 XL |
1150 | ty::TyInt(_) | ty::TyUint(_) => { |
1151 | let i = match val { | |
1152 | F32(f) if f >= 0.0 => Infer(f as u64), | |
1153 | FInfer { f64: f, .. } | | |
1154 | F64(f) if f >= 0.0 => Infer(f as u64), | |
1155 | ||
1156 | F32(f) => InferSigned(f as i64), | |
1157 | FInfer { f64: f, .. } | | |
1158 | F64(f) => InferSigned(f as i64) | |
1159 | }; | |
1160 | ||
1161 | if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) { | |
1162 | return Err(CannotCast); | |
1163 | } | |
1164 | ||
1165 | cast_const_int(tcx, i, ty) | |
1166 | } | |
1167 | ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val { | |
1168 | F32(f) => f as f64, | |
1169 | FInfer { f64: f, .. } | F64(f) => f | |
1170 | }))), | |
1171 | ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val { | |
1172 | F64(f) => f as f32, | |
1173 | FInfer { f32: f, .. } | F32(f) => f | |
1174 | }))), | |
54a0048b SL |
1175 | _ => Err(CannotCast), |
1176 | } | |
1177 | } | |
1178 | ||
a7813a04 | 1179 | fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult { |
54a0048b SL |
1180 | match val { |
1181 | Integral(i) => cast_const_int(tcx, i, ty), | |
1182 | Bool(b) => cast_const_int(tcx, Infer(b as u64), ty), | |
1183 | Float(f) => cast_const_float(tcx, f, ty), | |
1184 | Char(c) => cast_const_int(tcx, Infer(c as u64), ty), | |
1185 | Function(_) => Err(UnimplementedConstVal("casting fn pointers")), | |
5bcae85e | 1186 | ByteStr(b) => match ty.sty { |
a7813a04 XL |
1187 | ty::TyRawPtr(_) => { |
1188 | Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) | |
1189 | }, | |
5bcae85e SL |
1190 | ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { |
1191 | ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)), | |
1192 | ty::TySlice(_) => { | |
1193 | Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")) | |
1194 | }, | |
1195 | _ => Err(CannotCast), | |
1196 | }, | |
1197 | _ => Err(CannotCast), | |
1198 | }, | |
1199 | Str(s) => match ty.sty { | |
1200 | ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")), | |
1201 | ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { | |
1202 | ty::TyStr => Ok(Str(s)), | |
1203 | _ => Err(CannotCast), | |
1204 | }, | |
a7813a04 XL |
1205 | _ => Err(CannotCast), |
1206 | }, | |
54a0048b SL |
1207 | _ => Err(CannotCast), |
1208 | } | |
1209 | } | |
1210 | ||
a7813a04 XL |
1211 | fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, |
1212 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
9e0c209e | 1213 | ty_hint: Option<Ty<'tcx>>) |
a7813a04 | 1214 | -> Result<ConstVal, ErrKind> { |
54a0048b SL |
1215 | use syntax::ast::*; |
1216 | use syntax::ast::LitIntType::*; | |
1217 | match *lit { | |
1218 | LitKind::Str(ref s, _) => Ok(Str((*s).clone())), | |
1219 | LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), | |
1220 | LitKind::Byte(n) => Ok(Integral(U8(n))), | |
1221 | LitKind::Int(n, Signed(ity)) => { | |
a7813a04 | 1222 | infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) |
54a0048b SL |
1223 | }, |
1224 | ||
1225 | LitKind::Int(n, Unsuffixed) => { | |
1226 | match ty_hint.map(|t| &t.sty) { | |
1227 | Some(&ty::TyInt(ity)) => { | |
a7813a04 | 1228 | infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) |
54a0048b SL |
1229 | }, |
1230 | Some(&ty::TyUint(uty)) => { | |
a7813a04 | 1231 | infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) |
54a0048b SL |
1232 | }, |
1233 | None => Ok(Integral(Infer(n))), | |
9e0c209e | 1234 | Some(&ty::TyAdt(adt, _)) => { |
54a0048b SL |
1235 | let hints = tcx.lookup_repr_hints(adt.did); |
1236 | let int_ty = tcx.enum_repr_type(hints.iter().next()); | |
a7813a04 | 1237 | infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) |
54a0048b SL |
1238 | }, |
1239 | Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), | |
1240 | } | |
1241 | }, | |
1242 | LitKind::Int(n, Unsigned(ity)) => { | |
a7813a04 | 1243 | infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral) |
54a0048b SL |
1244 | }, |
1245 | ||
3157f602 | 1246 | LitKind::Float(ref n, fty) => { |
9e0c209e | 1247 | parse_float(n, Some(fty)).map(Float) |
3157f602 | 1248 | } |
54a0048b | 1249 | LitKind::FloatUnsuffixed(ref n) => { |
3157f602 XL |
1250 | let fty_hint = match ty_hint.map(|t| &t.sty) { |
1251 | Some(&ty::TyFloat(fty)) => Some(fty), | |
1252 | _ => None | |
1253 | }; | |
9e0c209e | 1254 | parse_float(n, fty_hint).map(Float) |
54a0048b SL |
1255 | } |
1256 | LitKind::Bool(b) => Ok(Bool(b)), | |
1257 | LitKind::Char(c) => Ok(Char(c)), | |
1258 | } | |
1259 | } | |
1260 | ||
9e0c209e SL |
1261 | fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>) |
1262 | -> Result<ConstFloat, ErrKind> { | |
3157f602 XL |
1263 | let val = match fty_hint { |
1264 | Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32), | |
1265 | Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64), | |
1266 | None => { | |
1267 | num.parse::<f32>().and_then(|f32| { | |
1268 | num.parse::<f64>().map(|f64| { | |
1269 | FInfer { f32: f32, f64: f64 } | |
1270 | }) | |
1271 | }) | |
1272 | } | |
1273 | }; | |
9e0c209e | 1274 | val.map_err(|_| { |
3157f602 | 1275 | // FIXME(#31407) this is only necessary because float parsing is buggy |
9e0c209e | 1276 | UnimplementedConstVal("could not evaluate float literal (see issue #31407)") |
3157f602 XL |
1277 | }) |
1278 | } | |
1279 | ||
5bcae85e SL |
1280 | pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) |
1281 | -> Result<Ordering, ErrorReported> | |
1282 | { | |
1283 | let result = match (a, b) { | |
54a0048b | 1284 | (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), |
3157f602 | 1285 | (&Float(a), &Float(b)) => a.try_cmp(b).ok(), |
54a0048b SL |
1286 | (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), |
1287 | (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), | |
1288 | (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)), | |
1289 | (&Char(a), &Char(ref b)) => Some(a.cmp(b)), | |
1290 | _ => None, | |
5bcae85e SL |
1291 | }; |
1292 | ||
1293 | match result { | |
1294 | Some(result) => Ok(result), | |
1295 | None => { | |
1296 | // FIXME: can this ever be reached? | |
1297 | span_err!(tcx.sess, span, E0298, | |
1298 | "type mismatch comparing {} and {}", | |
1299 | a.description(), | |
1300 | b.description()); | |
1301 | Err(ErrorReported) | |
1302 | } | |
54a0048b SL |
1303 | } |
1304 | } | |
1305 | ||
a7813a04 | 1306 | pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
5bcae85e | 1307 | span: Span, |
a7813a04 | 1308 | a: &Expr, |
5bcae85e | 1309 | b: &Expr) -> Result<Ordering, ErrorReported> { |
54a0048b SL |
1310 | let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) { |
1311 | Ok(a) => a, | |
1312 | Err(e) => { | |
5bcae85e SL |
1313 | report_const_eval_err(tcx, &e, a.span, "expression").emit(); |
1314 | return Err(ErrorReported); | |
54a0048b SL |
1315 | } |
1316 | }; | |
1317 | let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) { | |
1318 | Ok(b) => b, | |
1319 | Err(e) => { | |
5bcae85e SL |
1320 | report_const_eval_err(tcx, &e, b.span, "expression").emit(); |
1321 | return Err(ErrorReported); | |
54a0048b SL |
1322 | } |
1323 | }; | |
5bcae85e | 1324 | compare_const_vals(tcx, span, &a, &b) |
54a0048b SL |
1325 | } |
1326 | ||
1327 | ||
5bcae85e SL |
1328 | /// Returns the value of the length-valued expression |
1329 | pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
1330 | count_expr: &hir::Expr, | |
1331 | reason: &str) | |
1332 | -> Result<usize, ErrorReported> | |
1333 | { | |
54a0048b SL |
1334 | let hint = UncheckedExprHint(tcx.types.usize); |
1335 | match eval_const_expr_partial(tcx, count_expr, hint, None) { | |
1336 | Ok(Integral(Usize(count))) => { | |
1337 | let val = count.as_u64(tcx.sess.target.uint_type); | |
1338 | assert_eq!(val as usize as u64, val); | |
5bcae85e | 1339 | Ok(val as usize) |
54a0048b SL |
1340 | }, |
1341 | Ok(const_val) => { | |
5bcae85e SL |
1342 | struct_span_err!(tcx.sess, count_expr.span, E0306, |
1343 | "expected `usize` for {}, found {}", | |
1344 | reason, | |
1345 | const_val.description()) | |
1346 | .span_label(count_expr.span, &format!("expected `usize`")) | |
1347 | .emit(); | |
1348 | ||
1349 | Err(ErrorReported) | |
54a0048b SL |
1350 | } |
1351 | Err(err) => { | |
5bcae85e SL |
1352 | let mut diag = report_const_eval_err( |
1353 | tcx, &err, count_expr.span, reason); | |
1354 | ||
1355 | match count_expr.node { | |
54a0048b SL |
1356 | hir::ExprPath(None, hir::Path { |
1357 | global: false, | |
1358 | ref segments, | |
1359 | .. | |
5bcae85e SL |
1360 | }) if segments.len() == 1 => { |
1361 | if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) { | |
1362 | diag.note(&format!("`{}` is a variable", segments[0].name)); | |
1363 | } | |
54a0048b | 1364 | } |
5bcae85e SL |
1365 | _ => {} |
1366 | } | |
1367 | ||
1368 | diag.emit(); | |
1369 | Err(ErrorReported) | |
54a0048b SL |
1370 | } |
1371 | } | |
1372 | } |