Skip to content

Commit c0b76ab

Browse files
committed
auto merge of rust-lang#15388 : jakub-/rust/issue-12285, r=pcwalton
Unit-like struct patterns are irrefutable, no need for a branch. And some cleanup while I'm at it.
2 parents 36d7d74 + c2c27fa commit c0b76ab

File tree

3 files changed

+78
-93
lines changed

3 files changed

+78
-93
lines changed

src/librustc/middle/check_match.rs

Lines changed: 51 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ pub enum Constructor {
9393
Slice(uint)
9494
}
9595

96-
#[deriving(Clone)]
96+
#[deriving(Clone, PartialEq)]
9797
enum Usefulness {
98-
Useful(Vec<Gc<Pat>>),
98+
Useful,
99+
UsefulWithWitness(Vec<Gc<Pat>>),
99100
NotUseful
100101
}
101102

@@ -104,15 +105,6 @@ enum WitnessPreference {
104105
LeaveOutWitness
105106
}
106107

107-
impl Usefulness {
108-
fn useful(self) -> Option<Vec<Gc<Pat>>> {
109-
match self {
110-
Useful(pats) => Some(pats),
111-
_ => None
112-
}
113-
}
114-
}
115-
116108
impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
117109
fn visit_expr(&mut self, ex: &Expr, _: ()) {
118110
check_expr(self, ex);
@@ -203,7 +195,8 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
203195
let v = vec!(*pat);
204196
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
205197
NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
206-
_ => ()
198+
Useful => (),
199+
UsefulWithWitness(_) => unreachable!()
207200
}
208201
if arm.guard.is_none() {
209202
let Matrix(mut rows) = seen;
@@ -223,7 +216,7 @@ fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
223216

224217
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
225218
match is_useful(cx, m, [wild()], ConstructWitness) {
226-
Useful(pats) => {
219+
UsefulWithWitness(pats) => {
227220
let witness = match pats.as_slice() {
228221
[witness] => witness,
229222
[] => wild(),
@@ -234,7 +227,8 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
234227
}
235228
NotUseful => {
236229
// This is good, wildcard pattern isn't reachable
237-
}
230+
},
231+
_ => unreachable!()
238232
}
239233
}
240234

@@ -404,11 +398,14 @@ fn all_constructors(cx: &MatchCheckCtxt, left_ty: ty::t,
404398

405399
// Note: is_useful doesn't work on empty types, as the paper notes.
406400
// So it assumes that v is non-empty.
407-
fn is_useful(cx: &MatchCheckCtxt, m @ &Matrix(ref rows): &Matrix,
401+
fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix,
408402
v: &[Gc<Pat>], witness: WitnessPreference) -> Usefulness {
409-
debug!("{:}", m);
403+
debug!("{:}", matrix);
410404
if rows.len() == 0u {
411-
return Useful(vec!());
405+
return match witness {
406+
ConstructWitness => UsefulWithWitness(vec!()),
407+
LeaveOutWitness => Useful
408+
};
412409
}
413410
if rows.get(0).len() == 0u {
414411
return NotUseful;
@@ -438,53 +435,46 @@ fn is_useful(cx: &MatchCheckCtxt, m @ &Matrix(ref rows): &Matrix,
438435

439436
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
440437
if constructors.is_empty() {
441-
match missing_constructor(cx, m, left_ty, max_slice_length) {
438+
match missing_constructor(cx, matrix, left_ty, max_slice_length) {
442439
None => {
443-
all_constructors(cx, left_ty, max_slice_length).move_iter().filter_map(|c| {
444-
is_useful_specialized(cx, m, v, c.clone(),
445-
left_ty, witness).useful().map(|pats| {
446-
Useful(match witness {
447-
ConstructWitness => {
448-
let arity = constructor_arity(cx, &c, left_ty);
449-
let subpats = {
450-
let pat_slice = pats.as_slice();
451-
Vec::from_fn(arity, |i| {
452-
pat_slice.get(i).map(|p| p.clone())
453-
.unwrap_or_else(|| wild())
454-
})
455-
};
456-
let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
457-
result.extend(pats.move_iter().skip(arity));
458-
result
459-
}
460-
LeaveOutWitness => vec!()
461-
})
462-
})
463-
}).nth(0).unwrap_or(NotUseful)
440+
all_constructors(cx, left_ty, max_slice_length).move_iter().map(|c| {
441+
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
442+
UsefulWithWitness(pats) => UsefulWithWitness({
443+
let arity = constructor_arity(cx, &c, left_ty);
444+
let subpats = {
445+
let pat_slice = pats.as_slice();
446+
Vec::from_fn(arity, |i| {
447+
pat_slice.get(i).map(|p| p.clone())
448+
.unwrap_or_else(|| wild())
449+
})
450+
};
451+
let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
452+
result.extend(pats.move_iter().skip(arity));
453+
result
454+
}),
455+
result => result
456+
}
457+
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
464458
},
465459

466460
Some(constructor) => {
467461
let matrix = Matrix(rows.iter().filter_map(|r|
468462
default(cx, r.as_slice())).collect());
469463
match is_useful(cx, &matrix, v.tail(), witness) {
470-
Useful(pats) => Useful(match witness {
471-
ConstructWitness => {
472-
let arity = constructor_arity(cx, &constructor, left_ty);
473-
let wild_pats = Vec::from_elem(arity, wild());
474-
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
475-
(vec!(enum_pat)).append(pats.as_slice())
476-
}
477-
LeaveOutWitness => vec!()
478-
}),
464+
UsefulWithWitness(pats) => {
465+
let arity = constructor_arity(cx, &constructor, left_ty);
466+
let wild_pats = Vec::from_elem(arity, wild());
467+
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
468+
UsefulWithWitness(vec!(enum_pat).append(pats.as_slice()))
469+
},
479470
result => result
480471
}
481472
}
482473
}
483474
} else {
484-
constructors.move_iter().filter_map(|c| {
485-
is_useful_specialized(cx, m, v, c.clone(), left_ty, witness)
486-
.useful().map(|pats| Useful(pats))
487-
}).nth(0).unwrap_or(NotUseful)
475+
constructors.move_iter().map(|c|
476+
is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness)
477+
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
488478
}
489479
}
490480

@@ -519,6 +509,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
519509
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
520510
vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
521511
},
512+
Some(&DefStruct(_)) => vec!(Single),
522513
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
523514
_ => vec!()
524515
},
@@ -560,21 +551,6 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
560551
}
561552
}
562553

563-
fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
564-
let pat = raw_pat(p);
565-
match pat.node {
566-
PatWild | PatWildMulti => true,
567-
PatIdent(_, _, _) =>
568-
match cx.tcx.def_map.borrow().find(&pat.id) {
569-
Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
570-
_ => true
571-
},
572-
PatVec(ref before, Some(_), ref after) =>
573-
before.is_empty() && after.is_empty(),
574-
_ => false
575-
}
576-
}
577-
578554
/// This computes the arity of a constructor. The arity of a constructor
579555
/// is how many subpattern patterns of that constructor should be expanded to.
580556
///
@@ -780,7 +756,7 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
780756
}
781757

