_match.rs 78.2 KB
Newer Older
V
Virgile Andreani 已提交
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// 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.

S
Steve Klabnik 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
//! # Compilation of match statements
//!
//! I will endeavor to explain the code as best I can.  I have only a loose
//! understanding of some parts of it.
//!
//! ## Matching
//!
//! The basic state of the code is maintained in an array `m` of `Match`
//! objects.  Each `Match` describes some list of patterns, all of which must
//! match against the current list of values.  If those patterns match, then
//! the arm listed in the match is the correct arm.  A given arm may have
//! multiple corresponding match entries, one for each alternative that
//! remains.  As we proceed these sets of matches are adjusted by the various
//! `enter_XXX()` functions, each of which adjusts the set of options given
//! some information about the value which has been matched.
//!
//! So, initially, there is one value and N matches, each of which have one
//! constituent pattern.  N here is usually the number of arms but may be
//! greater, if some arms have multiple alternatives.  For example, here:
//!
31
//!     enum Foo { A, B(int), C(usize, usize) }
S
Steve Klabnik 已提交
32 33 34
//!     match foo {
//!         A => ...,
//!         B(x) => ...,
35
//!         C(1, 2) => ...,
S
Steve Klabnik 已提交
36 37 38 39 40 41 42 43
//!         C(_) => ...
//!     }
//!
//! The value would be `foo`.  There would be four matches, each of which
//! contains one pattern (and, in one case, a guard).  We could collect the
//! various options and then compile the code for the case where `foo` is an
//! `A`, a `B`, and a `C`.  When we generate the code for `C`, we would (1)
//! drop the two matches that do not match a `C` and (2) expand the other two
44
//! into two patterns each.  In the first case, the two patterns would be `1`
S
Steve Klabnik 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
//! and `2`, and the in the second case the _ pattern would be expanded into
//! `_` and `_`.  The two values are of course the arguments to `C`.
//!
//! Here is a quick guide to the various functions:
//!
//! - `compile_submatch()`: The main workhouse.  It takes a list of values and
//!   a list of matches and finds the various possibilities that could occur.
//!
//! - `enter_XXX()`: modifies the list of matches based on some information
//!   about the value that has been matched.  For example,
//!   `enter_rec_or_struct()` adjusts the values given that a record or struct
//!   has been matched.  This is an infallible pattern, so *all* of the matches
//!   must be either wildcards or record/struct patterns.  `enter_opt()`
//!   handles the fallible cases, and it is correspondingly more complex.
//!
//! ## Bindings
//!
//! We store information about the bound variables for each arm as part of the
//! per-arm `ArmData` struct.  There is a mapping from identifiers to
//! `BindingInfo` structs.  These structs contain the mode/id/type of the
//! binding, but they also contain an LLVM value which points at an alloca
//! called `llmatch`. For by value bindings that are Copy, we also create
//! an extra alloca that we copy the matched value to so that any changes
//! we do to our copy is not reflected in the original and vice-versa.
//! We don't do this if it's a move since the original value can't be used
//! and thus allowing us to cheat in not creating an extra alloca.
//!
//! The `llmatch` binding always stores a pointer into the value being matched
//! which points at the data for the binding.  If the value being matched has
//! type `T`, then, `llmatch` will point at an alloca of type `T*` (and hence
//! `llmatch` has type `T**`).  So, if you have a pattern like:
//!
//!    let a: A = ...;
//!    let b: B = ...;
//!    match (a, b) { (ref c, d) => { ... } }
//!
//! For `c` and `d`, we would generate allocas of type `C*` and `D*`
//! respectively.  These are called the `llmatch`.  As we match, when we come
//! up against an identifier, we store the current pointer into the
//! corresponding alloca.
//!
//! Once a pattern is completely matched, and assuming that there is no guard
//! pattern, we will branch to a block that leads to the body itself.  For any
//! by-value bindings, this block will first load the ptr from `llmatch` (the
//! one of type `D*`) and then load a second time to get the actual value (the
//! one of type `D`). For by ref bindings, the value of the local variable is
//! simply the first alloca.
//!
//! So, for the example above, we would generate a setup kind of like this:
//!
//!        +-------+
//!        | Entry |
//!        +-------+
//!            |
//!        +--------------------------------------------+
//!        | llmatch_c = (addr of first half of tuple)  |
//!        | llmatch_d = (addr of second half of tuple) |
//!        +--------------------------------------------+
//!            |
//!        +--------------------------------------+
//!        | *llbinding_d = **llmatch_d           |
//!        +--------------------------------------+
//!
//! If there is a guard, the situation is slightly different, because we must
//! execute the guard code.  Moreover, we need to do so once for each of the
//! alternatives that lead to the arm, because if the guard fails, they may
//! have different points from which to continue the search. Therefore, in that
//! case, we generate code that looks more like:
//!
//!        +-------+
//!        | Entry |
//!        +-------+
//!            |
//!        +-------------------------------------------+
//!        | llmatch_c = (addr of first half of tuple) |
//!        | llmatch_d = (addr of first half of tuple) |
//!        +-------------------------------------------+
//!            |
//!        +-------------------------------------------------+
//!        | *llbinding_d = **llmatch_d                      |
//!        | check condition                                 |
//!        | if false { goto next case }                     |
//!        | if true { goto body }                           |
//!        +-------------------------------------------------+
//!
//! The handling for the cleanups is a bit... sensitive.  Basically, the body
//! is the one that invokes `add_clean()` for each binding.  During the guard
//! evaluation, we add temporary cleanups and revoke them after the guard is
//! evaluated (it could fail, after all). Note that guards and moves are
//! just plain incompatible.
//!
//! Some relevant helper functions that manage bindings:
//! - `create_bindings_map()`
//! - `insert_lllocals()`
//!
//!
//! ## Notes on vector pattern matching.
//!
//! Vector pattern matching is surprisingly tricky. The problem is that
//! the structure of the vector isn't fully known, and slice matches
//! can be done on subparts of it.
//!
//! The way that vector pattern matches are dealt with, then, is as
//! follows. First, we make the actual condition associated with a
//! vector pattern simply a vector length comparison. So the pattern
//! [1, .. x] gets the condition "vec len >= 1", and the pattern
//! [.. x] gets the condition "vec len >= 0". The problem here is that
//! having the condition "vec len >= 1" hold clearly does not mean that
//! only a pattern that has exactly that condition will match. This
//! means that it may well be the case that a condition holds, but none
//! of the patterns matching that condition match; to deal with this,
//! when doing vector length matches, we have match failures proceed to
//! the next condition to check.
//!
//! There are a couple more subtleties to deal with. While the "actual"
//! condition associated with vector length tests is simply a test on
//! the vector length, the actual vec_len Opt entry contains more
//! information used to restrict which matches are associated with it.
//! So that all matches in a submatch are matching against the same
//! values from inside the vector, they are split up by how many
//! elements they match at the front and at the back of the vector. In
//! order to make sure that arms are properly checked in order, even
//! with the overmatching conditions, each vec_len Opt entry is
//! associated with a range of matches.
//! Consider the following:
//!
//!   match &[1, 2, 3] {
//!       [1, 1, .. _] => 0,
//!       [1, 2, 2, .. _] => 1,
//!       [1, 2, 3, .. _] => 2,
//!       [1, 2, .. _] => 3,
//!       _ => 4
//!   }
//! The proper arm to match is arm 2, but arms 0 and 3 both have the
//! condition "len >= 2". If arm 3 was lumped in with arm 0, then the
//! wrong branch would be taken. Instead, vec_len Opts are associated
//! with a contiguous range of matches that have the same "shape".
//! This is sort of ugly and requires a bunch of special handling of
//! vec_len options.
184

S
Steven Fackler 已提交
185 186 187 188 189 190
pub use self::BranchKind::*;
pub use self::OptResult::*;
pub use self::TransBindingMode::*;
use self::Opt::*;
use self::FailureHandler::*;

191
use llvm::{ValueRef, BasicBlockRef};
192 193
use middle::check_match::StaticInliner;
use middle::check_match;
194
use middle::const_eval;
195
use middle::def::{self, DefMap};
N
Niko Matsakis 已提交
196
use middle::def_id::DefId;
197
use middle::expr_use_visitor as euv;
198
use middle::infer;
199
use middle::lang_items::StrEqFnLangItem;
200
use middle::mem_categorization as mc;
201
use middle::mem_categorization::Categorization;
202
use middle::pat_util::*;
203 204
use trans::adt;
use trans::base::*;
205
use trans::build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast};
206
use trans::build::{Not, Store, Sub, add_comment};
207 208
use trans::build;
use trans::callee;
209
use trans::cleanup::{self, CleanupMethods, DropHintMethods};
210 211 212
use trans::common::*;
use trans::consts;
use trans::datum::*;
213
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
214
use trans::expr::{self, Dest};
215
use trans::monomorphize;
216 217
use trans::tvec;
use trans::type_of;
218
use middle::ty::{self, Ty};
219
use session::config::NoDebugInfo;
220
use util::common::indenter;
221
use util::nodemap::FnvHashMap;
222
use util::ppaux;
223

224
use std;
J
Jonathan S 已提交
225
use std::cell::RefCell;
226
use std::cmp::Ordering;
227
use std::fmt;
228
use std::rc::Rc;
229 230
use rustc_front::hir;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
231
use syntax::ext::mtwt;
232
use syntax::codemap::Span;
233
use rustc_front::fold::Folder;
234
use syntax::ptr::P;
235

N
Niko Matsakis 已提交
236
#[derive(Copy, Clone, Debug)]
237
struct ConstantExpr<'a>(&'a hir::Expr);
238

239 240
impl<'a> ConstantExpr<'a> {
    fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
241
        match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
242
            Some(result) => result == Ordering::Equal,
S
Steve Klabnik 已提交
243
            None => panic!("compare_list_exprs: type mismatch"),
244 245
        }
    }
246 247
}

