2
// cfold.cs: Constant Folding
5
// Miguel de Icaza (miguel@ximian.com)
6
// Marek Safar (marek.safar@seznam.cz)
8
// Copyright 2002, 2003 Ximian, Inc.
9
// Copyright 2003-2008, Novell, Inc.
13
namespace Mono.CSharp {
15
public static class ConstantFold
17
public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
19
return new TypeSpec[] {
20
types.Decimal, types.Double, types.Float,
21
types.ULong, types.Long, types.UInt
26
// Performs the numeric promotions on the left and right expresions
27
// and deposits the results on `lc' and `rc'.
29
// On success, the types of `lc' and `rc' on output will always match,
30
// and the pair will be one of:
32
// TODO: BinaryFold should be called as an optimization step only,
33
// error checking here is weak
35
static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
37
TypeSpec ltype = left.Type;
38
TypeSpec rtype = right.Type;
40
foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
42
return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
45
return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
48
left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
49
right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
50
return left != null && right != null;
53
static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
55
Constant c = prim.ConvertImplicitly (type);
61
if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
62
type = rc.BuiltinTypes.Long;
63
prim = prim.ConvertImplicitly (type);
64
second = second.ConvertImplicitly (type);
65
return prim != null && second != null;
71
internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
73
rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
77
/// Constant expression folder for binary operations.
79
/// Returns null if the expression can not be folded.
81
static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
82
Constant left, Constant right, Location loc)
84
Constant result = null;
86
if (left is EmptyConstantCast)
87
return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
89
if (left is SideEffectConstant) {
90
result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
93
return new SideEffectConstant (result, left, loc);
96
if (right is EmptyConstantCast)
97
return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
99
if (right is SideEffectConstant) {
100
result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
103
return new SideEffectConstant (result, right, loc);
106
TypeSpec lt = left.Type;
107
TypeSpec rt = right.Type;
110
if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) {
111
bool lv = (bool) left.GetValue ();
112
bool rv = (bool) right.GetValue ();
114
case Binary.Operator.BitwiseAnd:
115
case Binary.Operator.LogicalAnd:
116
return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location);
117
case Binary.Operator.BitwiseOr:
118
case Binary.Operator.LogicalOr:
119
return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
120
case Binary.Operator.ExclusiveOr:
121
return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
122
case Binary.Operator.Equality:
123
return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
124
case Binary.Operator.Inequality:
125
return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location);
131
// During an enum evaluation, none of the rules are valid
132
// Not sure whether it is bug in csc or in documentation
134
if (ec.HasSet (ResolveContext.Options.EnumScope)){
135
if (left is EnumConstant)
136
left = ((EnumConstant) left).Child;
138
if (right is EnumConstant)
139
right = ((EnumConstant) right).Child;
140
} else if (left is EnumConstant && rt == lt) {
143
/// E operator |(E x, E y);
144
/// E operator &(E x, E y);
145
/// E operator ^(E x, E y);
147
case Binary.Operator.BitwiseOr:
148
case Binary.Operator.BitwiseAnd:
149
case Binary.Operator.ExclusiveOr:
150
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
152
result = result.TryReduce (ec, lt, loc);
156
/// U operator -(E x, E y);
158
case Binary.Operator.Subtraction:
159
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
161
result = result.TryReduce (ec, EnumSpec.GetUnderlyingType (lt), loc);
165
/// bool operator ==(E x, E y);
166
/// bool operator !=(E x, E y);
167
/// bool operator <(E x, E y);
168
/// bool operator >(E x, E y);
169
/// bool operator <=(E x, E y);
170
/// bool operator >=(E x, E y);
172
case Binary.Operator.Equality:
173
case Binary.Operator.Inequality:
174
case Binary.Operator.LessThan:
175
case Binary.Operator.GreaterThan:
176
case Binary.Operator.LessThanOrEqual:
177
case Binary.Operator.GreaterThanOrEqual:
178
return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
184
case Binary.Operator.BitwiseOr:
186
// bool? operator &(bool? x, bool? y);
188
if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
189
(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
190
var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
192
// false | null => null
193
// null | false => null
194
if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
195
return Nullable.LiftedNull.CreateFromExpression (ec, b);
197
// true | null => true
198
// null | true => true
199
return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b);
202
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
205
if (left is IntConstant){
206
int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
208
return new IntConstant (ec.BuiltinTypes, res, left.Location);
210
if (left is UIntConstant){
211
uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
213
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
215
if (left is LongConstant){
216
long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
218
return new LongConstant (ec.BuiltinTypes, res, left.Location);
220
if (left is ULongConstant){
221
ulong res = ((ULongConstant)left).Value |
222
((ULongConstant)right).Value;
224
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
228
case Binary.Operator.BitwiseAnd:
230
// bool? operator &(bool? x, bool? y);
232
if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
233
(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
234
var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
236
// false & null => false
237
// null & false => false
238
if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
239
return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b);
241
// true & null => null
242
// null & true => null
243
return Nullable.LiftedNull.CreateFromExpression (ec, b);
246
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
250
/// int operator &(int x, int y);
251
/// uint operator &(uint x, uint y);
252
/// long operator &(long x, long y);
253
/// ulong operator &(ulong x, ulong y);
255
if (left is IntConstant){
256
int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
257
return new IntConstant (ec.BuiltinTypes, res, left.Location);
259
if (left is UIntConstant){
260
uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
261
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
263
if (left is LongConstant){
264
long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
265
return new LongConstant (ec.BuiltinTypes, res, left.Location);
267
if (left is ULongConstant){
268
ulong res = ((ULongConstant)left).Value &
269
((ULongConstant)right).Value;
271
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
275
case Binary.Operator.ExclusiveOr:
276
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
279
if (left is IntConstant){
280
int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
281
return new IntConstant (ec.BuiltinTypes, res, left.Location);
283
if (left is UIntConstant){
284
uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
286
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
288
if (left is LongConstant){
289
long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
291
return new LongConstant (ec.BuiltinTypes, res, left.Location);
293
if (left is ULongConstant){
294
ulong res = ((ULongConstant)left).Value ^
295
((ULongConstant)right).Value;
297
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
301
case Binary.Operator.Addition:
302
if (lt == InternalType.NullLiteral)
305
if (rt == InternalType.NullLiteral)
309
// If both sides are strings, then concatenate, if
310
// one is a string, and the other is not, then defer
311
// to runtime concatenation
313
if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
315
return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
322
// handle "E operator + (E x, U y)"
323
// handle "E operator + (Y y, E x)"
325
EnumConstant lc = left as EnumConstant;
326
EnumConstant rc = right as EnumConstant;
327
if (lc != null || rc != null){
334
// U has to be implicitly convetible to E.base
335
right = right.ConvertImplicitly (lc.Child.Type);
339
result = BinaryFold (ec, oper, lc.Child, right, loc);
343
result = result.TryReduce (ec, lt, loc);
347
return new EnumConstant (result, lt);
350
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
354
if (left is DoubleConstant){
357
if (ec.ConstantCheckState)
358
res = checked (((DoubleConstant) left).Value +
359
((DoubleConstant) right).Value);
361
res = unchecked (((DoubleConstant) left).Value +
362
((DoubleConstant) right).Value);
364
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
366
if (left is FloatConstant){
369
if (ec.ConstantCheckState)
370
res = checked (((FloatConstant) left).Value +
371
((FloatConstant) right).Value);
373
res = unchecked (((FloatConstant) left).Value +
374
((FloatConstant) right).Value);
376
result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
377
} else if (left is ULongConstant){
380
if (ec.ConstantCheckState)
381
res = checked (((ULongConstant) left).Value +
382
((ULongConstant) right).Value);
384
res = unchecked (((ULongConstant) left).Value +
385
((ULongConstant) right).Value);
387
result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
388
} else if (left is LongConstant){
391
if (ec.ConstantCheckState)
392
res = checked (((LongConstant) left).Value +
393
((LongConstant) right).Value);
395
res = unchecked (((LongConstant) left).Value +
396
((LongConstant) right).Value);
398
result = new LongConstant (ec.BuiltinTypes, res, left.Location);
399
} else if (left is UIntConstant){
402
if (ec.ConstantCheckState)
403
res = checked (((UIntConstant) left).Value +
404
((UIntConstant) right).Value);
406
res = unchecked (((UIntConstant) left).Value +
407
((UIntConstant) right).Value);
409
result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
410
} else if (left is IntConstant){
413
if (ec.ConstantCheckState)
414
res = checked (((IntConstant) left).Value +
415
((IntConstant) right).Value);
417
res = unchecked (((IntConstant) left).Value +
418
((IntConstant) right).Value);
420
result = new IntConstant (ec.BuiltinTypes, res, left.Location);
421
} else if (left is DecimalConstant) {
424
if (ec.ConstantCheckState)
425
res = checked (((DecimalConstant) left).Value +
426
((DecimalConstant) right).Value);
428
res = unchecked (((DecimalConstant) left).Value +
429
((DecimalConstant) right).Value);
431
result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
433
} catch (OverflowException){
434
Error_CompileTimeOverflow (ec, loc);
439
case Binary.Operator.Subtraction:
441
// handle "E operator - (E x, U y)"
442
// handle "E operator - (Y y, E x)"
444
lc = left as EnumConstant;
445
rc = right as EnumConstant;
446
if (lc != null || rc != null){
453
// U has to be implicitly convetible to E.base
454
right = right.ConvertImplicitly (lc.Child.Type);
458
result = BinaryFold (ec, oper, lc.Child, right, loc);
462
result = result.TryReduce (ec, lt, loc);
466
return new EnumConstant (result, lt);
469
if (left is NullLiteral && right is NullLiteral) {
470
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
471
lifted_int.ResolveAsType (ec);
472
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
475
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
479
if (left is DoubleConstant){
482
if (ec.ConstantCheckState)
483
res = checked (((DoubleConstant) left).Value -
484
((DoubleConstant) right).Value);
486
res = unchecked (((DoubleConstant) left).Value -
487
((DoubleConstant) right).Value);
489
result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
490
} else if (left is FloatConstant){
493
if (ec.ConstantCheckState)
494
res = checked (((FloatConstant) left).Value -
495
((FloatConstant) right).Value);
497
res = unchecked (((FloatConstant) left).Value -
498
((FloatConstant) right).Value);
500
result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
501
} else if (left is ULongConstant){
504
if (ec.ConstantCheckState)
505
res = checked (((ULongConstant) left).Value -
506
((ULongConstant) right).Value);
508
res = unchecked (((ULongConstant) left).Value -
509
((ULongConstant) right).Value);
511
result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
512
} else if (left is LongConstant){
515
if (ec.ConstantCheckState)
516
res = checked (((LongConstant) left).Value -
517
((LongConstant) right).Value);
519
res = unchecked (((LongConstant) left).Value -
520
((LongConstant) right).Value);
522
result = new LongConstant (ec.BuiltinTypes, res, left.Location);
523
} else if (left is UIntConstant){
526
if (ec.ConstantCheckState)
527
res = checked (((UIntConstant) left).Value -
528
((UIntConstant) right).Value);
530
res = unchecked (((UIntConstant) left).Value -
531
((UIntConstant) right).Value);
533
result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
534
} else if (left is IntConstant){
537
if (ec.ConstantCheckState)
538
res = checked (((IntConstant) left).Value -
539
((IntConstant) right).Value);
541
res = unchecked (((IntConstant) left).Value -
542
((IntConstant) right).Value);
544
result = new IntConstant (ec.BuiltinTypes, res, left.Location);
545
} else if (left is DecimalConstant) {
548
if (ec.ConstantCheckState)
549
res = checked (((DecimalConstant) left).Value -
550
((DecimalConstant) right).Value);
552
res = unchecked (((DecimalConstant) left).Value -
553
((DecimalConstant) right).Value);
555
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
557
throw new Exception ( "Unexepected subtraction input: " + left);
559
} catch (OverflowException){
560
Error_CompileTimeOverflow (ec, loc);
565
case Binary.Operator.Multiply:
566
if (left is NullLiteral && right is NullLiteral) {
567
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
568
lifted_int.ResolveAsType (ec);
569
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
572
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
576
if (left is DoubleConstant){
579
if (ec.ConstantCheckState)
580
res = checked (((DoubleConstant) left).Value *
581
((DoubleConstant) right).Value);
583
res = unchecked (((DoubleConstant) left).Value *
584
((DoubleConstant) right).Value);
586
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
587
} else if (left is FloatConstant){
590
if (ec.ConstantCheckState)
591
res = checked (((FloatConstant) left).Value *
592
((FloatConstant) right).Value);
594
res = unchecked (((FloatConstant) left).Value *
595
((FloatConstant) right).Value);
597
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
598
} else if (left is ULongConstant){
601
if (ec.ConstantCheckState)
602
res = checked (((ULongConstant) left).Value *
603
((ULongConstant) right).Value);
605
res = unchecked (((ULongConstant) left).Value *
606
((ULongConstant) right).Value);
608
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
609
} else if (left is LongConstant){
612
if (ec.ConstantCheckState)
613
res = checked (((LongConstant) left).Value *
614
((LongConstant) right).Value);
616
res = unchecked (((LongConstant) left).Value *
617
((LongConstant) right).Value);
619
return new LongConstant (ec.BuiltinTypes, res, left.Location);
620
} else if (left is UIntConstant){
623
if (ec.ConstantCheckState)
624
res = checked (((UIntConstant) left).Value *
625
((UIntConstant) right).Value);
627
res = unchecked (((UIntConstant) left).Value *
628
((UIntConstant) right).Value);
630
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
631
} else if (left is IntConstant){
634
if (ec.ConstantCheckState)
635
res = checked (((IntConstant) left).Value *
636
((IntConstant) right).Value);
638
res = unchecked (((IntConstant) left).Value *
639
((IntConstant) right).Value);
641
return new IntConstant (ec.BuiltinTypes, res, left.Location);
642
} else if (left is DecimalConstant) {
645
if (ec.ConstantCheckState)
646
res = checked (((DecimalConstant) left).Value *
647
((DecimalConstant) right).Value);
649
res = unchecked (((DecimalConstant) left).Value *
650
((DecimalConstant) right).Value);
652
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
654
throw new Exception ( "Unexepected multiply input: " + left);
656
} catch (OverflowException){
657
Error_CompileTimeOverflow (ec, loc);
661
case Binary.Operator.Division:
662
if (left is NullLiteral && right is NullLiteral) {
663
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
664
lifted_int.ResolveAsType (ec);
665
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
668
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
672
if (left is DoubleConstant){
675
if (ec.ConstantCheckState)
676
res = checked (((DoubleConstant) left).Value /
677
((DoubleConstant) right).Value);
679
res = unchecked (((DoubleConstant) left).Value /
680
((DoubleConstant) right).Value);
682
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
683
} else if (left is FloatConstant){
686
if (ec.ConstantCheckState)
687
res = checked (((FloatConstant) left).Value /
688
((FloatConstant) right).Value);
690
res = unchecked (((FloatConstant) left).Value /
691
((FloatConstant) right).Value);
693
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
694
} else if (left is ULongConstant){
697
if (ec.ConstantCheckState)
698
res = checked (((ULongConstant) left).Value /
699
((ULongConstant) right).Value);
701
res = unchecked (((ULongConstant) left).Value /
702
((ULongConstant) right).Value);
704
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
705
} else if (left is LongConstant){
708
if (ec.ConstantCheckState)
709
res = checked (((LongConstant) left).Value /
710
((LongConstant) right).Value);
712
res = unchecked (((LongConstant) left).Value /
713
((LongConstant) right).Value);
715
return new LongConstant (ec.BuiltinTypes, res, left.Location);
716
} else if (left is UIntConstant){
719
if (ec.ConstantCheckState)
720
res = checked (((UIntConstant) left).Value /
721
((UIntConstant) right).Value);
723
res = unchecked (((UIntConstant) left).Value /
724
((UIntConstant) right).Value);
726
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
727
} else if (left is IntConstant){
730
if (ec.ConstantCheckState)
731
res = checked (((IntConstant) left).Value /
732
((IntConstant) right).Value);
734
res = unchecked (((IntConstant) left).Value /
735
((IntConstant) right).Value);
737
return new IntConstant (ec.BuiltinTypes, res, left.Location);
738
} else if (left is DecimalConstant) {
741
if (ec.ConstantCheckState)
742
res = checked (((DecimalConstant) left).Value /
743
((DecimalConstant) right).Value);
745
res = unchecked (((DecimalConstant) left).Value /
746
((DecimalConstant) right).Value);
748
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
750
throw new Exception ( "Unexepected division input: " + left);
752
} catch (OverflowException){
753
Error_CompileTimeOverflow (ec, loc);
755
} catch (DivideByZeroException) {
756
ec.Report.Error (20, loc, "Division by constant zero");
761
case Binary.Operator.Modulus:
762
if (left is NullLiteral && right is NullLiteral) {
763
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
764
lifted_int.ResolveAsType (ec);
765
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
768
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
772
if (left is DoubleConstant){
775
if (ec.ConstantCheckState)
776
res = checked (((DoubleConstant) left).Value %
777
((DoubleConstant) right).Value);
779
res = unchecked (((DoubleConstant) left).Value %
780
((DoubleConstant) right).Value);
782
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
783
} else if (left is FloatConstant){
786
if (ec.ConstantCheckState)
787
res = checked (((FloatConstant) left).Value %
788
((FloatConstant) right).Value);
790
res = unchecked (((FloatConstant) left).Value %
791
((FloatConstant) right).Value);
793
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
794
} else if (left is ULongConstant){
797
if (ec.ConstantCheckState)
798
res = checked (((ULongConstant) left).Value %
799
((ULongConstant) right).Value);
801
res = unchecked (((ULongConstant) left).Value %
802
((ULongConstant) right).Value);
804
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
805
} else if (left is LongConstant){
808
if (ec.ConstantCheckState)
809
res = checked (((LongConstant) left).Value %
810
((LongConstant) right).Value);
812
res = unchecked (((LongConstant) left).Value %
813
((LongConstant) right).Value);
815
return new LongConstant (ec.BuiltinTypes, res, left.Location);
816
} else if (left is UIntConstant){
819
if (ec.ConstantCheckState)
820
res = checked (((UIntConstant) left).Value %
821
((UIntConstant) right).Value);
823
res = unchecked (((UIntConstant) left).Value %
824
((UIntConstant) right).Value);
826
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
827
} else if (left is IntConstant){
830
if (ec.ConstantCheckState)
831
res = checked (((IntConstant) left).Value %
832
((IntConstant) right).Value);
834
res = unchecked (((IntConstant) left).Value %
835
((IntConstant) right).Value);
837
return new IntConstant (ec.BuiltinTypes, res, left.Location);
839
throw new Exception ( "Unexepected modulus input: " + left);
841
} catch (DivideByZeroException){
842
ec.Report.Error (20, loc, "Division by constant zero");
843
} catch (OverflowException){
844
Error_CompileTimeOverflow (ec, loc);
849
// There is no overflow checking on left shift
851
case Binary.Operator.LeftShift:
852
if (left is NullLiteral && right is NullLiteral) {
853
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
854
lifted_int.ResolveAsType (ec);
855
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
858
IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
860
Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
864
int lshift_val = ic.Value;
865
switch (left.Type.BuiltinType) {
866
case BuiltinTypeSpec.Type.ULong:
867
return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
868
case BuiltinTypeSpec.Type.Long:
869
return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
870
case BuiltinTypeSpec.Type.UInt:
871
return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
874
// null << value => null
875
if (left is NullLiteral)
876
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
878
left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
879
if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
880
return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
882
Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
886
// There is no overflow checking on right shift
888
case Binary.Operator.RightShift:
889
if (left is NullLiteral && right is NullLiteral) {
890
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
891
lifted_int.ResolveAsType (ec);
892
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
895
IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
897
Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
900
int rshift_val = sic.Value;
901
switch (left.Type.BuiltinType) {
902
case BuiltinTypeSpec.Type.ULong:
903
return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
904
case BuiltinTypeSpec.Type.Long:
905
return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
906
case BuiltinTypeSpec.Type.UInt:
907
return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
910
// null >> value => null
911
if (left is NullLiteral)
912
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
914
left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
915
if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
916
return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
918
Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
921
case Binary.Operator.Equality:
922
if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
923
(left is Nullable.LiftedNull && right.IsNull) ||
924
(right is Nullable.LiftedNull && left.IsNull)) {
925
if (left.IsNull || right.IsNull) {
926
return ReducedExpression.Create (
927
new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
928
new Binary (oper, left, right, loc));
931
if (left is StringConstant && right is StringConstant)
932
return new BoolConstant (ec.BuiltinTypes,
933
((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
938
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
942
if (left is DoubleConstant)
943
bool_res = ((DoubleConstant) left).Value ==
944
((DoubleConstant) right).Value;
945
else if (left is FloatConstant)
946
bool_res = ((FloatConstant) left).Value ==
947
((FloatConstant) right).Value;
948
else if (left is ULongConstant)
949
bool_res = ((ULongConstant) left).Value ==
950
((ULongConstant) right).Value;
951
else if (left is LongConstant)
952
bool_res = ((LongConstant) left).Value ==
953
((LongConstant) right).Value;
954
else if (left is UIntConstant)
955
bool_res = ((UIntConstant) left).Value ==
956
((UIntConstant) right).Value;
957
else if (left is IntConstant)
958
bool_res = ((IntConstant) left).Value ==
959
((IntConstant) right).Value;
963
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
965
case Binary.Operator.Inequality:
966
if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
967
(left is Nullable.LiftedNull && right.IsNull) ||
968
(right is Nullable.LiftedNull && left.IsNull)) {
969
if (left.IsNull || right.IsNull) {
970
return ReducedExpression.Create (
971
new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
972
new Binary (oper, left, right, loc));
975
if (left is StringConstant && right is StringConstant)
976
return new BoolConstant (ec.BuiltinTypes,
977
((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
982
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
986
if (left is DoubleConstant)
987
bool_res = ((DoubleConstant) left).Value !=
988
((DoubleConstant) right).Value;
989
else if (left is FloatConstant)
990
bool_res = ((FloatConstant) left).Value !=
991
((FloatConstant) right).Value;
992
else if (left is ULongConstant)
993
bool_res = ((ULongConstant) left).Value !=
994
((ULongConstant) right).Value;
995
else if (left is LongConstant)
996
bool_res = ((LongConstant) left).Value !=
997
((LongConstant) right).Value;
998
else if (left is UIntConstant)
999
bool_res = ((UIntConstant) left).Value !=
1000
((UIntConstant) right).Value;
1001
else if (left is IntConstant)
1002
bool_res = ((IntConstant) left).Value !=
1003
((IntConstant) right).Value;
1007
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1009
case Binary.Operator.LessThan:
1010
if (right is NullLiteral) {
1011
if (left is NullLiteral) {
1012
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1013
lifted_int.ResolveAsType (ec);
1014
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1017
if (left is Nullable.LiftedNull) {
1018
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1022
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1026
if (left is DoubleConstant)
1027
bool_res = ((DoubleConstant) left).Value <
1028
((DoubleConstant) right).Value;
1029
else if (left is FloatConstant)
1030
bool_res = ((FloatConstant) left).Value <
1031
((FloatConstant) right).Value;
1032
else if (left is ULongConstant)
1033
bool_res = ((ULongConstant) left).Value <
1034
((ULongConstant) right).Value;
1035
else if (left is LongConstant)
1036
bool_res = ((LongConstant) left).Value <
1037
((LongConstant) right).Value;
1038
else if (left is UIntConstant)
1039
bool_res = ((UIntConstant) left).Value <
1040
((UIntConstant) right).Value;
1041
else if (left is IntConstant)
1042
bool_res = ((IntConstant) left).Value <
1043
((IntConstant) right).Value;
1047
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1049
case Binary.Operator.GreaterThan:
1050
if (right is NullLiteral) {
1051
if (left is NullLiteral) {
1052
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1053
lifted_int.ResolveAsType (ec);
1054
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1057
if (left is Nullable.LiftedNull) {
1058
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1062
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1066
if (left is DoubleConstant)
1067
bool_res = ((DoubleConstant) left).Value >
1068
((DoubleConstant) right).Value;
1069
else if (left is FloatConstant)
1070
bool_res = ((FloatConstant) left).Value >
1071
((FloatConstant) right).Value;
1072
else if (left is ULongConstant)
1073
bool_res = ((ULongConstant) left).Value >
1074
((ULongConstant) right).Value;
1075
else if (left is LongConstant)
1076
bool_res = ((LongConstant) left).Value >
1077
((LongConstant) right).Value;
1078
else if (left is UIntConstant)
1079
bool_res = ((UIntConstant) left).Value >
1080
((UIntConstant) right).Value;
1081
else if (left is IntConstant)
1082
bool_res = ((IntConstant) left).Value >
1083
((IntConstant) right).Value;
1087
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1089
case Binary.Operator.GreaterThanOrEqual:
1090
if (right is NullLiteral) {
1091
if (left is NullLiteral) {
1092
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1093
lifted_int.ResolveAsType (ec);
1094
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1097
if (left is Nullable.LiftedNull) {
1098
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1102
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1106
if (left is DoubleConstant)
1107
bool_res = ((DoubleConstant) left).Value >=
1108
((DoubleConstant) right).Value;
1109
else if (left is FloatConstant)
1110
bool_res = ((FloatConstant) left).Value >=
1111
((FloatConstant) right).Value;
1112
else if (left is ULongConstant)
1113
bool_res = ((ULongConstant) left).Value >=
1114
((ULongConstant) right).Value;
1115
else if (left is LongConstant)
1116
bool_res = ((LongConstant) left).Value >=
1117
((LongConstant) right).Value;
1118
else if (left is UIntConstant)
1119
bool_res = ((UIntConstant) left).Value >=
1120
((UIntConstant) right).Value;
1121
else if (left is IntConstant)
1122
bool_res = ((IntConstant) left).Value >=
1123
((IntConstant) right).Value;
1127
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1129
case Binary.Operator.LessThanOrEqual:
1130
if (right is NullLiteral) {
1131
if (left is NullLiteral) {
1132
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1133
lifted_int.ResolveAsType (ec);
1134
return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1137
if (left is Nullable.LiftedNull) {
1138
return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1142
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1146
if (left is DoubleConstant)
1147
bool_res = ((DoubleConstant) left).Value <=
1148
((DoubleConstant) right).Value;
1149
else if (left is FloatConstant)
1150
bool_res = ((FloatConstant) left).Value <=
1151
((FloatConstant) right).Value;
1152
else if (left is ULongConstant)
1153
bool_res = ((ULongConstant) left).Value <=
1154
((ULongConstant) right).Value;
1155
else if (left is LongConstant)
1156
bool_res = ((LongConstant) left).Value <=
1157
((LongConstant) right).Value;
1158
else if (left is UIntConstant)
1159
bool_res = ((UIntConstant) left).Value <=
1160
((UIntConstant) right).Value;
1161
else if (left is IntConstant)
1162
bool_res = ((IntConstant) left).Value <=
1163
((IntConstant) right).Value;
1167
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);