Skip to content

Commit a4f91e5

Browse files
committed
Support generic associated consts
1 parent 1447ce7 commit a4f91e5

15 files changed

+217
-72
lines changed

src/librustc/middle/check_const.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -657,13 +657,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
657657
Some(def::DefConst(did)) |
658658
Some(def::DefAssociatedConst(did)) => {
659659
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
660-
Some(e.id)) {
660+
Some(e.id),
661+
None) {
661662
let inner = v.global_expr(Mode::Const, expr);
662663
v.add_qualif(inner);
663-
} else {
664-
v.tcx.sess.span_bug(e.span,
665-
"DefConst or DefAssociatedConst \
666-
doesn't point to a constant");
667664
}
668665
}
669666
Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {

src/librustc/middle/check_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
455455
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
456456
match def {
457457
Some(DefAssociatedConst(did)) |
458-
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
458+
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did,
459+
Some(pat.id), None) {
459460
Some(const_expr) => {
460461
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
461462

src/librustc/middle/const_eval.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use front::map as ast_map;
1818
use front::map::blocks::FnLikeNode;
1919
use middle::cstore::{self, CrateStore, InlinedItem};
2020
use middle::{def, infer, subst, traits};
21+
use middle::subst::Subst;
2122
use middle::def_id::DefId;
2223
use middle::pat_util::def_to_path;
2324
use middle::ty::{self, Ty};
@@ -48,7 +49,7 @@ fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
4849
match opt_def {
4950
Some(def::DefConst(def_id)) |
5051
Some(def::DefAssociatedConst(def_id)) => {
51-
lookup_const_by_id(tcx, def_id, Some(e.id))
52+
lookup_const_by_id(tcx, def_id, Some(e.id), None)
5253
}
5354
Some(def::DefVariant(enum_def, variant_def, _)) => {
5455
lookup_variant_by_id(tcx, enum_def, variant_def)
@@ -88,9 +89,17 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
8889
}
8990
}
9091

92+
/// * `def_id` is the id of the constant.
93+
/// * `maybe_ref_id` is the id of the expr referencing the constant.
94+
/// * `param_substs` is the monomorphization substitution for the expression.
95+
///
96+
/// `maybe_ref_id` and `param_substs` are optional and are used for
97+
/// finding substitutions in associated constants. This generally
98+
/// happens in late/trans const evaluation.
9199
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
92100
def_id: DefId,
93-
maybe_ref_id: Option<ast::NodeId>)
101+
maybe_ref_id: Option<ast::NodeId>,
102+
param_substs: Option<&'tcx subst::Substs<'tcx>>)
94103
-> Option<&'tcx Expr> {
95104
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
96105
match tcx.map.find(node_id) {
@@ -111,8 +120,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
111120
Some(ref_id) => {
112121
let trait_id = tcx.trait_of_item(def_id)
113122
.unwrap();
114-
let substs = tcx.node_id_item_substs(ref_id)
115-
.substs;
123+
let mut substs = tcx.node_id_item_substs(ref_id)
124+
.substs;
125+
if let Some(param_substs) = param_substs {
126+
substs = substs.subst(tcx, param_substs);
127+
}
116128
resolve_trait_associated_const(tcx, ti, trait_id,
117129
substs)
118130
}
@@ -158,8 +170,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
158170
// a trait-associated const if the caller gives us
159171
// the expression that refers to it.
160172
Some(ref_id) => {
161-
let substs = tcx.node_id_item_substs(ref_id)
162-
.substs;
173+
let mut substs = tcx.node_id_item_substs(ref_id)
174+
.substs;
175+
if let Some(param_substs) = param_substs {
176+
substs = substs.subst(tcx, param_substs);
177+
}
163178
resolve_trait_associated_const(tcx, ti, trait_id,
164179
substs).map(|e| e.id)
165180
}
@@ -1013,7 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10131028
_ => (None, None)
10141029
}
10151030
} else {
1016-
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
1031+
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
10171032
}
10181033
}
10191034
Some(def::DefAssociatedConst(def_id)) => {
@@ -1048,7 +1063,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10481063
},
10491064
}
10501065
} else {
1051-
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
1066+
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
10521067
}
10531068
}
10541069
Some(def::DefVariant(enum_def, variant_def, _)) => {
@@ -1260,20 +1275,16 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
12601275
Ok(None) => {
12611276
return None
12621277
}
1263-
Err(e) => {
1264-
tcx.sess.span_bug(ti.span,
1265-
&format!("Encountered error `{:?}` when trying \
1266-
to select an implementation for \
1267-
constant trait item reference.",
1268-
e))
1278+
Err(_) => {
1279+
return None
12691280
}
12701281
};
12711282

12721283
match selection {
12731284
traits::VtableImpl(ref impl_data) => {
12741285
match tcx.associated_consts(impl_data.impl_def_id)
12751286
.iter().find(|ic| ic.name == ti.name) {
1276-
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
1287+
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
12771288
None => match ti.node {
12781289
hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
12791290
_ => None,

src/librustc_mir/hair/cx/pattern.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
8585
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
8686
match def {
8787
def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
88-
match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id)) {
88+
match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
89+
Some(pat.id), None) {
8990
Some(const_expr) => {
9091
let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
9192
pat.span);

src/librustc_trans/trans/consts.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
217217

218218
pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
219219
def_id: DefId,
220-
ref_expr: &hir::Expr)
220+
ref_expr: &hir::Expr,
221+
param_substs: &'tcx Substs<'tcx>)
221222
-> &'tcx hir::Expr {
222223
let def_id = inline::maybe_instantiate_inline(ccx, def_id);
223224

@@ -226,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
226227
"cross crate constant could not be inlined");
227228
}
228229

229-
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
230+
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
230231
Some(ref expr) => expr,
231232
None => {
232233
ccx.sess().span_bug(ref_expr.span, "constant item not found")
@@ -264,10 +265,12 @@ pub enum TrueConst {
264265

265266
use self::ConstEvalFailure::*;
266267

267-
fn get_const_val(ccx: &CrateContext,
268-
def_id: DefId,
269-
ref_expr: &hir::Expr) -> Result<ValueRef, ConstEvalFailure> {
270-
let expr = get_const_expr(ccx, def_id, ref_expr);
268+
fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
269+
def_id: DefId,
270+
ref_expr: &hir::Expr,
271+
param_substs: &'tcx Substs<'tcx>)
272+
-> Result<ValueRef, ConstEvalFailure> {
273+
let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
271274
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
272275
match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
273276
empty_substs, TrueConst::Yes) {
@@ -297,7 +300,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
297300
if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
298301
debug!("get_const_expr_as_global ({:?}): found const {:?}",
299302
expr.id, def_id);
300-
return get_const_val(ccx, def_id, expr);
303+
return get_const_val(ccx, def_id, expr, param_substs);
301304
}
302305
},
303306
_ => {},
@@ -888,7 +891,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
888891
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
889892
}
890893
def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
891-
const_deref_ptr(cx, try!(get_const_val(cx, def_id, e)))
894+
const_deref_ptr(cx, try!(get_const_val(cx, def_id, e, param_substs)))
892895
}
893896
def::DefVariant(enum_did, variant_did, _) => {
894897
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);

