separate normal coalesce operations from converted coalesce nodes
[mono.git] / mcs / class / System.Core / System.Linq.Expressions / BinaryExpression.cs
1 //
2 // BinaryExpression.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //   Miguel de Icaza (miguel@novell.com)
7 //
8 // Contains code from the Mono C# compiler:
9 //   Marek Safar (marek.safar@seznam.cz)
10 //   Martin Baulig (martin@ximian.com)
11 //   Raja Harinath (harinath@gmail.com)
12 //
13 // (C) 2001-2003 Ximian, Inc.
14 // (C) 2004-2008 Novell, Inc. (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System;
37 using System.Reflection;
38 using System.Reflection.Emit;
39
40 namespace System.Linq.Expressions {
41
42         public sealed class BinaryExpression : Expression {
43
44                 Expression left;
45                 Expression right;
46                 LambdaExpression conversion;
47                 MethodInfo method;
48                 bool lift_to_null, is_lifted;
49
50                 public Expression Left {
51                         get { return left; }
52                 }
53
54                 public Expression Right {
55                         get { return right; }
56                 }
57
58                 public MethodInfo Method {
59                         get { return method; }
60                 }
61
62                 public bool IsLifted {
63                         get { return is_lifted;  }
64                 }
65
66                 public bool IsLiftedToNull {
67                         get { return lift_to_null; }
68                 }
69
70                 public LambdaExpression Conversion {
71                         get { return conversion; }
72                 }
73
74                 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right)
75                         : base (node_type, type)
76                 {
77                         this.left = left;
78                         this.right = right;
79                 }
80
81                 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, MethodInfo method)
82                         : base (node_type, type)
83                 {
84                         this.left = left;
85                         this.right = right;
86                         this.method = method;
87                 }
88
89                 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, bool lift_to_null,
90                         bool is_lifted, MethodInfo method, LambdaExpression conversion) : base (node_type, type)
91                 {
92                         this.left = left;
93                         this.right = right;
94                         this.method = method;
95                         this.conversion = conversion;
96                         this.lift_to_null = lift_to_null;
97                         this.is_lifted = is_lifted;
98                 }
99
100                 void EmitArrayAccess (EmitContext ec)
101                 {
102                         left.Emit (ec);
103                         right.Emit (ec);
104                         ec.ig.Emit (OpCodes.Ldelem, this.Type);
105                 }
106
107                 void EmitLogicalBinary (EmitContext ec)
108                 {
109                         switch (NodeType) {
110                         case ExpressionType.And:
111                         case ExpressionType.Or:
112                                 if (!IsLifted)
113                                         EmitLogical (ec);
114                                 else if (Type == typeof (bool?))
115                                         EmitLiftedLogical (ec);
116                                 else
117                                         EmitLiftedArithmeticBinary (ec);
118                                 break;
119                         case ExpressionType.AndAlso:
120                         case ExpressionType.OrElse:
121                                 if (!IsLifted)
122                                         EmitLogicalShortCircuit (ec);
123                                 else
124                                         EmitLiftedLogicalShortCircuit (ec);
125                                 break;
126                         }
127                 }
128
129                 void EmitLogical (EmitContext ec)
130                 {
131                         EmitNonLiftedBinary (ec);
132                 }
133
134                 void EmitLiftedLogical (EmitContext ec)
135                 {
136                         var ig = ec.ig;
137                         var and = NodeType == ExpressionType.And;
138                         var left = ec.EmitStored (this.left);
139                         var right = ec.EmitStored (this.right);
140
141                         var ret_from_left = ig.DefineLabel ();
142                         var ret_from_right = ig.DefineLabel ();
143                         var done = ig.DefineLabel ();
144
145                         ec.EmitNullableGetValueOrDefault (left);
146                         ig.Emit (OpCodes.Brtrue, ret_from_left);
147                         ec.EmitNullableGetValueOrDefault (right);
148                         ig.Emit (OpCodes.Brtrue, ret_from_right);
149
150                         ec.EmitNullableHasValue (left);
151                         ig.Emit (OpCodes.Brfalse, ret_from_left);
152
153                         ig.MarkLabel (ret_from_right);
154                         ec.EmitLoad (and ? left : right);
155                         ig.Emit (OpCodes.Br, done);
156
157                         ig.MarkLabel (ret_from_left);
158                         ec.EmitLoad (and ? right : left);
159
160                         ig.MarkLabel (done);
161                 }
162
163                 void EmitLogicalShortCircuit (EmitContext ec)
164                 {
165                         var ig = ec.ig;
166                         var and = NodeType == ExpressionType.AndAlso;
167                         var ret = ig.DefineLabel ();
168                         var done = ig.DefineLabel ();
169
170                         ec.Emit (left);
171                         ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret);
172
173                         ec.Emit (right);
174
175                         ig.Emit (OpCodes.Br, done);
176
177                         ig.MarkLabel (ret);
178                         ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
179
180                         ig.MarkLabel (done);
181                 }
182
183                 MethodInfo GetFalseOperator ()
184                 {
185                         return left.Type.GetMethod ("op_False", AllStatic);
186                 }
187
188                 MethodInfo GetTrueOperator ()
189                 {
190                         return left.Type.GetMethod ("op_True", AllStatic);
191                 }
192
193                 void EmitUserDefinedLogicalShortCircuit (EmitContext ec)
194                 {
195                         var ig = ec.ig;
196                         var and = NodeType == ExpressionType.AndAlso;
197
198                         var done = ig.DefineLabel ();
199
200                         var left = ec.EmitStored (this.left);
201
202                         ec.EmitLoad (left);
203                         ig.Emit (OpCodes.Dup);
204                         ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
205                         ig.Emit (OpCodes.Brtrue, done);
206
207                         ec.Emit (this.right);
208                         ec.EmitCall (method);
209
210                         ig.MarkLabel (done);
211                 }
212
213                 void EmitLiftedLogicalShortCircuit (EmitContext ec)
214                 {
215                         var ig = ec.ig;
216                         var and = NodeType == ExpressionType.AndAlso;
217                         var left_is_null = ig.DefineLabel ();
218                         var ret_from_left = ig.DefineLabel ();
219                         var ret_null = ig.DefineLabel ();
220                         var ret_new = ig.DefineLabel();
221                         var done = ig.DefineLabel();
222
223                         var left = ec.EmitStored (this.left);
224
225                         ec.EmitNullableHasValue (left);
226                         ig.Emit (OpCodes.Brfalse, left_is_null);
227
228                         ec.EmitNullableGetValueOrDefault (left);
229
230                         ig.Emit (OpCodes.Ldc_I4_0);
231                         ig.Emit (OpCodes.Ceq);
232                         ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
233
234                         ig.MarkLabel (left_is_null);
235                         var right = ec.EmitStored (this.right);
236
237                         ec.EmitNullableHasValue (right);
238                         ig.Emit (OpCodes.Brfalse_S, ret_null);
239
240                         ec.EmitNullableGetValueOrDefault (right);
241
242                         ig.Emit (OpCodes.Ldc_I4_0);
243                         ig.Emit (OpCodes.Ceq);
244
245                         ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
246
247                         ec.EmitNullableHasValue (left);
248                         ig.Emit (OpCodes.Brfalse, ret_null);
249
250                         ig.Emit (and ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
251                         ig.Emit (OpCodes.Br_S, ret_new);
252
253                         ig.MarkLabel (ret_from_left);
254                         ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
255
256                         ig.MarkLabel (ret_new);
257                         ec.EmitNullableNew (typeof (bool?));
258                         ig.Emit (OpCodes.Br, done);
259
260                         ig.MarkLabel (ret_null);
261                         var ret = ig.DeclareLocal (typeof (bool?));
262                         ec.EmitNullableInitialize (ret);
263
264                         ig.MarkLabel (done);
265                 }
266
267                 void EmitCoalesce (EmitContext ec)
268                 {
269                         var ig = ec.ig;
270                         var done = ig.DefineLabel ();
271                         var load_right = ig.DefineLabel ();
272
273                         var left = ec.EmitStored (this.left);
274                         var left_is_nullable = left.LocalType.IsNullable ();
275
276                         if (left_is_nullable)
277                                 ec.EmitNullableHasValue (left);
278                         else
279                                 ec.EmitLoad (left);
280
281                         ig.Emit (OpCodes.Brfalse, load_right);
282
283                         if (left_is_nullable && !Type.IsNullable ())
284                                 ec.EmitNullableGetValue (left);
285                         else
286                                 ec.EmitLoad (left);
287
288                         ig.Emit (OpCodes.Br, done);
289
290                         ig.MarkLabel (load_right);
291                         ec.Emit (this.right);
292
293                         ig.MarkLabel (done);
294                 }
295
296                 void EmitConvertedCoalesce (EmitContext ec)
297                 {
298                         throw new NotImplementedException ();
299                 }
300
301                 static bool IsInt32OrInt64 (Type type)
302                 {
303                         return type == typeof (int) || type == typeof (long);
304                 }
305
306                 static bool IsSingleOrDouble (Type type)
307                 {
308                         return type == typeof (float) || type == typeof (double);
309                 }
310
311                 void EmitBinaryOperator (EmitContext ec)
312                 {
313                         var ig = ec.ig;
314                         bool is_unsigned = IsUnsigned (left.Type);
315
316                         switch (NodeType) {
317                         case ExpressionType.Add:
318                                 ig.Emit (OpCodes.Add);
319                                 break;
320                         case ExpressionType.AddChecked:
321                                 if (IsInt32OrInt64 (left.Type))
322                                         ig.Emit (OpCodes.Add_Ovf);
323                                 else
324                                         ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
325                                 break;
326                         case ExpressionType.Subtract:
327                                 ig.Emit (OpCodes.Sub);
328                                 break;
329                         case ExpressionType.SubtractChecked:
330                                 if (IsInt32OrInt64 (left.Type))
331                                         ig.Emit (OpCodes.Sub_Ovf);
332                                 else
333                                         ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
334                                 break;
335                         case ExpressionType.Multiply:
336                                 ig.Emit (OpCodes.Mul);
337                                 break;
338                         case ExpressionType.MultiplyChecked:
339                                 if (IsInt32OrInt64 (left.Type))
340                                         ig.Emit (OpCodes.Mul_Ovf);
341                                 else
342                                         ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
343                                 break;
344                         case ExpressionType.Divide:
345                                 ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
346                                 break;
347                         case ExpressionType.Modulo:
348                                 ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
349                                 break;
350                         case ExpressionType.RightShift:
351                                 ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
352                                 break;
353                         case ExpressionType.LeftShift:
354                                 ig.Emit (OpCodes.Shl);
355                                 break;
356                         case ExpressionType.And:
357                                 ig.Emit (OpCodes.And);
358                                 break;
359                         case ExpressionType.Or:
360                                 ig.Emit (OpCodes.Or);
361                                 break;
362                         case ExpressionType.ExclusiveOr:
363                                 ig.Emit (OpCodes.Xor);
364                                 break;
365                         case ExpressionType.GreaterThan:
366                                 ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
367                                 break;
368                         case ExpressionType.GreaterThanOrEqual:
369                                 if (is_unsigned || IsSingleOrDouble (left.Type))
370                                         ig.Emit (OpCodes.Clt_Un);
371                                 else
372                                         ig.Emit (OpCodes.Clt);
373
374                                 ig.Emit (OpCodes.Ldc_I4_0);
375                                 ig.Emit (OpCodes.Ceq);
376                                 break;
377                         case ExpressionType.LessThan:
378                                 ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
379                                 break;
380                         case ExpressionType.LessThanOrEqual:
381                                 if (is_unsigned || IsSingleOrDouble (left.Type))
382                                         ig.Emit (OpCodes.Cgt_Un);
383                                 else
384                                         ig.Emit (OpCodes.Cgt);
385
386                                 ig.Emit (OpCodes.Ldc_I4_0);
387                                 ig.Emit (OpCodes.Ceq);
388                                 break;
389                         case ExpressionType.Equal:
390                                 ig.Emit (OpCodes.Ceq);
391                                 break;
392                         case ExpressionType.NotEqual:
393                                 ig.Emit (OpCodes.Ceq);
394                                 ig.Emit (OpCodes.Ldc_I4_0);
395                                 ig.Emit (OpCodes.Ceq);
396                                 break;
397                         case ExpressionType.Power:
398                                 ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
399                                 break;
400                         default:
401                                 throw new InvalidOperationException (
402                                         string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
403                         }
404                 }
405
406                 bool IsLeftLiftedBinary ()
407                 {
408                         return left.Type.IsNullable () && !right.Type.IsNullable ();
409                 }
410
411                 void EmitLeftLiftedToNullBinary (EmitContext ec)
412                 {
413                         var ig = ec.ig;
414
415                         var ret = ig.DefineLabel ();
416                         var done = ig.DefineLabel ();
417
418                         var left = ec.EmitStored (this.left);
419
420                         ec.EmitNullableHasValue (left);
421                         ig.Emit (OpCodes.Brfalse, ret);
422
423                         ec.EmitNullableGetValueOrDefault (left);
424                         ec.Emit (right);
425
426                         EmitBinaryOperator (ec);
427
428                         ec.EmitNullableNew (Type);
429
430                         ig.Emit (OpCodes.Br, done);
431
432                         ig.MarkLabel (ret);
433
434                         var temp = ig.DeclareLocal (Type);
435                         ec.EmitNullableInitialize (temp);
436
437                         ig.MarkLabel (done);
438                 }
439
440                 void EmitLiftedArithmeticBinary (EmitContext ec)
441                 {
442                         if (IsLeftLiftedBinary ())
443                                 EmitLeftLiftedToNullBinary (ec);
444                         else
445                                 EmitLiftedToNullBinary (ec);
446                 }
447
448                 void EmitLiftedToNullBinary (EmitContext ec)
449                 {
450                         var ig = ec.ig;
451                         var left = ec.EmitStored (this.left);
452                         var right = ec.EmitStored (this.right);
453                         var result = ig.DeclareLocal (Type);
454
455                         var has_value = ig.DefineLabel ();
456                         var done = ig.DefineLabel ();
457
458                         ec.EmitNullableHasValue (left);
459                         ec.EmitNullableHasValue (right);
460                         ig.Emit (OpCodes.And);
461                         ig.Emit (OpCodes.Brtrue, has_value);
462
463                         ec.EmitNullableInitialize (result);
464
465                         ig.Emit (OpCodes.Br, done);
466
467                         ig.MarkLabel (has_value);
468
469                         ec.EmitNullableGetValueOrDefault (left);
470                         ec.EmitNullableGetValueOrDefault (right);
471
472                         EmitBinaryOperator (ec);
473
474                         ec.EmitNullableNew (result.LocalType);
475
476                         ig.MarkLabel (done);
477                 }
478
479                 void EmitLiftedRelationalBinary (EmitContext ec)
480                 {
481                         var ig = ec.ig;
482                         var left = ec.EmitStored (this.left);
483                         var right = ec.EmitStored (this.right);
484
485                         var ret = ig.DefineLabel ();
486                         var done = ig.DefineLabel ();
487
488                         ec.EmitNullableGetValueOrDefault (left);
489                         ec.EmitNullableGetValueOrDefault (right);
490
491                         switch (NodeType) {
492                         case ExpressionType.Equal:
493                         case ExpressionType.NotEqual:
494                                 ig.Emit (OpCodes.Bne_Un, ret);
495                                 break;
496                         default:
497                                 EmitBinaryOperator (ec);
498                                 ig.Emit (OpCodes.Brfalse, ret);
499                                 break;
500                         }
501
502                         ec.EmitNullableHasValue (left);
503                         ec.EmitNullableHasValue (right);
504
505                         switch (NodeType) {
506                         case ExpressionType.Equal:
507                                 ig.Emit (OpCodes.Ceq);
508                                 break;
509                         case ExpressionType.NotEqual:
510                                 ig.Emit (OpCodes.Ceq);
511                                 ig.Emit (OpCodes.Ldc_I4_0);
512                                 ig.Emit (OpCodes.Ceq);
513                                 break;
514                         default:
515                                 ig.Emit (OpCodes.And);
516                                 break;
517                         }
518
519                         ig.Emit (OpCodes.Br, done);
520
521                         ig.MarkLabel (ret);
522
523                         ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
524
525                         ig.MarkLabel (done);
526                 }
527
528                 void EmitArithmeticBinary (EmitContext ec)
529                 {
530                         if (!IsLifted)
531                                 EmitNonLiftedBinary (ec);
532                         else
533                                 EmitLiftedArithmeticBinary (ec);
534                 }
535
536                 void EmitNonLiftedBinary (EmitContext ec)
537                 {
538                         ec.Emit (left);
539                         ec.Emit (right);
540                         EmitBinaryOperator (ec);
541                 }
542
543                 void EmitRelationalBinary (EmitContext ec)
544                 {
545                         if (!IsLifted)
546                                 EmitNonLiftedBinary (ec);
547                         else if (IsLiftedToNull)
548                                 EmitLiftedToNullBinary (ec);
549                         else
550                                 EmitLiftedRelationalBinary (ec);
551                 }
552
553                 void EmitLiftedUserDefinedOperator (EmitContext ec)
554                 {
555                         var ig = ec.ig;
556
557                         var ret_true = ig.DefineLabel ();
558                         var ret_false = ig.DefineLabel ();
559                         var done = ig.DefineLabel ();
560
561                         var left = ec.EmitStored (this.left);
562                         var right = ec.EmitStored (this.right);
563
564                         ec.EmitNullableHasValue (left);
565                         ec.EmitNullableHasValue (right);
566                         switch (NodeType) {
567                         case ExpressionType.Equal:
568                                 ig.Emit (OpCodes.Bne_Un, ret_false);
569                                 ec.EmitNullableHasValue (left);
570                                 ig.Emit (OpCodes.Brfalse, ret_true);
571                                 break;
572                         case ExpressionType.NotEqual:
573                                 ig.Emit (OpCodes.Bne_Un, ret_true);
574                                 ec.EmitNullableHasValue (left);
575                                 ig.Emit (OpCodes.Brfalse, ret_false);
576                                 break;
577                         default:
578                                 ig.Emit (OpCodes.And);
579                                 ig.Emit (OpCodes.Brfalse, ret_false);
580                                 break;
581                         }
582
583                         ec.EmitNullableGetValueOrDefault (left);
584                         ec.EmitNullableGetValueOrDefault (right);
585                         ec.EmitCall (method);
586                         ig.Emit (OpCodes.Br, done);
587
588                         ig.MarkLabel (ret_true);
589                         ig.Emit (OpCodes.Ldc_I4_1);
590                         ig.Emit (OpCodes.Br, done);
591
592                         ig.MarkLabel (ret_false);
593                         ig.Emit (OpCodes.Ldc_I4_0);
594                         ig.Emit (OpCodes.Br, done);
595
596                         ig.MarkLabel (done);
597                 }
598
599                 void EmitLiftedToNullUserDefinedOperator (EmitContext ec)
600                 {
601                         var ig = ec.ig;
602
603                         var ret = ig.DefineLabel ();
604                         var done = ig.DefineLabel ();
605
606                         var left = ec.EmitStored (this.left);
607                         var right = ec.EmitStored (this.right);
608
609                         ec.EmitNullableHasValue (left);
610                         ec.EmitNullableHasValue (right);
611                         ig.Emit (OpCodes.And);
612                         ig.Emit (OpCodes.Brfalse, ret);
613
614                         ec.EmitNullableGetValueOrDefault (left);
615                         ec.EmitNullableGetValueOrDefault (right);
616                         ec.EmitCall (method);
617                         ec.EmitNullableNew (Type);
618                         ig.Emit (OpCodes.Br, done);
619
620                         ig.MarkLabel (ret);
621                         var temp = ig.DeclareLocal (Type);
622                         ec.EmitNullableInitialize (temp);
623
624                         ig.MarkLabel (done);
625                 }
626
627                 void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
628                 {
629                         throw new NotImplementedException ();
630                 }
631
632                 void EmitUserDefinedOperator (EmitContext ec)
633                 {
634                         if (!IsLifted) {
635                                 switch (NodeType) {
636                                 case ExpressionType.AndAlso:
637                                 case ExpressionType.OrElse:
638                                         EmitUserDefinedLogicalShortCircuit (ec);
639                                         break;
640                                 default:
641                                         left.Emit (ec);
642                                         right.Emit (ec);
643                                         ec.EmitCall (method);
644                                         break;
645                                 }
646                         } else if (IsLiftedToNull) {
647                                 switch (NodeType) {
648                                 case ExpressionType.AndAlso:
649                                 case ExpressionType.OrElse:
650                                         EmitUserDefinedLiftedLogicalShortCircuit (ec);
651                                         break;
652                                 default:
653                                         EmitLiftedToNullUserDefinedOperator (ec);
654                                         break;
655                                 }
656                         }  else
657                                 EmitLiftedUserDefinedOperator (ec);
658                 }
659
660                 internal override void Emit (EmitContext ec)
661                 {
662                         if (method != null){
663                                 EmitUserDefinedOperator (ec);
664                                 return;
665                         }
666
667                         switch (NodeType){
668                         case ExpressionType.ArrayIndex:
669                                 EmitArrayAccess (ec);
670                                 return;
671                         case ExpressionType.Coalesce:
672                                 if (conversion != null)
673                                         EmitConvertedCoalesce (ec);
674                                 else
675                                         EmitCoalesce (ec);
676                                 return;
677                         case ExpressionType.Power:
678                         case ExpressionType.Add:
679                         case ExpressionType.AddChecked:
680                         case ExpressionType.Divide:
681                         case ExpressionType.ExclusiveOr:
682                         case ExpressionType.LeftShift:
683                         case ExpressionType.Modulo:
684                         case ExpressionType.Multiply:
685                         case ExpressionType.MultiplyChecked:
686                         case ExpressionType.RightShift:
687                         case ExpressionType.Subtract:
688                         case ExpressionType.SubtractChecked:
689                                 EmitArithmeticBinary (ec);
690                                 return;
691                         case ExpressionType.Equal:
692                         case ExpressionType.GreaterThan:
693                         case ExpressionType.GreaterThanOrEqual:
694                         case ExpressionType.LessThan:
695                         case ExpressionType.LessThanOrEqual:
696                         case ExpressionType.NotEqual:
697                                 EmitRelationalBinary (ec);
698                                 return;
699                         case ExpressionType.And:
700                         case ExpressionType.Or:
701                         case ExpressionType.AndAlso:
702                         case ExpressionType.OrElse:
703                                 EmitLogicalBinary (ec);
704                                 return;
705                         default:
706                                 throw new NotSupportedException (this.NodeType.ToString ());
707                         }
708                 }
709         }
710 }