782758
fn default(cx: &MatchCheckCtxt, r: &[Gc<Pat>]) -> Option<Vec<Gc<Pat>>> {
783-
if is_wild(cx, r[0]) {
759+
if pat_is_binding_or_wild(&cx.tcx.def_map, &*raw_pat(r[0])) {
784760
Some(Vec::from_slice(r.tail()))
785761
} else {
786762
None
@@ -833,12 +809,14 @@ fn check_fn(cx: &mut MatchCheckCtxt,
833809

834810
fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
835811
let pats = Matrix(vec!(vec!(pat)));
836-
is_useful(cx, &pats, [wild()], ConstructWitness)
837-
.useful()
838-
.map(|pats| {
812+
match is_useful(cx, &pats, [wild()], ConstructWitness) {
813+
UsefulWithWitness(pats) => {
839814
assert_eq!(pats.len(), 1);
840-
pats.get(0).clone()
841-
})
815+
Some(pats.get(0).clone())
816+
},
817+
NotUseful => None,
818+
Useful => unreachable!()
819+
}
842820
}
843821

844822
// Legality of move bindings checking

src/librustc/middle/trans/_match.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ use middle::trans::cleanup::CleanupMethods;
206206
use middle::trans::common::*;
207207
use middle::trans::consts;
208208
use middle::trans::controlflow;
209-
use middle::trans::datum;
210209
use middle::trans::datum::*;
211210
use middle::trans::expr::Dest;
212211
use middle::trans::expr;
@@ -227,10 +226,8 @@ use syntax::ast::Ident;
227226
use syntax::codemap::Span;
228227
use syntax::parse::token::InternedString;
229228

230-
// An option identifying a literal: either a unit-like struct or an
231-
// expression.
229+
// An option identifying a literal: either an expression or a DefId of a static expression.
232230
enum Lit {
233-
UnitLikeStructLit(ast::NodeId), // the node ID of the pattern
234231
ExprLit(Gc<ast::Expr>),
235232
ConstLit(ast::DefId), // the def ID of the constant
236233
}
@@ -253,14 +250,12 @@ enum Opt {
253250
fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc<ast::Expr> {
254251
match *a {
255252
ExprLit(existing_a_expr) => existing_a_expr,
256-
ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap(),
257-
UnitLikeStructLit(_) => fail!("lit_to_expr: unexpected struct lit"),
253+
ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap()
258254
}
259255
}
260256

261257
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
262258
match (a, b) {
263-
(&lit(UnitLikeStructLit(a)), &lit(UnitLikeStructLit(b))) => a == b,
264259
(&lit(a), &lit(b)) => {
265260
let a_expr = lit_to_expr(tcx, &a);
266261
let b_expr = lit_to_expr(tcx, &b);
@@ -301,11 +296,6 @@ fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
301296
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
302297
return single_result(Result::new(bcx, lit_datum.val));
303298
}
304-
lit(UnitLikeStructLit(pat_id)) => {
305-
let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id);
306-
let datum = datum::rvalue_scratch_datum(bcx, struct_ty, "");
307-
return single_result(Result::new(bcx, datum.val));
308-
}
309299
lit(l @ ConstLit(ref def_id)) => {
310300
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_to_expr(bcx.tcx(), &l).id);
311301
let (llval, _) = consts::get_const_val(bcx.ccx(), *def_id);
@@ -338,9 +328,6 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
338328
let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
339329
var(variant.disr_val, adt::represent_node(bcx, pat_id), var_id)
340330
}
341-
def::DefFn(..) | def::DefStruct(_) => {
342-
lit(UnitLikeStructLit(pat_id))
343-
}
344331
_ => {
345332
ccx.sess().bug("non-variant or struct in variant_opt()");
346333
}
@@ -559,7 +546,6 @@ fn enter_opt<'a, 'b>(
559546
let _indenter = indenter();
560547

561548
let ctor = match opt {
562-
&lit(UnitLikeStructLit(_)) => check_match::Single,
563549
&lit(x) => check_match::ConstantValue(const_eval::eval_const_expr(
564550
bcx.tcx(), lit_to_expr(bcx.tcx(), &x))),
565551
&range(ref lo, ref hi) => check_match::ConstantRange(
@@ -664,11 +650,10 @@ fn get_options(bcx: &Block, m: &[Match], col: uint) -> Vec<Opt> {
664650
add_to_set(ccx.tcx(), &mut found, lit(ExprLit(l)));
665651
}
666652
ast::PatIdent(..) => {
667-
// This is one of: an enum variant, a unit-like struct, or a
668-
// variable binding.
653+
// This is either an enum variant or a variable binding.
669654
let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
670655
match opt_def {
671-
Some(def::DefVariant(..)) | Some(def::DefStruct(..)) => {
656+
Some(def::DefVariant(..)) => {
672657
add_to_set(ccx.tcx(), &mut found,
673658
variant_opt(bcx, cur.id));
674659
}
@@ -819,7 +804,7 @@ fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
819804
let pat = *br.pats.get(col);
820805
match pat.node {
821806
ast::PatTup(_) => true,
822-
ast::PatStruct(_, _, _) | ast::PatEnum(_, _) =>
807+
ast::PatEnum(..) | ast::PatIdent(_, _, None) | ast::PatStruct(..) =>
823808
match bcx.tcx().def_map.borrow().find(&pat.id) {
824809
Some(&def::DefFn(..)) |
825810
Some(&def::DefStruct(..)) => true,

src/test/run-pass/issue-12285.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S;
12+
13+
fn main() {
14+
match Some(&S) {
15+
Some(&S) => {},
16+
_x => unreachable!()
17+
}
18+
match Some(&S) {
19+
Some(&S) => {},
20+
None => unreachable!()
21+
}
22+
}

0 commit comments

Comments
 (0)