Skip to content

Commit 683af0d

Browse files
committed
Auto merge of #30446 - michaelwu:associated-const-type-params-pt1, r=nikomatsakis
This provides limited support for using associated consts on type parameters. It generally works on things that can be figured out at trans time. This doesn't work for array lengths or match arms. I have another patch to make it work in const expressions. CC @eddyb @nikomatsakis
2 parents f4befa6 + a4f91e5 commit 683af0d

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)