Skip to content

Commit 0ea80fa

Browse files
committed
Auto merge of #25091 - quantheory:trait_associated_const_fixes, r=nikomatsakis
Closes #25046 (by rejecting the code that causes the ICE) and #24946. I haven't been able to deal with the array size or recursion issues yet for associated consts, though my hope was that the change I made for range match patterns might help with array sizes, too. This PR is pretty much orthogonal to #25065.
2 parents a83201f + 8db699d commit 0ea80fa

File tree

7 files changed

+133
-15
lines changed

7 files changed

+133
-15
lines changed

Diff for: src/librustc/middle/const_eval.rs

+35-13
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
128128
Some(ref_id) => {
129129
let trait_id = ty::trait_of_item(tcx, def_id)
130130
.unwrap();
131+
let substs = ty::node_id_item_substs(tcx, ref_id)
132+
.substs;
131133
resolve_trait_associated_const(tcx, ti, trait_id,
132-
ref_id)
134+
substs)
133135
}
134136
// Technically, without knowing anything about the
135137
// expression that generates the obligation, we could
@@ -174,8 +176,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
174176
// a trait-associated const if the caller gives us
175177
// the expression that refers to it.
176178
Some(ref_id) => {
179+
let substs = ty::node_id_item_substs(tcx, ref_id)
180+
.substs;
177181
resolve_trait_associated_const(tcx, ti, trait_id,
178-
ref_id).map(|e| e.id)
182+
substs).map(|e| e.id)
179183
}
180184
None => None
181185
}
@@ -702,9 +706,23 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
702706
uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
703707
}}
704708

709+
// After type checking, `eval_const_expr_partial` should always suffice. The
710+
// reason for providing `eval_const_expr_with_substs` is to allow
711+
// trait-associated consts to be evaluated *during* type checking, when the
712+
// substs for each expression have not been written into `tcx` yet.
705713
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
706714
e: &Expr,
707715
ty_hint: Option<Ty<'tcx>>) -> EvalResult {
716+
eval_const_expr_with_substs(tcx, e, ty_hint, |id| {
717+
ty::node_id_item_substs(tcx, id).substs
718+
})
719+
}
720+
721+
pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
722+
e: &Expr,
723+
ty_hint: Option<Ty<'tcx>>,
724+
get_substs: S) -> EvalResult
725+
where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
708726
fn fromb(b: bool) -> const_val { const_int(b as i64) }
709727

710728
let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e));
@@ -895,8 +913,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
895913
def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
896914
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
897915
ast::ConstTraitItem(ref ty, _) => {
898-
(resolve_trait_associated_const(tcx, ti,
899-
trait_id, e.id),
916+
let substs = get_substs(e.id);
917+
(resolve_trait_associated_const(tcx,
918+
ti,
919+
trait_id,
920+
substs),
900921
Some(&**ty))
901922
}
902923
_ => (None, None)
@@ -995,10 +1016,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
9951016
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
9961017
ti: &'tcx ast::TraitItem,
9971018
trait_id: ast::DefId,
998-
ref_id: ast::NodeId)
1019+
rcvr_substs: subst::Substs<'tcx>)
9991020
-> Option<&'tcx Expr>
10001021
{
1001-
let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
10021022
let subst::SeparateVecsPerParamSpace {
10031023
types: rcvr_type,
10041024
selfs: rcvr_self,
@@ -1150,19 +1170,21 @@ pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<Ordering> {
11501170
})
11511171
}
11521172

