diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index a9b3043e09095..a458c2e14bee6 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -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 => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index a33142433463a..dc777585e4194 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -455,7 +455,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { 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| { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d5cfff4aff8a4..de7f543e3280d 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -18,6 +18,7 @@ use front::map as ast_map; 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 lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, } } +/// * `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) + maybe_ref_id: Option, + 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, diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 1f425aafa256a..dc377ac731a65 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -85,7 +85,8 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, '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); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 3ea358a8f4cd3..d5a7995b65dfc 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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 { - 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 { + 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); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 57afd0b580f17..f0ee518a0f553 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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. diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs index 0e2387e3e349e..3238869cac5c1 100644 --- a/src/librustc_trans/trans/mir/did.rs +++ b/src/librustc_trans/trans/mir/did.rs @@ -50,7 +50,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }, 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. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e644178ddd62f..0f87dc8885243 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, '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 { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9bbbcc66ca6c0..30b478f486e0a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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 index 0000000000000..5d8007defc906 --- /dev/null +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -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 or the MIT license +// , 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; ::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 index 0000000000000..89d1ac13087a9 --- /dev/null +++ b/src/test/compile-fail/associated-const-no-item.rs @@ -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 or the MIT license +// , 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 = ::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 index 0000000000000..f564157b49814 --- /dev/null +++ b/src/test/compile-fail/associated-const-type-parameter-arms.rs @@ -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 or the MIT license +// , 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(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 index 0000000000000..2f687350f34e0 --- /dev/null +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -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 or the MIT license +// , 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() { + let _array = [4; ::Y]; //~ error: expected constant integer +} + +fn main() { +} diff --git a/src/test/compile-fail/associated-const-type-parameters.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs similarity index 67% rename from src/test/compile-fail/associated-const-type-parameters.rs rename to src/test/compile-fail/associated-const-type-parameter-arrays.rs index e48ff59d1dc8e..3d3b795b2291a 100644 --- a/src/test/compile-fail/associated-const-type-parameters.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs @@ -11,16 +11,22 @@ #![feature(associated_consts)] pub trait Foo { - const MIN: i32; + const Y: usize; +} + +struct Abc; +impl Foo for Abc { + const Y: usize = 8; +} - fn get_min() -> i32 { - Self::MIN //~ ERROR E0329 - } +struct Def; +impl Foo for Def { + const Y: usize = 33; } -fn get_min() -> i32 { - T::MIN; //~ ERROR E0329 - ::MIN //~ ERROR E0329 +pub fn test() { + let _array: [u32; ::Y]; //~ error: the parameter type } -fn main() {} +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 index 0000000000000..e3d1761dfffdb --- /dev/null +++ b/src/test/run-pass/associated-const-type-parameters.rs @@ -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 or the MIT license +// , 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() -> 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::()); + assert_eq!(86, sub::()); +}