@@ -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,99 @@ 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, self_f : P < Expr > , other_fs : & [ P < Expr > ] , default| {
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
+ // `PartialOrd::partial_cmp(self.fi, other.fi)`
211
+ let cmp_path = cx. expr_path ( cx. path_global ( span, cx. std_path ( & [ "cmp" ,
212
+ "PartialOrd" ,
213
+ "partial_cmp" ] ) ) ) ;
214
+ let cmp = cx. expr_call ( span,
215
+ cmp_path,
216
+ vec ! [ cx. expr_addr_of( span, self_f) ,
217
+ cx. expr_addr_of( span, other_f. clone( ) ) ] ) ;
218
+
219
+ let default = ordering_path ( cx, default) ;
220
+ // `Option::unwrap_or(_, Ordering::Equal)`
221
+ let unwrap_path = cx. expr_path ( cx. path_global ( span, cx. std_path ( & [ "option" ,
222
+ "Option" ,
223
+ "unwrap_or" ] ) ) ) ;
224
+ cx. expr_call ( span, unwrap_path, vec ! [ cmp, default ] )
225
+ } ;
226
+
227
+ let fold = cs_fold1 ( false , // need foldr
195
228
|cx, span, subexpr, self_f, other_fs| {
196
- // build up a series of chain ||'s and &&' s from the inside
229
+ // build up a series of `partial_cmp` s from the inside
197
230
// out (hence foldr) to get lexical ordering, i.e. for op ==
198
231
// `ast::lt`
199
232
//
200
233
// ```
201
- // self.f1 < other.f1 || (!(other.f1 < self.f1) &&
202
- // self.f2 < other.f2
234
+ // Ordering::then_with(
235
+ // Option::unwrap_or(
236
+ // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
237
+ // ),
238
+ // Option::unwrap_or(
239
+ // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
240
+ // )
203
241
// )
242
+ // == Ordering::Less
204
243
// ```
205
244
//
206
245
// and for op ==
207
246
// `ast::le`
208
247
//
209
248
// ```
210
- // self.f1 < other.f1 || (self.f1 == other.f1 &&
211
- // self.f2 <= other.f2
249
+ // Ordering::then_with(
250
+ // Option::unwrap_or(
251
+ // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
252
+ // ),
253
+ // Option::unwrap_or(
254
+ // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
255
+ // )
212
256
// )
257
+ // != Ordering::Greater
213
258
// ```
214
259
//
215
260
// The optimiser should remove the redundancy. We explicitly
216
261
// get use the binops to avoid auto-deref dereferencing too many
217
262
// 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
263
224
- let strict_ineq = cx. expr_binary ( span, strict_op, self_f. clone ( ) , other_f. clone ( ) ) ;
264
+ // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)`
265
+ let par_cmp = par_cmp ( cx, span, self_f, other_fs, "Equal" ) ;
225
266
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)
267
+ // `Ordering::then_with(Option::unwrap_or(..), ..)`
268
+ let then_with_path = cx. expr_path ( cx. path_global ( span,
269
+ cx. std_path ( & [ "cmp" ,
270
+ "Ordering" ,
271
+ "then_with" ] ) ) ) ;
272
+ cx. expr_call ( span, then_with_path, vec ! [ par_cmp, cx. lambda0( span, subexpr) ] )
236
273
} ,
237
274
|cx, args| {
238
275
match args {
239
276
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)
277
+ let opposite = if less { "Greater" } else { "Less" } ;
278
+ par_cmp ( cx, span, self_f, other_fs, opposite)
279
+ } ,
280
+ None => cx. expr_bool ( span, inclusive)
257
281
}
258
282
} ,
259
283
Box :: new ( |cx, span, ( self_args, tag_tuple) , _non_self_args| {
260
284
if self_args. len ( ) != 2 {
261
285
cx. span_bug ( span, "not exactly 2 arguments in `derive(PartialOrd)`" )
262
286
} else {
263
- let op = match ( less, equal ) {
287
+ let op = match ( less, inclusive ) {
264
288
( false , false ) => GtOp ,
265
289
( false , true ) => GeOp ,
266
290
( true , false ) => LtOp ,
@@ -271,5 +295,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substru
271
295
} ) ,
272
296
cx,
273
297
span,
274
- substr)
298
+ substr) ;
299
+
300
+ match * substr. fields {
301
+ EnumMatching ( .., ref all_fields) |
302
+ Struct ( .., ref all_fields) if !all_fields. is_empty ( ) => {
303
+ let ordering = ordering_path ( cx, if less ^ inclusive { "Less" } else { "Greater" } ) ;
304
+ let comp_op = if inclusive { BinOpKind :: Ne } else { BinOpKind :: Eq } ;
305
+
306
+ cx. expr_binary ( span, comp_op, fold, ordering)
307
+ }
308
+ _ => fold
309
+ }
275
310
}
0 commit comments