]> git.lizzy.rs Git - rust.git/commitdiff
Support generic associated consts
authorMichael Wu <mwu@mozilla.com>
Tue, 4 Aug 2015 02:16:24 +0000 (22:16 -0400)
committerMichael Wu <mwu@mozilla.com>
Thu, 14 Jan 2016 22:35:55 +0000 (17:35 -0500)
16 files changed:
src/librustc/middle/check_const.rs
src/librustc/middle/check_match.rs
src/librustc/middle/const_eval.rs
src/librustc_mir/hair/cx/pattern.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/mir/did.rs
src/librustc_typeck/check/mod.rs
src/librustdoc/clean/inline.rs
src/test/compile-fail/associated-const-array-len.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-no-item.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-type-parameter-arms.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-type-parameter-arrays-2.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-type-parameter-arrays.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-type-parameters.rs [deleted file]
src/test/run-pass/associated-const-type-parameters.rs [new file with mode: 0644]

index a9b3043e0909569e72558d3bab10e7ddba2598bd..a458c2e14bee6eadd5dad27669af48372e4d3057 100644 (file)
@@ -657,13 +657,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 Some(def::DefConst(did)) |
                 Some(def::DefAssociatedConst(did)) => {
                     if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
-                                                                       Some(e.id)) {
+                                                                       Some(e.id),
+                                                                       None) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
-                    } else {
-                        v.tcx.sess.span_bug(e.span,
-                                            "DefConst or DefAssociatedConst \
-                                             doesn't point to a constant");
                     }
                 }
                 Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {
index a33142433463adb5b0760b50b4a49abc57b10a3e..dc777585e4194e941b08b1478e5cde2ce88e7b31 100644 (file)
@@ -455,7 +455,8 @@ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
                 let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
                 match def {
                     Some(DefAssociatedConst(did)) |
-                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
+                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did,
+                                                                    Some(pat.id), None) {
                         Some(const_expr) => {
                             const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
 
index d5cfff4aff8a466f3a0090eb4e7063303630b7e7..de7f543e3280d3702be57a6038d9267582320cb7 100644 (file)
@@ -18,6 +18,7 @@
 use front::map::blocks::FnLikeNode;
 use middle::cstore::{self, CrateStore, InlinedItem};
 use middle::{def, infer, subst, traits};
+use middle::subst::Subst;
 use middle::def_id::DefId;
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty};
@@ -48,7 +49,7 @@ fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
     match opt_def {
         Some(def::DefConst(def_id)) |
         Some(def::DefAssociatedConst(def_id)) => {
-            lookup_const_by_id(tcx, def_id, Some(e.id))
+            lookup_const_by_id(tcx, def_id, Some(e.id), None)
         }
         Some(def::DefVariant(enum_def, variant_def, _)) => {
             lookup_variant_by_id(tcx, enum_def, variant_def)
@@ -88,9 +89,17 @@ fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
     }
 }
 
+/// * `def_id` is the id of the constant.
+/// * `maybe_ref_id` is the id of the expr referencing the constant.
+/// * `param_substs` is the monomorphization substitution for the expression.
+///
+/// `maybe_ref_id` and `param_substs` are optional and are used for
+/// finding substitutions in associated constants. This generally
+/// happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                                         def_id: DefId,
-                                        maybe_ref_id: Option<ast::NodeId>)
+                                        maybe_ref_id: Option<ast::NodeId>,
+                                        param_substs: Option<&'tcx subst::Substs<'tcx>>)
                                         -> Option<&'tcx Expr> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
@@ -111,8 +120,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                         Some(ref_id) => {
                             let trait_id = tcx.trait_of_item(def_id)
                                               .unwrap();
-                            let substs = tcx.node_id_item_substs(ref_id)
-                                            .substs;
+                            let mut substs = tcx.node_id_item_substs(ref_id)
+                                                .substs;
+                            if let Some(param_substs) = param_substs {
+                                substs = substs.subst(tcx, param_substs);
+                            }
                             resolve_trait_associated_const(tcx, ti, trait_id,
                                                            substs)
                         }
@@ -158,8 +170,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                         // a trait-associated const if the caller gives us
                         // the expression that refers to it.
                         Some(ref_id) => {
-                            let substs = tcx.node_id_item_substs(ref_id)
-                                            .substs;
+                            let mut substs = tcx.node_id_item_substs(ref_id)
+                                                .substs;
+                            if let Some(param_substs) = param_substs {
+                                substs = substs.subst(tcx, param_substs);
+                            }
                             resolve_trait_associated_const(tcx, ti, trait_id,
                                                            substs).map(|e| e.id)
                         }
