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