about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-10-26 07:04:33 +0000
committerbors <bors@rust-lang.org>2017-10-26 07:04:33 +0000
commite0febe71449008fd35ccc762b0a42d106aa8e4f7 (patch)
treeead27705749d9217f86caf351f4236bc8f0a8cfb
parent56dc171a2f2dc2373b1930f71140a354fa84b982 (diff)
parent1ee0ff3bfed4ecf56b175b166286b7cd2163a81b (diff)
downloadrust-e0febe71449008fd35ccc762b0a42d106aa8e4f7.tar.gz
rust-e0febe71449008fd35ccc762b0a42d106aa8e4f7.zip
Auto merge of #45488 - oli-obk:ctfe_resolve, r=eddyb
Resolve types properly in const eval

r? @eddyb

cc @arielb1
-rw-r--r--src/librustc/ty/instance.rs4
-rw-r--r--src/librustc_const_eval/eval.rs98
-rw-r--r--src/test/run-pass/ctfe/assoc-const.rs28
3 files changed, 38 insertions, 92 deletions
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 600b2572f92..442c79393fd 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -100,7 +100,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
 impl<'a, 'b, 'tcx> Instance<'tcx> {
     pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
                -> Instance<'tcx> {
-        assert!(substs.is_normalized_for_trans() && !substs.has_escaping_regions(),
+        assert!(!substs.has_escaping_regions(),
                 "substs of instance {:?} not normalized for trans: {:?}",
                 def_id, substs);
         Instance { def: InstanceDef::Item(def_id), substs: substs }
@@ -139,7 +139,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
                    substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
         let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
-            debug!(" => associated item, attempting to find impl");
+            debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
             let item = tcx.associated_item(def_id);
             resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
         } else {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 7520c6ac652..657156902b5 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -13,9 +13,7 @@ use rustc::middle::const_val::ConstAggregate::*;
 use rustc::middle::const_val::ErrKind::*;
 use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
 
-use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
-use rustc::traits;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -54,33 +52,12 @@ macro_rules! math {
 pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
                                     -> Option<(DefId, &'tcx Substs<'tcx>)> {
-    let (def_id, _) = key.value;
-    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        match tcx.hir.find(node_id) {
-            Some(hir_map::NodeTraitItem(_)) => {
-                // If we have a trait item and the substitutions for it,
-                // `resolve_trait_associated_const` will select an impl
-                // or the default.
-                resolve_trait_associated_const(tcx, key)
-            }
-            _ => Some(key.value)
-        }
-    } else {
-        match tcx.describe_def(def_id) {
-            Some(Def::AssociatedConst(_)) => {
-                // As mentioned in the comments above for in-crate
-                // constants, we only try to find the expression for a
-                // trait-associated const if the caller gives us the
-                // substitutions for the reference to it.
-                if tcx.trait_of_item(def_id).is_some() {
-                    resolve_trait_associated_const(tcx, key)
-                } else {
-                    Some(key.value)
-                }
-            }
-            _ => Some(key.value)
-        }
-    }
+    ty::Instance::resolve(
+        tcx,
+        key.param_env,
+        key.value.0,
+        key.value.1,
+    ).map(|instance| (instance.def_id(), instance.substs))
 }
 
 pub struct ConstContext<'a, 'tcx: 'a> {
@@ -119,6 +96,7 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                                      e: &'tcx Expr) -> EvalResult<'tcx> {
+    trace!("eval_const_expr_partial: {:?}", e);
     let tcx = cx.tcx;
     let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
     let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
@@ -289,6 +267,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           match cx.tables.qpath_def(qpath, e.hir_id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
+                    let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
                     match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
                         Ok(val) => val,
                         Err(ConstEvalErr { kind: TypeckError, .. }) => {
@@ -486,67 +465,6 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
     Ok(result)
 }
 
-fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                            key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-                                            -> Option<(DefId, &'tcx Substs<'tcx>)> {
-    let param_env = key.param_env;
-    let (def_id, substs) = key.value;
-    let trait_item = tcx.associated_item(def_id);
-    let trait_id = trait_item.container.id();
-    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
-    debug!("resolve_trait_associated_const: trait_ref={:?}",
-           trait_ref);
-
-    tcx.infer_ctxt().enter(|infcx| {
-        let mut selcx = traits::SelectionContext::new(&infcx);
-        let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
-                                                 param_env,
-                                                 trait_ref.to_poly_trait_predicate());
-        let selection = match selcx.select(&obligation) {
-            Ok(Some(vtable)) => vtable,
-            // Still ambiguous, so give up and let the caller decide whether this
-            // expression is really needed yet. Some associated constant values
-            // can't be evaluated until monomorphization is done in trans.
-            Ok(None) => {
-                return None
-            }
-            Err(_) => {
-                return None
-            }
-        };
-
-        // NOTE: this code does not currently account for specialization, but when
-        // it does so, it should hook into the param_env.reveal to determine when the
-        // constant should resolve.
-        match selection {
-            traits::VtableImpl(ref impl_data) => {
-                let name = trait_item.name;
-                let ac = tcx.associated_items(impl_data.impl_def_id)
-                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
-                match ac {
-                    // FIXME(eddyb) Use proper Instance resolution to
-                    // get the correct Substs returned from here.
-                    Some(ic) => {
-                        let substs = Substs::identity_for_item(tcx, ic.def_id);
-                        Some((ic.def_id, substs))
-                    }
-                    None => {
-                        if trait_item.defaultness.has_value() {
-                            Some(key.value)
-                        } else {
-                            None
-                        }
-                    }
-                }
-            }
-            traits::VtableParam(_) => None,
-            _ => {
-                bug!("resolve_trait_associated_const: unexpected vtable type {:?}", selection)
-            }
-        }
-    })
-}
-
 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             val: ConstInt,
                             ty: Ty<'tcx>)
diff --git a/src/test/run-pass/ctfe/assoc-const.rs b/src/test/run-pass/ctfe/assoc-const.rs
new file mode 100644
index 00000000000..6a740dc1dd3
--- /dev/null
+++ b/src/test/run-pass/ctfe/assoc-const.rs
@@ -0,0 +1,28 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Nat {
+    const VALUE: usize;
+}
+
+struct Zero;
+struct Succ<N>(N);
+
+impl Nat for Zero {
+    const VALUE: usize = 0;
+}
+
+impl<N: Nat> Nat for Succ<N> {
+    const VALUE: usize = N::VALUE + 1;
+}
+
+fn main() {
+    let x: [i32; <Succ<Succ<Succ<Succ<Zero>>>>>::VALUE] = [1, 2, 3, 4];
+}