Skip to content

Commit 4da1cfe

Browse files
committed
auto merge of #8285 : huonw/rust/deriving+++, r=alexcrichton
Some general clean-up relating to deriving: - `TotalOrd` was too eager, and evaluated the `.cmp` call for every field, even if it could short-circuit earlier. - the pointer types didn't have impls for `TotalOrd` or `TotalEq`. - the Makefiles didn't reach deep enough into libsyntax for dependencies. (Split out from #8258.)
2 parents 62dbdc4 + 4f3944a commit 4da1cfe

File tree

7 files changed

+143
-20
lines changed

7 files changed

+143
-20
lines changed

Makefile.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \
297297

298298
LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs
299299
LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
300-
*.rs */*.rs */*/*.rs))
300+
*.rs */*.rs */*/*.rs */*/*/*.rs))
301301

302302
DRIVER_CRATE := $(S)src/driver/driver.rs
303303

src/libstd/borrow.rs

+12
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,15 @@ impl<'self, T: Ord> Ord for &'self T {
5858
*(*self) > *(*other)
5959
}
6060
}
61+
62+
#[cfg(not(test))]
63+
impl<'self, T: TotalOrd> TotalOrd for &'self T {
64+
#[inline]
65+
fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
66+
}
67+
68+
#[cfg(not(test))]
69+
impl<'self, T: TotalEq> TotalEq for &'self T {
70+
#[inline]
71+
fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
72+
}

src/libstd/cmp.rs

-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ pub fn cmp2<A:TotalOrd,B:TotalOrd>(
153153
Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the
154154
lexical ordering on a type `(int, int)`.
155155
*/
156-
// used in deriving code in libsyntax
157156
#[inline]
158157
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
159158
match o1 {

src/libstd/managed.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
use ptr::to_unsafe_ptr;
1414

15-
#[cfg(not(test))] use cmp::{Eq, Ord};
15+
#[cfg(not(test))] use cmp::*;
1616

1717
pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
1818
pub static RC_IMMORTAL : uint = 0x77777777;
@@ -71,6 +71,29 @@ impl<T:Ord> Ord for @mut T {
7171
fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
7272
}
7373

74+
#[cfg(not(test))]
75+
impl<T: TotalOrd> TotalOrd for @T {
76+
#[inline]
77+
fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
78+
}
79+
80+
#[cfg(not(test))]
81+
impl<T: TotalOrd> TotalOrd for @mut T {
82+
#[inline]
83+
fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) }
84+
}
85+
86+
#[cfg(not(test))]
87+
impl<T: TotalEq> TotalEq for @T {
88+
#[inline]
89+
fn equals(&self, other: &@T) -> bool { (**self).equals(*other) }
90+
}
91+
92+
#[cfg(not(test))]
93+
impl<T: TotalEq> TotalEq for @mut T {
94+
#[inline]
95+
fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) }
96+
}
7497
#[test]
7598
fn test() {
7699
let x = @3;

src/libstd/owned.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! Operations on unique pointer types
1212
13-
#[cfg(not(test))] use cmp::{Eq, Ord};
13+
#[cfg(not(test))] use cmp::*;
1414

1515
#[cfg(not(test))]
1616
impl<T:Eq> Eq for ~T {
@@ -31,3 +31,15 @@ impl<T:Ord> Ord for ~T {
3131
#[inline]
3232
fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
3333
}
34+
35+
#[cfg(not(test))]
36+
impl<T: TotalOrd> TotalOrd for ~T {
37+
#[inline]
38+
fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) }
39+
}
40+
41+
#[cfg(not(test))]
42+
impl<T: TotalEq> TotalEq for ~T {
43+
#[inline]
44+
fn equals(&self, other: &~T) -> bool { (**self).equals(*other) }
45+
}

src/libsyntax/ext/deriving/cmp/totalord.rs

+47-16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use ast;
1112
use ast::{MetaItem, item, expr};
1213
use codemap::span;
1314
use ext::base::ExtCtxt;
@@ -40,40 +41,70 @@ pub fn expand_deriving_totalord(cx: @ExtCtxt,
4041
}
4142

4243

43-
pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> @expr {
44+
pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> ast::Path {
4445
let cnst = match cnst {
4546
Less => "Less",
4647
Equal => "Equal",
4748
Greater => "Greater"
4849
};
49-
cx.expr_path(
50-
cx.path_global(span,
51-
~[cx.ident_of("std"),
52-
cx.ident_of("cmp"),
53-
cx.ident_of(cnst)]))
50+
cx.path_global(span,
51+
~[cx.ident_of("std"),
52+
cx.ident_of("cmp"),
53+
cx.ident_of(cnst)])
5454
}
5555

5656
pub fn cs_cmp(cx: @ExtCtxt, span: span,
5757
substr: &Substructure) -> @expr {
58+
let test_id = cx.ident_of("__test");
59+
let equals_path = ordering_const(cx, span, Equal);
5860

61+
/*
62+
Builds:
63+
64+
let __test = self_field1.cmp(&other_field2);
65+
if other == ::std::cmp::Equal {
66+
let __test = self_field2.cmp(&other_field2);
67+
if __test == ::std::cmp::Equal {
68+
...
69+
} else {
70+
__test
71+
}
72+
} else {
73+
__test
74+
}
75+
76+
FIXME #6449: These `if`s could/should be `match`es.
77+
*/
5978
cs_same_method_fold(
60-
// foldr (possibly) nests the matches in lexical_ordering better
79+
// foldr nests the if-elses correctly, leaving the first field
80+
// as the outermost one, and the last as the innermost.
6181
false,
6282
|cx, span, old, new| {
63-
cx.expr_call_global(span,
64-
~[cx.ident_of("std"),
65-
cx.ident_of("cmp"),
66-
cx.ident_of("lexical_ordering")],
67-
~[old, new])
83+
// let __test = new;
84+
// if __test == ::std::cmp::Equal {
85+
// old
86+
// } else {
87+
// __test
88+
// }
89+
90+
let assign = cx.stmt_let(span, false, test_id, new);
91+
92+
let cond = cx.expr_binary(span, ast::eq,
93+
cx.expr_ident(span, test_id),
94+
cx.expr_path(equals_path.clone()));
95+
let if_ = cx.expr_if(span,
96+
cond,
97+
old, Some(cx.expr_ident(span, test_id)));
98+
cx.expr_block(cx.block(span, ~[assign], Some(if_)))
6899
},
69-
ordering_const(cx, span, Equal),
100+
cx.expr_path(equals_path.clone()),
70101
|cx, span, list, _| {
71102
match list {
72103
// an earlier nonmatching variant is Less than a
73-
// later one
104+
// later one.
74105
[(self_var, _, _),
75-
(other_var, _, _)] => ordering_const(cx, span,
76-
self_var.cmp(&other_var)),
106+
(other_var, _, _)] => cx.expr_path(ordering_const(cx, span,
107+
self_var.cmp(&other_var))),
77108
_ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`")
78109
}
79110
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2013 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+
// check that the derived impls for the comparison traits shortcircuit
12+
// where possible, by having a type that fails when compared as the
13+
// second element, so this passes iff the instances shortcircuit.
14+
15+
pub struct FailCmp;
16+
impl Eq for FailCmp {
17+
fn eq(&self, _: &FailCmp) -> bool { fail!("eq") }
18+
}
19+
20+
impl Ord for FailCmp {
21+
fn lt(&self, _: &FailCmp) -> bool { fail!("lt") }
22+
}
23+
24+
impl TotalEq for FailCmp {
25+
fn equals(&self, _: &FailCmp) -> bool { fail!("equals") }
26+
}
27+
28+
impl TotalOrd for FailCmp {
29+
fn cmp(&self, _: &FailCmp) -> Ordering { fail!("cmp") }
30+
}
31+
32+
#[deriving(Eq,Ord,TotalEq,TotalOrd)]
33+
struct ShortCircuit {
34+
x: int,
35+
y: FailCmp
36+
}
37+
38+
fn main() {
39+
let a = ShortCircuit { x: 1, y: FailCmp };
40+
let b = ShortCircuit { x: 2, y: FailCmp };
41+
42+
assert!(a != b);
43+
assert!(a < b);
44+
assert!(!a.equals(&b));
45+
assert_eq!(a.cmp(&b), ::std::cmp::Less);
46+
}

0 commit comments

Comments
 (0)