248
// An option identifying a branch (either a literal, an enum variant or a range)
J
Jorge Aparicio 已提交
249
#[derive(Debug)]
250
enum Opt<'a, 'tcx> {
251 252
    ConstantValue(ConstantExpr<'a>, DebugLoc),
    ConstantRange(ConstantExpr<'a>, ConstantExpr<'a>, DebugLoc),
N
Niko Matsakis 已提交
253
    Variant(ty::Disr, Rc<adt::Repr<'tcx>>, DefId, DebugLoc),
254 255 256
    SliceLengthEqual(usize, DebugLoc),
    SliceLengthGreaterOrEqual(/* prefix length */ usize,
                              /* suffix length */ usize,
257
                              DebugLoc),
258
}
259

260 261
impl<'a, 'tcx> Opt<'a, 'tcx> {
    fn eq(&self, other: &Opt<'a, 'tcx>, tcx: &ty::ctxt<'tcx>) -> bool {
262
        match (self, other) {
263 264
            (&ConstantValue(a, _), &ConstantValue(b, _)) => a.eq(b, tcx),
            (&ConstantRange(a1, a2, _), &ConstantRange(b1, b2, _)) => {
265 266
                a1.eq(b1, tcx) && a2.eq(b2, tcx)
            }
267 268
            (&Variant(a_disr, ref a_repr, a_def, _),
             &Variant(b_disr, ref b_repr, b_def, _)) => {
269 270
                a_disr == b_disr && *a_repr == *b_repr && a_def == b_def
            }
271 272 273
            (&SliceLengthEqual(a, _), &SliceLengthEqual(b, _)) => a == b,
            (&SliceLengthGreaterOrEqual(a1, a2, _),
             &SliceLengthGreaterOrEqual(b1, b2, _)) => {
274 275 276 277 278 279
                a1 == b1 && a2 == b2
            }
            _ => false
        }
    }

280
    fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> {
O
Oliver Schneider 已提交
281
        use trans::consts::TrueConst::Yes;
282 283 284
        let _icx = push_ctxt("match::trans_opt");
        let ccx = bcx.ccx();
        match *self {
285
            ConstantValue(ConstantExpr(lit_expr), _) => {
286
                let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id);
O
Oliver Schneider 已提交
287 288 289 290 291
                let expr = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None, Yes);
                let llval = match expr {
                    Ok((llval, _)) => llval,
                    Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
                };
292 293 294
                let lit_datum = immediate_rvalue(llval, lit_ty);
                let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
                SingleResult(Result::new(bcx, lit_datum.val))
295
            }
296
            ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
O
Oliver Schneider 已提交
297 298 299 300 301 302 303 304
                let l1 = match consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None, Yes) {
                    Ok((l1, _)) => l1,
                    Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
                };
                let l2 = match consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None, Yes) {
                    Ok((l2, _)) => l2,
                    Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
                };
305 306
                RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
            }
307
            Variant(disr_val, ref repr, _, _) => {
308
                SingleResult(Result::new(bcx, adt::trans_case(bcx, &**repr, disr_val)))
309
            }
310
            SliceLengthEqual(length, _) => {
311 312
                SingleResult(Result::new(bcx, C_uint(ccx, length)))
            }
313
            SliceLengthGreaterOrEqual(prefix, suffix, _) => {
314
                LowerBound(Result::new(bcx, C_uint(ccx, prefix + suffix)))
J
Jihyun Yu 已提交
315 316
            }
        }
317
    }
318 319 320 321 322 323 324 325 326 327

    fn debug_loc(&self) -> DebugLoc {
        match *self {
            ConstantValue(_,debug_loc)                 |
            ConstantRange(_, _, debug_loc)             |
            Variant(_, _, _, debug_loc)                |
            SliceLengthEqual(_, debug_loc)             |
            SliceLengthGreaterOrEqual(_, _, debug_loc) => debug_loc
        }
    }
328
}
329

N
Niko Matsakis 已提交
330
#[derive(Copy, Clone, PartialEq)]
331 332 333 334 335 336
pub enum BranchKind {
    NoBranch,
    Single,
    Switch,
    Compare,
    CompareSliceLength
337
}
338

339 340 341 342
pub enum OptResult<'blk, 'tcx: 'blk> {
    SingleResult(Result<'blk, 'tcx>),
    RangeResult(Result<'blk, 'tcx>, Result<'blk, 'tcx>),
    LowerBound(Result<'blk, 'tcx>)
343 344
}

345
#[derive(Clone, Copy, PartialEq)]
346
pub enum TransBindingMode {
347 348
    /// By-value binding for a copy type: copies from matched data
    /// into a fresh LLVM alloca.
349
    TrByCopy(/* llbinding */ ValueRef),
350 351 352 353 354 355 356 357 358 359 360 361

    /// By-value binding for a non-copy type where we copy into a
    /// fresh LLVM alloca; this most accurately reflects the language
    /// semantics (e.g. it properly handles overwrites of the matched
    /// input), but potentially injects an unwanted copy.
    TrByMoveIntoCopy(/* llbinding */ ValueRef),

    /// Binding a non-copy type by reference under the hood; this is
    /// a codegen optimization to avoid unnecessary memory traffic.
    TrByMoveRef,

    /// By-ref binding exposed in the original source input.
362
    TrByRef,
363 364
}

365 366 367 368 369 370 371 372 373 374 375
impl TransBindingMode {
    /// if binding by making a fresh copy; returns the alloca that it
    /// will copy into; otherwise None.
    fn alloca_if_copy(&self) -> Option<ValueRef> {
        match *self {
            TrByCopy(llbinding) | TrByMoveIntoCopy(llbinding) => Some(llbinding),
            TrByMoveRef | TrByRef => None,
        }
    }
}

S
Steve Klabnik 已提交
376 377 378 379 380 381 382
/// Information about a pattern binding:
/// - `llmatch` is a pointer to a stack slot.  The stack slot contains a
///   pointer into the value being matched.  Hence, llmatch has type `T**`
///   where `T` is the value being matched.
/// - `trmode` is the trans binding mode
/// - `id` is the node id of the binding
/// - `ty` is the Rust type of the binding
383
#[derive(Clone, Copy)]
384
pub struct BindingInfo<'tcx> {
385 386 387 388
    pub llmatch: ValueRef,
    pub trmode: TransBindingMode,
    pub id: ast::NodeId,
    pub span: Span,
389
    pub ty: Ty<'tcx>,
390
}
391

392
type BindingsMap<'tcx> = FnvHashMap<ast::Name, BindingInfo<'tcx>>;
393

394
struct ArmData<'p, 'blk, 'tcx: 'blk> {
395
    bodycx: Block<'blk, 'tcx>,
396
    arm: &'p hir::Arm,
397
    bindings_map: BindingsMap<'tcx>
398 399
}

S
Steve Klabnik 已提交
400 401 402 403
/// Info about Match.
/// If all `pats` are matched then arm `data` will be executed.
/// As we proceed `bound_ptrs` are filled with pointers to values to be bound,
/// these pointers are stored in llmatch variables just before executing `data` arm.
404
struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
405
    pats: Vec<&'p hir::Pat>,
406
    data: &'a ArmData<'p, 'blk, 'tcx>,
407
    bound_ptrs: Vec<(ast::Name, ValueRef)>,
408 409 410
    // Thread along renamings done by the check_match::StaticInliner, so we can
    // map back to original NodeIds
    pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
411 412
}

413 414
impl<'a, 'p, 'blk, 'tcx> fmt::Debug for Match<'a, 'p, 'blk, 'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415
        if ppaux::verbose() {
M
Michael Sullivan 已提交
416
            // for many programs, this just take too long to serialize
417
            write!(f, "{:?}", self.pats)
M
Michael Sullivan 已提交
418
        } else {
419
            write!(f, "{} pats", self.pats.len())
M
Michael Sullivan 已提交
420
        }
M
Marijn Haverbeke 已提交
421 422 423
    }
}

424
fn has_nested_bindings(m: &[Match], col: usize) -> bool {
425
    for br in m {
426
        match br.pats[col].node {
427
            hir::PatIdent(_, _, Some(_)) => return true,
428
            _ => ()
429 430
        }
    }
B
Brian Anderson 已提交
431
    return false;
432 433
}

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
// As noted in `fn match_datum`, we should eventually pass around a
// `Datum<Lvalue>` for the `val`; but until we get to that point, this
// `MatchInput` struct will serve -- it has everything `Datum<Lvalue>`
// does except for the type field.
#[derive(Copy, Clone)]
pub struct MatchInput { val: ValueRef, lval: Lvalue }

impl<'tcx> Datum<'tcx, Lvalue> {
    pub fn match_input(&self) -> MatchInput {
        MatchInput {
            val: self.val,
            lval: self.kind,
        }
    }
}

impl MatchInput {
    fn from_val(val: ValueRef) -> MatchInput {
        MatchInput {
            val: val,
454
            lval: Lvalue::new("MatchInput::from_val"),
455 456 457 458 459 460 461 462
        }
    }

    fn to_datum<'tcx>(self, ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> {
        Datum::new(self.val, ty, self.lval)
    }
}

463 464
fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                              m: &[Match<'a, 'p, 'blk, 'tcx>],
465
                                              col: usize,
466
                                              val: MatchInput)
467
                                              -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
468
    debug!("expand_nested_bindings(bcx={}, m={:?}, col={}, val={})",
469
           bcx.to_str(),
470
           m,
471
           col,
472
           bcx.val_to_string(val.val));
473 474
    let _indenter = indenter();

475
    m.iter().map(|br| {
476
        let mut bound_ptrs = br.bound_ptrs.clone();
477
        let mut pat = br.pats[col];
478 479
        loop {
            pat = match pat.node {
480
                hir::PatIdent(_, ref path, Some(ref inner)) => {
481
                    bound_ptrs.push((mtwt::resolve(path.node), val.val));
482
                    &**inner
483 484
                },
                _ => break
485 486
            }
        }
487 488

        let mut pats = br.pats.clone();
489
        pats[col] = pat;
490 491 492
        Match {
            pats: pats,
            data: &*br.data,
493 494
            bound_ptrs: bound_ptrs,
            pat_renaming_map: br.pat_renaming_map,
495
        }
496
    }).collect()
497 498
}

499
fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
J
Jonathan S 已提交
500
                                          dm: &RefCell<DefMap>,
501
                                          m: &[Match<'a, 'p, 'blk, 'tcx>],
502
                                          col: usize,
503
                                          val: MatchInput,
504 505
                                          mut e: F)
                                          -> Vec<Match<'a, 'p, 'blk, 'tcx>> where
506
    F: FnMut(&[&'p hir::Pat]) -> Option<Vec<&'p hir::Pat>>,
507
{
508
    debug!("enter_match(bcx={}, m={:?}, col={}, val={})",
509
           bcx.to_str(),
510
           m,
511
           col,
512
           bcx.val_to_string(val.val));
513 514
    let _indenter = indenter();

E
Eduard Burtescu 已提交
515
    m.iter().filter_map(|br| {
516
        e(&br.pats).map(|pats| {
517
            let this = br.pats[col];
E
Eduard Burtescu 已提交
518 519
            let mut bound_ptrs = br.bound_ptrs.clone();
            match this.node {
520
                hir::PatIdent(_, ref path, None) => {
521
                    if pat_is_binding(&dm.borrow(), &*this) {
522
                        bound_ptrs.push((mtwt::resolve(path.node), val.val));
523 524
                    }
                }
525 526
                hir::PatVec(ref before, Some(ref slice), ref after) => {
                    if let hir::PatIdent(_, ref path, None) = slice.node {
527 528 529
                        let subslice_val = bind_subslice_pat(
                            bcx, this.id, val,
                            before.len(), after.len());
530
                        bound_ptrs.push((mtwt::resolve(path.node), subslice_val));
531 532
                    }
                }
E
Eduard Burtescu 已提交
533
                _ => {}
534
            }
E
Eduard Burtescu 已提交
535 536 537
            Match {
                pats: pats,
                data: br.data,
538 539
                bound_ptrs: bound_ptrs,
                pat_renaming_map: br.pat_renaming_map,
E
Eduard Burtescu 已提交
540 541 542
            }
        })
    }).collect()
543 544
}

545
fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
J
Jonathan S 已提交
546
                                     dm: &RefCell<DefMap>,
547
                                     m: &[Match<'a, 'p, 'blk, 'tcx>],
548
                                     col: usize,
549
                                     val: MatchInput)
550
                                     -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
551
    debug!("enter_default(bcx={}, m={:?}, col={}, val={})",
552
           bcx.to_str(),
553
           m,
554
           col,
555
           bcx.val_to_string(val.val));
556
    let _indenter = indenter();
557

558
    // Collect all of the matches that can match against anything.
559
    enter_match(bcx, dm, m, col, val, |pats| {
560
        if pat_is_binding_or_wild(&dm.borrow(), &*pats[col]) {
561
            let mut r = pats[..col].to_vec();
562
            r.push_all(&pats[col + 1..]);
563
            Some(r)
564 565
        } else {
            None
566
        }
E
Edward Wang 已提交
567
    })
568 569
}

570
// <pcwalton> nmatsakis: what does enter_opt do?
571 572
// <pcwalton> in trans/match
// <pcwalton> trans/match.rs is like stumbling around in a dark cave
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
// <nmatsakis> pcwalton: the enter family of functions adjust the set of
//             patterns as needed
// <nmatsakis> yeah, at some point I kind of achieved some level of
//             understanding
// <nmatsakis> anyhow, they adjust the patterns given that something of that
//             kind has been found
// <nmatsakis> pcwalton: ok, right, so enter_XXX() adjusts the patterns, as I
//             said
// <nmatsakis> enter_match() kind of embodies the generic code
// <nmatsakis> it is provided with a function that tests each pattern to see
//             if it might possibly apply and so forth
// <nmatsakis> so, if you have a pattern like {a: _, b: _, _} and one like _
// <nmatsakis> then _ would be expanded to (_, _)
// <nmatsakis> one spot for each of the sub-patterns
// <nmatsakis> enter_opt() is one of the more complex; it covers the fallible
//             cases
// <nmatsakis> enter_rec_or_struct() or enter_tuple() are simpler, since they
//             are infallible patterns
// <nmatsakis> so all patterns must either be records (resp. tuples) or
//             wildcards

594 595 596 597
/// The above is now outdated in that enter_match() now takes a function that
/// takes the complete row of patterns rather than just the first one.
/// Also, most of the enter_() family functions have been unified with
/// the check_match specialization step.
598
fn enter_opt<'a, 'p, 'blk, 'tcx>(
599
             bcx: Block<'blk, 'tcx>,
600
             _: ast::NodeId,
J
Jonathan S 已提交
601
             dm: &RefCell<DefMap>,
602
             m: &[Match<'a, 'p, 'blk, 'tcx>],
603
             opt: &Opt,
604 605
             col: usize,
             variant_size: usize,
606
             val: MatchInput)
607
             -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
608
    debug!("enter_opt(bcx={}, m={:?}, opt={:?}, col={}, val={})",
609
           bcx.to_str(),
610
           m,
611
           *opt,
612
           col,
613
           bcx.val_to_string(val.val));
614 615
    let _indenter = indenter();

616
    let ctor = match opt {
617
        &ConstantValue(ConstantExpr(expr), _) => check_match::ConstantValue(
618 619
            const_eval::eval_const_expr(bcx.tcx(), &*expr)
        ),
620
        &ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => check_match::ConstantRange(
621 622
            const_eval::eval_const_expr(bcx.tcx(), &*lo),
            const_eval::eval_const_expr(bcx.tcx(), &*hi)
623
        ),
624
        &SliceLengthEqual(n, _) =>
625
            check_match::Slice(n),
626
        &SliceLengthGreaterOrEqual(before, after, _) =>
627
            check_match::SliceWithSubslice(before, after),
628
        &Variant(_, _, def_id, _) =>
S
Steven Fackler 已提交
629
            check_match::Constructor::Variant(def_id)
630
    };
631

632
    let param_env = bcx.tcx().empty_parameter_environment();
N
Niko Matsakis 已提交
633 634 635 636
    let mcx = check_match::MatchCheckCtxt {
        tcx: bcx.tcx(),
        param_env: param_env,
    };
637
    enter_match(bcx, dm, m, col, val, |pats|
638
        check_match::specialize(&mcx, &pats[..], &ctor, col, variant_size)
639
    )
640 641
}

642 643 644
// Returns the options in one column of matches. An option is something that
// needs to be conditionally matched at runtime; for example, the discriminant
// on a set of enum variants or a literal.
645
fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
646
                                    m: &[Match<'a, 'p, 'blk, 'tcx>],
647
                                    col: usize)
648
                                    -> Vec<Opt<'p, 'tcx>> {
649
    let tcx = bcx.tcx();
650

651
    let mut found: Vec<Opt> = vec![];
652
    for br in m {
653
        let cur = br.pats[col];
654 655 656 657 658 659 660 661 662
        let debug_loc = match br.pat_renaming_map {
            Some(pat_renaming_map) => {
                match pat_renaming_map.get(&(cur.id, cur.span)) {
                    Some(&id) => DebugLoc::At(id, cur.span),
                    None => DebugLoc::At(cur.id, cur.span),
                }
            }
            None => DebugLoc::None
        };
663

664
        let opt = match cur.node {
665
            hir::PatLit(ref l) => {
666 667
                ConstantValue(ConstantExpr(&**l), debug_loc)
            }
668
            hir::PatIdent(..) | hir::PatEnum(..) | hir::PatStruct(..) => {
J
Jakub Wieczorek 已提交
669
                // This is either an enum variant or a variable binding.
670
                let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def());
P
Patrick Walton 已提交
671
                match opt_def {
672
                    Some(def::DefVariant(enum_id, var_id, _)) => {
673
                        let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id);
674 675 676 677
                        Variant(variant.disr_val,
                                adt::represent_node(bcx, cur.id),
                                var_id,
                                debug_loc)
678
                    }
679
                    _ => continue
680
                }
M
Marijn Haverbeke 已提交
681
            }
682
            hir::PatRange(ref l1, ref l2) => {
683
                ConstantRange(ConstantExpr(&**l1), ConstantExpr(&**l2), debug_loc)
684
            }
685
            hir::PatVec(ref before, None, ref after) => {
686
                SliceLengthEqual(before.len() + after.len(), debug_loc)
687
            }
688
            hir::PatVec(ref before, Some(_), ref after) => {
689
                SliceLengthGreaterOrEqual(before.len(), after.len(), debug_loc)
690
            }
691 692 693 694 695
            _ => continue
        };

        if !found.iter().any(|x| x.eq(&opt, tcx)) {
            found.push(opt);
696 697
        }
    }
698
    found
699 700
}

701 702 703
struct ExtractedBlock<'blk, 'tcx: 'blk> {
    vals: Vec<ValueRef>,
    bcx: Block<'blk, 'tcx>,
704 705
}

706
fn extract_variant_args<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
707
                                    repr: &adt::Repr<'tcx>,
708
                                    disr_val: ty::Disr,
709
                                    val: MatchInput)
710
                                    -> ExtractedBlock<'blk, 'tcx> {
711
    let _icx = push_ctxt("match::extract_variant_args");
712
    let args = (0..adt::num_args(repr, disr_val)).map(|i| {
713
        adt::trans_field_ptr(bcx, repr, val.val, disr_val, i)
A
Aaron Turon 已提交
714
    }).collect();
L
Luqman Aden 已提交
715

716
    ExtractedBlock { vals: args, bcx: bcx }
717 718
}

S
Steve Klabnik 已提交
719 720
/// Helper for converting from the ValueRef that we pass around in the match code, which is always
/// an lvalue, into a Datum. Eventually we should just pass around a Datum and be done with it.
721 722
fn match_datum<'tcx>(val: MatchInput, left_ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> {
    val.to_datum(left_ty)
723 724
}

725 726
fn bind_subslice_pat(bcx: Block,
                     pat_id: ast::NodeId,
727
                     val: MatchInput,
728 729
                     offset_left: usize,
                     offset_right: usize) -> ValueRef {
730 731
    let _icx = push_ctxt("match::bind_subslice_pat");
    let vec_ty = node_id_type(bcx, pat_id);
732 733 734 735 736 737
    let vec_ty_contents = match vec_ty.sty {
        ty::TyBox(ty) => ty,
        ty::TyRef(_, mt) | ty::TyRawPtr(mt) => mt.ty,
        _ => vec_ty
    };
    let unit_ty = vec_ty_contents.sequence_element_type(bcx.tcx());
738 739 740
    let vec_datum = match_datum(val, vec_ty);
    let (base, len) = vec_datum.get_vec_base_and_len(bcx);

741
    let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
742
    let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
743
    let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None);
744 745
    let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic),
                                         bcx.tcx().mk_slice(unit_ty));
746
    let scratch = rvalue_scratch_datum(bcx, slice_ty, "");
747 748
    Store(bcx, slice_begin, expr::get_dataptr(bcx, scratch.val));
    Store(bcx, slice_len, expr::get_meta(bcx, scratch.val));
749 750
    scratch.val
}
751

752
fn extract_vec_elems<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
753
                                 left_ty: Ty<'tcx>,
754 755
                                 before: usize,
                                 after: usize,
756
                                 val: MatchInput)
757
                                 -> ExtractedBlock<'blk, 'tcx> {
758
    let _icx = push_ctxt("match::extract_vec_elems");
759
    let vec_datum = match_datum(val, left_ty);
760
    let (base, len) = vec_datum.get_vec_base_and_len(bcx);
761
    let mut elems = vec![];
762 763
    elems.extend((0..before).map(|i| GEPi(bcx, base, &[i])));
    elems.extend((0..after).rev().map(|i| {
N
Nick Cameron 已提交
764
        InBoundsGEP(bcx, base, &[
765
            Sub(bcx, len, C_uint(bcx.ccx(), i + 1), DebugLoc::None)
766 767
        ])
    }));
768
    ExtractedBlock { vals: elems, bcx: bcx }
769 770
}

771 772 773 774
// Macro for deciding whether any of the remaining matches fit a given kind of
// pattern.  Note that, because the macro is well-typed, either ALL of the
// matches should fit that sort of pattern or NONE (however, some of the
// matches may be wildcards like _ or identifiers).
775
macro_rules! any_pat {
776
    ($m:expr, $col:expr, $pattern:pat) => (
777
        ($m).iter().any(|br| {
778
            match br.pats[$col].node {
779 780 781
                $pattern => true,
                _ => false
            }
782
        })
783
    )
784
}
785

786
fn any_uniq_pat(m: &[Match], col: usize) -> bool {
787
    any_pat!(m, col, hir::PatBox(_))
788 789
}

790
fn any_region_pat(m: &[Match], col: usize) -> bool {
791
    any_pat!(m, col, hir::PatRegion(..))
792 793
}

794
fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: usize) -> bool {
795
    m.iter().any(|br| {
796
        let pat = br.pats[col];
797
        match pat.node {
798 799
            hir::PatTup(_) => true,
            hir::PatStruct(..) => {
800 801
                match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
                    Some(def::DefVariant(..)) => false,
802 803 804
                    _ => true,
                }
            }
805
            hir::PatEnum(..) | hir::PatIdent(_, _, None) => {
806 807
                match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
                    Some(def::DefStruct(..)) => true,
808
                    _ => false
809 810
                }
            }
811 812
            _ => false
        }
813
    })
814 815
}

816
/// What to do when the pattern match fails.
817
enum FailureHandler {
818 819
    Infallible,
    JumpToBasicBlock(BasicBlockRef),
820
    Unreachable
821 822
}

823
impl FailureHandler {
824
    fn is_fallible(&self) -> bool {
825
        match *self {
826 827
            Infallible => false,
            _ => true
828 829 830
        }
    }

831 832
    fn is_infallible(&self) -> bool {
        !self.is_fallible()
833 834
    }

835
    fn handle_fail(&self, bcx: Block) {
836
        match *self {
837
            Infallible =>
S
Steve Klabnik 已提交
838
                panic!("attempted to panic in a non-panicking panic handler!"),
839
            JumpToBasicBlock(basic_block) =>
840
                Br(bcx, basic_block, DebugLoc::None),
841 842
            Unreachable =>
                build::Unreachable(bcx)
843 844 845
        }
    }
}
846

J
Jonathan S 已提交
847 848
fn pick_column_to_specialize(def_map: &RefCell<DefMap>, m: &[Match]) -> Option<usize> {
    fn pat_score(def_map: &RefCell<DefMap>, pat: &hir::Pat) -> usize {
849
        match pat.node {
850
            hir::PatIdent(_, _, Some(ref inner)) => pat_score(def_map, &**inner),
851
            _ if pat_is_refutable(&def_map.borrow(), pat) => 1,
852
            _ => 0
853 854
        }
    }
855

856
    let column_score = |m: &[Match], col: usize| -> usize {
857 858 859 860 861 862 863
        let total_score = m.iter()
            .map(|row| row.pats[col])
            .map(|pat| pat_score(def_map, pat))
            .sum();

        // Irrefutable columns always go first, they'd only be duplicated in the branches.
        if total_score == 0 {
864
            std::usize::MAX
865 866
        } else {
            total_score
867
        }
868 869
    };

870
    let column_contains_any_nonwild_patterns = |&col: &usize| -> bool {
871
        m.iter().any(|row| match row.pats[col].node {
V
Vadim Petrochenkov 已提交
872
            hir::PatWild => false,
873 874 875 876
            _ => true
        })
    };

877
    (0..m[0].pats.len())
878 879 880 881
        .filter(column_contains_any_nonwild_patterns)
        .map(|col| (col, column_score(m, col)))
        .max_by(|&(_, score)| score)
        .map(|(col, _)| col)
882
}
883

884
// Compiles a comparison between two things.
885 886 887
fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                              lhs: ValueRef,
                              rhs: ValueRef,
888 889
                              rhs_t: Ty<'tcx>,
                              debug_loc: DebugLoc)
890 891
                              -> Result<'blk, 'tcx> {
    fn compare_str<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
892 893 894 895
                               lhs_data: ValueRef,
                               lhs_len: ValueRef,
                               rhs_data: ValueRef,
                               rhs_len: ValueRef,
896 897
                               rhs_t: Ty<'tcx>,
                               debug_loc: DebugLoc)
898
                               -> Result<'blk, 'tcx> {
899 900
        let did = langcall(cx,
                           None,
901
                           &format!("comparison of `{}`", rhs_t),
902
                           StrEqFnLangItem);
903
        callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc)
904 905
    }

906
    let _icx = push_ctxt("compare_values");
907
    if rhs_t.is_scalar() {
908
        let cmp = compare_scalar_types(cx, lhs, rhs, rhs_t, hir::BiEq, debug_loc);
909
        return Result::new(cx, cmp);
910 911
    }

912
    match rhs_t.sty {
913
        ty::TyRef(_, mt) => match mt.ty.sty {
914 915 916 917 918 919 920
            ty::TyStr => {
                let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
                let lhs_len = Load(cx, expr::get_meta(cx, lhs));
                let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
                let rhs_len = Load(cx, expr::get_meta(cx, rhs));
                compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
            }
921
            ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty {
922
                ty::TyUint(ast::TyU8) => {
923
                    // NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
924
                    // which calls memcmp().
925
                    let pat_len = val_ty(rhs).element_type().array_length();
926
                    let ty_str_slice = cx.tcx().mk_static_str();
927

928 929
                    let rhs_data = GEPi(cx, rhs, &[0, 0]);
                    let rhs_len = C_uint(cx.ccx(), pat_len);
930

931 932
                    let lhs_data;
                    let lhs_len;
933 934
                    if val_ty(lhs) == val_ty(rhs) {
                        // Both the discriminant and the pattern are thin pointers
935 936 937
                        lhs_data = GEPi(cx, lhs, &[0, 0]);
                        lhs_len = C_uint(cx.ccx(), pat_len);
                    } else {
938 939
                        // The discriminant is a fat pointer
                        let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to();
940 941 942
                        let lhs_str = PointerCast(cx, lhs, llty_str_slice);
                        lhs_data = Load(cx, expr::get_dataptr(cx, lhs_str));
                        lhs_len = Load(cx, expr::get_meta(cx, lhs_str));
943 944
                    }

945
                    compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
946 947 948
                },
                _ => cx.sess().bug("only byte strings supported in compare_values"),
            },
949
            _ => cx.sess().bug("only string and byte strings supported in compare_values"),
950
        },
951
        _ => cx.sess().bug("only scalars, byte strings, and strings supported in compare_values"),
952
    }
953 954
}

S
Steve Klabnik 已提交
955
/// For each binding in `data.bindings_map`, adds an appropriate entry into the `fcx.lllocals` map
956
fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
957
                               bindings_map: &BindingsMap<'tcx>,