@@ -1013,7 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                           _ => (None, None)
                       }
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
+                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
                   }
               }
               Some(def::DefAssociatedConst(def_id)) => {
@@ -1048,7 +1063,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                           },
                       }
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
+                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
                   }
               }
               Some(def::DefVariant(enum_def, variant_def, _)) => {
@@ -1260,12 +1275,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
         Ok(None) => {
             return None
         }
-        Err(e) => {
-            tcx.sess.span_bug(ti.span,
-                              &format!("Encountered error `{:?}` when trying \
-                                        to select an implementation for \
-                                        constant trait item reference.",
-                                       e))
+        Err(_) => {
+            return None
         }
     };
 
@@ -1273,7 +1284,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
         traits::VtableImpl(ref impl_data) => {
             match tcx.associated_consts(impl_data.impl_def_id)
                      .iter().find(|ic| ic.name == ti.name) {
-                Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
                 None => match ti.node {
                     hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
                     _ => None,
index 1f425aafa256adc40f4cc4bd740c242235c053c1..dc377ac731a6581ddf9346c4c7e1cebfb37d61ed 100644 (file)
@@ -85,7 +85,8 @@ fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                 let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
                 match def {
                     def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
-                        match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id)) {
+                        match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
+                                                             Some(pat.id), None) {
                             Some(const_expr) => {
                                 let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
                                                                         pat.span);
index 3ea358a8f4cd345b80b97ec429ce04c692bd9c57..d5a7995b65dfc21538e09db53899ed3720c53485 100644 (file)
@@ -217,7 +217,8 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 def_id: DefId,
-                                ref_expr: &hir::Expr)
+                                ref_expr: &hir::Expr,
+                                param_substs: &'tcx Substs<'tcx>)
                                 -> &'tcx hir::Expr {
     let def_id = inline::maybe_instantiate_inline(ccx, def_id);
 
@@ -226,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             "cross crate constant could not be inlined");
     }
 
-    match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
+    match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
         Some(ref expr) => expr,
         None => {
             ccx.sess().span_bug(ref_expr.span, "constant item not found")
@@ -264,10 +265,12 @@ pub enum TrueConst {
 
 use self::ConstEvalFailure::*;
 
-fn get_const_val(ccx: &CrateContext,
-                 def_id: DefId,
-                 ref_expr: &hir::Expr) -> Result<ValueRef, ConstEvalFailure> {
-    let expr = get_const_expr(ccx, def_id, ref_expr);
+fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                           def_id: DefId,
+                           ref_expr: &hir::Expr,
+                           param_substs: &'tcx Substs<'tcx>)
+                           -> Result<ValueRef, ConstEvalFailure> {
+    let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
     let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
     match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
                                    empty_substs, TrueConst::Yes) {
@@ -297,7 +300,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
                     debug!("get_const_expr_as_global ({:?}): found const {:?}",
                            expr.id, def_id);
-                    return get_const_val(ccx, def_id, expr);
+                    return get_const_val(ccx, def_id, expr, param_substs);
                 }
             },
             _ => {},
@@ -888,7 +891,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
                 }
                 def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
-                    const_deref_ptr(cx, try!(get_const_val(cx, def_id, e)))
+                    const_deref_ptr(cx, try!(get_const_val(cx, def_id, e, param_substs)))
                 }
                 def::DefVariant(enum_did, variant_did, _) => {
                     let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
index fb6f2190207ee3c8e33efe303b558371152800ba..0a89fd92845881fc732990dfd36798b7f471899b 100644 (file)
@@ -165,7 +165,9 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 hir::ExprPath(..) => {
                     match bcx.def(expr.id) {
                         def::DefConst(did) => {
-                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr);
+                            let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
+                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
+                                                                    empty_substs);
                             // Temporarily get cleanup scopes out of the way,
                             // as they require sub-expressions to be contained
                             // inside the current AST scope.
index 0e2387e3e349e3839725964fb9d8ced5c8e529a8..3238869cac5c1ad9adb165faf70ec246ca769fba 100644 (file)
@@ -50,7 +50,7 @@ pub fn trans_item_ref(&mut self,
             },
             ItemKind::Constant => {
                 let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None)
+                let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs))
                             .expect("def was const, but lookup_const_by_id failed");
                 // FIXME: this is falling back to translating from HIR. This is not easy to fix,
                 // because we would have somehow adapt const_eval to work on MIR rather than HIR.
