]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_const_eval/eval.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_const_eval / eval.rs
index 73b54c4374ffb65dce75dcf20a6a0bbe29545af5..4ae3c7d37db8dec202f82f0bf9f34cf2c3b49930 100644 (file)
@@ -22,8 +22,9 @@ use rustc::traits;
 use rustc::hir::def::{Def, PathResolution};
 use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::def_to_path;
-use rustc::ty::{self, Ty, TyCtxt, subst};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
+use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
@@ -56,7 +57,6 @@ macro_rules! math {
 }
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  enum_def: DefId,
                                   variant_def: DefId)
                                   -> Option<&'tcx Expr> {
     fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
@@ -69,8 +69,8 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         None
     }
 
-    if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
-        let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
+    if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
+        let enum_node_id = tcx.map.get_parent(variant_node_id);
         match tcx.map.find(enum_node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
@@ -93,7 +93,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<&'tcx subst::Substs<'tcx>>)
+                                        substs: Option<&'tcx Substs<'tcx>>)
                                         -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
@@ -105,12 +105,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     if let Some(substs) = substs {
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
                         // or the default.
-                        let trait_id = tcx.trait_of_item(def_id).unwrap();
+                        let trait_id = tcx.map.get_parent(node_id);
+                        let trait_id = tcx.map.local_def_id(trait_id);
                         resolve_trait_associated_const(tcx, ti, trait_id, substs)
                     } else {
                         // Technically, without knowing anything about the
@@ -149,7 +150,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     used_substs = true;
                     if let Some(substs) = substs {
                         // As mentioned in the comments above for in-crate
@@ -226,10 +227,10 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
     };
 
     match fn_like.kind() {
-        FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => {
+        FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
             Some(fn_like)
         }
-        FnKind::Method(_, m, _, _) => {
+        FnKind::Method(_, m, ..) => {
             if m.constness == hir::Constness::Const {
                 Some(fn_like)
             } else {
@@ -255,8 +256,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 format!("floating point constants cannot be used in patterns"));
         }
-        ty::TyEnum(adt_def, _) |
-        ty::TyStruct(adt_def, _) => {
+        ty::TyAdt(adt_def, _) if adt_def.is_union() => {
+            // Matching on union fields is unsafe, we can't hide it in constants
+            tcx.sess.span_err(span, "cannot use unions in constant patterns");
+        }
+        ty::TyAdt(adt_def, _) => {
             if !tcx.has_attr(adt_def.did, "structural_match") {
                 tcx.sess.add_lint(
                     lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
@@ -273,9 +277,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
     let pat = match expr.node {
         hir::ExprTup(ref exprs) =>
-            PatKind::Tuple(try!(exprs.iter()
-                                     .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                                     .collect()), None),
+            PatKind::Tuple(exprs.iter()
+                                .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
+                                .collect::<Result<_, _>>()?, None),
 
         hir::ExprCall(ref callee, ref args) => {
             let def = tcx.expect_def(callee.id);
@@ -284,7 +288,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
             let path = match def {
                 Def::Struct(def_id) => def_to_path(tcx, def_id),
-                Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
+                Def::Variant(variant_did) => def_to_path(tcx, variant_did),
                 Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
                     id: expr.id,
                     node: PatKind::Lit(P(expr.clone())),
@@ -292,34 +296,31 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 })),
                 _ => bug!()
             };
-            let pats = try!(args.iter()
-                                .map(|expr| const_expr_to_pat(tcx, &**expr,
-                                                              pat_id, span))
-                                .collect());
+            let pats = args.iter()
+                           .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span))
+                           .collect::<Result<_, _>>()?;
             PatKind::TupleStruct(path, pats, None)
         }
 
         hir::ExprStruct(ref path, ref fields, None) => {
             let field_pats =
-                try!(fields.iter()
-                           .map(|field| Ok(codemap::Spanned {
-                               span: syntax_pos::DUMMY_SP,
-                               node: hir::FieldPat {
-                                   name: field.name.node,
-                                   pat: try!(const_expr_to_pat(tcx, &field.expr,
-                                                               pat_id, span)),
-                                   is_shorthand: false,
-                               },
-                           }))
-                           .collect());
+                fields.iter()
+                      .map(|field| Ok(codemap::Spanned {
+                          span: syntax_pos::DUMMY_SP,
+                          node: hir::FieldPat {
+                              name: field.name.node,
+                              pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
+                              is_shorthand: false,
+                          },
+                      }))
+                      .collect::<Result<_, _>>()?;
             PatKind::Struct(path.clone(), field_pats, false)
         }
 
         hir::ExprVec(ref exprs) => {
-            let pats = try!(exprs.iter()
-                                 .map(|expr| const_expr_to_pat(tcx, &expr,
-                                                               pat_id, span))
-                                 .collect());
+            let pats = exprs.iter()
+                            .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
+                            .collect::<Result<_, _>>()?;
             PatKind::Vec(pats, None, hir::HirVec::new())
         }
 
@@ -806,8 +807,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Variant(enum_def, variant_def) => {
-                  if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
+              Def::Variant(variant_def) => {
+                  if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) {
                       match eval_const_expr_partial(tcx, const_expr, ty_hint, None) {
                           Ok(val) => val,
                           Err(err) => {
@@ -822,7 +823,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Def::Struct(..) => {
                   ConstVal::Struct(e.id)
               }
-              Def::Local(_, id) => {
+              Def::Local(def_id) => {
+                  let id = tcx.map.as_local_node_id(def_id).unwrap();
                   debug!("Def::Local({:?}): {:?}", id, fn_args);
                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
                       val.clone()
@@ -866,7 +868,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
           debug!("const call({:?})", call_args);
           eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
       },
-      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
+      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
           Err(err) => signal!(e, err),
       },
@@ -1033,7 +1035,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
         (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
         (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
 
-        (&ty::TyEnum(ref adt, _), i) => {
+        (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
             let hints = tcx.lookup_repr_hints(adt.did);
             let int_ty = tcx.enum_repr_type(hints.iter().next());
             infer(i, tcx, &int_ty.to_ty(tcx).sty)
@@ -1045,16 +1047,14 @@ fn infer<'a, 'tcx>(i: ConstInt,
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 ti: &'tcx hir::TraitItem,
                                                 trait_id: DefId,
-                                                rcvr_substs: &'tcx subst::Substs<'tcx>)
+                                                rcvr_substs: &'tcx Substs<'tcx>)
                                                 -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
-    let trait_ref = ty::Binder(
-        rcvr_substs.clone().erase_regions().to_trait_ref(tcx, trait_id)
-    );
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
+    tcx.populate_implementations_for_trait_if_necessary(trait_id);
     tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@@ -1079,8 +1079,14 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
-                match tcx.associated_consts(impl_data.impl_def_id)
-                        .iter().find(|ic| ic.name == ti.name) {
+                let ac = tcx.impl_or_trait_items(impl_data.impl_def_id)
+                    .iter().filter_map(|&def_id| {
+                        match tcx.impl_or_trait_item(def_id) {
+                            ty::ConstTraitItem(ic) => Some(ic),
+                            _ => None
+                        }
+                    }).find(|ic| ic.name == ti.name);
+                match ac {
                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
                     None => match ti.node {
                         hir::ConstTraitItem(ref ty, Some(ref expr)) => {
@@ -1204,8 +1210,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
 
 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty_hint: Option<Ty<'tcx>>,
-                          span: Span)
+                          ty_hint: Option<Ty<'tcx>>)
                           -> Result<ConstVal, ErrKind> {
     use syntax::ast::*;
     use syntax::ast::LitIntType::*;
@@ -1226,7 +1231,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                     infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral)
                 },
                 None => Ok(Integral(Infer(n))),
-                Some(&ty::TyEnum(ref adt, _)) => {
+                Some(&ty::TyAdt(adt, _)) => {
                     let hints = tcx.lookup_repr_hints(adt.did);
                     let int_ty = tcx.enum_repr_type(hints.iter().next());
                     infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
@@ -1239,21 +1244,22 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
         },
 
         LitKind::Float(ref n, fty) => {
-            Ok(Float(parse_float(n, Some(fty), span)))
+            parse_float(n, Some(fty)).map(Float)
         }
         LitKind::FloatUnsuffixed(ref n) => {
             let fty_hint = match ty_hint.map(|t| &t.sty) {
                 Some(&ty::TyFloat(fty)) => Some(fty),
                 _ => None
             };
-            Ok(Float(parse_float(n, fty_hint, span)))
+            parse_float(n, fty_hint).map(Float)
         }
         LitKind::Bool(b) => Ok(Bool(b)),
         LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFloat {
+fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
+               -> Result<ConstFloat, ErrKind> {
     let val = match fty_hint {
         Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
         Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
@@ -1265,9 +1271,9 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl
             })
         }
     };
-    val.unwrap_or_else(|_| {
+    val.map_err(|_| {
         // FIXME(#31407) this is only necessary because float parsing is buggy
-        span_bug!(span, "could not evaluate float literal (see issue #31407)");
+        UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
     })
 }