Skip to content

Commit c91037b

Browse files
committed
Fix cross-crate associated constant evaluation
1 parent 936dbbc commit c91037b

File tree

5 files changed

+102
-13
lines changed

5 files changed

+102
-13
lines changed

src/librustc/middle/cstore.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ impl<'a> InlinedItemRef<'a> {
181181
pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, _map: &hir_map::Map) -> InlinedItemRef<'a> {
182182
let (body, kind) = match item.node {
183183
hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)),
184+
hir::ConstTraitItem(_, None) => bug!("InlinedItemRef::from_trait_item called for const without body"),
184185
_ => bug!("InlinedItemRef::from_trait_item wrong kind")
185186
};
186187
InlinedItemRef {

src/librustc_const_eval/eval.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,15 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
102102
_ => None
103103
},
104104
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
105-
hir::ConstTraitItem(..) => {
105+
hir::ConstTraitItem(ref ty, ref expr_option) => {
106106
if let Some(substs) = substs {
107107
// If we have a trait item and the substitutions for it,
108108
// `resolve_trait_associated_const` will select an impl
109109
// or the default.
110110
let trait_id = tcx.map.get_parent(node_id);
111111
let trait_id = tcx.map.local_def_id(trait_id);
112-
resolve_trait_associated_const(tcx, ti, trait_id, substs)
112+
let default_value = expr_option.as_ref().map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
113+
resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
113114
} else {
114115
// Technically, without knowing anything about the
115116
// expression that generates the obligation, we could
@@ -145,6 +146,27 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
145146
}
146147
_ => None
147148
};
149+
let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
150+
Some(Def::AssociatedConst(_)) => {
151+
let trait_id = tcx.sess.cstore.trait_of_item(def_id);
152+
// As mentioned in the comments above for in-crate
153+
// constants, we only try to find the expression for a
154+
// trait-associated const if the caller gives us the
155+
// substitutions for the reference to it.
156+
if let Some(trait_id) = trait_id {
157+
used_substs = true;
158+
159+
if let Some(substs) = substs {
160+
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
161+
} else {
162+
None
163+
}
164+
} else {
165+
expr_ty
166+
}
167+
}
168+
_ => expr_ty
169+
};
148170
// If we used the substitutions, particularly to choose an impl
149171
// of a trait-associated const, don't cache that, because the next
150172
// lookup with the same def_id may yield a different result.
@@ -1036,7 +1058,8 @@ fn infer<'a, 'tcx>(i: ConstInt,
10361058
}
10371059

10381060
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1039-
ti: &'tcx hir::TraitItem,
1061+
trait_item_id: DefId,
1062+
default_value: Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>,
10401063
trait_id: DefId,
10411064
rcvr_substs: &'tcx Substs<'tcx>)
10421065
-> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
@@ -1070,21 +1093,16 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10701093
// when constructing the inference context above.
10711094
match selection {
10721095
traits::VtableImpl(ref impl_data) => {
1096+
let name = tcx.associated_item(trait_item_id).name;
10731097
let ac = tcx.associated_items(impl_data.impl_def_id)
1074-
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name);
1098+
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
10751099
match ac {
10761100
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
1077-
None => match ti.node {
1078-
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
1079-
Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
1080-
},
1081-
_ => None,
1082-
},
1101+
None => default_value,
10831102
}
10841103
}
10851104
_ => {
1086-
span_bug!(ti.span,
1087-
"resolve_trait_associated_const: unexpected vtable type")
1105+
bug!("resolve_trait_associated_const: unexpected vtable type")
10881106
}
10891107
}
10901108
})

src/librustc_metadata/encoder.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
516516
generics: Some(self.encode_generics(def_id)),
517517
predicates: Some(self.encode_predicates(def_id)),
518518

519-
ast: if trait_item.kind == ty::AssociatedKind::Const {
519+
ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
520+
// We only save the HIR for associated consts with bodies
521+
// (InlinedItemRef::from_trait_item panics otherwise)
520522
let trait_def_id = trait_item.container.id();
521523
Some(self.encode_inlined_item(InlinedItemRef::from_trait_item(trait_def_id, ast_item, &tcx.map)))
522524
} else {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
trait Foo {
14+
const NUM: usize;
15+
}
16+
17+
impl Foo for i32 {
18+
const NUM: usize = 1;
19+
}
20+
21+
const FOO: usize = <i32 as Foo>::NUM;
22+
23+
fn main() {
24+
assert_eq!(1, FOO);
25+
26+
match 1 {
27+
<i32 as Foo>::NUM => {},
28+
_ => assert!(false)
29+
}
30+
}
Lines changed: 38 additions & 0 deletions
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+
// aux-build:associated-const-cc-lib.rs
12+
13+
#![feature(associated_consts)]
14+
15+
extern crate associated_const_cc_lib as foolib;
16+
17+
pub struct LocalFoo;
18+
19+
impl foolib::Foo for LocalFoo {
20+
const BAR: usize = 1;
21+
}
22+
23+
const FOO_1: usize = <foolib::FooNoDefault as foolib::Foo>::BAR;
24+
const FOO_2: usize = <LocalFoo as foolib::Foo>::BAR;
25+
const FOO_3: usize = foolib::InherentBar::BAR;
26+
27+
fn main() {
28+
assert_eq!(0, FOO_1);
29+
assert_eq!(1, FOO_2);
30+
assert_eq!(3, FOO_3);
31+
32+
match 0 {
33+
<foolib::FooNoDefault as foolib::Foo>::BAR => {},
34+
<LocalFoo as foolib::Foo>::BAR => assert!(false),
35+
foolib::InherentBar::BAR => assert!(false),
36+
_ => assert!(false)
37+
}
38+
}

0 commit comments

Comments
 (0)