958 959
                               cs: Option<cleanup::ScopeId>)
                               -> Block<'blk, 'tcx> {
960
    for (&name, &binding_info) in bindings_map {
961
        let (llval, aliases_other_state) = match binding_info.trmode {
962 963
            // By value mut binding for a copy type: load from the ptr
            // into the matched value and copy to our alloca
964 965
            TrByCopy(llbinding) |
            TrByMoveIntoCopy(llbinding) => {
966
                let llval = Load(bcx, binding_info.llmatch);
967
                let lvalue = match binding_info.trmode {
968 969
                    TrByCopy(..) =>
                        Lvalue::new("_match::insert_lllocals"),
970 971
                    TrByMoveIntoCopy(..) => {
                        // match_input moves from the input into a
972 973 974 975 976 977 978 979
                        // separate stack slot.
                        //
                        // E.g. consider moving the value `D(A)` out
                        // of the tuple `(D(A), D(B))` and into the
                        // local variable `x` via the pattern `(x,_)`,
                        // leaving the remainder of the tuple `(_,
                        // D(B))` still to be dropped in the future.
                        //
980 981
                        // Thus, here we must zero the place that we
                        // are moving *from*, because we do not yet
982 983 984 985 986 987 988 989
                        // track drop flags for a fragmented parent
                        // match input expression.
                        //
                        // Longer term we will be able to map the move
                        // into `(x, _)` up to the parent path that
                        // owns the whole tuple, and mark the
                        // corresponding stack-local drop-flag
                        // tracking the first component of the tuple.
990 991 992 993
                        let hint_kind = HintKind::ZeroAndMaintain;
                        Lvalue::new_with_hint("_match::insert_lllocals (match_input)",
                                              bcx, binding_info.id, hint_kind)
                    }
994 995
                    _ => unreachable!(),
                };
996
                let datum = Datum::new(llval, binding_info.ty, lvalue);
997
                call_lifetime_start(bcx, llbinding);
998
                bcx = datum.store_to(bcx, llbinding);
999 1000
                if let Some(cs) = cs {
                    bcx.fcx.schedule_lifetime_end(cs, llbinding);
1001
                }
1002

1003
                (llbinding, false)
1004 1005 1006
            },

            // By value move bindings: load from the ptr into the matched value
1007
            TrByMoveRef => (Load(bcx, binding_info.llmatch), true),
1008

1009
            // By ref binding: use the ptr into the matched value
1010
            TrByRef => (binding_info.llmatch, true),
1011
        };
1012

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028

        // A local that aliases some other state must be zeroed, since
        // the other state (e.g. some parent data that we matched
        // into) will still have its subcomponents (such as this
        // local) destructed at the end of the parent's scope. Longer
        // term, we will properly map such parents to the set of
        // unique drop flags for its fragments.
        let hint_kind = if aliases_other_state {
            HintKind::ZeroAndMaintain
        } else {
            HintKind::DontZeroJustUse
        };
        let lvalue = Lvalue::new_with_hint("_match::insert_lllocals (local)",
                                           bcx,
                                           binding_info.id,
                                           hint_kind);
1029
        let datum = Datum::new(llval, binding_info.ty, lvalue);
1030
        if let Some(cs) = cs {
1031
            let opt_datum = lvalue.dropflag_hint(bcx);
1032
            bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
1033
            bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty, opt_datum);
1034
        }
1035

1036
        debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
1037
        bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
1038
        debuginfo::create_match_binding_metadata(bcx, name, binding_info);
1039
    }
1040
    bcx
1041 1042
}

1043
fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1044
                                     guard_expr: &hir::Expr,
1045
                                     data: &ArmData<'p, 'blk, 'tcx>,
1046
                                     m: &[Match<'a, 'p, 'blk, 'tcx>],
1047
                                     vals: &[MatchInput],
1048 1049 1050
                                     chk: &FailureHandler,
                                     has_genuine_default: bool)
                                     -> Block<'blk, 'tcx> {
1051
    debug!("compile_guard(bcx={}, guard_expr={:?}, m={:?}, vals=[{}])",
1052
           bcx.to_str(),
1053 1054
           guard_expr,
           m,
1055
           vals.iter().map(|v| bcx.val_to_string(v.val)).collect::<Vec<_>>().join(", "));
1056 1057
    let _indenter = indenter();

1058
    let mut bcx = insert_lllocals(bcx, &data.bindings_map, None);
1059

1060 1061 1062
    let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
    let val = val.to_llbool(bcx);

1063
    for (_, &binding_info) in &data.bindings_map {
1064 1065
        if let Some(llbinding) = binding_info.trmode.alloca_if_copy() {
            call_lifetime_end(bcx, llbinding)
1066 1067 1068
        }
    }

1069 1070 1071 1072
    for (_, &binding_info) in &data.bindings_map {
        bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
    }

1073
    with_cond(bcx, Not(bcx, val, guard_expr.debug_loc()), |bcx| {
1074
        for (_, &binding_info) in &data.bindings_map {
1075
            call_lifetime_end(bcx, binding_info.llmatch);
1076
        }
1077 1078 1079 1080 1081
        match chk {
            // If the default arm is the only one left, move on to the next
            // condition explicitly rather than (possibly) falling back to
            // the default arm.
            &JumpToBasicBlock(_) if m.len() == 1 && has_genuine_default => {
1082
                chk.handle_fail(bcx);
1083 1084 1085 1086 1087
            }
            _ => {
                compile_submatch(bcx, m, vals, chk, has_genuine_default);
            }
        };
1088
        bcx
1089
    })
1090 1091
}

1092 1093
fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                        m: &[Match<'a, 'p, 'blk, 'tcx>],
1094
                                        vals: &[MatchInput],
1095 1096
                                        chk: &FailureHandler,
                                        has_genuine_default: bool) {
1097
    debug!("compile_submatch(bcx={}, m={:?}, vals=[{}])",
1098
           bcx.to_str(),
1099
           m,
1100
           vals.iter().map(|v| bcx.val_to_string(v.val)).collect::<Vec<_>>().join(", "));
1101
    let _indenter = indenter();
1102
    let _icx = push_ctxt("match::compile_submatch");
1103
    let mut bcx = bcx;
1104
    if m.is_empty() {
E
Edward Wang 已提交
1105
        if chk.is_fallible() {
1106
            chk.handle_fail(bcx);
E
Edward Wang 已提交
1107
        }
1108 1109
        return;
    }
1110

1111 1112 1113 1114 1115 1116 1117 1118
    let tcx = bcx.tcx();
    let def_map = &tcx.def_map;
    match pick_column_to_specialize(def_map, m) {
        Some(col) => {
            let val = vals[col];
            if has_nested_bindings(m, col) {
                let expanded = expand_nested_bindings(bcx, m, col, val);
                compile_submatch_continue(bcx,
1119
                                          &expanded[..],
1120 1121 1122 1123 1124 1125 1126 1127
                                          vals,
                                          chk,
                                          col,
                                          val,
                                          has_genuine_default)
            } else {
                compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default)
            }
1128
        }
1129 1130
        None => {
            let data = &m[0].data;
1131 1132
            for &(ref name, ref value_ptr) in &m[0].bound_ptrs {
                let binfo = *data.bindings_map.get(name).unwrap();
1133 1134 1135 1136 1137 1138 1139
                call_lifetime_start(bcx, binfo.llmatch);
                if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
                    expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
                }
                else {
                    Store(bcx, *value_ptr, binfo.llmatch);
                }
1140
            }
1141 1142 1143 1144 1145
            match data.arm.guard {
                Some(ref guard_expr) => {
                    bcx = compile_guard(bcx,
                                        &**guard_expr,
                                        m[0].data,
J
Jorge Aparicio 已提交
1146
                                        &m[1..m.len()],
1147 1148 1149 1150 1151 1152
                                        vals,
                                        chk,
                                        has_genuine_default);
                }
                _ => ()
            }
1153
            Br(bcx, data.bodycx.llbb, DebugLoc::None);
1154
        }
1155 1156 1157
    }
}

1158 1159
fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                                 m: &[Match<'a, 'p, 'blk, 'tcx>],
1160
                                                 vals: &[MatchInput],
1161
                                                 chk: &FailureHandler,
1162
                                                 col: usize,
1163
                                                 val: MatchInput,
1164
                                                 has_genuine_default: bool) {
1165
    let fcx = bcx.fcx;
1166
    let tcx = bcx.tcx();
E
Eduard Burtescu 已提交
1167
    let dm = &tcx.def_map;
1168

1169 1170
    let mut vals_left = vals[0..col].to_vec();
    vals_left.push_all(&vals[col + 1..]);
J
James Miller 已提交
1171
    let ccx = bcx.fcx.ccx;
M
Marijn Haverbeke 已提交
1172

1173 1174
    // Find a real id (we're adding placeholder wildcard patterns, but
    // each column is guaranteed to have at least one real pattern)
1175
    let pat_id = m.iter().map(|br| br.pats[col].id)
1176 1177
                         .find(|&id| id != DUMMY_NODE_ID)
                         .unwrap_or(DUMMY_NODE_ID);
1178

1179
    let left_ty = if pat_id == DUMMY_NODE_ID {
1180
        tcx.mk_nil()
1181 1182 1183
    } else {
        node_id_type(bcx, pat_id)
    };
1184

N
Niko Matsakis 已提交
1185 1186
    let mcx = check_match::MatchCheckCtxt {
        tcx: bcx.tcx(),
1187
        param_env: bcx.tcx().empty_parameter_environment(),
N
Niko Matsakis 已提交
1188
    };
1189
    let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
1190 1191
        let repr = adt::represent_type(bcx.ccx(), left_ty);
        let arg_count = adt::num_args(&*repr, 0);
1192
        let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) {
1193
            (arg_count, val.val)
1194 1195 1196 1197 1198
        } else {
            // For an unsized ADT (i.e. DST struct), we need to treat
            // the last field specially: instead of simply passing a
            // ValueRef pointing to that field, as with all the others,
            // we skip it and instead construct a 'fat ptr' below.
1199
            (arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val.val)))
1200 1201 1202
        };
        let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
            adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix)
1203
        ).collect();
1204 1205

        match left_ty.sty {
1206
            ty::TyStruct(def, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
1207 1208 1209
                // The last field is technically unsized but
                // since we can only ever match that field behind
                // a reference we construct a fat ptr here.
1210 1211
                let unsized_ty = def.struct_variant().fields.last().map(|field| {
                    monomorphize::field_ty(bcx.tcx(), substs, field)
1212
                }).unwrap();
1213
                let scratch = alloc_ty(bcx, unsized_ty, "__struct_field_fat_ptr");
1214
                let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
1215
                let len = Load(bcx, expr::get_meta(bcx, val.val));
1216
                Store(bcx, data, expr::get_dataptr(bcx, scratch));
1217
                Store(bcx, len, expr::get_meta(bcx, scratch));
1218 1219 1220 1221
                field_vals.push(scratch);
            }
            _ => {}
        }
