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.
This commit is contained in:
parent
fbe8066ac3
commit
6665758614
4 changed files with 75 additions and 15 deletions
|
@ -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());
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
35
src/test/run-pass/associated-const-range-match-patterns.rs
Normal file
35
src/test/run-pass/associated-const-range-match-patterns.rs
Normal file
|
@ -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,
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue