1
Fork 0

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:
Sean Patrick Santos 2015-05-04 01:55:16 -06:00
parent fbe8066ac3
commit 6665758614
4 changed files with 75 additions and 15 deletions

View file

@ -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());

View file

@ -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"),
}

View file

@ -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) => {

View 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,
});
}