1222 1223
        Some(field_vals)
    } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
1224
        Some(vec!(Load(bcx, val.val)))
1225
    } else {
1226
        match left_ty.sty {
1227
            ty::TyArray(_, n) => {
1228 1229 1230 1231 1232
                let args = extract_vec_elems(bcx, left_ty, n, 0, val);
                Some(args.vals)
            }
            _ => None
        }
1233 1234 1235 1236
    };
    match adt_vals {
        Some(field_vals) => {
            let pats = enter_match(bcx, dm, m, col, val, |pats|
1237
                check_match::specialize(&mcx, pats,
1238 1239
                                        &check_match::Single, col,
                                        field_vals.len())
1240
            );
1241 1242 1243
            let mut vals: Vec<_> = field_vals.into_iter()
                .map(|v|MatchInput::from_val(v))
                .collect();
1244 1245
            vals.push_all(&vals_left);
            compile_submatch(bcx, &pats, &vals, chk, has_genuine_default);
1246 1247 1248
            return;
        }
        _ => ()
1249 1250
    }

1251
    // Decide what kind of branch we need
1252
    let opts = get_branches(bcx, m, col);
1253
    debug!("options={:?}", opts);
1254
    let mut kind = NoBranch;
1255
    let mut test_val = val.val;
1256
    debug!("test_val={}", bcx.val_to_string(test_val));
1257
    if !opts.is_empty() {
1258
        match opts[0] {
1259
            ConstantValue(..) | ConstantRange(..) => {
1260
                test_val = load_if_immediate(bcx, val.val, left_ty);
1261
                kind = if left_ty.is_integral() {
1262 1263 1264 1265 1266
                    Switch
                } else {
                    Compare
                };
            }
1267
            Variant(_, ref repr, _, _) => {
1268
                let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val.val);
1269
                kind = the_kind;
1270
                if let Some(tval) = val_opt { test_val = tval; }
1271
            }
1272
            SliceLengthEqual(..) | SliceLengthGreaterOrEqual(..) => {
1273
                let (_, len) = tvec::get_base_and_len(bcx, val.val, left_ty);
1274
                test_val = len;
1275
                kind = Switch;
1276
            }
1277 1278
        }
    }
1279
    for o in &opts {
1280
        match *o {
1281 1282
            ConstantRange(..) => { kind = Compare; break },
            SliceLengthGreaterOrEqual(..) => { kind = CompareSliceLength; break },
1283
            _ => ()
1284 1285
        }
    }
1286
    let else_cx = match kind {
1287
        NoBranch | Single => bcx,
1288
        _ => bcx.fcx.new_temp_block("match_else")
1289
    };
1290 1291
    let sw = if kind == Switch {
        build::Switch(bcx, test_val, else_cx.llbb, opts.len())
1292
    } else {
T
Tobias Bucher 已提交
1293
        C_int(ccx, 0) // Placeholder for when not using a switch
1294
    };
M
Marijn Haverbeke 已提交
1295

E
Edward Wang 已提交
1296
    let defaults = enter_default(else_cx, dm, m, col, val);
1297
    let exhaustive = chk.is_infallible() && defaults.is_empty();
1298
    let len = opts.len();
1299

1300 1301 1302 1303
    if exhaustive && kind == Switch {
        build::Unreachable(else_cx);
    }

1304
    // Compile subtrees for each option
1305
    for (i, opt) in opts.iter().enumerate() {
1306 1307 1308
        // In some cases of range and vector pattern matching, we need to
        // override the failure case so that instead of failing, it proceeds
        // to try more matching. branch_chk, then, is the proper failure case
1309
        // for the current conditional branch.
1310
        let mut branch_chk = None;
1311
        let mut opt_cx = else_cx;
1312 1313
        let debug_loc = opt.debug_loc();

1314
        if kind == Switch || !exhaustive || i + 1 < len {
1315
            opt_cx = bcx.fcx.new_temp_block("match_case");
1316
            match kind {
1317
                Single => Br(bcx, opt_cx.llbb, debug_loc),
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
                Switch => {
                    match opt.trans(bcx) {
                        SingleResult(r) => {
                            AddCase(sw, r.val, opt_cx.llbb);
                            bcx = r.bcx;
                        }
                        _ => {
                            bcx.sess().bug(
                                "in compile_submatch, expected \
                                 opt.trans() to return a SingleResult")
1328
                        }
1329 1330 1331 1332 1333 1334
                    }
                }
                Compare | CompareSliceLength => {
                    let t = if kind == Compare {
                        left_ty
                    } else {
1335
                        tcx.types.usize // vector length
1336 1337 1338 1339
                    };
                    let Result { bcx: after_cx, val: matches } = {
                        match opt.trans(bcx) {
                            SingleResult(Result { bcx, val }) => {
1340
                                compare_values(bcx, test_val, val, t, debug_loc)
1341 1342 1343
                            }
                            RangeResult(Result { val: vbegin, .. },
                                        Result { bcx, val: vend }) => {
1344
                                let llge = compare_scalar_types(bcx, test_val, vbegin,
1345
                                                                t, hir::BiGe, debug_loc);
1346
                                let llle = compare_scalar_types(bcx, test_val, vend,
1347
                                                                t, hir::BiLe, debug_loc);
1348
                                Result::new(bcx, And(bcx, llge, llle, DebugLoc::None))
1349 1350
                            }
                            LowerBound(Result { bcx, val }) => {
1351
                                Result::new(bcx, compare_scalar_types(bcx, test_val,
1352
                                                                      val, t, hir::BiGe,
1353
                                                                      debug_loc))
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
                            }
                        }
                    };
                    bcx = fcx.new_temp_block("compare_next");

                    // If none of the sub-cases match, and the current condition
                    // is guarded or has multiple patterns, move on to the next
                    // condition, if there is any, rather than falling back to
                    // the default.
                    let guarded = m[i].data.arm.guard.is_some();
                    let multi_pats = m[i].pats.len() > 1;
                    if i + 1 < len && (guarded || multi_pats || kind == CompareSliceLength) {
                        branch_chk = Some(JumpToBasicBlock(bcx.llbb));
                    }
1368
                    CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb, debug_loc);
1369 1370
                }
                _ => ()
1371
            }
1372
        } else if kind == Compare || kind == CompareSliceLength {
1373
            Br(bcx, else_cx.llbb, debug_loc);
1374 1375
        }

1376
        let mut size = 0;
1377
        let mut unpacked = Vec::new();
1378
        match *opt {
1379
            Variant(disr_val, ref repr, _, _) => {
1380
                let ExtractedBlock {vals: argvals, bcx: new_bcx} =
E
Eduard Burtescu 已提交
1381
                    extract_variant_args(opt_cx, &**repr, disr_val, val);
1382 1383 1384
                size = argvals.len();
                unpacked = argvals;
                opt_cx = new_bcx;
1385
            }
1386
            SliceLengthEqual(len, _) => {
1387
                let args = extract_vec_elems(opt_cx, left_ty, len, 0, val);
1388
                size = args.vals.len();
1389
                unpacked = args.vals.clone();
1390 1391
                opt_cx = args.bcx;
            }
1392
            SliceLengthGreaterOrEqual(before, after, _) => {
1393 1394 1395 1396 1397
                let args = extract_vec_elems(opt_cx, left_ty, before, after, val);
                size = args.vals.len();
                unpacked = args.vals.clone();
                opt_cx = args.bcx;
            }
1398
            ConstantValue(..) | ConstantRange(..) => ()
1399
        }
1400
        let opt_ms = enter_opt(opt_cx, pat_id, dm, m, opt, col, size, val);
1401 1402 1403
        let mut opt_vals: Vec<_> = unpacked.into_iter()
            .map(|v|MatchInput::from_val(v))
            .collect();
1404
        opt_vals.push_all(&vals_left[..]);
1405
        compile_submatch(opt_cx,
1406 1407
                         &opt_ms[..],
                         &opt_vals[..],
1408 1409
                         branch_chk.as_ref().unwrap_or(chk),
                         has_genuine_default);
1410 1411
    }

1412
    // Compile the fall-through case, if any
1413 1414
    if !exhaustive && kind != Single {
        if kind == Compare || kind == CompareSliceLength {
1415
            Br(bcx, else_cx.llbb, DebugLoc::None);
1416
        }
1417 1418 1419 1420 1421
        match chk {
            // If there is only one default arm left, move on to the next
            // condition explicitly rather than (eventually) falling back to
            // the last default arm.
            &JumpToBasicBlock(_) if defaults.len() == 1 && has_genuine_default => {
1422
                chk.handle_fail(else_cx);
1423 1424 1425
            }
            _ => {
                compile_submatch(else_cx,
1426 1427
                                 &defaults[..],
                                 &vals_left[..],
1428 1429 1430
                                 chk,
                                 has_genuine_default);
            }
1431
        }
1432
    }
1433 1434
}

1435
pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1436 1437 1438
                               match_expr: &hir::Expr,
                               discr_expr: &hir::Expr,
                               arms: &[hir::Arm],
1439 1440
                               dest: Dest)
                               -> Block<'blk, 'tcx> {
1441
    let _icx = push_ctxt("match::trans_match");
1442
    trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest)
1443 1444
}

1445
/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
1446
fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
1447
    let (vid, field) = match discr.node {
1448
        hir::ExprPath(..) => match bcx.def(discr.id) {
1449
            def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None),
1450 1451
            _ => return false
        },
1452
        hir::ExprField(ref base, field) => {
1453
            let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
1454
                Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
1455 1456
                _ => return false
            };
1457
            (vid, Some(mc::NamedField(field.node)))
1458
        },
1459
        hir::ExprTupField(ref base, field) => {
1460
            let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
1461
                Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
1462 1463 1464
                _ => return false
            };
            (vid, Some(mc::PositionalField(field.node)))
1465
        },
1466 1467 1468 1469 1470 1471 1472 1473 1474
        _ => return false
    };

    let mut rc = ReassignmentChecker {
        node: vid,
        field: field,
        reassigned: false
    };
    {
1475
        let infcx = infer::normalizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables);
