From d2cccd07bce0477b0fd873590299eb042bc164f5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 9 Mar 2015 22:19:11 +0300 Subject: [PATCH] Fix byte string literal patterns in match --- src/librustc_trans/trans/_match.rs | 33 ++++++++++++++++++++++------- src/librustc_typeck/check/_match.rs | 20 +++++++++++++++-- src/test/run-pass/byte-literals.rs | 13 ++++++------ 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 2ab6f5b0f95..d7bd8e3d882 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -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"), }, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index dd2ab6c6b13..8e2f4dcefa0 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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); diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index abeda3964dd..fbe2a65bc89 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -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);