Fix cross-crate associated constant evaluation
This commit is contained in:
parent
936dbbce37
commit
c91037b964
@ -181,6 +181,7 @@ impl<'a> InlinedItemRef<'a> {
|
||||
pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, _map: &hir_map::Map) -> InlinedItemRef<'a> {
|
||||
let (body, kind) = match item.node {
|
||||
hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)),
|
||||
hir::ConstTraitItem(_, None) => bug!("InlinedItemRef::from_trait_item called for const without body"),
|
||||
_ => bug!("InlinedItemRef::from_trait_item wrong kind")
|
||||
};
|
||||
InlinedItemRef {
|
||||
|
@ -102,14 +102,15 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_ => None
|
||||
},
|
||||
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
|
||||
hir::ConstTraitItem(..) => {
|
||||
hir::ConstTraitItem(ref ty, ref expr_option) => {
|
||||
if let Some(substs) = substs {
|
||||
// If we have a trait item and the substitutions for it,
|
||||
// `resolve_trait_associated_const` will select an impl
|
||||
// or the default.
|
||||
let trait_id = tcx.map.get_parent(node_id);
|
||||
let trait_id = tcx.map.local_def_id(trait_id);
|
||||
resolve_trait_associated_const(tcx, ti, trait_id, substs)
|
||||
let default_value = expr_option.as_ref().map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
|
||||
resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
|
||||
} else {
|
||||
// Technically, without knowing anything about the
|
||||
// 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>,
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
|
||||
Some(Def::AssociatedConst(_)) => {
|
||||
let trait_id = tcx.sess.cstore.trait_of_item(def_id);
|
||||
// As mentioned in the comments above for in-crate
|
||||
// constants, we only try to find the expression for a
|
||||
// trait-associated const if the caller gives us the
|
||||
// substitutions for the reference to it.
|
||||
if let Some(trait_id) = trait_id {
|
||||
used_substs = true;
|
||||
|
||||
if let Some(substs) = substs {
|
||||
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
expr_ty
|
||||
}
|
||||
}
|
||||
_ => expr_ty
|
||||
};
|
||||
// If we used the substitutions, particularly to choose an impl
|
||||
// of a trait-associated const, don't cache that, because the next
|
||||
// lookup with the same def_id may yield a different result.
|
||||
@ -1036,7 +1058,8 @@ fn infer<'a, 'tcx>(i: ConstInt,
|
||||
}
|
||||
|
||||
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ti: &'tcx hir::TraitItem,
|
||||
trait_item_id: DefId,
|
||||
default_value: Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>,
|
||||
trait_id: DefId,
|
||||
rcvr_substs: &'tcx Substs<'tcx>)
|
||||
-> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
|
||||
@ -1070,21 +1093,16 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// when constructing the inference context above.
|
||||
match selection {
|
||||
traits::VtableImpl(ref impl_data) => {
|
||||
let name = tcx.associated_item(trait_item_id).name;
|
||||
let ac = tcx.associated_items(impl_data.impl_def_id)
|
||||
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name);
|
||||
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
|
||||
match ac {
|
||||
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
|
||||
None => match ti.node {
|
||||
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
|
||||
Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
None => default_value,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_bug!(ti.span,
|
||||
"resolve_trait_associated_const: unexpected vtable type")
|
||||
bug!("resolve_trait_associated_const: unexpected vtable type")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -516,7 +516,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
generics: Some(self.encode_generics(def_id)),
|
||||
predicates: Some(self.encode_predicates(def_id)),
|
||||
|
||||
ast: if trait_item.kind == ty::AssociatedKind::Const {
|
||||
ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
|
||||
// We only save the HIR for associated consts with bodies
|
||||
// (InlinedItemRef::from_trait_item panics otherwise)
|
||||
let trait_def_id = trait_item.container.id();
|
||||
Some(self.encode_inlined_item(InlinedItemRef::from_trait_item(trait_def_id, ast_item, &tcx.map)))
|
||||
} else {
|
||||
|
30
src/test/run-pass/associated-const-const-eval.rs
Normal file
30
src/test/run-pass/associated-const-const-eval.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 NUM: usize;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const NUM: usize = 1;
|
||||
}
|
||||
|
||||
const FOO: usize = <i32 as Foo>::NUM;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, FOO);
|
||||
|
||||
match 1 {
|
||||
<i32 as Foo>::NUM => {},
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
38
src/test/run-pass/associated-const-cross-crate-const-eval.rs
Normal file
38
src/test/run-pass/associated-const-cross-crate-const-eval.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:associated-const-cc-lib.rs
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
extern crate associated_const_cc_lib as foolib;
|
||||
|
||||
pub struct LocalFoo;
|
||||
|
||||
impl foolib::Foo for LocalFoo {
|
||||
const BAR: usize = 1;
|
||||
}
|
||||
|
||||
const FOO_1: usize = <foolib::FooNoDefault as foolib::Foo>::BAR;
|
||||
const FOO_2: usize = <LocalFoo as foolib::Foo>::BAR;
|
||||
const FOO_3: usize = foolib::InherentBar::BAR;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(0, FOO_1);
|
||||
assert_eq!(1, FOO_2);
|
||||
assert_eq!(3, FOO_3);
|
||||
|
||||
match 0 {
|
||||
<foolib::FooNoDefault as foolib::Foo>::BAR => {},
|
||||
<LocalFoo as foolib::Foo>::BAR => assert!(false),
|
||||
foolib::InherentBar::BAR => assert!(false),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user