diff options
| author | Sean Patrick Santos <SeanPatrickSantos@gmail.com> | 2015-05-04 01:55:16 -0600 |
|---|---|---|
| committer | Sean Patrick Santos <SeanPatrickSantos@gmail.com> | 2015-05-17 15:30:32 -0600 |
| commit | 666575861405712d302fe32cbe563ced8d98b8ad (patch) | |
| tree | 662e4be3e70bbead344af67a22d85cdb310ebdd9 /src | |
| parent | fbe8066ac39546073b4d76bcb9928cf83886e8b2 (diff) | |
| download | rust-666575861405712d302fe32cbe563ced8d98b8ad.tar.gz rust-666575861405712d302fe32cbe563ced8d98b8ad.zip | |
Fix issue where trait-associated consts could cause ICEs in match patterns.
This allows some lookup of trait-associated consts during type-checking, which may be helpful for future fixes as well.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/middle/const_eval.rs | 48 | ||||
| -rw-r--r-- | src/librustc_trans/trans/_match.rs | 3 | ||||
| -rw-r--r-- | src/librustc_typeck/check/_match.rs | 4 | ||||
| -rw-r--r-- | src/test/run-pass/associated-const-range-match-patterns.rs | 35 |
4 files changed, 75 insertions, 15 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 091092e3b60..4faf46921d8 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<Ty<'tcx>>) -> 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<Ty<'tcx>>, + 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<Ordering> { }) } -pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, - a: &Expr, - b: &Expr, - ty_hint: Option<Ty<'tcx>>) - -> Option<Ordering> { - 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<Ty<'tcx>>, + get_substs: S) -> Option<Ordering> + 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 84d464e8f07..dd1e9494780 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 1f4d6cc2fd4..63470604084 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/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 00000000000..d38ccca6891 --- /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 <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)] + +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 ... <Foo as HasNum>::NUM => true, + _ => false, + }); + assert!(match 1 { + <Foo as HasNum>::NUM ... <Foo>::NUM => true, + _ => false, + }); +} |