src/librustc_trans/trans/expr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
165165
hir::ExprPath(..) => {
166166
match bcx.def(expr.id) {
167167
def::DefConst(did) => {
168-
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr);
168+
let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
169+
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
170+
empty_substs);
169171
// Temporarily get cleanup scopes out of the way,
170172
// as they require sub-expressions to be contained
171173
// inside the current AST scope.

src/librustc_trans/trans/mir/did.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
5050
},
5151
ItemKind::Constant => {
5252
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
53-
let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None)
53+
let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs))
5454
.expect("def was const, but lookup_const_by_id failed");
5555
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
5656
// because we would have somehow adapt const_eval to work on MIR rather than HIR.

src/librustc_typeck/check/mod.rs

-30
Original file line numberDiff line numberDiff line change
@@ -3785,35 +3785,8 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
37853785
def::Def)>
37863786
{
37873787

3788-
// Associated constants can't depend on generic types.
3789-
fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3790-
def: def::Def,
3791-
ty: Ty<'tcx>,
3792-
span: Span,
3793-
node_id: ast::NodeId) -> bool {
3794-
match def {
3795-
def::DefAssociatedConst(..) => {
3796-
if ty.has_param_types() || ty.has_self_ty() {
3797-
span_err!(fcx.sess(), span, E0329,
3798-
"Associated consts cannot depend \
3799-
on type parameters or Self.");
3800-
fcx.write_error(node_id);
3801-
return true;
3802-
}
3803-
}
3804-
_ => {}
3805-
}
3806-
false
3807-
}
3808-
38093788
// If fully resolved already, we don't have to do anything.
38103789
if path_res.depth == 0 {
3811-
if let Some(ty) = opt_self_ty {
3812-
if have_disallowed_generic_consts(fcx, path_res.full_def(), ty,
3813-
span, node_id) {
3814-
return None;
3815-
}
3816-
}
38173790
Some((opt_self_ty, &path.segments, path_res.base_def))
38183791
} else {
38193792
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>,
38293802
let item_name = item_segment.identifier.name;
38303803
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
38313804
Ok((def, lp)) => {
3832-
if have_disallowed_generic_consts(fcx, def, ty, span, node_id) {
3833-
return None;
3834-
}
38353805
// Write back the new resolution.
38363806
fcx.ccx.tcx.def_map.borrow_mut()
38373807
.insert(node_id, def::PathResolution {

src/librustdoc/clean/inline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext,
321321
let did = assoc_const.def_id;
322322
let type_scheme = tcx.lookup_item_type(did);
323323
let default = if assoc_const.has_value {
324-
Some(const_eval::lookup_const_by_id(tcx, did, None)
324+
Some(const_eval::lookup_const_by_id(tcx, did, None, None)
325325
.unwrap().span.to_src(cx))
326326
} else {
327327
None
@@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt,
479479
use rustc::middle::const_eval;
480480
use rustc_front::print::pprust;
481481

482-
let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
482+
let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
483483
panic!("expected lookup_const_by_id to succeed for {:?}", did);
484484
});
485485
debug!("converting constant expr {:?} to snippet", expr);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
trait Foo {
14+
const ID: usize;
15+
}
16+
17+
const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
18+
19+
fn main() {
20+
assert_eq!(1, X);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
trait Foo {
14+
const ID: i32;
15+
}
16+
17+
const X: i32 = <i32>::ID;
18+
//~^ ERROR no associated item named `ID` found for type `i32`
19+
20+
fn main() {
21+
assert_eq!(1, X);
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
pub enum EFoo { A, B, C, D }
14+
15+
pub trait Foo {
16+
const X: EFoo;
17+
}
18+
19+
struct Abc;
20+
impl Foo for Abc {
21+
const X: EFoo = EFoo::B;
22+
}
23+
24+
struct Def;
25+
impl Foo for Def {
26+
const X: EFoo = EFoo::D;
27+
}
28+
29+
pub fn test<A: Foo, B: Foo>(arg: EFoo) {
30+
match arg {
31+
A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158]
32+
B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158]
33+
_ => (),
34+
}
35+
}
36+
37+
fn main() {
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
pub trait Foo {
14+
const Y: usize;
15+
}
16+
17+
struct Abc;
18+
impl Foo for Abc {
19+
const Y: usize = 8;
20+
}
21+
22+
struct Def;
23+
impl Foo for Def {
24+
const Y: usize = 33;
25+
}
26+
27+
pub fn test<A: Foo, B: Foo>() {
28+
let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
29+
}
30+
31+
fn main() {
32+
}

0 commit comments

Comments
 (0)