diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 00a7fe68f2fb..f03a2d342d7b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1002,21 +1002,23 @@ pub fn get_associated_consts<'tcx>(intr: Rc, let item = lookup_item(id, data); let mut result = Vec::new(); - reader::tagged_docs(item, tag_item_trait_item, |ac_id| { - let did = item_def_id(ac_id, cdata); - let ac_doc = lookup_item(did.node, data); + for &tag in &[tag_item_trait_item, tag_item_impl_item] { + reader::tagged_docs(item, tag, |ac_id| { + let did = item_def_id(ac_id, cdata); + let ac_doc = lookup_item(did.node, data); - if item_sort(ac_doc) == Some('C') { - let trait_item = get_impl_or_trait_item(intr.clone(), - cdata, - did.node, - tcx); - if let ty::ConstTraitItem(ref ac) = trait_item { - result.push((*ac).clone()) + if item_sort(ac_doc) == Some('C') { + let trait_item = get_impl_or_trait_item(intr.clone(), + cdata, + did.node, + tcx); + if let ty::ConstTraitItem(ref ac) = trait_item { + result.push((*ac).clone()) + } } - } - true - }); + true + }); + } return result; } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index b5a173a569f4..916874f1c51a 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -117,15 +117,25 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, _ => None }, Some(ast_map::NodeTraitItem(ti)) => match ti.node { - ast::ConstTraitItem(_, ref default) => { + ast::ConstTraitItem(_, _) => { match maybe_ref_id { + // If we have a trait item, and we know the expression + // that's the source of the obligation to resolve it, + // `resolve_trait_associated_const` will select an impl + // or the default. Some(ref_id) => { let trait_id = ty::trait_of_item(tcx, def_id) .unwrap(); resolve_trait_associated_const(tcx, ti, trait_id, ref_id) } - None => default.as_ref().map(|expr| &**expr), + // Technically, without knowing anything about the + // expression that generates the obligation, we could + // still return the default if there is one. However, + // it's safer to return `None` than to return some value + // that may differ from what you would get from + // correctly selecting an impl. + None => None } } _ => None @@ -153,17 +163,19 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, ast::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None }, - csearch::FoundAst::Found(&ast::IITraitItem(_, ref ti)) => match ti.node { - ast::ConstTraitItem(_, ref default) => { + csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node { + ast::ConstTraitItem(_, _) => { used_ref_id = true; match maybe_ref_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 expression that refers to it. Some(ref_id) => { - let trait_id = ty::trait_of_item(tcx, def_id) - .unwrap(); resolve_trait_associated_const(tcx, ti, trait_id, ref_id).map(|e| e.id) } - None => default.as_ref().map(|expr| expr.id), + None => None } } _ => None @@ -177,7 +189,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, // If we used the reference expression, 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. - if used_ref_id { + if !used_ref_id { tcx.extern_const_statics .borrow_mut().insert(def_id, expr_id.unwrap_or(ast::DUMMY_NODE_ID)); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1b5e31f61d8a..41745c6384b3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5167,8 +5167,7 @@ pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) } } } else { - let acs = csearch::get_associated_consts(cx, id); - acs.iter().map(|ac| (*ac).clone()).collect() + csearch::get_associated_consts(cx, id) } } diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 2034c6223c13..3f44bc40f356 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -134,6 +134,14 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); + // Associated consts already have to be evaluated in `typeck`, so + // the logic to do that already exists in `middle`. In order to + // reuse that code, it needs to be able to look up the traits for + // inlined items. + let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone(); + ccx.tcx().impl_or_trait_items.borrow_mut() + .insert(local_def(trait_item.id), ty_trait_item); + // If this is a default method, we can't look up the // impl type. But we aren't going to translate anyways, so // don't. diff --git a/src/test/auxiliary/associated-const-cc-lib.rs b/src/test/auxiliary/associated-const-cc-lib.rs new file mode 100644 index 000000000000..9735c6cb54d2 --- /dev/null +++ b/src/test/auxiliary/associated-const-cc-lib.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="lib"] + +use std::marker::MarkerTrait; + +// These items are for testing that associated consts work cross-crate. +pub trait Foo: MarkerTrait { + const BAR: usize; +} + +pub struct FooNoDefault; + +impl Foo for FooNoDefault { + const BAR: usize = 0; +} + +// These test that defaults and default resolution work cross-crate. +pub trait FooDefault: MarkerTrait { + const BAR: usize = 1; +} + +pub struct FooOverwriteDefault; + +impl FooDefault for FooOverwriteDefault { + const BAR: usize = 2; +} + +pub struct FooUseDefault; + +impl FooDefault for FooUseDefault {} + +// Test inherent impls. +pub struct InherentBar; + +impl InherentBar { + pub const BAR: usize = 3; +} diff --git a/src/test/run-pass/associated-const-cross-crate-defaults.rs b/src/test/run-pass/associated-const-cross-crate-defaults.rs new file mode 100644 index 000000000000..944466f359da --- /dev/null +++ b/src/test/run-pass/associated-const-cross-crate-defaults.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:associated-const-cc-lib.rs + +extern crate associated_const_cc_lib as foolib; + +pub struct LocalFooUseDefault; + +impl foolib::FooDefault for LocalFooUseDefault {} + +pub struct LocalFooOverwriteDefault; + +impl foolib::FooDefault for LocalFooOverwriteDefault { + const BAR: usize = 4; +} + +fn main() { + assert_eq!(1, ::BAR); + assert_eq!(2, ::BAR); + assert_eq!(1, ::BAR); + assert_eq!(4, ::BAR); +} diff --git a/src/test/run-pass/associated-const-cross-crate.rs b/src/test/run-pass/associated-const-cross-crate.rs new file mode 100644 index 000000000000..c18cda018d87 --- /dev/null +++ b/src/test/run-pass/associated-const-cross-crate.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:associated-const-cc-lib.rs + +extern crate associated_const_cc_lib as foolib; + +pub struct LocalFoo; + +impl foolib::Foo for LocalFoo { + const BAR: usize = 1; +} + +fn main() { + assert_eq!(0, ::BAR); + assert_eq!(1, ::BAR); + assert_eq!(3, foolib::InherentBar::BAR); +} diff --git a/src/test/run-pass/associated-const-in-global-const.rs b/src/test/run-pass/associated-const-in-global-const.rs new file mode 100644 index 000000000000..b9fb067d4fa8 --- /dev/null +++ b/src/test/run-pass/associated-const-in-global-const.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo; + +impl Foo { + const BAR: f32 = 1.5; +} + +const FOOBAR: f32 = ::BAR; + +fn main() { + assert_eq!(1.5f32, FOOBAR); +}