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 => {
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| {
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};
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)
}
}
+/// * `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) {
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)
}
// 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)
}
_ => (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)) => {
},
}
} 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, _)) => {
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
}
};
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,
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);
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);
"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")
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) {
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);
}
},
_ => {},
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);
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.
},
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.
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;
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 {
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
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);
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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() {
+}
+++ /dev/null
-// 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() {}
--- /dev/null
+// 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>());
+}