Fix byte string literal patterns in match

This commit is contained in:
Vadim Petrochenkov 2015-03-09 22:19:11 +03:00
parent 3c31794d31
commit d2cccd07bc
3 changed files with 49 additions and 17 deletions

View File

@ -200,7 +200,7 @@ use middle::mem_categorization as mc;
use middle::pat_util::*;
use trans::adt;
use trans::base::*;
use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
use trans::build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast};
use trans::build::{Not, Store, Sub, add_comment};
use trans::build;
use trans::callee;
@ -853,14 +853,31 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
ty::ty_vec(ty, _) => match ty.sty {
ty::ty_uint(ast::TyU8) => {
// NOTE: cast &[u8] to &str and abuse the str_eq lang item,
// NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
// which calls memcmp().
let t = ty::mk_str_slice(cx.tcx(),
cx.tcx().mk_region(ty::ReStatic),
ast::MutImmutable);
let lhs = BitCast(cx, lhs, type_of::type_of(cx.ccx(), t).ptr_to());
let rhs = BitCast(cx, rhs, type_of::type_of(cx.ccx(), t).ptr_to());
compare_str(cx, lhs, rhs, rhs_t, debug_loc)
let pat_len = val_ty(rhs).element_type().array_length();
let ty_str_slice = ty::mk_str_slice(cx.tcx(),
cx.tcx().mk_region(ty::ReStatic),
ast::MutImmutable);
let rhs_str = alloc_ty(cx, ty_str_slice, "rhs_str");
Store(cx, GEPi(cx, rhs, &[0, 0]), expr::get_dataptr(cx, rhs_str));
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, rhs_str));
let lhs_str;
if val_ty(lhs) == val_ty(rhs) {
// Both the discriminant and the pattern are thin pointers
lhs_str = alloc_ty(cx, ty_str_slice, "lhs_str");
Store(cx, GEPi(cx, lhs, &[0, 0]), expr::get_dataptr(cx, lhs_str));
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, lhs_str));
}
else {
// The discriminant is a fat pointer
let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to();
lhs_str = PointerCast(cx, lhs, llty_str_slice);
}
compare_str(cx, lhs_str, rhs_str, rhs_t, debug_loc)
},
_ => cx.sess().bug("only byte strings supported in compare_values"),
},

View File

@ -48,7 +48,23 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
ast::PatLit(ref lt) => {
check_expr(fcx, &**lt);
let expr_ty = fcx.expr_ty(&**lt);
fcx.write_ty(pat.id, expr_ty);
// Byte string patterns behave the same way as array patterns
// They can denote both statically and dynamically sized byte arrays
let mut pat_ty = expr_ty;
if let ast::ExprLit(ref lt) = lt.node {
if let ast::LitBinary(_) = lt.node {
let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
if let ty::ty_rptr(_, mt) = expected_ty.sty {
if let ty::ty_vec(_, None) = mt.ty.sty {
pat_ty = ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic),
ty::mt{ ty: tcx.types.u8, mutbl: ast::MutImmutable })
}
}
}
}
fcx.write_ty(pat.id, pat_ty);
// somewhat surprising: in this case, the subtyping
// relation goes the opposite way as the other
@ -62,7 +78,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
// &'static str <: expected
//
// that's equivalent to there existing a LUB.
demand::suptype(fcx, pat.span, expected, expr_ty);
demand::suptype(fcx, pat.span, expected, pat_ty);
}
ast::PatRange(ref begin, ref end) => {
check_expr(fcx, &**begin);

View File

@ -58,13 +58,12 @@ pub fn main() {
_ => panic!(),
}
// FIXME: There are no DST coercions &[T; N] -> &[T] in patterns
// let buf = vec!(97u8, 98, 99, 100);
// assert_eq!(match &buf[0..3] {
// b"def" => 1_usize,
// b"abc" => 2_usize,
// _ => 3_usize
// }, 2);
let buf = vec!(97u8, 98, 99, 100);
assert_eq!(match &buf[0..3] {
b"def" => 1,
b"abc" => 2,
_ => 3
}, 2);
let expected: &[_] = &[97u8, 92u8, 110u8];
assert_eq!(BAZ, expected);