1153-
pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
1154-
a: &Expr,
1155-
b: &Expr,
1156-
ty_hint: Option<Ty<'tcx>>)
1157-
-> Option<Ordering> {
1158-
let a = match eval_const_expr_partial(tcx, a, ty_hint) {
1173+
pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
1174+
a: &Expr,
1175+
b: &Expr,
1176+
ty_hint: Option<Ty<'tcx>>,
1177+
get_substs: S) -> Option<Ordering>
1178+
where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
1179+
let a = match eval_const_expr_with_substs(tcx, a, ty_hint,
1180+
|id| {get_substs(id)}) {
11591181
Ok(a) => a,
11601182
Err(e) => {
11611183
tcx.sess.span_err(a.span, &e.description());
11621184
return None;
11631185
}
11641186
};
1165-
let b = match eval_const_expr_partial(tcx, b, ty_hint) {
1187+
let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) {
11661188
Ok(b) => b,
11671189
Err(e) => {
11681190
tcx.sess.span_err(b.span, &e.description());

Diff for: src/librustc_trans/trans/_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ struct ConstantExpr<'a>(&'a ast::Expr);
233233

234234
impl<'a> ConstantExpr<'a> {
235235
fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
236-
match const_eval::compare_lit_exprs(tcx, self.0, other.0, None) {
236+
match const_eval::compare_lit_exprs(tcx, self.0, other.0, None,
237+
|id| {ty::node_id_item_substs(tcx, id).substs}) {
237238
Some(result) => result == Ordering::Equal,
238239
None => panic!("compare_list_exprs: type mismatch"),
239240
}

Diff for: src/librustc_typeck/check/_match.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
9898
lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty));
9999

100100
if numeric_or_char {
101-
match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty)) {
101+
match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty),
102+
|id| {fcx.item_substs()[&id].substs
103+
.clone()}) {
102104
Some(Ordering::Less) |
103105
Some(Ordering::Equal) => {}
104106
Some(Ordering::Greater) => {

Diff for: src/librustc_typeck/check/mod.rs

+31
Original file line numberDiff line numberDiff line change
@@ -3759,8 +3759,36 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
37593759
&'a [ast::PathSegment],
37603760
def::Def)>
37613761
{
3762+
3763+
// Associated constants can't depend on generic types.
3764+
fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3765+
def: def::Def,
3766+
ty: Ty<'tcx>,
3767+
span: Span,
3768+
node_id: ast::NodeId) -> bool {
3769+
match def {
3770+
def::DefAssociatedConst(..) => {
3771+
if ty::type_has_params(ty) || ty::type_has_self(ty) {
3772+
span_err!(fcx.sess(), span, E0329,
3773+
"Associated consts cannot depend \
3774+
on type parameters or Self.");
3775+
fcx.write_error(node_id);
3776+
return true;
3777+
}
3778+
}
3779+
_ => {}
3780+
}
3781+
false
3782+
}
3783+
37623784
// If fully resolved already, we don't have to do anything.
37633785
if path_res.depth == 0 {
3786+
if let Some(ty) = opt_self_ty {
3787+
if have_disallowed_generic_consts(fcx, path_res.full_def(), ty,
3788+
span, node_id) {
3789+
return None;
3790+
}
3791+
}
37643792
Some((opt_self_ty, &path.segments, path_res.base_def))
37653793
} else {
37663794
let mut def = path_res.base_def;
@@ -3776,6 +3804,9 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
37763804
let item_name = item_segment.identifier.name;
37773805
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
37783806
Ok((def, lp)) => {
3807+
if have_disallowed_generic_consts(fcx, def, ty, span, node_id) {
3808+
return None;
3809+
}
37793810
// Write back the new resolution.
37803811
fcx.ccx.tcx.def_map.borrow_mut()
37813812
.insert(node_id, def::PathResolution {

Diff for: src/librustc_typeck/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ register_diagnostics! {
11031103
E0326, // associated const implemented with different type from trait
11041104
E0327, // referred to method instead of constant in match pattern
11051105
E0328, // cannot implement Unsize explicitly
1106+
E0329, // associated const depends on type parameter or Self.
11061107
E0366, // dropck forbid specialization to concrete type or region
11071108
E0367, // dropck forbid specialization to predicate not in struct/enum
11081109
E0369, // binary operation `<op>` cannot be applied to types
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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 MIN: i32;
15+
16+
fn get_min() -> i32 {
17+
Self::MIN //~ ERROR E0329
18+
}
19+
}
20+
21+
fn get_min<T: Foo>() -> i32 {
22+
T::MIN; //~ ERROR E0329
23+
<T as Foo>::MIN //~ ERROR E0329
24+
}
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
struct Foo;
14+
15+
trait HasNum {
16+
const NUM: isize;
17+
}
18+
impl HasNum for Foo {
19+
const NUM: isize = 1;
20+
}
21+
22+
fn main() {
23+
assert!(match 2 {
24+
Foo::NUM ... 3 => true,
25+
_ => false,
26+
});
27+
assert!(match 0 {
28+
-1 ... <Foo as HasNum>::NUM => true,
29+
_ => false,
30+
});
31+
assert!(match 1 {
32+
<Foo as HasNum>::NUM ... <Foo>::NUM => true,
33+
_ => false,
34+
});
35+
}

0 commit comments

Comments
 (0)