diff options
| author | bors <bors@rust-lang.org> | 2016-01-15 21:33:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-01-15 21:33:58 +0000 |
| commit | 683af0d9e09d799e74cef5f3d0dd1ed7c74c093b (patch) | |
| tree | 803c91191014328b5f324a94fa4199d2e4b4c4ba /src | |
| parent | f4befa6712487141610b2a3618384a238b8a4409 (diff) | |
| parent | a4f91e5fed85164a8535a2300ca6445520d25059 (diff) | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/middle/check_const.rs | 7 | ||||
| -rw-r--r-- | src/librustc/middle/check_match.rs | 3 | ||||
| -rw-r--r-- | src/librustc/middle/const_eval.rs | 41 | ||||
| -rw-r--r-- | src/librustc_mir/hair/cx/pattern.rs | 3 | ||||
| -rw-r--r-- | src/librustc_trans/trans/consts.rs | 19 | ||||
| -rw-r--r-- | src/librustc_trans/trans/expr.rs | 4 | ||||
| -rw-r--r-- | src/librustc_trans/trans/mir/did.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 30 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/associated-const-array-len.rs | 21 | ||||
| -rw-r--r-- | src/test/compile-fail/associated-const-no-item.rs | 22 | ||||
| -rw-r--r-- | src/test/compile-fail/associated-const-type-parameter-arms.rs | 38 | ||||
| -rw-r--r-- | src/test/compile-fail/associated-const-type-parameter-arrays-2.rs | 32 | ||||
| -rw-r--r-- | src/test/compile-fail/associated-const-type-parameter-arrays.rs (renamed from src/test/compile-fail/associated-const-type-parameters.rs) | 22 | ||||
| -rw-r--r-- | src/test/run-pass/associated-const-type-parameters.rs | 41 |
15 files changed, 217 insertions, 72 deletions
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index a9b3043e090..a458c2e14be 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -657,13 +657,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, Some(def::DefConst(did)) | Some(def::DefAssociatedConst(did)) => { if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did, - Some(e.id)) { + Some(e.id), + None) { let inner = v.global_expr(Mode::Const, expr); v.add_qualif(inner); - } else { - v.tcx.sess.span_bug(e.span, - "DefConst or DefAssociatedConst \ - doesn't point to a constant"); } } Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index a3314243346..dc777585e41 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -455,7 +455,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()); match def { Some(DefAssociatedConst(did)) | - Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) { + Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, + Some(pat.id), None) { Some(const_expr) => { const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d5cfff4aff8..de7f543e328 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -18,6 +18,7 @@ use front::map as ast_map; use front::map::blocks::FnLikeNode; use middle::cstore::{self, CrateStore, InlinedItem}; use middle::{def, infer, subst, traits}; +use middle::subst::Subst; use middle::def_id::DefId; use middle::pat_util::def_to_path; use middle::ty::{self, Ty}; @@ -48,7 +49,7 @@ fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> { match opt_def { Some(def::DefConst(def_id)) | Some(def::DefAssociatedConst(def_id)) => { - lookup_const_by_id(tcx, def_id, Some(e.id)) + lookup_const_by_id(tcx, def_id, Some(e.id), None) } Some(def::DefVariant(enum_def, variant_def, _)) => { lookup_variant_by_id(tcx, enum_def, variant_def) @@ -88,9 +89,17 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, } } +/// * `def_id` is the id of the constant. +/// * `maybe_ref_id` is the id of the expr referencing the constant. +/// * `param_substs` is the monomorphization substitution for the expression. +/// +/// `maybe_ref_id` and `param_substs` are optional and are used for +/// finding substitutions in associated constants. This generally +/// happens in late/trans const evaluation. pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, def_id: DefId, - maybe_ref_id: Option<ast::NodeId>) + maybe_ref_id: Option<ast::NodeId>, + param_substs: Option<&'tcx subst::Substs<'tcx>>) -> Option<&'tcx Expr> { if let Some(node_id) = tcx.map.as_local_node_id(def_id) { match tcx.map.find(node_id) { @@ -111,8 +120,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, Some(ref_id) => { let trait_id = tcx.trait_of_item(def_id) .unwrap(); - let substs = tcx.node_id_item_substs(ref_id) - .substs; + let mut substs = tcx.node_id_item_substs(ref_id) + .substs; + if let Some(param_substs) = param_substs { + substs = substs.subst(tcx, param_substs); + } resolve_trait_associated_const(tcx, ti, trait_id, substs) } @@ -158,8 +170,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, // a trait-associated const if the caller gives us // the expression that refers to it. Some(ref_id) => { - let substs = tcx.node_id_item_substs(ref_id) - .substs; + let mut substs = tcx.node_id_item_substs(ref_id) + .substs; + if let Some(param_substs) = param_substs { + substs = substs.subst(tcx, param_substs); + } resolve_trait_associated_const(tcx, ti, trait_id, substs).map(|e| e.id) } @@ -1013,7 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, _ => (None, None) } } else { - (lookup_const_by_id(tcx, def_id, Some(e.id)), None) + (lookup_const_by_id(tcx, def_id, Some(e.id), None), None) } } Some(def::DefAssociatedConst(def_id)) => { @@ -1048,7 +1063,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, }, } } else { - (lookup_const_by_id(tcx, def_id, Some(e.id)), None) + (lookup_const_by_id(tcx, def_id, Some(e.id), None), None) } } Some(def::DefVariant(enum_def, variant_def, _)) => { @@ -1260,12 +1275,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, Ok(None) => { return None } - Err(e) => { - tcx.sess.span_bug(ti.span, - &format!("Encountered error `{:?}` when trying \ - to select an implementation for \ - constant trait item reference.", - e)) + Err(_) => { + return None } }; @@ -1273,7 +1284,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, traits::VtableImpl(ref impl_data) => { match tcx.associated_consts(impl_data.impl_def_id) .iter().find(|ic| ic.name == ti.name) { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), + Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None), None => match ti.node { hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr), _ => None, diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 1f425aafa25..dc377ac731a 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -85,7 +85,8 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> { let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); match def { def::DefConst(def_id) | def::DefAssociatedConst(def_id) => - match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id)) { + match const_eval::lookup_const_by_id(self.cx.tcx, def_id, + Some(pat.id), None) { Some(const_expr) => { let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr, pat.span); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 3ea358a8f4c..d5a7995b65d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -217,7 +217,8 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, - ref_expr: &hir::Expr) + ref_expr: &hir::Expr, + param_substs: &'tcx Substs<'tcx>) -> &'tcx hir::Expr { let def_id = inline::maybe_instantiate_inline(ccx, def_id); @@ -226,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, "cross crate constant could not be inlined"); } - match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) { + match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) { Some(ref expr) => expr, None => { ccx.sess().span_bug(ref_expr.span, "constant item not found") @@ -264,10 +265,12 @@ pub enum TrueConst { use self::ConstEvalFailure::*; -fn get_const_val(ccx: &CrateContext, - def_id: DefId, - ref_expr: &hir::Expr) -> Result<ValueRef, ConstEvalFailure> { - let expr = get_const_expr(ccx, def_id, ref_expr); +fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + ref_expr: &hir::Expr, + param_substs: &'tcx Substs<'tcx>) + -> Result<ValueRef, ConstEvalFailure> { + let expr = get_const_expr(ccx, def_id, ref_expr, param_substs); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), empty_substs, TrueConst::Yes) { @@ -297,7 +300,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { debug!("get_const_expr_as_global ({:?}): found const {:?}", expr.id, def_id); - return get_const_val(ccx, def_id, expr); + return get_const_val(ccx, def_id, expr, param_substs); } }, _ => {}, @@ -888,7 +891,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } def::DefConst(def_id) | def::DefAssociatedConst(def_id) => { - const_deref_ptr(cx, try!(get_const_val(cx, def_id, e))) + const_deref_ptr(cx, try!(get_const_val(cx, def_id, e, param_substs))) } def::DefVariant(enum_did, variant_did, _) => { let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 57afd0b580f..f0ee518a0f5 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -165,7 +165,9 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, hir::ExprPath(..) => { match bcx.def(expr.id) { def::DefConst(did) => { - let const_expr = consts::get_const_expr(bcx.ccx(), did, expr); + let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty()); + let const_expr = consts::get_const_expr(bcx.ccx(), did, expr, + empty_substs); // Temporarily get cleanup scopes out of the way, // as they require sub-expressions to be contained // inside the current AST scope. diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs index 0e2387e3e34..3238869cac5 100644 --- a/src/librustc_trans/trans/mir/did.rs +++ b/src/librustc_trans/trans/mir/did.rs @@ -50,7 +50,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }, ItemKind::Constant => { let did = inline::maybe_instantiate_inline(bcx.ccx(), did); - let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None) + let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs)) .expect("def was const, but lookup_const_by_id failed"); // FIXME: this is falling back to translating from HIR. This is not easy to fix, // because we would have somehow adapt const_eval to work on MIR rather than HIR. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e644178ddd6..0f87dc88852 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3785,35 +3785,8 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, def::Def)> { - // Associated constants can't depend on generic types. - fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - def: def::Def, - ty: Ty<'tcx>, - span: Span, - node_id: ast::NodeId) -> bool { - match def { - def::DefAssociatedConst(..) => { - if ty.has_param_types() || ty.has_self_ty() { - span_err!(fcx.sess(), span, E0329, - "Associated consts cannot depend \ - on type parameters or Self."); - fcx.write_error(node_id); - return true; - } - } - _ => {} - } - false - } - // If fully resolved already, we don't have to do anything. if path_res.depth == 0 { - if let Some(ty) = opt_self_ty { - if have_disallowed_generic_consts(fcx, path_res.full_def(), ty, - span, node_id) { - return None; - } - } Some((opt_self_ty, &path.segments, path_res.base_def)) } else { 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>, let item_name = item_segment.identifier.name; match method::resolve_ufcs(fcx, span, item_name, ty, node_id) { Ok((def, lp)) => { - if have_disallowed_generic_consts(fcx, def, ty, span, node_id) { - return None; - } // Write back the new resolution. fcx.ccx.tcx.def_map.borrow_mut() .insert(node_id, def::PathResolution { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9bbbcc66ca6..30b478f486e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, let did = assoc_const.def_id; let type_scheme = tcx.lookup_item_type(did); let default = if assoc_const.has_value { - Some(const_eval::lookup_const_by_id(tcx, did, None) + Some(const_eval::lookup_const_by_id(tcx, did, None, None) .unwrap().span.to_src(cx)) } else { None @@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt, use rustc::middle::const_eval; use rustc_front::print::pprust; - let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { + let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| { panic!("expected lookup_const_by_id to succeed for {:?}", did); }); debug!("converting constant expr {:?} to snippet", expr); diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs new file mode 100644 index 00000000000..5d8007defc9 --- /dev/null +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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 ID: usize; +} + +const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250 + +fn main() { + assert_eq!(1, X); +} diff --git a/src/test/compile-fail/associated-const-no-item.rs b/src/test/compile-fail/associated-const-no-item.rs new file mode 100644 index 00000000000..89d1ac13087 --- /dev/null +++ b/src/test/compile-fail/associated-const-no-item.rs @@ -0,0 +1,22 @@ +// Copyright 2016 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 ID: i32; +} + +const X: i32 = <i32>::ID; +//~^ ERROR no associated item named `ID` found for type `i32` + +fn main() { + assert_eq!(1, X); +} diff --git a/src/test/compile-fail/associated-const-type-parameter-arms.rs b/src/test/compile-fail/associated-const-type-parameter-arms.rs new file mode 100644 index 00000000000..f564157b498 --- /dev/null +++ b/src/test/compile-fail/associated-const-type-parameter-arms.rs @@ -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. + +#![feature(associated_consts)] + +pub enum EFoo { A, B, C, D } + +pub trait Foo { + const X: EFoo; +} + +struct Abc; +impl Foo for Abc { + const X: EFoo = EFoo::B; +} + +struct Def; +impl Foo for Def { + const X: EFoo = EFoo::D; +} + +pub fn test<A: Foo, B: Foo>(arg: EFoo) { + match arg { + A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158] + B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158] + _ => (), + } +} + +fn main() { +} diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs new file mode 100644 index 00000000000..2f687350f34 --- /dev/null +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -0,0 +1,32 @@ +// 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)] + +pub trait Foo { + const Y: usize; +} + +struct Abc; +impl Foo for Abc { + const Y: usize = 8; +} + +struct Def; +impl Foo for Def { + const Y: usize = 33; +} + +pub fn test<A: Foo, B: Foo>() { + let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer +} + +fn main() { +} diff --git a/src/test/compile-fail/associated-const-type-parameters.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs index e48ff59d1dc..3d3b795b229 100644 --- a/src/test/compile-fail/associated-const-type-parameters.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs @@ -11,16 +11,22 @@ #![feature(associated_consts)] pub trait Foo { - const MIN: i32; + const Y: usize; +} + +struct Abc; +impl Foo for Abc { + const Y: usize = 8; +} - fn get_min() -> i32 { - Self::MIN //~ ERROR E0329 - } +struct Def; +impl Foo for Def { + const Y: usize = 33; } -fn get_min<T: Foo>() -> i32 { - T::MIN; //~ ERROR E0329 - <T as Foo>::MIN //~ ERROR E0329 +pub fn test<A: Foo, B: Foo>() { + let _array: [u32; <A as Foo>::Y]; //~ error: the parameter type } -fn main() {} +fn main() { +} diff --git a/src/test/run-pass/associated-const-type-parameters.rs b/src/test/run-pass/associated-const-type-parameters.rs new file mode 100644 index 00000000000..e3d1761dfff --- /dev/null +++ b/src/test/run-pass/associated-const-type-parameters.rs @@ -0,0 +1,41 @@ +// 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 X: i32; + fn get_x() -> i32 { + Self::X + } +} + +struct Abc; +impl Foo for Abc { + const X: i32 = 11; +} + +struct Def; +impl Foo for Def { + const X: i32 = 97; +} + +fn sub<A: Foo, B: Foo>() -> i32 { + A::X - B::X +} + +fn main() { + assert_eq!(11, Abc::X); + assert_eq!(97, Def::X); + assert_eq!(11, Abc::get_x()); + assert_eq!(97, Def::get_x()); + assert_eq!(-86, sub::<Abc, Def>()); + assert_eq!(86, sub::<Def, Abc>()); +} |
