diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 091092e3b6079..4faf46921d8e6 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -126,8 +126,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, Some(ref_id) => { let trait_id = ty::trait_of_item(tcx, def_id) .unwrap(); + let substs = ty::node_id_item_substs(tcx, ref_id) + .substs; resolve_trait_associated_const(tcx, ti, trait_id, - ref_id) + substs) } // Technically, without knowing anything about the // expression that generates the obligation, we could @@ -172,8 +174,10 @@ 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 = ty::node_id_item_substs(tcx, ref_id) + .substs; resolve_trait_associated_const(tcx, ti, trait_id, - ref_id).map(|e| e.id) + substs).map(|e| e.id) } None => None } @@ -633,9 +637,23 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) { uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow }} +// After type checking, `eval_const_expr_partial` should always suffice. The +// reason for providing `eval_const_expr_with_substs` is to allow +// trait-associated consts to be evaluated *during* type checking, when the +// substs for each expression have not been written into `tcx` yet. pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, ty_hint: Option>) -> EvalResult { + eval_const_expr_with_substs(tcx, e, ty_hint, |id| { + ty::node_id_item_substs(tcx, id).substs + }) +} + +pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, + e: &Expr, + ty_hint: Option>, + get_substs: S) -> EvalResult + where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { fn fromb(b: bool) -> const_val { const_int(b as i64) } let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e)); @@ -826,8 +844,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, def::FromTrait(trait_id) => match tcx.map.find(def_id.node) { Some(ast_map::NodeTraitItem(ti)) => match ti.node { ast::ConstTraitItem(ref ty, _) => { - (resolve_trait_associated_const(tcx, ti, - trait_id, e.id), + let substs = get_substs(e.id); + (resolve_trait_associated_const(tcx, + ti, + trait_id, + substs), Some(&**ty)) } _ => (None, None) @@ -926,10 +947,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, ti: &'tcx ast::TraitItem, trait_id: ast::DefId, - ref_id: ast::NodeId) + rcvr_substs: subst::Substs<'tcx>) -> Option<&'tcx Expr> { - let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs; let subst::SeparateVecsPerParamSpace { types: rcvr_type, selfs: rcvr_self, @@ -1081,19 +1101,21 @@ pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option { }) } -pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, - a: &Expr, - b: &Expr, - ty_hint: Option>) - -> Option { - let a = match eval_const_expr_partial(tcx, a, ty_hint) { +pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>, + a: &Expr, + b: &Expr, + ty_hint: Option>, + get_substs: S) -> Option + where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { + let a = match eval_const_expr_with_substs(tcx, a, ty_hint, + |id| {get_substs(id)}) { Ok(a) => a, Err(e) => { tcx.sess.span_err(a.span, &e.description()); return None; } }; - let b = match eval_const_expr_partial(tcx, b, ty_hint) { + let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) { Ok(b) => b, Err(e) => { tcx.sess.span_err(b.span, &e.description()); diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 84d464e8f0781..dd1e9494780e5 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -233,7 +233,8 @@ struct ConstantExpr<'a>(&'a ast::Expr); impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool { - match const_eval::compare_lit_exprs(tcx, self.0, other.0, None) { + match const_eval::compare_lit_exprs(tcx, self.0, other.0, None, + |id| {ty::node_id_item_substs(tcx, id).substs}) { Some(result) => result == Ordering::Equal, None => panic!("compare_list_exprs: type mismatch"), } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1f4d6cc2fd471..63470604084f8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -98,7 +98,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty)); if numeric_or_char { - match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty)) { + match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty), + |id| {fcx.item_substs()[&id].substs + .clone()}) { Some(Ordering::Less) | Some(Ordering::Equal) => {} Some(Ordering::Greater) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f13305bba343e..77aded3ccdbac 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3763,8 +3763,36 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, &'a [ast::PathSegment], 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::type_has_params(ty) || ty::type_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; @@ -3780,6 +3808,9 @@ 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/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 58d0963274181..200a7bee8331c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -771,6 +771,7 @@ register_diagnostics! { E0326, // associated const implemented with different type from trait E0327, // referred to method instead of constant in match pattern E0328, // cannot implement Unsize explicitly + E0329, // associated const depends on type parameter or Self. E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0369, // binary operation `` cannot be applied to types diff --git a/src/test/compile-fail/associated-const-type-parameters.rs b/src/test/compile-fail/associated-const-type-parameters.rs new file mode 100644 index 0000000000000..e48ff59d1dc8e --- /dev/null +++ b/src/test/compile-fail/associated-const-type-parameters.rs @@ -0,0 +1,26 @@ +// 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. + +#![feature(associated_consts)] + +pub trait Foo { + const MIN: i32; + + fn get_min() -> i32 { + Self::MIN //~ ERROR E0329 + } +} + +fn get_min() -> i32 { + T::MIN; //~ ERROR E0329 + ::MIN //~ ERROR E0329 +} + +fn main() {} diff --git a/src/test/run-pass/associated-const-range-match-patterns.rs b/src/test/run-pass/associated-const-range-match-patterns.rs new file mode 100644 index 0000000000000..d38ccca689141 --- /dev/null +++ b/src/test/run-pass/associated-const-range-match-patterns.rs @@ -0,0 +1,35 @@ +// 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. + +#![feature(associated_consts)] + +struct Foo; + +trait HasNum { + const NUM: isize; +} +impl HasNum for Foo { + const NUM: isize = 1; +} + +fn main() { + assert!(match 2 { + Foo::NUM ... 3 => true, + _ => false, + }); + assert!(match 0 { + -1 ... ::NUM => true, + _ => false, + }); + assert!(match 1 { + ::NUM ... ::NUM => true, + _ => false, + }); +}