@@ -14,7 +14,7 @@ use deriving::{path_local, pathvec_std, path_std};
14
14
use deriving:: generic:: * ;
15
15
use deriving:: generic:: ty:: * ;
16
16
17
- use syntax:: ast:: { self , BinOpKind , Expr , MetaItem } ;
17
+ use syntax:: ast:: { self , BinOpKind , Expr , MetaItem , Ident } ;
18
18
use syntax:: ext:: base:: { Annotatable , ExtCtxt } ;
19
19
use syntax:: ext:: build:: AstBuilder ;
20
20
use syntax:: ptr:: P ;
@@ -147,34 +147,37 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
147
147
// as the outermost one, and the last as the innermost.
148
148
false ,
149
149
|cx, span, old, self_f, other_fs| {
150
- // match new {
151
- // Some(::std::cmp::Ordering::Equal) => old,
152
- // cmp => cmp
153
- // }
150
+ // match new {
151
+ // Some(::std::cmp::Ordering::Equal) => old,
152
+ // cmp => cmp
153
+ // }
154
154
155
- let new = {
156
- let other_f = match ( other_fs. len ( ) , other_fs. get ( 0 ) ) {
157
- ( 1 , Some ( o_f) ) => o_f,
158
- _ => cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" ) ,
159
- } ;
155
+ let new = {
156
+ let other_f = match ( other_fs. len ( ) , other_fs. get ( 0 ) ) {
157
+ ( 1 , Some ( o_f) ) => o_f,
158
+ _ => {
159
+ cx. span_bug ( span,
160
+ "not exactly 2 arguments in `derive(PartialOrd)`" )
161
+ }
162
+ } ;
160
163
161
- let args = vec ! [
162
- cx. expr_addr_of( span, self_f) ,
163
- cx. expr_addr_of( span, other_f. clone( ) ) ,
164
- ] ;
164
+ let args = vec ! [
165
+ cx. expr_addr_of( span, self_f) ,
166
+ cx. expr_addr_of( span, other_f. clone( ) ) ,
167
+ ] ;
165
168
166
- cx. expr_call_global ( span, partial_cmp_path. clone ( ) , args)
167
- } ;
169
+ cx. expr_call_global ( span, partial_cmp_path. clone ( ) , args)
170
+ } ;
168
171
169
- let eq_arm = cx. arm ( span,
170
- vec ! [ cx. pat_some( span, cx. pat_path( span, ordering. clone( ) ) ) ] ,
171
- old) ;
172
- let neq_arm = cx. arm ( span,
173
- vec ! [ cx. pat_ident( span, test_id) ] ,
174
- cx. expr_ident ( span, test_id) ) ;
172
+ let eq_arm = cx. arm ( span,
173
+ vec ! [ cx. pat_some( span, cx. pat_path( span, ordering. clone( ) ) ) ] ,
174
+ old) ;
175
+ let neq_arm = cx. arm ( span,
176
+ vec ! [ cx. pat_ident( span, test_id) ] ,
177
+ cx. expr_ident ( span, test_id) ) ;
175
178
176
- cx. expr_match ( span, new, vec ! [ eq_arm, neq_arm] )
177
- } ,
179
+ cx. expr_match ( span, new, vec ! [ eq_arm, neq_arm] )
180
+ } ,
178
181
equals_expr. clone ( ) ,
179
182
Box :: new ( |cx, span, ( self_args, tag_tuple) , _non_self_args| {
180
183
if self_args. len ( ) != 2 {
@@ -189,78 +192,77 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
189
192
}
190
193
191
194
/// Strict inequality.
192
- fn cs_op ( less : bool , equal : bool , cx : & mut ExtCtxt , span : Span , substr : & Substructure ) -> P < Expr > {
193
- let strict_op = if less { BinOpKind :: Lt } else { BinOpKind :: Gt } ;
194
- cs_fold1 ( false , // need foldr,
195
+ fn cs_op ( less : bool ,
196
+ inclusive : bool ,
197
+ cx : & mut ExtCtxt ,
198
+ span : Span ,
199
+ substr : & Substructure ) -> P < Expr > {
200
+ let ordering_path = |cx : & mut ExtCtxt , name : & str | {
201
+ cx. expr_path ( cx. path_global ( span, cx. std_path ( & [ "cmp" , "Ordering" , name] ) ) )
202
+ } ;
203
+
204
+ let par_cmp = |cx : & mut ExtCtxt , span : Span , self_f : P < Expr > , other_fs : & [ P < Expr > ] | {
205
+ let other_f = match ( other_fs. len ( ) , other_fs. get ( 0 ) ) {
206
+ ( 1 , Some ( o_f) ) => o_f,
207
+ _ => cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" ) ,
208
+ } ;
209
+
210
+ // `self.fi.partial_cmp(other.fi)`
211
+ let cmp = cx. expr_method_call ( span,
212
+ cx. expr_addr_of ( span, self_f) ,
213
+ Ident :: from_str ( "partial_cmp" ) ,
214
+ vec ! [ cx. expr_addr_of( span, other_f. clone( ) ) ] ) ;
215
+
216
+ let default = ordering_path ( cx, if less { "Greater" } else { "Less" } ) ;
217
+ // `_.unwrap_or(Ordering::Greater/Less)`
218
+ cx. expr_method_call ( span, cmp, Ident :: from_str ( "unwrap_or" ) , vec ! [ default ] )
219
+ } ;
220
+
221
+ let fold = cs_fold1 ( false , // need foldr
195
222
|cx, span, subexpr, self_f, other_fs| {
196
- // build up a series of chain ||'s and &&' s from the inside
223
+ // build up a series of `partial_cmp` s from the inside
197
224
// out (hence foldr) to get lexical ordering, i.e. for op ==
198
225
// `ast::lt`
199
226
//
200
227
// ```
201
- // self.f1 < other.f1 || (!( other.f1 < self.f1) &&
202
- // self.f2 < other.f2
203
- // )
228
+ // self.f1.partial_cmp( other.f1).unwrap_or(Ordering::Greater)
229
+ // .then_with(|| self.f2.partial_cmp( other.f2).unwrap_or(Ordering::Greater))
230
+ // == Ordering::Less
204
231
// ```
205
232
//
206
233
// and for op ==
207
234
// `ast::le`
208
235
//
209
236
// ```
210
- // self.f1 < other.f1 || (self.f1 == other.f1 &&
211
- // self.f2 <= other.f2
212
- // )
237
+ // self.f1.partial_cmp( other.f1).unwrap_or(Ordering::Greater)
238
+ // .then_with(|| self.f2.partial_cmp( other.f2).unwrap_or(Ordering::Greater))
239
+ // != Ordering::Greater
213
240
// ```
214
241
//
215
242
// The optimiser should remove the redundancy. We explicitly
216
243
// get use the binops to avoid auto-deref dereferencing too many
217
244
// layers of pointers, if the type includes pointers.
218
- //
219
- let other_f = match ( other_fs. len ( ) , other_fs. get ( 0 ) ) {
220
- ( 1 , Some ( o_f) ) => o_f,
221
- _ => cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" ) ,
222
- } ;
223
245
224
- let strict_ineq = cx. expr_binary ( span, strict_op, self_f. clone ( ) , other_f. clone ( ) ) ;
246
+ // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less)`
247
+ let par_cmp = par_cmp ( cx, span, self_f, other_fs) ;
225
248
226
- let deleg_cmp = if !equal {
227
- cx. expr_unary ( span,
228
- ast:: UnOp :: Not ,
229
- cx. expr_binary ( span, strict_op, other_f. clone ( ) , self_f) )
230
- } else {
231
- cx. expr_binary ( span, BinOpKind :: Eq , self_f, other_f. clone ( ) )
232
- } ;
233
-
234
- let and = cx. expr_binary ( span, BinOpKind :: And , deleg_cmp, subexpr) ;
235
- cx. expr_binary ( span, BinOpKind :: Or , strict_ineq, and)
249
+ // `self.fi.partial_cmp(other.fi).unwrap_or(Ordering::Greater/Less).then_with(...)`
250
+ cx. expr_method_call ( span,
251
+ par_cmp,
252
+ Ident :: from_str ( "then_with" ) ,
253
+ vec ! [ cx. lambda0( span, subexpr) ] )
236
254
} ,
237
255
|cx, args| {
238
256
match args {
239
- Some ( ( span, self_f, other_fs) ) => {
240
- // Special-case the base case to generate cleaner code with
241
- // fewer operations (e.g. `<=` instead of `<` and `==`).
242
- let other_f = match ( other_fs. len ( ) , other_fs. get ( 0 ) ) {
243
- ( 1 , Some ( o_f) ) => o_f,
244
- _ => cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" ) ,
245
- } ;
246
-
247
- let op = match ( less, equal) {
248
- ( false , false ) => BinOpKind :: Gt ,
249
- ( false , true ) => BinOpKind :: Ge ,
250
- ( true , false ) => BinOpKind :: Lt ,
251
- ( true , true ) => BinOpKind :: Le ,
252
- } ;
253
-
254
- cx. expr_binary ( span, op, self_f, other_f. clone ( ) )
255
- }
256
- None => cx. expr_bool ( span, equal)
257
+ Some ( ( span, self_f, other_fs) ) => par_cmp ( cx, span, self_f, other_fs) ,
258
+ None => ordering_path ( cx, if less { "Less" } else { "Equal" } )
257
259
}
258
260
} ,
259
261
Box :: new ( |cx, span, ( self_args, tag_tuple) , _non_self_args| {
260
262
if self_args. len ( ) != 2 {
261
263
cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" )
262
264
} else {
263
- let op = match ( less, equal ) {
265
+ let op = match ( less, inclusive ) {
264
266
( false , false ) => GtOp ,
265
267
( false , true ) => GeOp ,
266
268
( true , false ) => LtOp ,
@@ -271,5 +273,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru
271
273
} ) ,
272
274
cx,
273
275
span,
274
- substr)
276
+ substr) ;
277
+
278
+ match * substr. fields {
279
+ EnumMatching ( ..) |
280
+ Struct ( ..) => {
281
+ let ordering = ordering_path ( cx, if less ^ inclusive { "Less" } else { "Greater" } ) ;
282
+ let comp_op = if inclusive { BinOpKind :: Ne } else { BinOpKind :: Eq } ;
283
+
284
+ cx. expr_binary ( span, comp_op, fold, ordering)
285
+ }
286
+ _ => fold
287
+ }
275
288
}
0 commit comments