1476
        let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
1477
        visitor.walk_expr(body);
1478
    }
1479
    rc.reassigned
1480 1481 1482 1483
}

struct ReassignmentChecker {
    node: ast::NodeId,
1484
    field: Option<mc::FieldName>,
1485 1486 1487
    reassigned: bool
}

1488 1489 1490 1491
// Determine if the expression we're matching on is reassigned to within
// the body of the match's arm.
// We only care for the `mutate` callback since this check only matters
// for cases where the matched value is moved.
1492
impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker {
1493
    fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {}
1494 1495
    fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {}
    fn consume_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::ConsumeMode) {}
1496 1497 1498
    fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region,
              _: ty::BorrowKind, _: euv::LoanCause) {}
    fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
1499

1500 1501
    fn mutate(&mut self, _: ast::NodeId, _: Span, cmt: mc::cmt, _: euv::MutateMode) {
        match cmt.cat {
1502 1503 1504
            Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, .. }, .. }) |
            Categorization::Local(vid) => self.reassigned |= self.node == vid,
            Categorization::Interior(ref base_cmt, mc::InteriorField(field)) => {
1505
                match base_cmt.cat {
1506 1507
                    Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, .. }, .. }) |
                    Categorization::Local(vid) => {
1508 1509
                        self.reassigned |= self.node == vid &&
                            (self.field.is_none() || Some(field) == self.field)
1510 1511 1512 1513
                    },
                    _ => {}
                }
            },
1514 1515 1516 1517 1518
            _ => {}
        }
    }
}

1519 1520
fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat,
                                   discr: &hir::Expr, body: &hir::Expr)
1521
                                   -> BindingsMap<'tcx> {
1522 1523 1524 1525 1526 1527
    // Create the bindings map, which is a mapping from each binding name
    // to an alloca() that will be the value for that local variable.
    // Note that we use the names because each binding will have many ids
    // from the various alternatives.
    let ccx = bcx.ccx();
    let tcx = bcx.tcx();
1528
    let reassigned = is_discr_reassigned(bcx, discr, body);
1529
    let mut bindings_map = FnvHashMap();
1530 1531
    pat_bindings_hygienic(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
        let name = mtwt::resolve(path1.node);
1532 1533
        let variable_ty = node_id_type(bcx, p_id);
        let llvariable_ty = type_of::type_of(ccx, variable_ty);
1534
        let tcx = bcx.tcx();
1535
        let param_env = tcx.empty_parameter_environment();
1536

1537 1538
        let llmatch;
        let trmode;
1539
        let moves_by_default = variable_ty.moves_by_default(&param_env, span);
1540
        match bm {
1541
            hir::BindByValue(_) if !moves_by_default || reassigned =>
1542
            {
1543 1544
                llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
                let llcopy = alloca(bcx, llvariable_ty, &bcx.name(name));
1545 1546 1547 1548 1549
                trmode = if moves_by_default {
                    TrByMoveIntoCopy(llcopy)
                } else {
                    TrByCopy(llcopy)
                };
1550
            }
1551
            hir::BindByValue(_) => {
1552 1553 1554
                // in this case, the final type of the variable will be T,
                // but during matching we need to store a *T as explained
                // above
1555
                llmatch = alloca(bcx, llvariable_ty.ptr_to(), &bcx.name(name));
1556
                trmode = TrByMoveRef;
1557
            }
1558
            hir::BindByRef(_) => {
1559
                llmatch = alloca(bcx, llvariable_ty, &bcx.name(name));
1560 1561 1562
                trmode = TrByRef;
            }
        };
1563
        bindings_map.insert(name, BindingInfo {
1564 1565 1566 1567 1568
            llmatch: llmatch,
            trmode: trmode,
            id: p_id,
            span: span,
            ty: variable_ty
1569
        });
1570
    });
1571 1572 1573
    return bindings_map;
}

1574 1575
fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
                                 match_id: ast::NodeId,
1576 1577
                                 discr_expr: &hir::Expr,
                                 arms: &[hir::Arm],
1578
                                 dest: Dest) -> Block<'blk, 'tcx> {
1579
    let _icx = push_ctxt("match::trans_match_inner");
1580
    let fcx = scope_cx.fcx;
1581 1582
    let mut bcx = scope_cx;
    let tcx = bcx.tcx();
1583

1584 1585
    let discr_datum = unpack_datum!(bcx, expr::trans_to_lvalue(bcx, discr_expr,
                                                               "match"));
1586
    if bcx.unreachable.get() {
1587 1588
        return bcx;
    }
1589

1590
    let t = node_id_type(bcx, discr_expr.id);
1591
    let chk = if t.is_empty(tcx) {
1592 1593 1594
        Unreachable
    } else {
        Infallible
1595
    };
E
Eduard Burtescu 已提交
1596 1597 1598 1599

    let arm_datas: Vec<ArmData> = arms.iter().map(|arm| ArmData {
        bodycx: fcx.new_id_block("case_body", arm.body.id),
        arm: arm,
1600
        bindings_map: create_bindings_map(bcx, &*arm.pats[0], discr_expr, &*arm.body)
E
Eduard Burtescu 已提交
1601 1602
    }).collect();

1603 1604 1605 1606 1607 1608
    let mut pat_renaming_map = if scope_cx.sess().opts.debuginfo != NoDebugInfo {
        Some(FnvHashMap())
    } else {
        None
    };

1609
    let arm_pats: Vec<Vec<P<hir::Pat>>> = {
1610 1611 1612 1613 1614 1615 1616
        let mut static_inliner = StaticInliner::new(scope_cx.tcx(),
                                                    pat_renaming_map.as_mut());
        arm_datas.iter().map(|arm_data| {
            arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect()
        }).collect()
    };

E
Eduard Burtescu 已提交
1617
    let mut matches = Vec::new();
1618
    for (arm_data, pats) in arm_datas.iter().zip(&arm_pats) {
1619 1620
        matches.extend(pats.iter().map(|p| Match {
            pats: vec![&**p],
E
Eduard Burtescu 已提交
1621 1622
            data: arm_data,
            bound_ptrs: Vec::new(),
1623
            pat_renaming_map: pat_renaming_map.as_ref()
E
Eduard Burtescu 已提交
1624 1625 1626
        }));
    }

1627 1628
    // `compile_submatch` works one column of arm patterns a time and
    // then peels that column off. So as we progress, it may become
E
Edward Wang 已提交
1629
    // impossible to tell whether we have a genuine default arm, i.e.
1630 1631 1632
    // `_ => foo` or not. Sometimes it is important to know that in order
    // to decide whether moving on to the next condition or falling back
    // to the default arm.
E
Edward Wang 已提交
1633 1634
    let has_default = arms.last().map_or(false, |arm| {
        arm.pats.len() == 1
V
Vadim Petrochenkov 已提交
1635
        && arm.pats.last().unwrap().node == hir::PatWild
E
Edward Wang 已提交
1636
    });
1637

1638
    compile_submatch(bcx, &matches[..], &[discr_datum.match_input()], &chk, has_default);
1639

1640
    let mut arm_cxs = Vec::new();
1641
    for arm_data in &arm_datas {
1642 1643
        let mut bcx = arm_data.bodycx;

1644 1645 1646
        // insert bindings into the lllocals map and add cleanups
        let cs = fcx.push_custom_cleanup_scope();
        bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs)));
1647
        bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest);
1648
        bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs);
1649
        arm_cxs.push(bcx);
1650
    }
1651

1652
    bcx = scope_cx.fcx.join_blocks(match_id, &arm_cxs[..]);
1653
    return bcx;
1654 1655
}

S
Steve Klabnik 已提交
1656 1657
/// Generates code for a local variable declaration like `let <pat>;` or `let <pat> =
/// <opt_init_expr>`.
1658
pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1659
                               local: &hir::Local)
1660
                               -> Block<'blk, 'tcx> {
N
Niko Matsakis 已提交
1661
    let _icx = push_ctxt("match::store_local");
1662
    let mut bcx = bcx;
1663
    let tcx = bcx.tcx();
1664 1665 1666
    let pat = &*local.pat;

    fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1667
                                       pat: &hir::Pat)
1668
                                       -> Block<'blk, 'tcx> {
1669
        let _icx = push_ctxt("create_dummy_locals");
1670 1671 1672 1673 1674 1675
        // create dummy memory for the variables if we have no
        // value to store into them immediately
        let tcx = bcx.tcx();
        pat_bindings(&tcx.def_map, pat, |_, p_id, _, path1| {
            let scope = cleanup::var_scope(tcx, p_id);
            bcx = mk_binding_alloca(
1676
                bcx, p_id, path1.node, scope, (),
1677
                "_match::store_local::create_dummy_locals",
1678 1679 1680 1681
                |(), bcx, Datum { val: llval, ty, kind }| {
                    // Dummy-locals start out uninitialized, so set their
                    // drop-flag hints (if any) to "moved."
                    if let Some(hint) = kind.dropflag_hint(bcx) {
1682
                        let moved_hint = adt::DTOR_MOVED_HINT;
1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
                        debug!("store moved_hint={} for hint={:?}, uninitialized dummy",
                               moved_hint, hint);
                        Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value());
                    }

                    if kind.drop_flag_info.must_zero() {
                        // if no drop-flag hint, or the hint requires
                        // we maintain the embedded drop-flag, then
                        // mark embedded drop-flag(s) as moved
                        // (i.e. "already dropped").
                        drop_done_fill_mem(bcx, llval, ty);
                    }
                    bcx
                });
1697 1698 1699
        });
        bcx
    }
1700