index e644178ddd62f26bec6680ae47689213f15f95a1..0f87dc888524378ab8a1615d713b848ef3620ac3 100644 (file)
@@ -3785,35 +3785,8 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
                                                         def::Def)>
 {
 
-    // Associated constants can't depend on generic types.
-    fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                def: def::Def,
-                                                ty: Ty<'tcx>,
-                                                span: Span,
-                                                node_id: ast::NodeId) -> bool {
-        match def {
-            def::DefAssociatedConst(..) => {
-                if ty.has_param_types() || ty.has_self_ty() {
-                    span_err!(fcx.sess(), span, E0329,
-                              "Associated consts cannot depend \
-                               on type parameters or Self.");
-                    fcx.write_error(node_id);
-                    return true;
-                }
-            }
-            _ => {}
-        }
-        false
-    }
-
     // If fully resolved already, we don't have to do anything.
     if path_res.depth == 0 {
-        if let Some(ty) = opt_self_ty {
-            if have_disallowed_generic_consts(fcx, path_res.full_def(), ty,
-                                              span, node_id) {
-                return None;
-            }
-        }
         Some((opt_self_ty, &path.segments, path_res.base_def))
     } else {
         let mut def = path_res.base_def;
@@ -3829,9 +3802,6 @@ fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         let item_name = item_segment.identifier.name;
         match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
             Ok((def, lp)) => {
-                if have_disallowed_generic_consts(fcx, def, ty, span, node_id) {
-                    return None;
-                }
                 // Write back the new resolution.
                 fcx.ccx.tcx.def_map.borrow_mut()
                        .insert(node_id, def::PathResolution {
index 9bbbcc66ca6c04b0cb1125221d1fccf8c7d50801..30b478f486e0a8b1f771f0666b9e1824746152cd 100644 (file)
@@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext,
                 let did = assoc_const.def_id;
                 let type_scheme = tcx.lookup_item_type(did);
                 let default = if assoc_const.has_value {
-                    Some(const_eval::lookup_const_by_id(tcx, did, None)
+                    Some(const_eval::lookup_const_by_id(tcx, did, None, None)
                          .unwrap().span.to_src(cx))
                 } else {
                     None
@@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt,
     use rustc::middle::const_eval;
     use rustc_front::print::pprust;
 
-    let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
+    let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs
new file mode 100644 (file)
index 0000000..5d8007d
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: usize;
+}
+
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
+
+fn main() {
+    assert_eq!(1, X);
+}
diff --git a/src/test/compile-fail/associated-const-no-item.rs b/src/test/compile-fail/associated-const-no-item.rs
new file mode 100644 (file)
index 0000000..89d1ac1
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: i32;
+}
+
+const X: i32 = <i32>::ID;
+//~^ ERROR no associated item named `ID` found for type `i32`
+
+fn main() {
+    assert_eq!(1, X);
+}
diff --git a/src/test/compile-fail/associated-const-type-parameter-arms.rs b/src/test/compile-fail/associated-const-type-parameter-arms.rs
new file mode 100644 (file)
index 0000000..f564157
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 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.
+
+#![feature(associated_consts)]
+
+pub enum EFoo { A, B, C, D }
+
+pub trait Foo {
+    const X: EFoo;
+}
+
+struct Abc;
+impl Foo for Abc {
+    const X: EFoo = EFoo::B;
+}
+
+struct Def;
+impl Foo for Def {
+    const X: EFoo = EFoo::D;
+}
+
+pub fn test<A: Foo, B: Foo>(arg: EFoo) {
+    match arg {
+        A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158]
+        B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158]
+        _ => (),
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
new file mode 100644 (file)
index 0000000..2f68735
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+#![feature(associated_consts)]
+
+pub trait Foo {
+    const Y: usize;
+}
+
+struct Abc;
+impl Foo for Abc {
+    const Y: usize = 8;
+}
+
+struct Def;
+impl Foo for Def {
+    const Y: usize = 33;
+}
+
+pub fn test<A: Foo, B: Foo>() {
+    let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
new file mode 100644 (file)
index 0000000..3d3b795
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+#![feature(associated_consts)]
+
+pub trait Foo {
+    const Y: usize;
+}
+
+struct Abc;
+impl Foo for Abc {
+    const Y: usize = 8;
+}
+
+struct Def;
+impl Foo for Def {
+    const Y: usize = 33;
+}
+
+pub fn test<A: Foo, B: Foo>() {
+    let _array: [u32; <A as Foo>::Y]; //~ error: the parameter type
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/associated-const-type-parameters.rs b/src/test/compile-fail/associated-const-type-parameters.rs
deleted file mode 100644 (file)
index e48ff59..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 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.
-
-#![feature(associated_consts)]
-
-pub trait Foo {
-    const MIN: i32;
-
-    fn get_min() -> i32 {
-        Self::MIN //~ ERROR E0329
-    }
-}
-
-fn get_min<T: Foo>() -> i32 {
-    T::MIN; //~ ERROR E0329
-    <T as Foo>::MIN //~ ERROR E0329
-}
-
-fn main() {}
diff --git a/src/test/run-pass/associated-const-type-parameters.rs b/src/test/run-pass/associated-const-type-parameters.rs
new file mode 100644 (file)
index 0000000..e3d1761
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2015 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.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const X: i32;
+    fn get_x() -> i32 {
+       Self::X
+    }
+}
+
+struct Abc;
+impl Foo for Abc {
+    const X: i32 = 11;
+}
+
+struct Def;
+impl Foo for Def {
+    const X: i32 = 97;
+}
+
+fn sub<A: Foo, B: Foo>() -> i32 {
+    A::X - B::X
+}
+
+fn main() {
+    assert_eq!(11, Abc::X);
+    assert_eq!(97, Def::X);
+    assert_eq!(11, Abc::get_x());
+    assert_eq!(97, Def::get_x());
+    assert_eq!(-86, sub::<Abc, Def>());
+    assert_eq!(86, sub::<Def, Abc>());
+}