about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-03-09 22:19:11 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-03-18 00:40:59 +0300
commitd2cccd07bce0477b0fd873590299eb042bc164f5 (patch)
tree8fcebb6a2242e53c8e4d1064e2affea8d7885d33
parent3c31794d31840f4a695fde45c4797c833a78b278 (diff)
downloadrust-d2cccd07bce0477b0fd873590299eb042bc164f5.tar.gz
rust-d2cccd07bce0477b0fd873590299eb042bc164f5.zip
Fix byte string literal patterns in match
-rw-r--r--src/librustc_trans/trans/_match.rs33
-rw-r--r--src/librustc_typeck/check/_match.rs20
-rw-r--r--src/test/run-pass/byte-literals.rs13
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);