Skip to content

Commit 3d0a457

Browse files
committed
---
yaml --- r: 105178 b: refs/heads/snap-stage3 c: 25e5238 h: refs/heads/master v: v3
1 parent fad1e33 commit 3d0a457

File tree

11 files changed

+340
-115
lines changed

11 files changed

+340
-115
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 62f1d68439dcfd509eaca29887afa97f22938373
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 5258e13d0b5ed1fb201579115d618728ab0b69c0
4+
refs/heads/snap-stage3: 25e523833e16c291618c624c1c44c4705b77d6ff
55
refs/heads/try: db814977d07bd798feb24f6b74c00800ef458a13
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/librustc/middle/trans/_match.rs

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -256,43 +256,23 @@ enum Opt {
256256
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
257257
}
258258

259+
fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> @ast::Expr {
260+
match *a {
261+
ExprLit(existing_a_expr) => existing_a_expr,
262+
ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap(),
263+
UnitLikeStructLit(_) => fail!("lit_to_expr: unexpected struct lit"),
264+
}
265+
}
266+
259267
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
260268
match (a, b) {
269+
(&lit(UnitLikeStructLit(a)), &lit(UnitLikeStructLit(b))) => a == b,
261270
(&lit(a), &lit(b)) => {
262-
match (a, b) {
263-
(UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b,
264-
_ => {
265-
let a_expr;
266-
match a {
267-
ExprLit(existing_a_expr) => a_expr = existing_a_expr,
268-
ConstLit(a_const) => {
269-
let e = const_eval::lookup_const_by_id(tcx, a_const);
270-
a_expr = e.unwrap();
271-
}
272-
UnitLikeStructLit(_) => {
273-
fail!("UnitLikeStructLit should have been handled \
274-
above")
275-
}
276-
}
277-
278-
let b_expr;
279-
match b {
280-
ExprLit(existing_b_expr) => b_expr = existing_b_expr,
281-
ConstLit(b_const) => {
282-
let e = const_eval::lookup_const_by_id(tcx, b_const);
283-
b_expr = e.unwrap();
284-
}
285-
UnitLikeStructLit(_) => {
286-
fail!("UnitLikeStructLit should have been handled \
287-
above")
288-
}
289-
}
290-
291-
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
292-
Some(val1) => val1 == 0,
293-
None => fail!("compare_list_exprs: type mismatch"),
294-
}
295-
}
271+
let a_expr = lit_to_expr(tcx, &a);
272+
let b_expr = lit_to_expr(tcx, &b);
273+
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
274+
Some(val1) => val1 == 0,
275+
None => fail!("compare_list_exprs: type mismatch"),
296276
}
297277
}
298278
(&range(a1, a2), &range(b1, b2)) => {
@@ -310,6 +290,42 @@ fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
310290
}
311291
}
312292

293+
fn opt_overlap(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
294+
match (a, b) {
295+
(&lit(a), &lit(b)) => {
296+
let a_expr = lit_to_expr(tcx, &a);
297+
let b_expr = lit_to_expr(tcx, &b);
298+
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
299+
Some(val1) => val1 == 0,
300+
None => fail!("opt_overlap: type mismatch"),
301+
}
302+
}
303+
304+
(&range(a1, a2), &range(b1, b2)) => {
305+
let m1 = const_eval::compare_lit_exprs(tcx, a1, b2);
306+
let m2 = const_eval::compare_lit_exprs(tcx, b1, a2);
307+
match (m1, m2) {
308+
// two ranges [a1, a2] and [b1, b2] overlap iff:
309+
// a1 <= b2 && b1 <= a2
310+
(Some(val1), Some(val2)) => (val1 <= 0 && val2 <= 0),
311+
_ => fail!("opt_overlap: type mismatch"),
312+
}
313+
}
314+
315+
(&range(a1, a2), &lit(b)) | (&lit(b), &range(a1, a2)) => {
316+
let b_expr = lit_to_expr(tcx, &b);
317+
let m1 = const_eval::compare_lit_exprs(tcx, a1, b_expr);
318+
let m2 = const_eval::compare_lit_exprs(tcx, a2, b_expr);
319+
match (m1, m2) {
320+
// b is in range [a1, a2] iff a1 <= b and b <= a2
321+
(Some(val1), Some(val2)) => (val1 <= 0 && 0 <= val2),
322+
_ => fail!("opt_overlap: type mismatch"),
323+
}
324+
}
325+
_ => fail!("opt_overlap: expect lit or range")
326+
}
327+
}
328+
313329
pub enum opt_result<'a> {
314330
single_result(Result<'a>),
315331
lower_bound(Result<'a>),
@@ -490,7 +506,7 @@ fn assert_is_binding_or_wild(bcx: &Block, p: @ast::Pat) {
490506
}
491507
}
492508

493-
type enter_pat<'a> = 'a |@ast::Pat| -> Option<Vec<@ast::Pat> >;
509+
type enter_pat<'a> = 'a |@ast::Pat| -> Option<Vec<@ast::Pat>>;
494510

495511
fn enter_match<'r,'b>(
496512
bcx: &'b Block<'b>,
@@ -632,16 +648,30 @@ fn enter_opt<'r,'b>(
632648
let tcx = bcx.tcx();
633649
let dummy = @ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
634650
let mut i = 0;
651+
// By the virtue of fact that we are in `trans` already, `enter_opt` is able
652+
// to prune sub-match tree aggressively based on exact equality. But when it
653+
// comes to literal or range, that strategy may lead to wrong result if there
654+
// are guard function or multiple patterns inside tuple; in that case, pruning
655+
// based on the overlap of patterns is required.
656+
//
657+
// Ideally, when constructing the sub-match tree for certain arm, only those
658+
// arms beneath it matter. But that isn't how algorithm works right now and
659+
// all other arms are taken into consideration when computing `guarded` below.
660+
// That is ok since each round of `compile_submatch` guarantees to trim one
661+
// "column" of arm patterns and the algorithm will converge.
662+
let guarded = m.iter().any(|x| x.data.arm.guard.is_some());
663+
let multi_pats = m.len() > 0 && m[0].pats.len() > 1;
635664
enter_match(bcx, tcx.def_map, m, col, val, |p| {
636665
let answer = match p.node {
637666
ast::PatEnum(..) |
638667
ast::PatIdent(_, _, None) if pat_is_const(tcx.def_map, p) => {
639668
let const_def = tcx.def_map.borrow().get_copy(&p.id);
640669
let const_def_id = ast_util::def_id_of_def(const_def);
641-
if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) {
642-
Some(Vec::new())
643-
} else {
644-
None
670+
let konst = lit(ConstLit(const_def_id));
671+
match guarded || multi_pats {
672+
false if opt_eq(tcx, &konst, opt) => Some(Vec::new()),
673+
true if opt_overlap(tcx, &konst, opt) => Some(Vec::new()),
674+
_ => None,
645675
}
646676
}
647677
ast::PatEnum(_, ref subpats) => {
@@ -666,10 +696,20 @@ fn enter_opt<'r,'b>(
666696
}
667697
}
668698
ast::PatLit(l) => {
669-
if opt_eq(tcx, &lit(ExprLit(l)), opt) {Some(Vec::new())} else {None}
699+
let lit_expr = lit(ExprLit(l));
700+
match guarded || multi_pats {
701+
false if opt_eq(tcx, &lit_expr, opt) => Some(Vec::new()),
702+
true if opt_overlap(tcx, &lit_expr, opt) => Some(Vec::new()),
703+
_ => None,
704+
}
670705
}
671706
ast::PatRange(l1, l2) => {
672-
if opt_eq(tcx, &range(l1, l2), opt) {Some(Vec::new())} else {None}
707+
let rng = range(l1, l2);
708+
match guarded || multi_pats {
709+
false if opt_eq(tcx, &rng, opt) => Some(Vec::new()),
710+
true if opt_overlap(tcx, &rng, opt) => Some(Vec::new()),
711+
_ => None,
712+
}
673713
}
674714
ast::PatStruct(_, ref field_pats, _) => {
675715
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {

branches/snap-stage3/src/libsyntax/parse/parser.rs

Lines changed: 18 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,6 @@ pub enum PathParsingMode {
111111
LifetimeAndTypesAndBounds,
112112
}
113113

114-
/// A pair of a path segment and group of type parameter bounds. (See `ast.rs`
115-
/// for the definition of a path segment.)
116-
struct PathSegmentAndBoundSet {
117-
segment: ast::PathSegment,
118-
bound_set: Option<OwnedSlice<TyParamBound>>,
119-
}
120-
121114
/// A path paired with optional type bounds.
122115
pub struct PathAndBounds {
123116
path: ast::Path,
@@ -1514,24 +1507,14 @@ impl<'a> Parser<'a> {
15141507
// First, parse an identifier.
15151508
let identifier = self.parse_ident();
15161509

1517-
// Next, parse a colon and bounded type parameters, if applicable.
1518-
let bound_set = if mode == LifetimeAndTypesAndBounds {
1519-
self.parse_optional_ty_param_bounds()
1520-
} else {
1521-
None
1522-
};
1523-
15241510
// Parse the '::' before type parameters if it's required. If
15251511
// it is required and wasn't present, then we're done.
15261512
if mode == LifetimeAndTypesWithColons &&
15271513
!self.eat(&token::MOD_SEP) {
1528-
segments.push(PathSegmentAndBoundSet {
1529-
segment: ast::PathSegment {
1530-
identifier: identifier,
1531-
lifetimes: Vec::new(),
1532-
types: OwnedSlice::empty(),
1533-
},
1534-
bound_set: bound_set
1514+
segments.push(ast::PathSegment {
1515+
identifier: identifier,
1516+
lifetimes: Vec::new(),
1517+
types: OwnedSlice::empty(),
15351518
});
15361519
break
15371520
}
@@ -1548,13 +1531,10 @@ impl<'a> Parser<'a> {
15481531
};
15491532

15501533
// Assemble and push the result.
1551-
segments.push(PathSegmentAndBoundSet {
1552-
segment: ast::PathSegment {
1553-
identifier: identifier,
1554-
lifetimes: lifetimes,
1555-
types: types,
1556-
},
1557-
bound_set: bound_set
1534+
segments.push(ast::PathSegment {
1535+
identifier: identifier,
1536+
lifetimes: lifetimes,
1537+
types: types,
15581538
});
15591539

15601540
// We're done if we don't see a '::', unless the mode required
@@ -1567,42 +1547,25 @@ impl<'a> Parser<'a> {
15671547
}
15681548
}
15691549

1550+
// Next, parse a colon and bounded type parameters, if applicable.
1551+
let bounds = if mode == LifetimeAndTypesAndBounds {
1552+
self.parse_optional_ty_param_bounds()
1553+
} else {
1554+
None
1555+
};
1556+
15701557
// Assemble the span.
15711558
let span = mk_sp(lo, self.last_span.hi);
15721559

1573-
// Assemble the path segments.
1574-
let mut path_segments = Vec::new();
1575-
let mut bounds = None;
1576-
let last_segment_index = segments.len() - 1;
1577-
for (i, segment_and_bounds) in segments.move_iter().enumerate() {
1578-
let PathSegmentAndBoundSet {
1579-
segment: segment,
1580-
bound_set: bound_set
1581-
} = segment_and_bounds;
1582-
path_segments.push(segment);
1583-
1584-
if bound_set.is_some() {
1585-
if i != last_segment_index {
1586-
self.span_err(span,
1587-
"type parameter bounds are allowed only \
1588-
before the last segment in a path")
1589-
}
1590-
1591-
bounds = bound_set
1592-
}
1593-
}
1594-
15951560
// Assemble the result.
1596-
let path_and_bounds = PathAndBounds {
1561+
PathAndBounds {
15971562
path: ast::Path {
15981563
span: span,
15991564
global: is_global,
1600-
segments: path_segments,
1565+
segments: segments,
16011566
},
16021567
bounds: bounds,
1603-
};
1604-
1605-
path_and_bounds
1568+
}
16061569
}
16071570

16081571
/// parses 0 or 1 lifetime

branches/snap-stage3/src/libsyntax/print/pprust.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,7 @@ impl<'a> State<'a> {
15261526
}
15271527

15281528
let mut first = true;
1529-
for (i, segment) in path.segments.iter().enumerate() {
1529+
for segment in path.segments.iter() {
15301530
if first {
15311531
first = false
15321532
} else {
@@ -1535,14 +1535,6 @@ impl<'a> State<'a> {
15351535

15361536
try!(self.print_ident(segment.identifier));
15371537

1538-
// If this is the last segment, print the bounds.
1539-
if i == path.segments.len() - 1 {
1540-
match *opt_bounds {
1541-
None => {}
1542-
Some(ref bounds) => try!(self.print_bounds(bounds, true)),
1543-
}
1544-
}
1545-
15461538
if !segment.lifetimes.is_empty() || !segment.types.is_empty() {
15471539
if colons_before_params {
15481540
try!(word(&mut self.s, "::"))
@@ -1571,7 +1563,11 @@ impl<'a> State<'a> {
15711563
try!(word(&mut self.s, ">"))
15721564
}
15731565
}
1574-
Ok(())
1566+
1567+
match *opt_bounds {
1568+
None => Ok(()),
1569+
Some(ref bounds) => self.print_bounds(bounds, true),
1570+
}
15751571
}
15761572

15771573
fn print_path(&mut self, path: &ast::Path,

branches/snap-stage3/src/test/compile-fail/kindck-owned-trait-contains.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ impl<A:Clone> Repeat<A> for A {
1414
fn get(&self) -> A { self.clone() }
1515
}
1616

17-
fn repeater<A:Clone>(v: A) -> ~Repeat:<A> {
18-
~v as ~Repeat:<A> // No
17+
fn repeater<A:Clone>(v: A) -> ~Repeat<A>: {
18+
~v as ~Repeat<A>: // No
1919
}
2020

2121
fn main() {

branches/snap-stage3/src/test/run-pass/alignment-gep-tup-like-1.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ impl<A:Clone> Invokable<A> for Invoker<A> {
2727
}
2828
}
2929

30-
fn f<A:Clone + 'static>(a: A, b: u16) -> ~Invokable:<A> {
30+
fn f<A:Clone + 'static>(a: A, b: u16) -> ~Invokable<A>: {
3131
~Invoker {
3232
a: a,
3333
b: b,
34-
} as ~Invokable:<A>
34+
} as ~Invokable<A>:
3535
}
3636

3737
pub fn main() {

branches/snap-stage3/src/test/run-pass/close-over-big-then-small-data.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ impl<A:Clone> Invokable<A> for Invoker<A> {
3131
}
3232
}
3333

34-
fn f<A:Clone + 'static>(a: A, b: u16) -> ~Invokable:<A> {
34+
fn f<A:Clone + 'static>(a: A, b: u16) -> ~Invokable<A>: {
3535
~Invoker {
3636
a: a,
3737
b: b,
38-
} as ~Invokable:<A>
38+
} as ~Invokable<A>:
3939
}
4040

4141
pub fn main() {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2012-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+
pub fn main() {
12+
let x = 1;
13+
let y = 2;
14+
15+
assert_eq!(3, match (x, y) {
16+
(1, 1) => 1,
17+
(2, 2) => 2,
18+
(1..2, 2) => 3,
19+
_ => 4,
20+
});
21+
22+
// nested tuple
23+
assert_eq!(3, match ((x, y),) {
24+
((1, 1),) => 1,
25+
((2, 2),) => 2,
26+
((1..2, 2),) => 3,
27+
_ => 4,
28+
});
29+
}

0 commit comments

Comments
 (0)