1701 1702
    match local.init {
        Some(ref init_expr) => {
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
            // Optimize the "let x = expr" case. This just writes
            // the result of evaluating `expr` directly into the alloca
            // for `x`. Often the general path results in similar or the
            // same code post-optimization, but not always. In particular,
            // in unsafe code, you can have expressions like
            //
            //    let x = intrinsics::uninit();
            //
            // In such cases, the more general path is unsafe, because
            // it assumes it is matching against a valid value.
1713 1714
            match simple_name(pat) {
                Some(name) => {
1715
                    let var_scope = cleanup::var_scope(tcx, local.id);
1716
                    return mk_binding_alloca(
1717
                        bcx, pat.id, name, var_scope, (),
1718
                        "_match::store_local",
1719 1720
                        |(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr,
                                                                         expr::SaveIn(v)));
1721 1722 1723
                }

                None => {}
1724 1725
            }

1726 1727
            // General path.
            let init_datum =
1728
                unpack_datum!(bcx, expr::trans_to_lvalue(bcx, &**init_expr, "let"));
J
Jakub Bukaj 已提交
1729 1730
            if bcx.sess().asm_comments() {
                add_comment(bcx, "creating zeroable ref llval");
1731
            }
J
Jakub Bukaj 已提交
1732
            let var_scope = cleanup::var_scope(tcx, local.id);
1733
            bind_irrefutable_pat(bcx, pat, init_datum.match_input(), var_scope)
1734 1735 1736 1737 1738 1739 1740
        }
        None => {
            create_dummy_locals(bcx, pat)
        }
    }
}

1741 1742
fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
                                       p_id: ast::NodeId,
1743
                                       name: ast::Name,
1744 1745
                                       cleanup_scope: cleanup::ScopeId,
                                       arg: A,
1746
                                       caller_name: &'static str,
1747 1748
                                       populate: F)
                                       -> Block<'blk, 'tcx> where
1749
    F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>,
1750
{
1751
    let var_ty = node_id_type(bcx, p_id);
1752 1753

    // Allocate memory on stack for the binding.
1754
    let llval = alloc_ty(bcx, var_ty, &bcx.name(name));
1755
    let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse);
1756
    let datum = Datum::new(llval, var_ty, lvalue);
1757 1758 1759

    // Subtle: be sure that we *populate* the memory *before*
    // we schedule the cleanup.
1760
    call_lifetime_start(bcx, llval);
1761
    let bcx = populate(arg, bcx, datum);
1762
    bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
1763
    bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx));
1764 1765

    // Now that memory is initialized and has cleanup scheduled,
1766
    // insert datum into the local variable map.
1767
    bcx.fcx.lllocals.borrow_mut().insert(p_id, datum);
1768
    bcx
1769 1770
}

S
Steve Klabnik 已提交
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
/// A simple version of the pattern matching code that only handles
/// irrefutable patterns. This is used in let/argument patterns,
/// not in match statements. Unifying this code with the code above
/// sounds nice, but in practice it produces very inefficient code,
/// since the match code is so much more general. In most cases,
/// LLVM is able to optimize the code, but it causes longer compile
/// times and makes the generated code nigh impossible to read.
///
/// # Arguments
/// - bcx: starting basic block context
/// - pat: the irrefutable pattern being matched.
/// - val: the value being matched -- must be an lvalue (by ref, with cleanup)
1783
pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1784
                                    pat: &hir::Pat,
1785
                                    val: MatchInput,
1786 1787
                                    cleanup_scope: cleanup::ScopeId)
                                    -> Block<'blk, 'tcx> {
1788
    debug!("bind_irrefutable_pat(bcx={}, pat={:?})",
1789
           bcx.to_str(),
1790
           pat);
1791 1792

    if bcx.sess().asm_comments() {
1793 1794
        add_comment(bcx, &format!("bind_irrefutable_pat(pat={:?})",
                                 pat));
1795 1796 1797 1798
    }

    let _indenter = indenter();

1799
    let _icx = push_ctxt("match::bind_irrefutable_pat");
1800 1801 1802 1803
    let mut bcx = bcx;
    let tcx = bcx.tcx();
    let ccx = bcx.ccx();
    match pat.node {
1804
        hir::PatIdent(pat_binding_mode, ref path1, ref inner) => {
1805
            if pat_is_binding(&tcx.def_map.borrow(), &*pat) {
1806 1807 1808 1809
                // Allocate the stack slot where the value of this
                // binding will live and place it into the appropriate
                // map.
                bcx = mk_binding_alloca(
1810
                    bcx, pat.id, path1.node.name, cleanup_scope, (),
1811
                    "_match::bind_irrefutable_pat",
1812
                    |(), bcx, Datum { val: llval, ty, kind: _ }| {
1813
                        match pat_binding_mode {
1814
                            hir::BindByValue(_) => {
1815 1816
                                // By value binding: move the value that `val`
                                // points at into the binding's stack slot.
1817
                                let d = val.to_datum(ty);
1818
                                d.store_to(bcx, llval)
1819 1820
                            }

1821
                            hir::BindByRef(_) => {
1822
                                // By ref binding: the value of the variable
1823 1824
                                // is the pointer `val` itself or fat pointer referenced by `val`
                                if type_is_fat_ptr(bcx.tcx(), ty) {
1825
                                    expr::copy_fat_ptr(bcx, val.val, llval);
1826 1827
                                }
                                else {
1828
                                    Store(bcx, val.val, llval);
1829 1830
                                }

1831 1832 1833 1834 1835 1836
                                bcx
                            }
                        }
                    });
            }

1837
            if let Some(ref inner_pat) = *inner {
1838
                bcx = bind_irrefutable_pat(bcx, &**inner_pat, val, cleanup_scope);
1839
            }
1840
        }
1841
        hir::PatEnum(_, ref sub_pats) => {
1842
            let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
1843
            match opt_def {
1844
                Some(def::DefVariant(enum_id, var_id, _)) => {
1845
                    let repr = adt::represent_node(bcx, pat.id);
1846
                    let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id);
1847
                    let args = extract_variant_args(bcx,
E
Eduard Burtescu 已提交
1848
                                                    &*repr,
1849 1850
                                                    vinfo.disr_val,
                                                    val);
1851
                    if let Some(ref sub_pat) = *sub_pats {
1852
                        for (i, &argval) in args.vals.iter().enumerate() {
1853 1854 1855 1856 1857
                            bcx = bind_irrefutable_pat(
                                bcx,
                                &*sub_pat[i],
                                MatchInput::from_val(argval),
                                cleanup_scope);
1858 1859 1860
                        }
                    }
                }
1861
                Some(def::DefStruct(..)) => {
1862
                    match *sub_pats {
1863 1864 1865
                        None => {
                            // This is a unit-like struct. Nothing to do here.
                        }
1866
                        Some(ref elems) => {
1867 1868
                            // This is the tuple struct case.
                            let repr = adt::represent_node(bcx, pat.id);
D
Daniel Micay 已提交
1869
                            for (i, elem) in elems.iter().enumerate() {
E
Eduard Burtescu 已提交
1870
                                let fldptr = adt::trans_field_ptr(bcx, &*repr,
1871 1872 1873 1874 1875 1876
                                                                  val.val, 0, i);
                                bcx = bind_irrefutable_pat(
                                    bcx,
                                    &**elem,
                                    MatchInput::from_val(fldptr),
                                    cleanup_scope);
1877 1878 1879 1880 1881 1882
                            }
                        }
                    }
                }
                _ => {
                    // Nothing to do here.
1883
                }
1884
            }
1885
        }
1886
        hir::PatStruct(_, ref fields, _) => {
1887 1888
            let tcx = bcx.tcx();
            let pat_ty = node_id_type(bcx, pat.id);
1889
            let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
1890 1891
            let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id);
            for f in fields {
1892
                let name = f.node.name;
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
                let fldptr = adt::trans_field_ptr(
                    bcx,
                    &*pat_repr,
                    val.val,
                    pat_v.discr,
                    pat_v.field_index(name));
                bcx = bind_irrefutable_pat(bcx,
                                           &*f.node.pat,
                                           MatchInput::from_val(fldptr),
                                           cleanup_scope);
            }
1904
        }
1905
        hir::PatTup(ref elems) => {
1906
            let repr = adt::represent_node(bcx, pat.id);
D
Daniel Micay 已提交
1907
            for (i, elem) in elems.iter().enumerate() {
1908 1909 1910 1911 1912 1913
                let fldptr = adt::trans_field_ptr(bcx, &*repr, val.val, 0, i);
                bcx = bind_irrefutable_pat(
                    bcx,
                    &**elem,
                    MatchInput::from_val(fldptr),
                    cleanup_scope);
1914
            }
1915
        }
1916
        hir::PatBox(ref inner) => {
1917 1918
            let llbox = Load(bcx, val.val);
            bcx = bind_irrefutable_pat(
1919
                bcx, &**inner, MatchInput::from_val(llbox), cleanup_scope);
M
Marijn Haverbeke 已提交
1920
        }
1921
        hir::PatRegion(ref inner, _) => {
1922 1923 1924 1925 1926 1927
            let loaded_val = Load(bcx, val.val);
            bcx = bind_irrefutable_pat(
                bcx,
                &**inner,
                MatchInput::from_val(loaded_val),
                cleanup_scope);
1928
        }
1929
        hir::PatVec(ref before, ref slice, ref after) => {
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940
            let pat_ty = node_id_type(bcx, pat.id);
            let mut extracted = extract_vec_elems(bcx, pat_ty, before.len(), after.len(), val);
            match slice {
                &Some(_) => {
                    extracted.vals.insert(
                        before.len(),
                        bind_subslice_pat(bcx, pat.id, val, before.len(), after.len())
                    );
                }
                &None => ()
            }
1941
            bcx = before
1942 1943 1944
                .iter()
                .chain(slice.iter())
                .chain(after.iter())
1945
                .zip(extracted.vals)
1946
                .fold(bcx, |bcx, (inner, elem)| {
1947 1948 1949 1950 1951
                    bind_irrefutable_pat(
                        bcx,
                        &**inner,
                        MatchInput::from_val(elem),
                        cleanup_scope)
1952
                });
1953
        }
V
Vadim Petrochenkov 已提交
1954
        hir::PatQPath(..) | hir::PatWild | hir::PatLit(_) |
1955
        hir::PatRange(_, _) => ()
1956
    }
B
Brian Anderson 已提交
1957
    return bcx;
1958
}